CreateTimerQueueTimer function

Windows specific questions.
Wilko
Posts: 23
Joined: Oct 26, 2016 7:57

CreateTimerQueueTimer function

Postby Wilko » Oct 26, 2016 8:05

Hi,
I am new to this forum; come from Powerbasic. In PowerBasic I used the function CreateTimerQueueTimer with this syntax:

Code: Select all

CreateTimerQueueTimer(hTimer, 0&, CodePtr(MyFunction), 0&, 2000, 200, %WT_EXECUTEDEFAULT)


and that worked. I am trying to do the same in FreeBasic but I can not figure out how. This syntax:

Code: Select all

CreateTimerQueueTimer(hTimer, 0&, ProcPtr(MyFunction), 0&, 2000, 1000, WT_EXECUTEDEFAULT)


causes the program to crash. Compiler warns me 'passing different pointer types at parameter 3' so something is wrong there. According to the function definition, parameter 3 has type

Code: Select all

byval Callback as WAITORTIMERCALLBACK
.
But how do I do that? Any help is appreciated.
Wilko
dkl
Site Admin
Posts: 3210
Joined: Jul 28, 2005 14:45
Location: Germany

Re: CreateTimerQueueTimer function

Postby dkl » Oct 26, 2016 16:07

Hi,

if you look at the MSDN documentation for CreateTimerQueueTimer(), there is a link to WaitOrTimerCallback callback function, which shows the needed callback function signature. Of course it's in C code, the corresponding FreeBASIC version is:

Code: Select all

sub MyFunction(byval lpParameter as PVOID, byval TimeOrWaitFired as WINBOOLEAN)
    print "hello!"
end sub


You can also check against the WAITORTIMERCALLBACK type definition in the FreeBASIC .bi header files:

Code: Select all

'' from FreeBASIC/inc/win/winnt.bi:
type WAITORTIMERCALLBACKFUNC as sub(byval as PVOID, byval as WINBOOLEAN)
type WAITORTIMERCALLBACK as WAITORTIMERCALLBACKFUNC
Wilko
Posts: 23
Joined: Oct 26, 2016 7:57

Re: CreateTimerQueueTimer function

Postby Wilko » Oct 26, 2016 19:43

Hi, thanks for your reaction. Your points are clear, but not sufficient to solve my problem. The point is that the line with CreateTimerQueueTimer as quoted in my first post, creates a crash of the program when it runs (although it compiles with only a warning). So I think there is something wrong in the way I use a pointer to the timer function. But what?
Wilko
dkl
Site Admin
Posts: 3210
Joined: Jul 28, 2005 14:45
Location: Germany

Re: CreateTimerQueueTimer function

Postby dkl » Oct 26, 2016 20:12

The compiler warning is a hint that an incompatible function signature is being used, which can result in crashes or other behaviour at run-time. Declaring the callback function with the proper signature (parameters, result, calling convention) should fix that (i.e. the compiler warning should disappear).

Other than that it looks correct. Could you post the whole code, if there still is a crash?
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Re: CreateTimerQueueTimer function

Postby MichaelW » Oct 28, 2016 10:50

The Timer Queue timers do not seem to me to be very useful. They appear to have the same maximum resolution (= minimum period) that the other Windows timers (other than the High-Resolution Performance Counter timer that the FreeBASIC Timer function is based on) have, 10 or 15.6ms, depending on the version of Windows. With each timer running in its own thread, synchronization could be a problem.

This code was tested only as a 64-bit app compiled with 1.05.0, under Windows 10:

Code: Select all

''=============================================================================
#include "windows.bi"
#include once "win\mmsystem.bi"
''=============================================================================

sub TimerCallback( lpParameter as any ptr, TimerOrWaitFired as BOOLEAN )
    static as integer i
    i += 1
    print i, *cast(integer ptr,lpParameter), TimerOrWaitFired
end sub

dim as HANDLE hTimer
dim as integer param = 12345

''-----------------------------------------
'' declare function CreateTimerQueueTimer(
''  byval phNewTimer as PHANDLE,
''  byval TimerQueue as HANDLE,
''  byval Callback as WAITORTIMERCALLBACK,
''  byval Parameter as PVOID,
''  byval DueTime as DWORD,
''  byval Period as DWORD,
''  byval Flags as ULONG) as WINBOOL
''-----------------------------------------

''--------------------------------------------
'' Create our timer, requesting a due time of
'' 2000ms and a period of 100ms.
''
'' All of the associated functions return
'' non-zero on success.
''--------------------------------------------

print CreateTimerQueueTimer( @hTimer, _
                             NULL, _
                             @TimerCallback, _
                             @param, _
                             2000, _
                             1000, _
                             WT_EXECUTEDEFAULT )
                             
sleep

print
print

print ChangeTimerQueueTimer( NULL, hTimer, 2000, 100 )

sleep

print
print

print ChangeTimerQueueTimer( NULL, hTimer, 2000, 10 )

sleep

print
print

print ChangeTimerQueueTimer( NULL, hTimer, 2000, 1 )

sleep

print DeleteTimerQueueTimer( NULL, hTimer, NULL )

sleep

I forgot to add that the minimum period for the timers can be set as low as 1ms with the timeBeginPeriod function, that being the reason for my inclusion of mmsystem.bi.
Wilko
Posts: 23
Joined: Oct 26, 2016 7:57

Re: CreateTimerQueueTimer function

Postby Wilko » Oct 28, 2016 20:05

My reply took some time because I wanted to strip the program to the smallest unit that causes the crash. You will find it here:

Code: Select all

#DEFINE UNICODE
#INCLUDE ONCE "windows.bi"
#INCLUDE ONCE "win\winbase.bi"

DECLARE FUNCTION Main_Proc(BYVAL hWndForm AS HWND, BYVAL wMsg AS UINTEGER, BYVAL wParam AS wParam, BYVAL lParam AS lParam) AS LRESULT
DECLARE SUB MyTimerFunction (BYVAL lpParameter AS PVOID, BYVAL TimerOrWaitFired AS WINBOOLEAN)
DECLARE FUNCTION RegisterClasses(BYVAL hInstance AS HINSTANCE) AS HWND
'-------------------------------------------------------------------------------
FUNCTION WINMAIN(BYVAL hInstance AS HINSTANCE, BYVAL hPrevInstance AS HINSTANCE, BYREF lpCmdLine AS STRING, BYVAL iCmdShow AS LONG) AS LONG

  DIM hWndMainForm AS HWND
  DIM Msg AS MSG
  DIM phTimer AS HWND PTR

  hWndMainForm = RegisterClasses(hInstance)
  ShowWindow hWndMainForm, SW_SHOWNORMAL
  UpdateWindow hWndMainForm

    'create timer
  CreateTimerQueueTimer(phTimer, 0&, PROCPTR(MyTimerFunction), 0&, 2000, 1000, WT_EXECUTEDEFAULT)

  DO WHILE GetMessage(@Msg, 0, 0, 0)
     TranslateMessage @Msg
     DispatchMessage @Msg
  LOOP

  FUNCTION = False

END FUNCTION
END WINMAIN(GetModuleHandle(NULL), NULL, COMMAND(), SW_NORMAL)
'-------------------------------------------------------------------------------
FUNCTION RegisterClasses(BYVAL hInstance AS HINSTANCE) AS HWND

  DIM ClassName AS wString * MAX_PATH
  DIM RC AS RECT
  DIM WCE AS WndClassEx

  ClassName = "MyClass" 
  WCE.cbSize = SIZEOF(WCE)

  IF GetClassInfoEx(hInstance, ClassName, VARPTR(WCE)) = 0 THEN 'means not initialized yet
    WCE.cbSize = SIZEOF(WCE)
    WCE.STYLE = CS_VREDRAW OR CS_HREDRAW OR CS_DBLCLKS
    WCE.lpfnWndProc = CAST(WNDPROC, @Main_Proc)
    WCE.cbClsExtra = 0
    WCE.cbWndExtra = 0
    WCE.hInstance = hInstance
    WCE.hIcon = LoadImage(hInstance, "IMAGE_CHEAQS", IMAGE_ICON, 32, 32, LR_SHARED)
    WCE.hCursor = LoadCursor(0, BYVAL IDC_ARROW)
    WCE.hbrBackground = CreateSolidBrush(BGR(250, 250, 250)) 'close to white...
    WCE.lpszMenuName = 0
    WCE.lpszClassName = VARPTR(ClassName)
    WCE.hIconSm = LoadIcon(hInstance, BYVAL IDI_APPLICATION)
    RegisterClassEx(VARPTR(WCE))
  END IF

  'determine desktop size (excluding taskbar)
  SystemParametersInfo(SPI_GETWORKAREA, 0, VARPTR(RC), 0)
  FUNCTION = CreateWindowEx(WS_EX_WINDOWEDGE OR WS_EX_CONTROLPARENT OR WS_EX_LEFT OR WS_EX_LTRREADING OR WS_EX_RIGHTSCROLLBAR, ClassName, "(text for title bar)", _
                 WS_POPUP OR WS_THICKFRAME OR WS_CAPTION OR WS_SYSMENU OR WS_MINIMIZEBOX OR WS_MAXIMIZEBOX OR WS_CLIPSIBLINGS OR WS_CLIPCHILDREN, RC.Left, RC.Top, _
                 RC.Right, RC.Bottom, 0, CAST(HMENU, CAST(LONG_PTR, Null)), hInstance, 0)

END FUNCTION
'-------------------------------------------------------------------------------
FUNCTION Main_Proc(BYVAL hWndForm AS HWND, BYVAL wMsg AS UINTEGER, BYVAL wParam AS wParam, BYVAL lParam AS lParam) AS LRESULT

  SELECT CASE wMsg
    CASE WM_CLOSE
      PostQuitMessage 0
      FUNCTION = 0
      EXIT FUNCTION
  END SELECT
 
  FUNCTION = DefWindowProc(hWndForm, wMsg, wParam, lParam)

END FUNCTION
SUB MyTimerFunction (BYVAL lpParameter AS PVOID, BYVAL TimerOrWaitFired AS WINBOOLEAN)
  'todo insert code here
END SUB


Any help is appreciated.
Wilko
Wilko
Posts: 23
Joined: Oct 26, 2016 7:57

Re: CreateTimerQueueTimer function

Postby Wilko » Oct 28, 2016 20:46

MichaelW,
Thanks, when I change in my previous post the following:

DIM hTimer AS HANDLE
CreateTimerQueueTimer(@hTimer, 0&, @MyTimerFunction, 0&, 2000, 1000, WT_EXECUTEDEFAULT)

it works without problems!
Wilko

Return to “Windows”

Who is online

Users browsing this forum: No registered users and 3 guests