windows.applicationmodel/tests: Use PathRemoveFileSpecW() instead of PathCchRemoveFil...
[wine.git] / dlls / winmm / driver.c
blob3a20aabda93596ec30225fbe91c2b22aa85ec8f6
1 /*
2 * WINE Drivers functions
4 * Copyright 1994 Martin Ayotte
5 * Copyright 1998 Marcus Meissner
6 * Copyright 1999 Eric Pouech
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.
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.
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
23 #include <string.h>
24 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
30 #include "winreg.h"
31 #include "mmddk.h"
32 #include "winemm.h"
33 #include "wine/debug.h"
34 #include "excpt.h"
35 #include "wine/exception.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(driver);
39 static CRITICAL_SECTION mmdriver_lock;
40 static CRITICAL_SECTION_DEBUG mmdriver_lock_debug =
42 0, 0, &mmdriver_lock,
43 { &mmdriver_lock_debug.ProcessLocksList, &mmdriver_lock_debug.ProcessLocksList },
44 0, 0, { (DWORD_PTR)(__FILE__ ": mmdriver_lock") }
46 static CRITICAL_SECTION mmdriver_lock = { &mmdriver_lock_debug, -1, 0, 0, 0, 0 };
48 static LPWINE_DRIVER lpDrvItemList /* = NULL */;
50 static void DRIVER_Dump(const char *comment)
52 #if 0
53 LPWINE_DRIVER lpDrv;
55 TRACE("%s\n", comment);
57 EnterCriticalSection( &mmdriver_lock );
59 for (lpDrv = lpDrvItemList; lpDrv != NULL; lpDrv = lpDrv->lpNextItem)
61 TRACE("%p, magic %04lx, id %p, next %p\n", lpDrv, lpDrv->dwMagic, lpDrv->d.d32.dwDriverID, lpDrv->lpNextItem);
64 LeaveCriticalSection( &mmdriver_lock );
65 #endif
68 /**************************************************************************
69 * DRIVER_GetNumberOfModuleRefs [internal]
71 * Returns the number of open drivers which share the same module.
73 static unsigned DRIVER_GetNumberOfModuleRefs(HMODULE hModule, WINE_DRIVER** found)
75 LPWINE_DRIVER lpDrv;
76 unsigned count = 0;
78 EnterCriticalSection( &mmdriver_lock );
80 if (found) *found = NULL;
81 for (lpDrv = lpDrvItemList; lpDrv; lpDrv = lpDrv->lpNextItem)
83 if (lpDrv->hModule == hModule)
85 if (found && !*found) *found = lpDrv;
86 count++;
90 LeaveCriticalSection( &mmdriver_lock );
91 return count;
94 /**************************************************************************
95 * DRIVER_FindFromHDrvr [internal]
97 * From a hDrvr being 32 bits, returns the WINE internal structure.
99 LPWINE_DRIVER DRIVER_FindFromHDrvr(HDRVR hDrvr)
101 LPWINE_DRIVER d;
103 __TRY
105 d = (LPWINE_DRIVER)hDrvr;
106 if (d && d->dwMagic != WINE_DI_MAGIC) d = NULL;
108 __EXCEPT_PAGE_FAULT
110 return NULL;
112 __ENDTRY;
114 if (d) TRACE("%p -> %p, %p\n", hDrvr, d->lpDrvProc, (void *)d->dwDriverID);
115 else TRACE("%p -> NULL\n", hDrvr);
117 return d;
120 /**************************************************************************
121 * DRIVER_SendMessage [internal]
123 static inline LRESULT DRIVER_SendMessage(LPWINE_DRIVER lpDrv, UINT msg,
124 LPARAM lParam1, LPARAM lParam2)
126 LRESULT ret;
128 TRACE("Before call32 proc=%p drvrID=%08Ix hDrv=%p wMsg=%04x p1=%08Ix p2=%08Ix\n",
129 lpDrv->lpDrvProc, lpDrv->dwDriverID, lpDrv, msg, lParam1, lParam2);
130 ret = lpDrv->lpDrvProc(lpDrv->dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2);
131 TRACE("After call32 proc=%p drvrID=%08Ix hDrv=%p wMsg=%04x p1=%08Ix p2=%08Ix => %08Ix\n",
132 lpDrv->lpDrvProc, lpDrv->dwDriverID, lpDrv, msg, lParam1, lParam2, ret);
134 return ret;
137 /**************************************************************************
138 * SendDriverMessage [WINMM.@]
139 * DrvSendMessage [WINMM.@]
141 LRESULT WINAPI SendDriverMessage(HDRVR hDriver, UINT msg, LPARAM lParam1,
142 LPARAM lParam2)
144 LPWINE_DRIVER lpDrv;
145 LRESULT retval = 0;
147 TRACE("(%p, %04X, %08IX, %08IX)\n", hDriver, msg, lParam1, lParam2);
149 if ((lpDrv = DRIVER_FindFromHDrvr(hDriver)) != NULL) {
150 retval = DRIVER_SendMessage(lpDrv, msg, lParam1, lParam2);
151 } else {
152 WARN("Bad driver handle %p\n", hDriver);
154 TRACE("retval = %Id\n", retval);
156 return retval;
159 /**************************************************************************
160 * DRIVER_RemoveFromList [internal]
162 * Generates all the logic to handle driver closure / deletion
163 * Removes a driver struct to the list of open drivers.
165 static BOOL DRIVER_RemoveFromList(LPWINE_DRIVER lpDrv)
167 /* last of this driver in list ? */
168 if (DRIVER_GetNumberOfModuleRefs(lpDrv->hModule, NULL) == 1) {
169 DRIVER_SendMessage(lpDrv, DRV_DISABLE, 0L, 0L);
170 DRIVER_SendMessage(lpDrv, DRV_FREE, 0L, 0L);
173 EnterCriticalSection( &mmdriver_lock );
175 if (lpDrv->lpPrevItem)
176 lpDrv->lpPrevItem->lpNextItem = lpDrv->lpNextItem;
177 else
178 lpDrvItemList = lpDrv->lpNextItem;
179 if (lpDrv->lpNextItem)
180 lpDrv->lpNextItem->lpPrevItem = lpDrv->lpPrevItem;
181 /* trash magic number */
182 lpDrv->dwMagic ^= 0xa5a5a5a5;
183 lpDrv->lpDrvProc = NULL;
184 lpDrv->dwDriverID = 0;
186 LeaveCriticalSection( &mmdriver_lock );
188 return TRUE;
191 /**************************************************************************
192 * DRIVER_AddToList [internal]
194 * Adds a driver struct to the list of open drivers.
195 * Generates all the logic to handle driver creation / open.
197 static BOOL DRIVER_AddToList(LPWINE_DRIVER lpNewDrv, LPARAM lParam1, LPARAM lParam2)
199 lpNewDrv->dwMagic = WINE_DI_MAGIC;
200 /* First driver to be loaded for this module, need to load correctly the module */
201 /* first of this driver in list ? */
202 if (DRIVER_GetNumberOfModuleRefs(lpNewDrv->hModule, NULL) == 0) {
203 if (DRIVER_SendMessage(lpNewDrv, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) {
204 TRACE("DRV_LOAD failed on driver %p\n", lpNewDrv);
205 return FALSE;
207 /* returned value is not checked */
208 DRIVER_SendMessage(lpNewDrv, DRV_ENABLE, 0L, 0L);
211 /* Now just open a new instance of a driver on this module */
212 lpNewDrv->dwDriverID = DRIVER_SendMessage(lpNewDrv, DRV_OPEN, lParam1, lParam2);
214 if (lpNewDrv->dwDriverID == 0)
216 TRACE("DRV_OPEN failed on driver %p\n", lpNewDrv);
217 return FALSE;
220 EnterCriticalSection( &mmdriver_lock );
222 lpNewDrv->lpNextItem = NULL;
223 if (lpDrvItemList == NULL) {
224 lpDrvItemList = lpNewDrv;
225 lpNewDrv->lpPrevItem = NULL;
226 } else {
227 LPWINE_DRIVER lpDrv = lpDrvItemList; /* find end of list */
228 while (lpDrv->lpNextItem != NULL)
229 lpDrv = lpDrv->lpNextItem;
231 lpDrv->lpNextItem = lpNewDrv;
232 lpNewDrv->lpPrevItem = lpDrv;
235 LeaveCriticalSection( &mmdriver_lock );
236 return TRUE;
239 /**************************************************************************
240 * DRIVER_GetLibName [internal]
243 BOOL DRIVER_GetLibName(LPCWSTR keyName, LPCWSTR sectName, LPWSTR buf, int sz)
245 HKEY hKey, hSecKey;
246 DWORD bufLen, lRet;
248 TRACE("registry: %s, %s, %p, %d\n", debugstr_w(keyName), debugstr_w(sectName), buf, sz);
250 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion",
251 0, KEY_QUERY_VALUE, &hKey);
252 if (lRet == ERROR_SUCCESS) {
253 lRet = RegOpenKeyExW(hKey, sectName, 0, KEY_QUERY_VALUE, &hSecKey);
254 if (lRet == ERROR_SUCCESS) {
255 bufLen = sz;
256 lRet = RegQueryValueExW(hSecKey, keyName, 0, 0, (void*)buf, &bufLen);
257 RegCloseKey( hSecKey );
259 RegCloseKey( hKey );
261 if (lRet == ERROR_SUCCESS) return TRUE;
263 /* default to system.ini if we can't find it in the registry,
264 * to support native installations where system.ini is still used */
265 TRACE("system.ini: %s, %s, %p, %d\n", debugstr_w(keyName), debugstr_w(sectName), buf, sz);
266 return GetPrivateProfileStringW(sectName, keyName, L"", buf, sz / sizeof(WCHAR), L"SYSTEM.INI");
269 /**************************************************************************
270 * DRIVER_TryOpenDriver32 [internal]
272 * Tries to load a 32 bit driver whose DLL's (module) name is fn
274 LPWINE_DRIVER DRIVER_TryOpenDriver32(LPCWSTR fn, LPARAM lParam2)
276 LPWINE_DRIVER lpDrv = NULL;
277 HMODULE hModule = 0;
278 LPWSTR ptr;
279 LPCSTR cause = 0;
281 TRACE("(%s, %08IX);\n", debugstr_w(fn), lParam2);
283 if ((ptr = wcschr(fn, ' ')) != NULL) {
284 *ptr++ = '\0';
285 while (*ptr == ' ') ptr++;
286 if (*ptr == '\0') ptr = NULL;
289 lpDrv = malloc(sizeof(WINE_DRIVER));
290 if (lpDrv == NULL) {cause = "OOM"; goto exit;}
292 if ((hModule = LoadLibraryW(fn)) == 0) {cause = "Not a 32 bit lib"; goto exit;}
294 lpDrv->lpDrvProc = (DRIVERPROC)GetProcAddress(hModule, "DriverProc");
295 if (lpDrv->lpDrvProc == NULL) {cause = "no DriverProc"; goto exit;}
297 lpDrv->dwFlags = 0;
298 lpDrv->hModule = hModule;
299 lpDrv->dwDriverID = 0;
301 /* Win32 installable drivers must support a two phase opening scheme:
302 * + first open with NULL as lParam2 (session instance),
303 * + then do a second open with the real non null lParam2)
305 if (DRIVER_GetNumberOfModuleRefs(lpDrv->hModule, NULL) == 0 && lParam2)
307 LPWINE_DRIVER ret;
309 if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, 0L))
311 cause = "load0 failed";
312 goto exit;
314 ret = DRIVER_TryOpenDriver32(fn, lParam2);
315 if (!ret)
317 CloseDriver((HDRVR)lpDrv, 0L, 0L);
318 cause = "load1 failed";
319 goto exit;
321 lpDrv->dwFlags |= WINE_GDF_SESSION;
322 return ret;
325 if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, lParam2))
326 {cause = "load failed"; goto exit;}
328 TRACE("=> %p\n", lpDrv);
329 return lpDrv;
330 exit:
331 FreeLibrary(hModule);
332 free(lpDrv);
333 TRACE("Unable to load 32 bit module %s: %s\n", debugstr_w(fn), cause);
334 return NULL;
337 /**************************************************************************
338 * OpenDriverA [WINMM.@]
339 * DrvOpenA [WINMM.@]
340 * (0,1,DRV_LOAD ,0 ,0)
341 * (0,1,DRV_ENABLE,0 ,0)
342 * (0,1,DRV_OPEN ,buf[256],0)
344 HDRVR WINAPI OpenDriverA(LPCSTR lpDriverName, LPCSTR lpSectionName, LPARAM lParam)
346 INT len;
347 LPWSTR dn = NULL;
348 LPWSTR sn = NULL;
349 HDRVR ret = 0;
351 if (lpDriverName)
353 len = MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, NULL, 0 );
354 dn = malloc( len * sizeof(WCHAR) );
355 if (!dn) goto done;
356 MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, dn, len );
359 if (lpSectionName)
361 len = MultiByteToWideChar( CP_ACP, 0, lpSectionName, -1, NULL, 0 );
362 sn = malloc( len * sizeof(WCHAR) );
363 if (!sn) goto done;
364 MultiByteToWideChar( CP_ACP, 0, lpSectionName, -1, sn, len );
367 ret = OpenDriver(dn, sn, lParam);
369 done:
370 free(dn);
371 free(sn);
372 return ret;
375 /**************************************************************************
376 * OpenDriver [WINMM.@]
377 * DrvOpen [WINMM.@]
379 HDRVR WINAPI OpenDriver(LPCWSTR lpDriverName, LPCWSTR lpSectionName, LPARAM lParam)
381 LPWINE_DRIVER lpDrv = NULL;
382 WCHAR libName[MAX_PATH + 1];
383 LPCWSTR lsn = lpSectionName;
385 TRACE("(%s, %s, 0x%08Ix);\n",
386 debugstr_w(lpDriverName), debugstr_w(lpSectionName), lParam);
388 DRIVER_Dump("BEFORE:");
390 if (lsn == NULL) {
391 lstrcpynW(libName, lpDriverName, ARRAY_SIZE(libName));
393 if ((lpDrv = DRIVER_TryOpenDriver32(libName, lParam)))
394 goto the_end;
395 lsn = L"Drivers32";
397 if (DRIVER_GetLibName(lpDriverName, lsn, libName, sizeof(libName)) &&
398 (lpDrv = DRIVER_TryOpenDriver32(libName, lParam)))
399 goto the_end;
401 TRACE("Failed to open driver %s from system.ini file, section %s\n",
402 debugstr_w(lpDriverName), debugstr_w(lpSectionName));
404 the_end:
405 TRACE("=> %p\n", lpDrv);
407 DRIVER_Dump("AFTER:");
409 return (HDRVR)lpDrv;
412 /**************************************************************************
413 * CloseDriver [WINMM.@]
414 * DrvClose [WINMM.@]
416 LRESULT WINAPI CloseDriver(HDRVR hDrvr, LPARAM lParam1, LPARAM lParam2)
418 BOOL ret;
419 LPWINE_DRIVER lpDrv;
421 TRACE("(%p, %08IX, %08IX);\n", hDrvr, lParam1, lParam2);
423 DRIVER_Dump("BEFORE:");
425 if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL)
427 LPWINE_DRIVER lpDrv0;
429 DRIVER_SendMessage(lpDrv, DRV_CLOSE, lParam1, lParam2);
431 DRIVER_RemoveFromList(lpDrv);
433 if (lpDrv->dwFlags & WINE_GDF_SESSION)
434 FIXME("WINE_GDF_SESSION: Shouldn't happen (%p)\n", lpDrv);
435 /* if driver has an opened session instance, we have to close it too */
436 if (DRIVER_GetNumberOfModuleRefs(lpDrv->hModule, &lpDrv0) == 1 &&
437 (lpDrv0->dwFlags & WINE_GDF_SESSION))
439 DRIVER_SendMessage(lpDrv0, DRV_CLOSE, 0, 0);
440 DRIVER_RemoveFromList(lpDrv0);
441 FreeLibrary(lpDrv0->hModule);
442 free(lpDrv0);
444 FreeLibrary(lpDrv->hModule);
446 free(lpDrv);
447 ret = TRUE;
449 else
451 WARN("Failed to close driver\n");
452 ret = FALSE;
455 DRIVER_Dump("AFTER:");
457 return ret;
460 /**************************************************************************
461 * GetDriverFlags [WINMM.@]
462 * [in] hDrvr handle to the driver
464 * Returns:
465 * 0x00000000 if hDrvr is an invalid handle
466 * 0x80000000 if hDrvr is a valid 32 bit driver
467 * 0x90000000 if hDrvr is a valid 16 bit driver
469 * native WINMM doesn't return those flags
470 * 0x80000000 for a valid 32 bit driver and that's it
471 * (I may have mixed up the two flags :-(
473 DWORD WINAPI GetDriverFlags(HDRVR hDrvr)
475 LPWINE_DRIVER lpDrv;
476 DWORD ret = 0;
478 TRACE("(%p)\n", hDrvr);
480 if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) {
481 ret = WINE_GDF_EXIST | (lpDrv->dwFlags & WINE_GDF_EXTERNAL_MASK);
483 return ret;
486 /**************************************************************************
487 * GetDriverModuleHandle [WINMM.@]
488 * DrvGetModuleHandle [WINMM.@]
490 HMODULE WINAPI GetDriverModuleHandle(HDRVR hDrvr)
492 LPWINE_DRIVER lpDrv;
493 HMODULE hModule = 0;
495 TRACE("(%p);\n", hDrvr);
497 if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) {
498 hModule = lpDrv->hModule;
500 TRACE("=> %p\n", hModule);
501 return hModule;
504 /**************************************************************************
505 * DefDriverProc [WINMM.@]
506 * DrvDefDriverProc [WINMM.@]
508 LRESULT WINAPI DefDriverProc(DWORD_PTR dwDriverIdentifier, HDRVR hDrv,
509 UINT Msg, LPARAM lParam1, LPARAM lParam2)
511 switch (Msg) {
512 case DRV_LOAD:
513 case DRV_FREE:
514 case DRV_ENABLE:
515 case DRV_DISABLE:
516 return 1;
517 case DRV_INSTALL:
518 case DRV_REMOVE:
519 return DRV_SUCCESS;
520 default:
521 return 0;
525 /**************************************************************************
526 * DRIVER_getCallback [internal]
528 static const char* DRIVER_getCallback(DWORD uFlags)
530 switch(uFlags & DCB_TYPEMASK) {
531 case DCB_NULL: return "null";
532 case DCB_WINDOW: return "window";
533 case DCB_TASK: return "task";
534 case DCB_EVENT: return "event";
535 case DCB_FUNCTION: return "32bit function";
536 default: return "UNKNOWN";
540 /**************************************************************************
541 * DriverCallback [WINMM.@]
543 BOOL WINAPI DriverCallback(DWORD_PTR dwCallBack, DWORD uFlags, HDRVR hDev,
544 DWORD wMsg, DWORD_PTR dwUser, DWORD_PTR dwParam1,
545 DWORD_PTR dwParam2)
547 BOOL ret = FALSE;
548 TRACE("(%08IX, %s %04lX, %p, %04lX, %08IX, %08IX, %08IX)\n",
549 dwCallBack, DRIVER_getCallback(uFlags), uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
550 if (!dwCallBack)
551 return ret;
553 switch (uFlags & DCB_TYPEMASK) {
554 case DCB_NULL:
555 /* Native returns FALSE = no notification, not TRUE */
556 return ret;
557 case DCB_WINDOW:
558 ret = PostMessageA((HWND)dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
559 break;
560 case DCB_TASK: /* aka DCB_THREAD */
561 ret = PostThreadMessageA(dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
562 break;
563 case DCB_FUNCTION:
564 ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
565 ret = TRUE;
566 break;
567 case DCB_EVENT:
568 ret = SetEvent((HANDLE)dwCallBack);
569 break;
570 #if 0
571 /* FIXME: for now only usable in mmsystem.dll16
572 * If needed, should be enabled back
574 case 6: /* I would dub it DCB_MMTHREADSIGNAL */
575 /* this is an undocumented DCB_ value used for mmThreads
576 * loword of dwCallBack contains the handle of the lpMMThd block
577 * which dwSignalCount has to be incremented
579 if (pFnGetMMThread16)
581 WINE_MMTHREAD* lpMMThd = pFnGetMMThread16(LOWORD(dwCallBack));
583 TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
584 /* same as mmThreadSignal16 */
585 InterlockedIncrement(&lpMMThd->dwSignalCount);
586 SetEvent(lpMMThd->hEvent);
587 /* some other stuff on lpMMThd->hVxD */
589 break;
590 #endif
591 #if 0
592 case 4:
593 /* this is an undocumented DCB_ value for... I don't know */
594 break;
595 #endif
596 default:
597 WARN("Unknown callback type %ld\n", uFlags & DCB_TYPEMASK);
598 return FALSE;
600 if (ret)
601 TRACE("Done\n");
602 else
603 WARN("Notification failure\n");
604 return ret;
607 /******************************************************************
608 * DRIVER_UnloadAll
612 void DRIVER_UnloadAll(void)
614 LPWINE_DRIVER lpDrv;
615 LPWINE_DRIVER lpNextDrv = NULL;
616 unsigned count = 0;
618 restart:
619 EnterCriticalSection( &mmdriver_lock );
621 for (lpDrv = lpDrvItemList; lpDrv != NULL; lpDrv = lpNextDrv)
623 lpNextDrv = lpDrv->lpNextItem;
625 /* session instances will be unloaded automatically */
626 if (!(lpDrv->dwFlags & WINE_GDF_SESSION))
628 LeaveCriticalSection( &mmdriver_lock );
629 CloseDriver((HDRVR)lpDrv, 0, 0);
630 count++;
631 /* restart from the beginning of the list */
632 goto restart;
636 LeaveCriticalSection( &mmdriver_lock );
638 TRACE("Unloaded %u drivers\n", count);