Added additional formats.
[wine] / dlls / winmm / driver.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  * WINE Drivers functions
5  *
6  * Copyright 1994 Martin Ayotte
7  * Copyright 1998 Marcus Meissner
8  * Copyright 1999 Eric Pouech
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 #include <string.h>
26 #include "heap.h"
27 #include "windef.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "mmddk.h"
31 #include "winemm.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(driver);
35
36 static LPWINE_DRIVER   lpDrvItemList  /* = NULL */;
37
38 WINE_MMTHREAD*  (*pFnGetMMThread16)(HANDLE16 h) /* = NULL */;
39 LPWINE_DRIVER   (*pFnOpenDriver16)(LPCSTR,LPCSTR,LPARAM) /* = NULL */;
40 LRESULT         (*pFnCloseDriver16)(HDRVR16,LPARAM,LPARAM) /* = NULL */;
41 LRESULT         (*pFnSendMessage16)(HDRVR16,UINT,LPARAM,LPARAM) /* = NULL */;
42
43 /**************************************************************************
44  *                      DRIVER_GetNumberOfModuleRefs            [internal]
45  *
46  * Returns the number of open drivers which share the same module.
47  */
48 static  unsigned DRIVER_GetNumberOfModuleRefs(HMODULE hModule, WINE_DRIVER** found)
49 {
50     LPWINE_DRIVER       lpDrv;
51     unsigned            count = 0;
52
53     if (found) *found = NULL;
54     for (lpDrv = lpDrvItemList; lpDrv; lpDrv = lpDrv->lpNextItem)
55     {
56         if (!(lpDrv->dwFlags & WINE_GDF_16BIT) && lpDrv->d.d32.hModule == hModule)
57         {
58             if (found && !*found) *found = lpDrv;
59             count++;
60         }
61     }
62     return count;
63 }
64
65 /**************************************************************************
66  *                              DRIVER_FindFromHDrvr            [internal]
67  *
68  * From a hDrvr being 32 bits, returns the WINE internal structure.
69  */
70 LPWINE_DRIVER   DRIVER_FindFromHDrvr(HDRVR hDrvr)
71 {
72     LPWINE_DRIVER       d = (LPWINE_DRIVER)hDrvr;
73
74     if (hDrvr && HeapValidate(GetProcessHeap(), 0, d) && d->dwMagic == WINE_DI_MAGIC) {
75         return d;
76     }
77     return NULL;
78 }
79
80 /**************************************************************************
81  *                              DRIVER_SendMessage              [internal]
82  */
83 static LRESULT inline DRIVER_SendMessage(LPWINE_DRIVER lpDrv, UINT msg,
84                                          LPARAM lParam1, LPARAM lParam2)
85 {
86     LRESULT             ret = 0;
87
88     if (lpDrv->dwFlags & WINE_GDF_16BIT) {
89         /* no need to check mmsystem presence: the driver must have been opened as a 16 bit one,
90          */
91         if (pFnSendMessage16)
92             ret = pFnSendMessage16(lpDrv->d.d16.hDriver16, msg, lParam1, lParam2);
93     } else {
94         TRACE("Before call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx\n", 
95               lpDrv->d.d32.lpDrvProc, lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2);
96         ret = lpDrv->d.d32.lpDrvProc(lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2);
97         TRACE("After  call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx => %08lx\n", 
98               lpDrv->d.d32.lpDrvProc, lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2, ret);
99     }
100     return ret;
101 }
102
103 /**************************************************************************
104  *                              SendDriverMessage               [WINMM.@]
105  *                              DrvSendMessage                  [WINMM.@]
106  */
107 LRESULT WINAPI SendDriverMessage(HDRVR hDriver, UINT msg, LPARAM lParam1,
108                                  LPARAM lParam2)
109 {
110     LPWINE_DRIVER       lpDrv;
111     LRESULT             retval = 0;
112
113     TRACE("(%p, %04X, %08lX, %08lX)\n", hDriver, msg, lParam1, lParam2);
114
115     if ((lpDrv = DRIVER_FindFromHDrvr(hDriver)) != NULL) {
116         retval = DRIVER_SendMessage(lpDrv, msg, lParam1, lParam2);
117     } else {
118         WARN("Bad driver handle %p\n", hDriver);
119     }
120     TRACE("retval = %ld\n", retval);
121
122     return retval;
123 }
124
125 /**************************************************************************
126  *                              DRIVER_RemoveFromList           [internal]
127  *
128  * Generates all the logic to handle driver closure / deletion
129  * Removes a driver struct to the list of open drivers.
130  */
131 static  BOOL    DRIVER_RemoveFromList(LPWINE_DRIVER lpDrv)
132 {
133     if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) {
134         /* last of this driver in list ? */
135         if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 1) {
136             DRIVER_SendMessage(lpDrv, DRV_DISABLE, 0L, 0L);
137             DRIVER_SendMessage(lpDrv, DRV_FREE,    0L, 0L);
138         }
139     }
140
141     if (lpDrv->lpPrevItem)
142         lpDrv->lpPrevItem->lpNextItem = lpDrv->lpNextItem;
143     else
144         lpDrvItemList = lpDrv->lpNextItem;
145     if (lpDrv->lpNextItem)
146         lpDrv->lpNextItem->lpPrevItem = lpDrv->lpPrevItem;
147     /* trash magic number */
148     lpDrv->dwMagic ^= 0xa5a5a5a5;
149
150     return TRUE;
151 }
152
153 /**************************************************************************
154  *                              DRIVER_AddToList                [internal]
155  *
156  * Adds a driver struct to the list of open drivers.
157  * Generates all the logic to handle driver creation / open.
158  */
159 static  BOOL    DRIVER_AddToList(LPWINE_DRIVER lpNewDrv, LPARAM lParam1, LPARAM lParam2)
160 {
161     lpNewDrv->dwMagic = WINE_DI_MAGIC;
162     /* First driver to be loaded for this module, need to load correctly the module */
163     if (!(lpNewDrv->dwFlags & WINE_GDF_16BIT)) {
164         /* first of this driver in list ? */
165         if (DRIVER_GetNumberOfModuleRefs(lpNewDrv->d.d32.hModule, NULL) == 0) {
166             if (DRIVER_SendMessage(lpNewDrv, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) {
167                 TRACE("DRV_LOAD failed on driver 0x%08lx\n", (DWORD)lpNewDrv);
168                 return FALSE;
169             }
170             /* returned value is not checked */
171             DRIVER_SendMessage(lpNewDrv, DRV_ENABLE, 0L, 0L);
172         }
173     }
174
175     lpNewDrv->lpNextItem = NULL;
176     if (lpDrvItemList == NULL) {
177         lpDrvItemList = lpNewDrv;
178         lpNewDrv->lpPrevItem = NULL;
179     } else {
180         LPWINE_DRIVER   lpDrv = lpDrvItemList;  /* find end of list */
181         while (lpDrv->lpNextItem != NULL)
182             lpDrv = lpDrv->lpNextItem;
183
184         lpDrv->lpNextItem = lpNewDrv;
185         lpNewDrv->lpPrevItem = lpDrv;
186     }
187
188     if (!(lpNewDrv->dwFlags & WINE_GDF_16BIT)) {
189         /* Now just open a new instance of a driver on this module */
190         lpNewDrv->d.d32.dwDriverID = DRIVER_SendMessage(lpNewDrv, DRV_OPEN, lParam1, lParam2);
191
192         if (lpNewDrv->d.d32.dwDriverID == 0) {
193             TRACE("DRV_OPEN failed on driver 0x%08lx\n", (DWORD)lpNewDrv);
194             DRIVER_RemoveFromList(lpNewDrv);
195             return FALSE;
196         }
197     }
198     return TRUE;
199 }
200
201 /**************************************************************************
202  *                              DRIVER_GetLibName               [internal]
203  *
204  */
205 BOOL    DRIVER_GetLibName(LPCSTR keyName, LPCSTR sectName, LPSTR buf, int sz)
206 {
207     /* should also do some registry diving */
208     return GetPrivateProfileStringA(sectName, keyName, "", buf, sz, "SYSTEM.INI");
209 }
210
211 /**************************************************************************
212  *                              DRIVER_TryOpenDriver32          [internal]
213  *
214  * Tries to load a 32 bit driver whose DLL's (module) name is fn
215  */
216 LPWINE_DRIVER   DRIVER_TryOpenDriver32(LPCSTR fn, LPARAM lParam2)
217 {
218     LPWINE_DRIVER       lpDrv = NULL;
219     HMODULE             hModule = 0;
220     LPSTR               ptr;
221     LPCSTR              cause = 0;
222
223     TRACE("(%s, %08lX);\n", debugstr_a(fn), lParam2);
224
225     if ((ptr = strchr(fn, ' ')) != NULL) {
226         *ptr++ = '\0';
227         while (*ptr == ' ') ptr++;
228         if (*ptr == '\0') ptr = NULL;
229     }
230
231     lpDrv = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_DRIVER));
232     if (lpDrv == NULL) {cause = "OOM"; goto exit;}
233
234     if ((hModule = LoadLibraryA(fn)) == 0) {cause = "Not a 32 bit lib"; goto exit;}
235
236     lpDrv->d.d32.lpDrvProc = (DRIVERPROC)GetProcAddress(hModule, "DriverProc");
237     if (lpDrv->d.d32.lpDrvProc == NULL) {cause = "no DriverProc"; goto exit;}
238
239     lpDrv->dwFlags          = 0;
240     lpDrv->d.d32.hModule    = hModule;
241     lpDrv->d.d32.dwDriverID = 0;
242
243     /* Win32 installable drivers must support a two phase opening scheme:
244      * + first open with NULL as lParam2 (session instance),
245      * + then do a second open with the real non null lParam2)
246      */
247     if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 0 && lParam2)
248     {
249         LPWINE_DRIVER   ret;
250
251         if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, 0L))
252         {
253             cause = "load0 failed";
254             goto exit;
255         }
256         ret = DRIVER_TryOpenDriver32(fn, lParam2);
257         if (!ret)
258         {
259             CloseDriver((HDRVR)lpDrv, 0L, 0L);
260             cause = "load1 failed";
261             goto exit;
262         }
263         return ret;
264     }
265
266     if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, lParam2))
267     {cause = "load failed"; goto exit;}
268
269     TRACE("=> %p\n", lpDrv);
270     return lpDrv;
271  exit:
272     FreeLibrary(hModule);
273     HeapFree(GetProcessHeap(), 0, lpDrv);
274     TRACE("Unable to load 32 bit module %s: %s\n", debugstr_a(fn), cause);
275     return NULL;
276 }
277
278 /**************************************************************************
279  *                              OpenDriverA                     [WINMM.@]
280  *                              DrvOpenA                        [WINMM.@]
281  * (0,1,DRV_LOAD  ,0       ,0)
282  * (0,1,DRV_ENABLE,0       ,0)
283  * (0,1,DRV_OPEN  ,buf[256],0)
284  */
285 HDRVR WINAPI OpenDriverA(LPCSTR lpDriverName, LPCSTR lpSectionName, LPARAM lParam2)
286 {
287     LPWINE_DRIVER       lpDrv = NULL;
288     char                libName[128];
289     LPCSTR              lsn = lpSectionName;
290
291     TRACE("(%s, %s, 0x%08lx);\n", debugstr_a(lpDriverName), debugstr_a(lpSectionName), lParam2);
292
293     if (lsn == NULL) {
294         lstrcpynA(libName, lpDriverName, sizeof(libName));
295
296         if ((lpDrv = DRIVER_TryOpenDriver32(libName, lParam2)))
297             goto the_end;
298         lsn = "Drivers32";
299     }
300     if (DRIVER_GetLibName(lpDriverName, lsn, libName, sizeof(libName)) &&
301         (lpDrv = DRIVER_TryOpenDriver32(libName, lParam2)))
302         goto the_end;
303
304     /* now we will try a 16 bit driver (and add all the glue to make it work... which
305      * is located in our mmsystem implementation)
306      * so ensure, we can load our mmsystem, otherwise just fail
307      */
308     WINMM_CheckForMMSystem();
309     if (pFnOpenDriver16 &&
310         (lpDrv = pFnOpenDriver16(lpDriverName, lpSectionName, lParam2)))
311     {
312         if (DRIVER_AddToList(lpDrv, 0, lParam2)) goto the_end;
313         HeapFree(GetProcessHeap(), 0, lpDrv);
314     }
315     TRACE("Failed to open driver %s from system.ini file, section %s\n", debugstr_a(lpDriverName), debugstr_a(lpSectionName));
316     return 0;
317
318  the_end:
319     if (lpDrv)  TRACE("=> %08lx\n", (DWORD)lpDrv);
320     return (HDRVR)lpDrv;
321 }
322
323 /**************************************************************************
324  *                              OpenDriver                      [WINMM.@]
325  *                              DrvOpen                         [WINMM.@]
326  */
327 HDRVR WINAPI OpenDriverW(LPCWSTR lpDriverName, LPCWSTR lpSectionName, LPARAM lParam)
328 {
329     LPSTR               dn = HEAP_strdupWtoA(GetProcessHeap(), 0, lpDriverName);
330     LPSTR               sn = HEAP_strdupWtoA(GetProcessHeap(), 0, lpSectionName);
331     HDRVR               ret = OpenDriverA(dn, sn, lParam);
332
333     if (dn) HeapFree(GetProcessHeap(), 0, dn);
334     if (sn) HeapFree(GetProcessHeap(), 0, sn);
335     return ret;
336 }
337
338 /**************************************************************************
339  *                      CloseDriver                             [WINMM.@]
340  *                      DrvClose                                [WINMM.@]
341  */
342 LRESULT WINAPI CloseDriver(HDRVR hDrvr, LPARAM lParam1, LPARAM lParam2)
343 {
344     LPWINE_DRIVER       lpDrv;
345
346     TRACE("(%p, %08lX, %08lX);\n", hDrvr, lParam1, lParam2);
347
348     if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL)
349     {
350         if (lpDrv->dwFlags & WINE_GDF_16BIT)
351         {
352             if (pFnCloseDriver16)
353                 pFnCloseDriver16(lpDrv->d.d16.hDriver16, lParam1, lParam2);
354         }
355         else
356         {
357             DRIVER_SendMessage(lpDrv, DRV_CLOSE, lParam1, lParam2);
358             lpDrv->d.d32.dwDriverID = 0;
359         }
360         if (DRIVER_RemoveFromList(lpDrv)) {
361             if (!(lpDrv->dwFlags & WINE_GDF_16BIT))
362             {
363                 LPWINE_DRIVER       lpDrv0;
364
365                 /* if driver has an opened session instance, we have to close it too */
366                 if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, &lpDrv0) == 1)
367                 {
368                     DRIVER_SendMessage(lpDrv0, DRV_CLOSE, 0L, 0L);
369                     lpDrv0->d.d32.dwDriverID = 0;
370                     DRIVER_RemoveFromList(lpDrv0);
371                     FreeLibrary(lpDrv->d.d32.hModule);
372                     HeapFree(GetProcessHeap(), 0, lpDrv0);
373                 }
374                 FreeLibrary(lpDrv->d.d32.hModule);
375             }
376             HeapFree(GetProcessHeap(), 0, lpDrv);
377             return TRUE;
378         }
379     }
380     WARN("Failed to close driver\n");
381     return FALSE;
382 }
383
384 /**************************************************************************
385  *                              GetDriverFlags          [WINMM.@]
386  * [in] hDrvr handle to the driver
387  *
388  * Returns:
389  *      0x00000000 if hDrvr is an invalid handle
390  *      0x80000000 if hDrvr is a valid 32 bit driver
391  *      0x90000000 if hDrvr is a valid 16 bit driver
392  *
393  * native WINMM doesn't return those flags
394  *      0x80000000 for a valid 32 bit driver and that's it
395  *      (I may have mixed up the two flags :-(
396  */
397 DWORD   WINAPI GetDriverFlags(HDRVR hDrvr)
398 {
399     LPWINE_DRIVER       lpDrv;
400     DWORD               ret = 0;
401
402     TRACE("(%p)\n", hDrvr);
403
404     if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) {
405         ret = WINE_GDF_EXIST | lpDrv->dwFlags;
406     }
407     return ret;
408 }
409
410 /**************************************************************************
411  *                              GetDriverModuleHandle   [WINMM.@]
412  *                              DrvGetModuleHandle      [WINMM.@]
413  */
414 HMODULE WINAPI GetDriverModuleHandle(HDRVR hDrvr)
415 {
416     LPWINE_DRIVER       lpDrv;
417     HMODULE             hModule = 0;
418
419     TRACE("(%p);\n", hDrvr);
420
421     if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) {
422         if (!(lpDrv->dwFlags & WINE_GDF_16BIT))
423             hModule = lpDrv->d.d32.hModule;
424     }
425     TRACE("=> %p\n", hModule);
426     return hModule;
427 }
428
429 /**************************************************************************
430  *                              DefDriverProc                     [WINMM.@]
431  *                              DrvDefDriverProc                  [WINMM.@]
432  */
433 LRESULT WINAPI DefDriverProc(DWORD dwDriverIdentifier, HDRVR hDrv,
434                              UINT Msg, LPARAM lParam1, LPARAM lParam2)
435 {
436     switch (Msg) {
437     case DRV_LOAD:
438     case DRV_FREE:
439     case DRV_ENABLE:
440     case DRV_DISABLE:
441         return 1;
442     case DRV_INSTALL:
443     case DRV_REMOVE:
444         return DRV_SUCCESS;
445     default:
446         return 0;
447     }
448 }
449
450 /**************************************************************************
451  *                              DriverCallback                  [WINMM.@]
452  */
453 BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev,
454                            UINT wMsg, DWORD dwUser, DWORD dwParam1,
455                            DWORD dwParam2)
456 {
457     TRACE("(%08lX, %04X, %p, %04X, %08lX, %08lX, %08lX); !\n",
458           dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
459
460     switch (uFlags & DCB_TYPEMASK) {
461     case DCB_NULL:
462         TRACE("Null !\n");
463         if (dwCallBack)
464             WARN("uFlags=%04X has null DCB value, but dwCallBack=%08lX is not null !\n", uFlags, dwCallBack);
465         break;
466     case DCB_WINDOW:
467         TRACE("Window(%04lX) handle=%p!\n", dwCallBack, hDev);
468         PostMessageA((HWND)dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
469         break;
470     case DCB_TASK: /* aka DCB_THREAD */
471         TRACE("Task(%04lx) !\n", dwCallBack);
472         PostThreadMessageA(dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
473         break;
474     case DCB_FUNCTION:
475         TRACE("Function (32 bit) !\n");
476         ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
477         break;
478     case DCB_EVENT:
479         TRACE("Event(%08lx) !\n", dwCallBack);
480         SetEvent((HANDLE)dwCallBack);
481         break;
482     case 6: /* I would dub it DCB_MMTHREADSIGNAL */
483         /* this is an undocumented DCB_ value used for mmThreads
484          * loword of dwCallBack contains the handle of the lpMMThd block
485          * which dwSignalCount has to be incremented
486          */     
487         if (pFnGetMMThread16)
488         {
489             WINE_MMTHREAD*      lpMMThd = pFnGetMMThread16(LOWORD(dwCallBack));
490
491             TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
492             /* same as mmThreadSignal16 */
493             InterlockedIncrement(&lpMMThd->dwSignalCount);
494             SetEvent(lpMMThd->hEvent);
495             /* some other stuff on lpMMThd->hVxD */
496         }
497         break;
498 #if 0
499     case 4:
500         /* this is an undocumented DCB_ value for... I don't know */
501         break;
502 #endif
503     default:
504         WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
505         return FALSE;
506     }
507     TRACE("Done\n");
508     return TRUE;
509 }
510
511 /******************************************************************
512  *              DRIVER_UnloadAll
513  *
514  *
515  */
516 void    DRIVER_UnloadAll(void)
517 {
518     LPWINE_DRIVER       lpDrv;
519     LPWINE_DRIVER       lpNextDrv = NULL;
520     unsigned            count = 0;
521
522     for (lpDrv = lpDrvItemList; lpDrv != NULL; lpDrv = lpNextDrv)
523     {
524         lpNextDrv = lpDrv->lpNextItem;
525         CloseDriver((HDRVR)lpDrv, 0, 0);
526         count++;
527     }
528     TRACE("Unloaded %u drivers\n", count);
529 }