Using a Multimedia Timer

The VCL TTimer component and the the API WM_TIMER message can both be used for timing or interval operations.  However, both of these solution have limited resolution.  In order to achieve a better resolution, you can use a multimedia timer.  There are many situations where a high resolution timer is prudent, including animations and sound manipulation applications.  Multimedia timers are documented in the MS Multimedia Programmer's Reference.  Below is a simple example demonstrating the use of a multimedia timer for a simple animation.

KEYWORDS: timeGetDevCaps(), timeSetEvent(), timeKillEvent().
 



 

//---------------------------------------------------------------------------

#include <mmsystem.h>
//---------------------------------------------------------------------------

typedef struct tagANIMATEINFO
{
    HWND HForm;
    Graphics::TBitmap *Bitmap;
} ANIMATEINFO, *LPANIMATEINFO;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    TimerID = 0;
}
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// wrapper functions
//---------------------------------------------------------------------------
int __fastcall TForm1::GetResolution(int target)
{
    TIMECAPS tc;
    unsigned int uiTimerRes;

    timeGetDevCaps(&tc, sizeof(TIMECAPS));
    uiTimerRes = min(max((int)tc.wPeriodMin, target), (int)tc.wPeriodMax);
    timeBeginPeriod(uiTimerRes);
    return uiTimerRes;
}

int __fastcall TForm1::StartMMTimer(int Interval, int Resolution, DWORD data)
{
    return timeSetEvent(Interval, Resolution, TimerProc,
                        data, TIME_PERIODIC);
}

void __fastcall TForm1::KillMMTimer(int FTimerID)
{
    timeKillEvent(FTimerID);
}
 

//---------------------------------------------------------------------------
// example useage functions...
//---------------------------------------------------------------------------

void CALLBACK TimerProc(unsigned int uID, unsigned int uMsg, DWORD dwUser,
    DWORD dw1, DWORD dw2)
{
    LPANIMATEINFO lpani = (ANIMATEINFO *)dwUser;

    HDC Hdc = GetDC(lpani->HForm);

    static int pos = 0;
    pos = pos + 5;

    RECT R = Rect(pos - 5, 0, pos, lpani->Bitmap->Height);
    FillRect(Hdc, &R, GetStockObject(LTGRAY_BRUSH));

    ::BitBlt(Hdc, pos, 0, lpani->Bitmap->Width, lpani->Bitmap->Height,
             lpani->Bitmap->Canvas->Handle, 0, 0, SRCCOPY);

    ReleaseDC(lpani->HForm, Hdc);
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    lpani = new ANIMATEINFO();
    lpani->HForm = Handle;
    lpani->Bitmap = Image1->Picture->Bitmap;

    int Resolution = GetResolution(1);
    TimerID = StartMMTimer(10, Resolution, (DWORD)lpani);
}

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
    delete lpani;
    if (TimerID) KillMMTimer(TimerID);
}