Question

At the risk of sounding like a total noob, how do I implement ISynchronizeInvoke on a System.Timers.Timer?

I have a class (no UI) that is making calls to mciSendString. I have a timer that is supposed to poll for the current status. All of the calls from the class work, but not the ones coming from the timers elapsed event. I've tracked it down to being on a different thread, but I've not gotten any further than that. I think I need to invoke a delegate on the same thread as the class, but I haven't had any luck accomplishing it yet.

Code Sample:

    [DllImport("winmm.dll")]
    private static extern Int32 mciSendString(string command, StringBuilder buffer, Int32 bufferSize, IntPtr hwndCallback);

    public cPlayer()
    {
        tmrPoll = new System.Timers.Timer(1000);
        tmrPoll.Enabled = false;
        tmrPoll.Elapsed += new ElapsedEventHandler(tmrPoll_tick);
    }

    public void tmrPoll_tick(object source, ElapsedEventArgs e)
    {
        Poll();
    }

    private void Poll()
    {
        Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
        tmrPoll.Stop();
        int res = 0;

        res = mciSendString("status MediaFile position", _sbBuffer, _sbBuffer.Capacity, IntPtr.Zero);
        if (res == 0) _position = int.Parse(_sbBuffer.ToString());
        if (res == 0)
        {
            Console.WriteLine("Position = " + _sbBuffer.ToString());
        } else {
            Console.WriteLine("Failed:  Error " + res.ToString());
        }

        res = mciSendString("status MediaFile length", _sbBuffer, _sbBuffer.Capacity, IntPtr.Zero);
        if (res == 0) Console.WriteLine("Length = " + _sbBuffer.ToString());
        if (res == 0) _length = int.Parse(_sbBuffer.ToString());

        res = mciSendString("status MediaFile mode", _sbBuffer, _sbBuffer.Capacity, IntPtr.Zero);
        if (res == 0) Console.WriteLine("Mode = " + _sbBuffer.ToString());
    }

    private void SendCommand(string cmd)
    {
        mciSendString(cmd, null, 0, IntPtr.Zero);
        Poll();

    }

For clarification, if I call from SendCommand (whatever it may be, Play, Stop, etc.) it works and the result of Poll() is what I'd expect. When the timer fires, the result (res) is 263 which is MCIERR_INVALID_DEVICE_NAME. The threadID on the failed call is different from the one that succeeds, that's why I figured I needed to use ISynchronizeInvoke.

Was it helpful?

Solution

I got an answer over at the msdn forum. Someone left me a message with a link to codeplex (nito.async). I used the GenericSynchronizingObject to get the job done.

OTHER TIPS

What is the error code that you are getting? I imagine part of it has to do with the hwndCallback parameter, but without seeing any code samples, it's hard to tell.

However, you don't need to implement ISynchronizeInvoke here. You might have to call it if you are passing a window handle for the callback. In that case, you will need to call the Invoke method on the managed representation that implements ISynchronizeInvoke. In other words, the control/form that you got the handle from.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top