2 * MMSYTEM time functions
4 * Copyright 1993 Martin Ayotte
21 static BOOL32 mmTimeStarted
= FALSE
;
22 static MMTIME16 mmSysTimeMS
;
23 static MMTIME16 mmSysTimeSMPTE
;
25 /* this is used to avoid infinite loop in timeGetTime, because
26 of the faked multimedia timers, and will desappear as soon as
27 the timers are implemented correctly.
29 static int time_called
=0;
31 typedef struct tagTIMERENTRY
{
35 HINSTANCE32 hInstance
;
41 struct tagTIMERENTRY
*Next
;
43 } TIMERENTRY
, *LPTIMERENTRY
;
45 static LPTIMERENTRY lpTimerList
= NULL
;
49 * We're using "1" as the mininum resolution to the timer,
50 * as Windows 95 does, according to the docs. Maybe it should
51 * depend on the computers resources!
53 #define MMSYSTIME_MININTERVAL (1)
54 #define MMSYSTIME_MAXINTERVAL (65535)
57 /**************************************************************************
60 static VOID
check_MMtimers()
62 LPTIMERENTRY lpTimer
= lpTimerList
;
63 DWORD curtick
= GetTickCount();
65 while (lpTimer
!= NULL
) {
66 if (lpTimer
->triggertime
<= curtick
) {
67 lpTimer
->wCurTime
= lpTimer
->wDelay
;
69 if (lpTimer
->lpFunc
!= (FARPROC16
) NULL
) {
70 TRACE(mmtime
, "before CallBack16 !\n");
71 TRACE(mmtime
, "lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
72 lpTimer
->lpFunc
, lpTimer
->wTimerID
, lpTimer
->dwUser
);
73 TRACE(mmtime
, "hInstance=%04X !\n", lpTimer
->hInstance
);
76 /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
77 * during interrupt time, is allowed to execute very limited number of API calls (like
78 * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
79 * guess current implementation via SetTimer has to be improved upon.
82 lpTimer
->lpFunc(lpTimer
->wTimerID
,0,lpTimer
->dwUser
,0,0);
84 Callbacks
->CallTimeFuncProc(lpTimer
->lpFunc
,
89 TRACE(mmtime
, "after CallBack16 !\n");
91 if (lpTimer
->wFlags
& TIME_ONESHOT
)
92 timeKillEvent32(lpTimer
->wTimerID
);
94 lpTimer
= lpTimer
->Next
;
98 /**************************************************************************
99 * TIME_MMSysTimeCallback
101 static VOID
TIME_MMSysTimeCallback( HWND32 hwnd
, UINT32 msg
,
102 UINT32 id
, DWORD dwTime
)
104 LPTIMERENTRY lpTimer
= lpTimerList
;
105 mmSysTimeMS
.u
.ms
+= MMSYSTIME_MININTERVAL
;
106 mmSysTimeSMPTE
.u
.smpte
.frame
++;
107 while (lpTimer
!= NULL
) {
109 if (lpTimer
->wCurTime
== 0) {
110 lpTimer
->wCurTime
= lpTimer
->wDelay
;
112 if (lpTimer
->lpFunc
!= (FARPROC16
) NULL
) {
113 TRACE(mmtime
, "before CallBack16 !\n");
114 TRACE(mmtime
, "lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
115 lpTimer
->lpFunc
, lpTimer
->wTimerID
, lpTimer
->dwUser
);
116 TRACE(mmtime
, "hInstance=%04X !\n", lpTimer
->hInstance
);
118 /* This is wrong (lpFunc is NULL all the time)
120 lpFunc = MODULE_GetEntryPoint( lpTimer->hInstance,
121 MODULE_GetOrdinal(lpTimer->hInstance,"TimerCallBack" ));
122 TRACE(mmtime, "lpFunc=%08lx !\n", lpFunc);
126 /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
127 * during interrupt time, is allowed to execute very limited number of API calls (like
128 * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
129 * guess current implementation via SetTimer has to be improved upon.
131 if (lpTimer
->iswin32
)
132 lpTimer
->lpFunc(lpTimer
->wTimerID
,0,lpTimer
->dwUser
,0,0);
134 Callbacks
->CallTimeFuncProc(lpTimer
->lpFunc
,
139 TRACE(mmtime
, "after CallBack16 !\n");
142 if (lpTimer
->wFlags
& TIME_ONESHOT
)
143 timeKillEvent32(lpTimer
->wTimerID
);
145 lpTimer
= lpTimer
->Next
;
149 /**************************************************************************
150 * StartMMTime [internal]
152 static void StartMMTime()
154 if (!mmTimeStarted
) {
155 mmTimeStarted
= TRUE
;
156 mmSysTimeMS
.wType
= TIME_MS
;
157 mmSysTimeMS
.u
.ms
= 0;
158 mmSysTimeSMPTE
.wType
= TIME_SMPTE
;
159 mmSysTimeSMPTE
.u
.smpte
.hour
= 0;
160 mmSysTimeSMPTE
.u
.smpte
.min
= 0;
161 mmSysTimeSMPTE
.u
.smpte
.sec
= 0;
162 mmSysTimeSMPTE
.u
.smpte
.frame
= 0;
163 mmSysTimeSMPTE
.u
.smpte
.fps
= 0;
164 mmSysTimeSMPTE
.u
.smpte
.dummy
= 0;
165 SetTimer32( 0, 1, MMSYSTIME_MININTERVAL
, TIME_MMSysTimeCallback
);
169 /**************************************************************************
170 * timeGetSystemTime [WINMM.140]
172 MMRESULT32 WINAPI
timeGetSystemTime32(LPMMTIME32 lpTime
, UINT32 wSize
)
174 TRACE(mmsys
, "(%p, %u);\n", lpTime
, wSize
);
177 lpTime
->wType
= TIME_MS
;
178 lpTime
->u
.ms
= mmSysTimeMS
.u
.ms
;
182 /**************************************************************************
183 * timeGetSystemTime [MMSYSTEM.601]
185 MMRESULT16 WINAPI
timeGetSystemTime16(LPMMTIME16 lpTime
, UINT16 wSize
)
187 TRACE(mmsys
, "(%p, %u);\n", lpTime
, wSize
);
190 lpTime
->wType
= TIME_MS
;
191 lpTime
->u
.ms
= mmSysTimeMS
.u
.ms
;
195 /**************************************************************************
196 * timeSetEvent [MMSYSTEM.602]
198 MMRESULT32 WINAPI
timeSetEvent32(UINT32 wDelay
,UINT32 wResol
,
199 LPTIMECALLBACK32 lpFunc
,DWORD dwUser
,
203 LPTIMERENTRY lpNewTimer
;
204 LPTIMERENTRY lpTimer
= lpTimerList
;
206 TRACE(mmtime
, "(%u, %u, %p, %08lX, %04X);\n",
207 wDelay
, wResol
, lpFunc
, dwUser
, wFlags
);
210 lpNewTimer
= (LPTIMERENTRY
)xmalloc(sizeof(TIMERENTRY
));
211 if (lpNewTimer
== NULL
)
213 while (lpTimer
!= NULL
) {
214 wNewID
= MAX(wNewID
, lpTimer
->wTimerID
);
215 lpTimer
= lpTimer
->Next
;
218 lpNewTimer
->Next
= lpTimerList
;
219 lpTimerList
= lpNewTimer
;
220 lpNewTimer
->wTimerID
= wNewID
+ 1;
221 lpNewTimer
->wCurTime
= wDelay
;
222 lpNewTimer
->triggertime
= wDelay
+GetTickCount();
223 lpNewTimer
->wDelay
= wDelay
;
224 lpNewTimer
->wResol
= wResol
;
225 lpNewTimer
->lpFunc
= (FARPROC16
) lpFunc
;
226 lpNewTimer
->iswin32
= 1;
227 lpNewTimer
->hInstance
= GetTaskDS();
228 TRACE(mmtime
, "hInstance=%04X !\n", lpNewTimer
->hInstance
);
229 TRACE(mmtime
, "lpFunc=%p !\n",
231 lpNewTimer
->dwUser
= dwUser
;
232 lpNewTimer
->wFlags
= wFlags
;
233 return lpNewTimer
->wTimerID
;
236 /**************************************************************************
237 * timeSetEvent [MMSYSTEM.602]
239 MMRESULT16 WINAPI
timeSetEvent16(UINT16 wDelay
, UINT16 wResol
,
240 LPTIMECALLBACK16 lpFunc
,DWORD dwUser
,
244 LPTIMERENTRY lpNewTimer
;
245 LPTIMERENTRY lpTimer
= lpTimerList
;
246 TRACE(mmtime
, "(%u, %u, %p, %08lX, %04X);\n",
247 wDelay
, wResol
, lpFunc
, dwUser
, wFlags
);
250 lpNewTimer
= (LPTIMERENTRY
)xmalloc(sizeof(TIMERENTRY
));
251 if (lpNewTimer
== NULL
)
253 while (lpTimer
!= NULL
) {
254 wNewID
= MAX(wNewID
, lpTimer
->wTimerID
);
255 lpTimer
= lpTimer
->Next
;
258 lpNewTimer
->Next
= lpTimerList
;
259 lpTimerList
= lpNewTimer
;
260 lpNewTimer
->wTimerID
= wNewID
+ 1;
261 lpNewTimer
->wCurTime
= wDelay
;
262 lpNewTimer
->wDelay
= wDelay
;
263 lpNewTimer
->triggertime
= wDelay
+GetTickCount();
264 lpNewTimer
->wResol
= wResol
;
265 lpNewTimer
->lpFunc
= (FARPROC16
) lpFunc
;
266 lpNewTimer
->iswin32
= 0;
267 lpNewTimer
->hInstance
= GetTaskDS();
268 TRACE(mmtime
, "hInstance=%04X !\n", lpNewTimer
->hInstance
);
269 TRACE(mmtime
, "(lpFunc)=%p !\n",
270 PTR_SEG_TO_LIN(lpFunc
));
271 lpNewTimer
->dwUser
= dwUser
;
272 lpNewTimer
->wFlags
= wFlags
;
273 return lpNewTimer
->wTimerID
;
276 /**************************************************************************
277 * timeKillEvent [WINMM.142]
279 MMRESULT32 WINAPI
timeKillEvent32(UINT32 wID
)
281 LPTIMERENTRY xlptimer
,*lpTimer
= &lpTimerList
;
283 if (wID
== (*lpTimer
)->wTimerID
) {
284 xlptimer
= (*lpTimer
)->Next
;
289 lpTimer
= &((*lpTimer
)->Next
);
294 /**************************************************************************
295 * timeKillEvent [MMSYSTEM.603]
297 MMRESULT16 WINAPI
timeKillEvent16(UINT16 wID
)
299 return timeKillEvent32(wID
);
302 /**************************************************************************
303 * timeGetDevCaps [WINMM.139]
305 MMRESULT32 WINAPI
timeGetDevCaps32(LPTIMECAPS32 lpCaps
,UINT32 wSize
)
307 TRACE(mmtime
, "(%p, %u) !\n", lpCaps
, wSize
);
310 lpCaps
->wPeriodMin
= MMSYSTIME_MININTERVAL
;
311 lpCaps
->wPeriodMax
= MMSYSTIME_MAXINTERVAL
;
315 /**************************************************************************
316 * timeGetDevCaps [MMSYSTEM.604]
318 MMRESULT16 WINAPI
timeGetDevCaps16(LPTIMECAPS16 lpCaps
, UINT16 wSize
)
320 TRACE(mmtime
, "(%p, %u) !\n", lpCaps
, wSize
);
323 lpCaps
->wPeriodMin
= MMSYSTIME_MININTERVAL
;
324 lpCaps
->wPeriodMax
= MMSYSTIME_MAXINTERVAL
;
328 /**************************************************************************
329 * timeBeginPeriod [WINMM.137]
331 MMRESULT32 WINAPI
timeBeginPeriod32(UINT32 wPeriod
)
333 TRACE(mmtime
, "(%u) !\n", wPeriod
);
336 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
337 return TIMERR_NOCANDO
;
340 /**************************************************************************
341 * timeBeginPeriod [MMSYSTEM.605]
343 MMRESULT16 WINAPI
timeBeginPeriod16(UINT16 wPeriod
)
345 TRACE(mmtime
, "(%u) !\n", wPeriod
);
348 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
349 return TIMERR_NOCANDO
;
353 /**************************************************************************
354 * timeEndPeriod [WINMM.138]
356 MMRESULT32 WINAPI
timeEndPeriod32(UINT32 wPeriod
)
358 TRACE(mmtime
, "(%u) !\n", wPeriod
);
359 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
360 return TIMERR_NOCANDO
;
364 /**************************************************************************
365 * timeEndPeriod [MMSYSTEM.606]
367 MMRESULT16 WINAPI
timeEndPeriod16(UINT16 wPeriod
)
369 TRACE(mmtime
, "(%u) !\n", wPeriod
);
370 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
371 return TIMERR_NOCANDO
;
375 /**************************************************************************
376 * timeGetTime [MMSYSTEM.607][WINMM.141]
378 DWORD WINAPI
timeGetTime()
380 /* FIXME all this function should have to be is
383 TRACE(mmtime,"timeGetTime(); !\n");
384 gettimeofday(&time, 0);
385 result = (((long)time.tv_sec * (long)1000) + ((long)time.tv_usec / (long)1000));
387 but the multimedia timers are not implemented correctly, so all the rest
388 is a workaround to fake them.
391 static DWORD lasttick
=0;
394 TRACE(mmtime
, "!\n");
397 newtick
= GetTickCount();
398 mmSysTimeMS
.u
.ms
+=newtick
-lasttick
; /* FIXME: faked timer */
399 if (newtick
!=lasttick
)
401 if (!time_called
) { /* to avoid infinite recursion if timeGetTime is called
402 inside check_MMtimers
407 } //check_MMtimers();
409 TRACE(mmtime
, "Time = %ld\n",mmSysTimeMS
.u
.ms
);
412 return mmSysTimeMS
.u
.ms
;