2 * MMSYTEM time functions
4 * Copyright 1993 Martin Ayotte
20 static BOOL32 mmTimeStarted
= FALSE
;
21 static MMTIME16 mmSysTimeMS
;
22 static MMTIME16 mmSysTimeSMPTE
;
24 /* this is used to avoid infinite loop in timeGetTime, because
25 of the faked multimedia timers, and will desappear as soon as
26 the timers are implemented correctly.
28 static int time_called
=0;
30 typedef struct tagTIMERENTRY
{
34 HINSTANCE32 hInstance
;
40 struct tagTIMERENTRY
*Next
;
42 } TIMERENTRY
, *LPTIMERENTRY
;
44 static LPTIMERENTRY lpTimerList
= NULL
;
48 * We're using "1" as the mininum resolution to the timer,
49 * as Windows 95 does, according to the docs. Maybe it should
50 * depend on the computers resources!
52 #define MMSYSTIME_MININTERVAL (1)
53 #define MMSYSTIME_MAXINTERVAL (65535)
56 /**************************************************************************
59 static VOID
check_MMtimers()
61 LPTIMERENTRY lpTimer
= lpTimerList
;
62 DWORD curtick
= GetTickCount();
64 while (lpTimer
!= NULL
) {
65 if (lpTimer
->triggertime
<= curtick
) {
66 lpTimer
->wCurTime
= lpTimer
->wDelay
;
68 if (lpTimer
->lpFunc
!= (FARPROC16
) NULL
) {
69 TRACE(mmtime
, "before CallBack16 !\n");
70 TRACE(mmtime
, "lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
71 lpTimer
->lpFunc
, lpTimer
->wTimerID
, lpTimer
->dwUser
);
72 TRACE(mmtime
, "hInstance=%04X !\n", lpTimer
->hInstance
);
75 /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
76 * during interrupt time, is allowed to execute very limited number of API calls (like
77 * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
78 * guess current implementation via SetTimer has to be improved upon.
81 lpTimer
->lpFunc(lpTimer
->wTimerID
,0,lpTimer
->dwUser
,0,0);
83 Callbacks
->CallTimeFuncProc(lpTimer
->lpFunc
,
88 TRACE(mmtime
, "after CallBack16 !\n");
90 if (lpTimer
->wFlags
& TIME_ONESHOT
)
91 timeKillEvent32(lpTimer
->wTimerID
);
93 lpTimer
= lpTimer
->Next
;
97 /**************************************************************************
98 * TIME_MMSysTimeCallback
100 static VOID
TIME_MMSysTimeCallback( HWND32 hwnd
, UINT32 msg
,
101 UINT32 id
, DWORD dwTime
)
103 LPTIMERENTRY lpTimer
= lpTimerList
;
104 mmSysTimeMS
.u
.ms
+= MMSYSTIME_MININTERVAL
;
105 mmSysTimeSMPTE
.u
.smpte
.frame
++;
106 while (lpTimer
!= NULL
) {
108 if (lpTimer
->wCurTime
== 0) {
109 lpTimer
->wCurTime
= lpTimer
->wDelay
;
111 if (lpTimer
->lpFunc
!= (FARPROC16
) NULL
) {
112 TRACE(mmtime
, "before CallBack16 !\n");
113 TRACE(mmtime
, "lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
114 lpTimer
->lpFunc
, lpTimer
->wTimerID
, lpTimer
->dwUser
);
115 TRACE(mmtime
, "hInstance=%04X !\n", lpTimer
->hInstance
);
117 /* This is wrong (lpFunc is NULL all the time)
119 lpFunc = MODULE_GetEntryPoint( lpTimer->hInstance,
120 MODULE_GetOrdinal(lpTimer->hInstance,"TimerCallBack" ));
121 TRACE(mmtime, "lpFunc=%08lx !\n", lpFunc);
125 /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
126 * during interrupt time, is allowed to execute very limited number of API calls (like
127 * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
128 * guess current implementation via SetTimer has to be improved upon.
130 if (lpTimer
->iswin32
)
131 lpTimer
->lpFunc(lpTimer
->wTimerID
,0,lpTimer
->dwUser
,0,0);
133 Callbacks
->CallTimeFuncProc(lpTimer
->lpFunc
,
138 TRACE(mmtime
, "after CallBack16 !\n");
141 if (lpTimer
->wFlags
& TIME_ONESHOT
)
142 timeKillEvent32(lpTimer
->wTimerID
);
144 lpTimer
= lpTimer
->Next
;
148 /**************************************************************************
149 * StartMMTime [internal]
151 static void StartMMTime()
153 if (!mmTimeStarted
) {
154 mmTimeStarted
= TRUE
;
155 mmSysTimeMS
.wType
= TIME_MS
;
156 mmSysTimeMS
.u
.ms
= 0;
157 mmSysTimeSMPTE
.wType
= TIME_SMPTE
;
158 mmSysTimeSMPTE
.u
.smpte
.hour
= 0;
159 mmSysTimeSMPTE
.u
.smpte
.min
= 0;
160 mmSysTimeSMPTE
.u
.smpte
.sec
= 0;
161 mmSysTimeSMPTE
.u
.smpte
.frame
= 0;
162 mmSysTimeSMPTE
.u
.smpte
.fps
= 0;
163 mmSysTimeSMPTE
.u
.smpte
.dummy
= 0;
164 SetTimer32( 0, 1, MMSYSTIME_MININTERVAL
, TIME_MMSysTimeCallback
);
168 /**************************************************************************
169 * timeGetSystemTime [WINMM.140]
171 MMRESULT32 WINAPI
timeGetSystemTime32(LPMMTIME32 lpTime
, UINT32 wSize
)
173 TRACE(mmsys
, "(%p, %u);\n", lpTime
, wSize
);
176 lpTime
->wType
= TIME_MS
;
177 lpTime
->u
.ms
= mmSysTimeMS
.u
.ms
;
181 /**************************************************************************
182 * timeGetSystemTime [MMSYSTEM.601]
184 MMRESULT16 WINAPI
timeGetSystemTime16(LPMMTIME16 lpTime
, UINT16 wSize
)
186 TRACE(mmsys
, "(%p, %u);\n", lpTime
, wSize
);
189 lpTime
->wType
= TIME_MS
;
190 lpTime
->u
.ms
= mmSysTimeMS
.u
.ms
;
194 /**************************************************************************
195 * timeSetEvent [MMSYSTEM.602]
197 MMRESULT32 WINAPI
timeSetEvent32(UINT32 wDelay
,UINT32 wResol
,
198 LPTIMECALLBACK32 lpFunc
,DWORD dwUser
,
202 LPTIMERENTRY lpNewTimer
;
203 LPTIMERENTRY lpTimer
= lpTimerList
;
205 TRACE(mmtime
, "(%u, %u, %p, %08lX, %04X);\n",
206 wDelay
, wResol
, lpFunc
, dwUser
, wFlags
);
209 lpNewTimer
= (LPTIMERENTRY
)xmalloc(sizeof(TIMERENTRY
));
210 if (lpNewTimer
== NULL
)
212 while (lpTimer
!= NULL
) {
213 wNewID
= MAX(wNewID
, lpTimer
->wTimerID
);
214 lpTimer
= lpTimer
->Next
;
217 lpNewTimer
->Next
= lpTimerList
;
218 lpTimerList
= lpNewTimer
;
219 lpNewTimer
->wTimerID
= wNewID
+ 1;
220 lpNewTimer
->wCurTime
= wDelay
;
221 lpNewTimer
->triggertime
= wDelay
+GetTickCount();
222 lpNewTimer
->wDelay
= wDelay
;
223 lpNewTimer
->wResol
= wResol
;
224 lpNewTimer
->lpFunc
= (FARPROC16
) lpFunc
;
225 lpNewTimer
->iswin32
= 1;
226 lpNewTimer
->hInstance
= GetTaskDS();
227 TRACE(mmtime
, "hInstance=%04X !\n", lpNewTimer
->hInstance
);
228 TRACE(mmtime
, "lpFunc=%p !\n",
230 lpNewTimer
->dwUser
= dwUser
;
231 lpNewTimer
->wFlags
= wFlags
;
232 return lpNewTimer
->wTimerID
;
235 /**************************************************************************
236 * timeSetEvent [MMSYSTEM.602]
238 MMRESULT16 WINAPI
timeSetEvent16(UINT16 wDelay
, UINT16 wResol
,
239 LPTIMECALLBACK16 lpFunc
,DWORD dwUser
,
243 LPTIMERENTRY lpNewTimer
;
244 LPTIMERENTRY lpTimer
= lpTimerList
;
245 TRACE(mmtime
, "(%u, %u, %p, %08lX, %04X);\n",
246 wDelay
, wResol
, lpFunc
, dwUser
, wFlags
);
249 lpNewTimer
= (LPTIMERENTRY
)xmalloc(sizeof(TIMERENTRY
));
250 if (lpNewTimer
== NULL
)
252 while (lpTimer
!= NULL
) {
253 wNewID
= MAX(wNewID
, lpTimer
->wTimerID
);
254 lpTimer
= lpTimer
->Next
;
257 lpNewTimer
->Next
= lpTimerList
;
258 lpTimerList
= lpNewTimer
;
259 lpNewTimer
->wTimerID
= wNewID
+ 1;
260 lpNewTimer
->wCurTime
= wDelay
;
261 lpNewTimer
->wDelay
= wDelay
;
262 lpNewTimer
->triggertime
= wDelay
+GetTickCount();
263 lpNewTimer
->wResol
= wResol
;
264 lpNewTimer
->lpFunc
= (FARPROC16
) lpFunc
;
265 lpNewTimer
->iswin32
= 0;
266 lpNewTimer
->hInstance
= GetTaskDS();
267 TRACE(mmtime
, "hInstance=%04X !\n", lpNewTimer
->hInstance
);
268 TRACE(mmtime
, "(lpFunc)=%p !\n",
269 PTR_SEG_TO_LIN(lpFunc
));
270 lpNewTimer
->dwUser
= dwUser
;
271 lpNewTimer
->wFlags
= wFlags
;
272 return lpNewTimer
->wTimerID
;
275 /**************************************************************************
276 * timeKillEvent [WINMM.142]
278 MMRESULT32 WINAPI
timeKillEvent32(UINT32 wID
)
280 LPTIMERENTRY xlptimer
,*lpTimer
= &lpTimerList
;
282 if (wID
== (*lpTimer
)->wTimerID
) {
283 xlptimer
= (*lpTimer
)->Next
;
288 lpTimer
= &((*lpTimer
)->Next
);
293 /**************************************************************************
294 * timeKillEvent [MMSYSTEM.603]
296 MMRESULT16 WINAPI
timeKillEvent16(UINT16 wID
)
298 return timeKillEvent32(wID
);
301 /**************************************************************************
302 * timeGetDevCaps [WINMM.139]
304 MMRESULT32 WINAPI
timeGetDevCaps32(LPTIMECAPS32 lpCaps
,UINT32 wSize
)
306 TRACE(mmtime
, "(%p, %u) !\n", lpCaps
, wSize
);
309 lpCaps
->wPeriodMin
= MMSYSTIME_MININTERVAL
;
310 lpCaps
->wPeriodMax
= MMSYSTIME_MAXINTERVAL
;
314 /**************************************************************************
315 * timeGetDevCaps [MMSYSTEM.604]
317 MMRESULT16 WINAPI
timeGetDevCaps16(LPTIMECAPS16 lpCaps
, UINT16 wSize
)
319 TRACE(mmtime
, "(%p, %u) !\n", lpCaps
, wSize
);
322 lpCaps
->wPeriodMin
= MMSYSTIME_MININTERVAL
;
323 lpCaps
->wPeriodMax
= MMSYSTIME_MAXINTERVAL
;
327 /**************************************************************************
328 * timeBeginPeriod [WINMM.137]
330 MMRESULT32 WINAPI
timeBeginPeriod32(UINT32 wPeriod
)
332 TRACE(mmtime
, "(%u) !\n", wPeriod
);
335 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
336 return TIMERR_NOCANDO
;
339 /**************************************************************************
340 * timeBeginPeriod [MMSYSTEM.605]
342 MMRESULT16 WINAPI
timeBeginPeriod16(UINT16 wPeriod
)
344 TRACE(mmtime
, "(%u) !\n", wPeriod
);
347 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
348 return TIMERR_NOCANDO
;
352 /**************************************************************************
353 * timeEndPeriod [WINMM.138]
355 MMRESULT32 WINAPI
timeEndPeriod32(UINT32 wPeriod
)
357 TRACE(mmtime
, "(%u) !\n", wPeriod
);
358 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
359 return TIMERR_NOCANDO
;
363 /**************************************************************************
364 * timeEndPeriod [MMSYSTEM.606]
366 MMRESULT16 WINAPI
timeEndPeriod16(UINT16 wPeriod
)
368 TRACE(mmtime
, "(%u) !\n", wPeriod
);
369 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
370 return TIMERR_NOCANDO
;
374 /**************************************************************************
375 * timeGetTime [MMSYSTEM.607][WINMM.141]
377 DWORD WINAPI
timeGetTime()
379 /* FIXME all this function should have to be is
382 TRACE(mmtime,"timeGetTime(); !\n");
383 gettimeofday(&time, 0);
384 result = (((long)time.tv_sec * (long)1000) + ((long)time.tv_usec / (long)1000));
386 but the multimedia timers are not implemented correctly, so all the rest
387 is a workaround to fake them.
390 static DWORD lasttick
=0;
393 TRACE(mmtime
, "!\n");
396 newtick
= GetTickCount();
397 mmSysTimeMS
.u
.ms
+=newtick
-lasttick
; /* FIXME: faked timer */
398 if (newtick
!=lasttick
)
400 if (!time_called
) { /* to avoid infinite recursion if timeGetTime is called
401 inside check_MMtimers
406 } //check_MMtimers();
408 TRACE(mmtime
, "Time = %ld\n",mmSysTimeMS
.u
.ms
);
411 return mmSysTimeMS
.u
.ms
;