SW Sam

I need a timer with the resolution of the multi media timer and the timeSetEvent function but it is not supported with CLR.

Is there an alternative with CLR

If not, Is there a way to use the multi media timer with CLR and be able to pass a managed object as an argument to the timeSetEvent call to be used in the timer callback

Thanks,

Sam



Re: Visual C# General Using multimedia timer with managed C++

nobugz

Here's a sample application that uses timeSetEvent(). A couple of problem I ran into when developing it. The IDE debugger can't handle the callback, avoid breakpoints in that code. I had trouble shutting down the timer with timeKillEvent(); calling Invoke() caused a strange ObjectDisposedException and asking for a synchronous kill just hung the program. Please post back any improvements you make. Good luck!


using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication1 {
public partial class Form1 : Form {
private int mTimerId;
private TimerEventHandler mHandler; // NOTE: declare at class scope so garbage collector doesn't release it!!!
private int mTestTick;
private DateTime mTestStart;

public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
timeBeginPeriod(1);
mHandler = new TimerEventHandler(TimerCallback);
mTimerId = timeSetEvent(1, 0, mHandler, IntPtr.Zero, EVENT_TYPE);
mTestStart = DateTime.Now;
mTestTick = 0;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
int err = timeKillEvent(mTimerId);
timeEndPeriod(1);
mTimerId = 0;
System.Threading.Thread.Sleep(1000); // Avoid ObjectDisposed exception !
}
// Testing:
private delegate void TestEventHandler(int tick, TimeSpan span);
private void TimerCallback(int id, int msg, IntPtr user, int dw1, int dw2) {
mTestTick += 1;
if ((mTestTick % 200) == 0 && mTimerId != 0)
this.BeginInvoke(new TestEventHandler(ShowTick), mTestTick, DateTime.Now - mTestStart);
}
private void ShowTick(int msec, TimeSpan span) {
label1.Text = msec.ToString();
label2.Text = span.TotalMilliseconds.ToString();
}
// P/Invoke declarations
private delegate void TimerEventHandler(int id, int msg, IntPtr user, int dw1, int dw2);
private const int TIME_PERIODIC = 1;
private const int EVENT_TYPE = TIME_PERIODIC;// + 0x100; // TIME_KILL_SYNCHRONOUS causes a hang !
[DllImport("winmm.dll")]
private static extern int timeSetEvent(int delay, int resolution, TimerEventHandler handler, IntPtr user, int eventType);
[DllImport("winmm.dll")]
private static extern int timeKillEvent(int id);
[DllImport("winmm.dll")]
private static extern int timeBeginPeriod(int msec);
[DllImport("winmm.dll")]
private static extern int timeEndPeriod(int msec);
}
}





Re: Visual C# General Using multimedia timer with managed C++

Feng Chen - MSFT

Hi SW Sam,

Moved from CLR forum, hope you can get satisfying answers here!

Thanks for your understanding!






Re: Visual C# General Using multimedia timer with managed C++

nobugz

Hi Feng,
The C++ forums are hostile to both SDK questions and code that is not written in C++. If you don't like it in the CLR forum, try to find a more hospitable place for it. Perhaps C# General.





Re: Visual C# General Using multimedia timer with managed C++

SW Sam

This is your sample code converted to C++.

Thanks,

Sam

Code Snippet

namespace MMTimerTest

{

using namespace System;

using namespace System::ComponentModel;

using namespace System::Collections;

using namespace System::Windows::Forms;

using namespace System::Data;

using namespace System::Drawing;

using namespace System::Runtime::InteropServices;

const int TIME_PERIODIC = 1;

const int EVENT_TYPE = TIME_PERIODIC;// + 0x100; // TIME_KILL_SYNCHRONOUS causes a hang !

delegate void TimerEventHandler( int id, int msg, IntPtr user, int dw1, int dw2 );

delegate void TestEventHandler( int tick, TimeSpan span );

[DllImport("winmm.dll")]

extern "C" int timeSetEvent(int delay, int resolution, TimerEventHandler ^handler, IntPtr user, int eventType);

[DllImport("winmm.dll")]

extern "C" int timeKillEvent(int id);

[DllImport("winmm.dll")]

extern "C" int timeBeginPeriod(int msec);

[DllImport("winmm.dll")]

extern "C" int timeEndPeriod(int msec);

/// <summary>

/// Summary for Form1

///

/// WARNING: If you change the name of this class, you will need to change the

/// 'Resource File Name' property for the managed resource compiler tool

/// associated with all .resx files this class depends on. Otherwise,

/// the designers will not be able to interact properly with localized

/// resources associated with this form.

/// </summary>

public ref class Form1 : public System::Windows::Forms::Form

{

private:

int mTimerId;

int mTestTick;

DateTime mTestStart;

TimerEventHandler ^mHandler; // NOTE: declare at class scope so garbage collector doesn't release it!!!

private: System::Windows::Forms::Label^ label1;

private: System::Windows::Forms::Label^ label2;

public:

Form1(void)

{

InitializeComponent();

//

//TODO: Add the constructor code here

//

}

protected:

/// <summary>

/// Clean up any resources being used.

/// </summary>

~Form1()

{

if (components)

{

delete components;

}

}

void ShowTick( int msec, TimeSpan span )

{

label1->Text = msec.ToString();

label2->Text = span.TotalMilliseconds.ToString();

}

void TimerCallback( int id, int msg, IntPtr user, int dw1, int dw2 )

{

mTestTick += 1;

if( ( ( mTestTick % 200 ) == 0 ) && ( mTimerId != 0 ) )

this->BeginInvoke( gcnew TestEventHandler(this, &Form1::ShowTick), mTestTick, DateTime::Now - mTestStart);

}

private:

/// <summary>

/// Required designer variable.

/// </summary>

System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

void InitializeComponent(void)

{

this->label1 = (gcnew System::Windows::Forms::Label());

this->label2 = (gcnew System::Windows::Forms::Label());

this->SuspendLayout();

//

// label1

//

this->label1->AutoSize = true;

this->label1->Location = System::Drawing::Point(12, 18);

this->label1->Name = L"label1";

this->label1->Size = System::Drawing::Size(35, 13);

this->label1->TabIndex = 0;

this->label1->Text = L"label1";

//

// label2

//

this->label2->AutoSize = true;

this->label2->Location = System::Drawing::Point(12, 59);

this->label2->Name = L"label2";

this->label2->Size = System::Drawing::Size(35, 13);

this->label2->TabIndex = 1;

this->label2->Text = L"label2";

//

// Form1

//

this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);

this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;

this->ClientSize = System::Drawing::Size(292, 266);

this->Controls->Add(this->label2);

this->Controls->Add(this->label1);

this->Name = L"Form1";

this->Text = L"Form1";

this->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &Form1::Form1_FormClosing);

this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);

this->ResumeLayout(false);

this->PerformLayout();

}

#pragma endregion

private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e)

{

timeBeginPeriod(1);

mHandler = gcnew TimerEventHandler(this, &Form1::TimerCallback);

mTimerId = timeSetEvent(1, 0, mHandler, IntPtr::Zero, EVENT_TYPE);

mTestStart = DateTime::Now;

mTestTick = 0;

}

private: System::Void Form1_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e)

{

int err = timeKillEvent(mTimerId);

timeEndPeriod(1);

mTimerId = 0;

System::Threading::Thread::Sleep(1000); // Avoid ObjectDisposed exception !

}

};