winmm: Remove WINE_NO_LONG_AS_INT.
[wine] / dlls / winmm / driver.c
1 /*
2  * WINE Drivers functions
3  *
4  * Copyright 1994 Martin Ayotte
5  * Copyright 1998 Marcus Meissner
6  * Copyright 1999 Eric Pouech
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <string.h>
27 #include <stdarg.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "winreg.h"
34 #include "mmddk.h"
35 #include "winemm.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38 #include "excpt.h"
39 #include "wine/exception.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(driver);
42
43 static CRITICAL_SECTION mmdriver_lock;
44 static CRITICAL_SECTION_DEBUG mmdriver_lock_debug =
45 {
46     0, 0, &mmdriver_lock,
47     { &mmdriver_lock_debug.ProcessLocksList, &mmdriver_lock_debug.ProcessLocksList },
48       0, 0, { (DWORD_PTR)(__FILE__ ": mmdriver_lock") }
49 };
50 static CRITICAL_SECTION mmdriver_lock = { &mmdriver_lock_debug, -1, 0, 0, 0, 0 };
51
52 static LPWINE_DRIVER   lpDrvItemList  /* = NULL */;
53 static const WCHAR HKLM_BASE[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
54                                   'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};
55
56 WINE_MMTHREAD*  (*pFnGetMMThread16)(UINT16 h) /* = NULL */;
57 LPWINE_DRIVER   (*pFnOpenDriver16)(LPCWSTR,LPCWSTR,LPARAM) /* = NULL */;
58 LRESULT         (*pFnCloseDriver16)(UINT16,LPARAM,LPARAM) /* = NULL */;
59 LRESULT         (*pFnSendMessage16)(UINT16,UINT,LPARAM,LPARAM) /* = NULL */;
60
61 static void DRIVER_Dump(const char *comment)
62 {
63 #if 0
64     LPWINE_DRIVER       lpDrv;
65
66     TRACE("%s\n", comment);
67
68     EnterCriticalSection( &mmdriver_lock );
69
70     for (lpDrv = lpDrvItemList; lpDrv != NULL; lpDrv = lpDrv->lpNextItem)
71     {
72         TRACE("%p, magic %04lx, id %p, next %p\n", lpDrv, lpDrv->dwMagic, (void *)lpDrv->d.d32.dwDriverID, lpDrv->lpNextItem);
73     }
74
75     LeaveCriticalSection( &mmdriver_lock );
76 #endif
77 }
78
79 /**************************************************************************
80  *                      DRIVER_GetNumberOfModuleRefs            [internal]
81  *
82  * Returns the number of open drivers which share the same module.
83  */
84 static  unsigned DRIVER_GetNumberOfModuleRefs(HMODULE hModule, WINE_DRIVER** found)
85 {
86     LPWINE_DRIVER       lpDrv;
87     unsigned            count = 0;
88
89     EnterCriticalSection( &mmdriver_lock );
90
91     if (found) *found = NULL;
92     for (lpDrv = lpDrvItemList; lpDrv; lpDrv = lpDrv->lpNextItem)
93     {
94         if (!(lpDrv->dwFlags & WINE_GDF_16BIT) && lpDrv->d.d32.hModule == hModule)
95         {
96             if (found && !*found) *found = lpDrv;
97             count++;
98         }
99     }
100
101     LeaveCriticalSection( &mmdriver_lock );
102     return count;
103 }
104
105 /**************************************************************************
106  *                              DRIVER_FindFromHDrvr            [internal]
107  *
108  * From a hDrvr being 32 bits, returns the WINE internal structure.
109  */
110 LPWINE_DRIVER   DRIVER_FindFromHDrvr(HDRVR hDrvr)
111 {
112     LPWINE_DRIVER d;
113
114     __TRY
115     {
116         d = (LPWINE_DRIVER)hDrvr;
117         if (d && d->dwMagic != WINE_DI_MAGIC) d = NULL;
118     }
119     __EXCEPT_PAGE_FAULT
120     {
121         return NULL;
122     }
123     __ENDTRY;
124
125     if (d) TRACE("%p -> %p, %p\n", hDrvr, d->d.d32.lpDrvProc, (void *)d->d.d32.dwDriverID);
126     else TRACE("%p -> NULL\n", hDrvr);
127
128     return d;
129 }
130
131 /**************************************************************************
132  *                              DRIVER_SendMessage              [internal]
133  */
134 inline static LRESULT DRIVER_SendMessage(LPWINE_DRIVER lpDrv, UINT msg,
135                                          LPARAM lParam1, LPARAM lParam2)
136 {
137     LRESULT             ret = 0;
138
139     if (lpDrv->dwFlags & WINE_GDF_16BIT) {
140         /* no need to check mmsystem presence: the driver must have been opened as a 16 bit one,
141          */
142         if (pFnSendMessage16)
143             ret = pFnSendMessage16(lpDrv->d.d16.hDriver16, msg, lParam1, lParam2);
144     } else {
145         TRACE("Before call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx\n", 
146               lpDrv->d.d32.lpDrvProc, lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2);
147         ret = lpDrv->d.d32.lpDrvProc(lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2);
148         TRACE("After  call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx => %08lx\n", 
149               lpDrv->d.d32.lpDrvProc, lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2, ret);
150     }
151     return ret;
152 }
153
154 /**************************************************************************
155  *                              SendDriverMessage               [WINMM.@]
156  *                              DrvSendMessage                  [WINMM.@]
157  */
158 LRESULT WINAPI SendDriverMessage(HDRVR hDriver, UINT msg, LPARAM lParam1,
159                                  LPARAM lParam2)
160 {
161     LPWINE_DRIVER       lpDrv;
162     LRESULT             retval = 0;
163
164     TRACE("(%p, %04X, %08lX, %08lX)\n", hDriver, msg, lParam1, lParam2);
165
166     if ((lpDrv = DRIVER_FindFromHDrvr(hDriver)) != NULL) {
167         retval = DRIVER_SendMessage(lpDrv, msg, lParam1, lParam2);
168     } else {
169         WARN("Bad driver handle %p\n", hDriver);
170     }
171     TRACE("retval = %ld\n", retval);
172
173     return retval;
174 }
175
176 /**************************************************************************
177  *                              DRIVER_RemoveFromList           [internal]
178  *
179  * Generates all the logic to handle driver closure / deletion
180  * Removes a driver struct to the list of open drivers.
181  */
182 static  BOOL    DRIVER_RemoveFromList(LPWINE_DRIVER lpDrv)
183 {
184     if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) {
185         /* last of this driver in list ? */
186         if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 1) {
187             DRIVER_SendMessage(lpDrv, DRV_DISABLE, 0L, 0L);
188             DRIVER_SendMessage(lpDrv, DRV_FREE,    0L, 0L);
189         }
190     }
191
192     EnterCriticalSection( &mmdriver_lock );
193
194     if (lpDrv->lpPrevItem)
195         lpDrv->lpPrevItem->lpNextItem = lpDrv->lpNextItem;
196     else
197         lpDrvItemList = lpDrv->lpNextItem;
198     if (lpDrv->lpNextItem)
199         lpDrv->lpNextItem->lpPrevItem = lpDrv->lpPrevItem;
200     /* trash magic number */
201     lpDrv->dwMagic ^= 0xa5a5a5a5;
202     lpDrv->d.d32.lpDrvProc = NULL;
203     lpDrv->d.d32.dwDriverID = 0;
204     lpDrv->d.d16.hDriver16 = 0;
205
206     LeaveCriticalSection( &mmdriver_lock );
207
208     return TRUE;
209 }
210
211 /**************************************************************************
212  *                              DRIVER_AddToList                [internal]
213  *
214  * Adds a driver struct to the list of open drivers.
215  * Generates all the logic to handle driver creation / open.
216  */
217 static  BOOL    DRIVER_AddToList(LPWINE_DRIVER lpNewDrv, LPARAM lParam1, LPARAM lParam2)
218 {
219     lpNewDrv->dwMagic = WINE_DI_MAGIC;
220     /* First driver to be loaded for this module, need to load correctly the module */
221     if (!(lpNewDrv->dwFlags & WINE_GDF_16BIT)) {
222         /* first of this driver in list ? */
223         if (DRIVER_GetNumberOfModuleRefs(lpNewDrv->d.d32.hModule, NULL) == 0) {
224             if (DRIVER_SendMessage(lpNewDrv, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) {
225                 TRACE("DRV_LOAD failed on driver %p\n", lpNewDrv);
226                 return FALSE;
227             }
228             /* returned value is not checked */
229             DRIVER_SendMessage(lpNewDrv, DRV_ENABLE, 0L, 0L);
230         }
231
232         /* Now just open a new instance of a driver on this module */
233         lpNewDrv->d.d32.dwDriverID = DRIVER_SendMessage(lpNewDrv, DRV_OPEN, lParam1, lParam2);
234
235         if (lpNewDrv->d.d32.dwDriverID == 0)
236         {
237             TRACE("DRV_OPEN failed on driver %p\n", lpNewDrv);
238             return FALSE;
239         }
240     }
241
242     EnterCriticalSection( &mmdriver_lock );
243
244     lpNewDrv->lpNextItem = NULL;
245     if (lpDrvItemList == NULL) {
246         lpDrvItemList = lpNewDrv;
247         lpNewDrv->lpPrevItem = NULL;
248     } else {
249         LPWINE_DRIVER   lpDrv = lpDrvItemList;  /* find end of list */
250         while (lpDrv->lpNextItem != NULL)
251             lpDrv = lpDrv->lpNextItem;
252
253         lpDrv->lpNextItem = lpNewDrv;
254         lpNewDrv->lpPrevItem = lpDrv;
255     }
256
257     LeaveCriticalSection( &mmdriver_lock );
258     return TRUE;
259 }
260
261 /**************************************************************************
262  *                              DRIVER_GetLibName               [internal]
263  *
264  */
265 BOOL    DRIVER_GetLibName(LPCWSTR keyName, LPCWSTR sectName, LPWSTR buf, int sz)
266 {
267     HKEY        hKey, hSecKey;
268     DWORD       bufLen, lRet;
269     static const WCHAR wszSystemIni[] = {'S','Y','S','T','E','M','.','I','N','I',0};
270     WCHAR       wsznull = '\0';
271
272     TRACE("registry: %s, %s, %p, %d\n", debugstr_w(keyName), debugstr_w(sectName), buf, sz);
273
274     lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, HKLM_BASE, 0, KEY_QUERY_VALUE, &hKey);
275     if (lRet == ERROR_SUCCESS) {
276         lRet = RegOpenKeyExW(hKey, sectName, 0, KEY_QUERY_VALUE, &hSecKey);
277         if (lRet == ERROR_SUCCESS) {
278             bufLen = sz;
279             lRet = RegQueryValueExW(hSecKey, keyName, 0, 0, (void*)buf, &bufLen);
280             RegCloseKey( hSecKey );
281         }
282         RegCloseKey( hKey );
283     }
284     if (lRet == ERROR_SUCCESS) return TRUE;
285
286     /* default to system.ini if we can't find it in the registry,
287      * to support native installations where system.ini is still used */
288     TRACE("system.ini: %s, %s, %p, %d\n", debugstr_w(keyName), debugstr_w(sectName), buf, sz);
289     return GetPrivateProfileStringW(sectName, keyName, &wsznull, buf, sz / sizeof(WCHAR), wszSystemIni);
290 }
291
292 /**************************************************************************
293  *                              DRIVER_TryOpenDriver32          [internal]
294  *
295  * Tries to load a 32 bit driver whose DLL's (module) name is fn
296  */
297 LPWINE_DRIVER   DRIVER_TryOpenDriver32(LPCWSTR fn, LPARAM lParam2)
298 {
299     LPWINE_DRIVER       lpDrv = NULL;
300     HMODULE             hModule = 0;
301     LPWSTR              ptr;
302     LPCSTR              cause = 0;
303
304     TRACE("(%s, %08lX);\n", debugstr_w(fn), lParam2);
305
306     if ((ptr = strchrW(fn, ' ')) != NULL) {
307         *ptr++ = '\0';
308         while (*ptr == ' ') ptr++;
309         if (*ptr == '\0') ptr = NULL;
310     }
311
312     lpDrv = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_DRIVER));
313     if (lpDrv == NULL) {cause = "OOM"; goto exit;}
314
315     if ((hModule = LoadLibraryW(fn)) == 0) {cause = "Not a 32 bit lib"; goto exit;}
316
317     lpDrv->d.d32.lpDrvProc = (DRIVERPROC)GetProcAddress(hModule, "DriverProc");
318     if (lpDrv->d.d32.lpDrvProc == NULL) {cause = "no DriverProc"; goto exit;}
319
320     lpDrv->dwFlags          = 0;
321     lpDrv->d.d32.hModule    = hModule;
322     lpDrv->d.d32.dwDriverID = 0;
323
324     /* Win32 installable drivers must support a two phase opening scheme:
325      * + first open with NULL as lParam2 (session instance),
326      * + then do a second open with the real non null lParam2)
327      */
328     if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 0 && lParam2)
329     {
330         LPWINE_DRIVER   ret;
331
332         if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, 0L))
333         {
334             cause = "load0 failed";
335             goto exit;
336         }
337         ret = DRIVER_TryOpenDriver32(fn, lParam2);
338         if (!ret)
339         {
340             CloseDriver((HDRVR)lpDrv, 0L, 0L);
341             cause = "load1 failed";
342             goto exit;
343         }
344         lpDrv->dwFlags |= WINE_GDF_SESSION;
345         return ret;
346     }
347
348     if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, lParam2))
349     {cause = "load failed"; goto exit;}
350
351     TRACE("=> %p\n", lpDrv);
352     return lpDrv;
353  exit:
354     FreeLibrary(hModule);
355     HeapFree(GetProcessHeap(), 0, lpDrv);
356     TRACE("Unable to load 32 bit module %s: %s\n", debugstr_w(fn), cause);
357     return NULL;
358 }
359
360 /**************************************************************************
361  *                              OpenDriverA                     [WINMM.@]
362  *                              DrvOpenA                        [WINMM.@]
363  * (0,1,DRV_LOAD  ,0       ,0)
364  * (0,1,DRV_ENABLE,0       ,0)
365  * (0,1,DRV_OPEN  ,buf[256],0)
366  */
367 HDRVR WINAPI OpenDriverA(LPCSTR lpDriverName, LPCSTR lpSectionName, LPARAM lParam)
368 {
369     INT                 len;
370     LPWSTR              dn = NULL;
371     LPWSTR              sn = NULL;
372     HDRVR               ret = 0;
373
374     if (lpDriverName)
375     {
376         len = MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, NULL, 0 );
377         dn = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
378         if (!dn) goto done;
379         MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, dn, len );
380     }
381
382     if (lpSectionName)
383     {
384         len = MultiByteToWideChar( CP_ACP, 0, lpSectionName, -1, NULL, 0 );
385         sn = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
386         if (!sn) goto done;
387         MultiByteToWideChar( CP_ACP, 0, lpSectionName, -1, sn, len );
388     }
389
390     ret = OpenDriver(dn, sn, lParam);
391
392 done:
393     HeapFree(GetProcessHeap(), 0, dn);
394     HeapFree(GetProcessHeap(), 0, sn);
395     return ret;
396 }
397
398 /**************************************************************************
399  *                              OpenDriver                      [WINMM.@]
400  *                              DrvOpen                         [WINMM.@]
401  */
402 HDRVR WINAPI OpenDriver(LPCWSTR lpDriverName, LPCWSTR lpSectionName, LPARAM lParam)
403 {
404     LPWINE_DRIVER       lpDrv = NULL;
405     WCHAR               libName[MAX_PATH + 1];
406     LPCWSTR             lsn = lpSectionName;
407
408     TRACE("(%s, %s, 0x%08lx);\n", 
409           debugstr_w(lpDriverName), debugstr_w(lpSectionName), lParam);
410
411     DRIVER_Dump("BEFORE:");
412
413     if (lsn == NULL) {
414         static const WCHAR wszDrivers32[] = {'D','r','i','v','e','r','s','3','2',0};
415         lstrcpynW(libName, lpDriverName, sizeof(libName) / sizeof(WCHAR));
416
417         if ((lpDrv = DRIVER_TryOpenDriver32(libName, lParam)))
418             goto the_end;
419         lsn = wszDrivers32;
420     }
421     if (DRIVER_GetLibName(lpDriverName, lsn, libName, sizeof(libName)) &&
422         (lpDrv = DRIVER_TryOpenDriver32(libName, lParam)))
423         goto the_end;
424
425     /* now we will try a 16 bit driver (and add all the glue to make it work... which
426      * is located in our mmsystem implementation)
427      * so ensure, we can load our mmsystem, otherwise just fail
428      */
429     WINMM_CheckForMMSystem();
430     if (pFnOpenDriver16 &&
431         (lpDrv = pFnOpenDriver16(lpDriverName, lpSectionName, lParam)))
432     {
433         if (DRIVER_AddToList(lpDrv, 0, lParam)) goto the_end;
434         HeapFree(GetProcessHeap(), 0, lpDrv);
435     }
436     TRACE("Failed to open driver %s from system.ini file, section %s\n", 
437           debugstr_w(lpDriverName), debugstr_w(lpSectionName));
438
439 the_end:
440     TRACE("=> %p\n", lpDrv);
441
442     DRIVER_Dump("AFTER:");
443
444     return (HDRVR)lpDrv;
445 }
446
447 /**************************************************************************
448  *                      CloseDriver                             [WINMM.@]
449  *                      DrvClose                                [WINMM.@]
450  */
451 LRESULT WINAPI CloseDriver(HDRVR hDrvr, LPARAM lParam1, LPARAM lParam2)
452 {
453     BOOL ret;
454     LPWINE_DRIVER       lpDrv;
455
456     TRACE("(%p, %08lX, %08lX);\n", hDrvr, lParam1, lParam2);
457
458     DRIVER_Dump("BEFORE:");
459
460     if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL)
461     {
462         if (lpDrv->dwFlags & WINE_GDF_16BIT)
463         {
464             if (pFnCloseDriver16)
465                 pFnCloseDriver16(lpDrv->d.d16.hDriver16, lParam1, lParam2);
466         }
467         else
468             DRIVER_SendMessage(lpDrv, DRV_CLOSE, lParam1, lParam2);
469
470         DRIVER_RemoveFromList(lpDrv);
471
472         if (!(lpDrv->dwFlags & WINE_GDF_16BIT))
473         {
474             LPWINE_DRIVER lpDrv0;
475
476             if (lpDrv->dwFlags & WINE_GDF_SESSION)
477                 FIXME("WINE_GDF_SESSION: Shouldn't happen (%p)\n", lpDrv);
478             /* if driver has an opened session instance, we have to close it too */
479             if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, &lpDrv0) == 1 &&
480                 (lpDrv0->dwFlags & WINE_GDF_SESSION))
481             {
482                 DRIVER_SendMessage(lpDrv0, DRV_CLOSE, 0, 0);
483                 DRIVER_RemoveFromList(lpDrv0);
484                 FreeLibrary(lpDrv0->d.d32.hModule);
485                 HeapFree(GetProcessHeap(), 0, lpDrv0);
486             }
487             FreeLibrary(lpDrv->d.d32.hModule);
488         }
489         HeapFree(GetProcessHeap(), 0, lpDrv);
490         ret = TRUE;
491     }
492     else
493     {
494         WARN("Failed to close driver\n");
495         ret = FALSE;
496     }
497
498     DRIVER_Dump("AFTER:");
499
500     return ret;
501 }
502
503 /**************************************************************************
504  *                              GetDriverFlags          [WINMM.@]
505  * [in] hDrvr handle to the driver
506  *
507  * Returns:
508  *      0x00000000 if hDrvr is an invalid handle
509  *      0x80000000 if hDrvr is a valid 32 bit driver
510  *      0x90000000 if hDrvr is a valid 16 bit driver
511  *
512  * native WINMM doesn't return those flags
513  *      0x80000000 for a valid 32 bit driver and that's it
514  *      (I may have mixed up the two flags :-(
515  */
516 DWORD   WINAPI GetDriverFlags(HDRVR hDrvr)
517 {
518     LPWINE_DRIVER       lpDrv;
519     DWORD               ret = 0;
520
521     TRACE("(%p)\n", hDrvr);
522
523     if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) {
524         ret = WINE_GDF_EXIST | (lpDrv->dwFlags & WINE_GDF_EXTERNAL_MASK);
525     }
526     return ret;
527 }
528
529 /**************************************************************************
530  *                              GetDriverModuleHandle   [WINMM.@]
531  *                              DrvGetModuleHandle      [WINMM.@]
532  */
533 HMODULE WINAPI GetDriverModuleHandle(HDRVR hDrvr)
534 {
535     LPWINE_DRIVER       lpDrv;
536     HMODULE             hModule = 0;
537
538     TRACE("(%p);\n", hDrvr);
539
540     if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) {
541         if (!(lpDrv->dwFlags & WINE_GDF_16BIT))
542             hModule = lpDrv->d.d32.hModule;
543     }
544     TRACE("=> %p\n", hModule);
545     return hModule;
546 }
547
548 /**************************************************************************
549  *                              DefDriverProc                     [WINMM.@]
550  *                              DrvDefDriverProc                  [WINMM.@]
551  */
552 LRESULT WINAPI DefDriverProc(DWORD_PTR dwDriverIdentifier, HDRVR hDrv,
553                              UINT Msg, LPARAM lParam1, LPARAM lParam2)
554 {
555     switch (Msg) {
556     case DRV_LOAD:
557     case DRV_FREE:
558     case DRV_ENABLE:
559     case DRV_DISABLE:
560         return 1;
561     case DRV_INSTALL:
562     case DRV_REMOVE:
563         return DRV_SUCCESS;
564     default:
565         return 0;
566     }
567 }
568
569 /**************************************************************************
570  *                              DriverCallback                  [WINMM.@]
571  */
572 BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev,
573                            UINT wMsg, DWORD dwUser, DWORD dwParam1,
574                            DWORD dwParam2)
575 {
576     TRACE("(%08X, %04X, %p, %04X, %08X, %08X, %08X); !\n",
577           dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
578
579     switch (uFlags & DCB_TYPEMASK) {
580     case DCB_NULL:
581         TRACE("Null !\n");
582         if (dwCallBack)
583             WARN("uFlags=%04X has null DCB value, but dwCallBack=%08X is not null !\n", uFlags, dwCallBack);
584         break;
585     case DCB_WINDOW:
586         TRACE("Window(%04X) handle=%p!\n", dwCallBack, hDev);
587         PostMessageA((HWND)dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
588         break;
589     case DCB_TASK: /* aka DCB_THREAD */
590         TRACE("Task(%04x) !\n", dwCallBack);
591         PostThreadMessageA(dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
592         break;
593     case DCB_FUNCTION:
594         TRACE("Function (32 bit) !\n");
595         ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
596         break;
597     case DCB_EVENT:
598         TRACE("Event(%08x) !\n", dwCallBack);
599         SetEvent((HANDLE)dwCallBack);
600         break;
601     case 6: /* I would dub it DCB_MMTHREADSIGNAL */
602         /* this is an undocumented DCB_ value used for mmThreads
603          * loword of dwCallBack contains the handle of the lpMMThd block
604          * which dwSignalCount has to be incremented
605          */     
606         if (pFnGetMMThread16)
607         {
608             WINE_MMTHREAD*      lpMMThd = pFnGetMMThread16(LOWORD(dwCallBack));
609
610             TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
611             /* same as mmThreadSignal16 */
612             InterlockedIncrement(&lpMMThd->dwSignalCount);
613             SetEvent(lpMMThd->hEvent);
614             /* some other stuff on lpMMThd->hVxD */
615         }
616         break;
617 #if 0
618     case 4:
619         /* this is an undocumented DCB_ value for... I don't know */
620         break;
621 #endif
622     default:
623         WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
624         return FALSE;
625     }
626     TRACE("Done\n");
627     return TRUE;
628 }
629
630 /******************************************************************
631  *              DRIVER_UnloadAll
632  *
633  *
634  */
635 void    DRIVER_UnloadAll(void)
636 {
637     LPWINE_DRIVER       lpDrv;
638     LPWINE_DRIVER       lpNextDrv = NULL;
639     unsigned            count = 0;
640
641 restart:
642     EnterCriticalSection( &mmdriver_lock );
643
644     for (lpDrv = lpDrvItemList; lpDrv != NULL; lpDrv = lpNextDrv)
645     {
646         lpNextDrv = lpDrv->lpNextItem;
647
648         /* session instances will be unloaded automatically */
649         if (!(lpDrv->dwFlags & WINE_GDF_SESSION))
650         {
651             LeaveCriticalSection( &mmdriver_lock );
652             CloseDriver((HDRVR)lpDrv, 0, 0);
653             count++;
654             /* restart from the beginning of the list */
655             goto restart;
656         }
657     }
658
659     LeaveCriticalSection( &mmdriver_lock );
660
661     TRACE("Unloaded %u drivers\n", count);
662 }