Search code examples
c#timermcisendstring

C# ISynchronizeInvoke 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.


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.