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