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