this serie of three patches implement what Microsoft calls "session instance" basically, when a driver is loaded: 1/ a first instance is created, with no argument in the creation (this aka session instance) 2/ this instance is kept opened as long as the driver is loaded, and is closed when the last "real" instance is closed 3/ any "real" opening of the driver (with parameters) is done as another instance of the driver this "feature" was already present in msacm32.dll (on top of winmm driver API) this serie of patches let wine behave as specified by MS: - patch #1: implement "first driver instance" session in winmm.dll. this patch also allows to unload a no longer needed driver - patch #2: removes the "session instance" code from MSACM (since now it's handled by winmm) - patch #3: most builtin MCI drivers need to support this feature... A+
Name: instdrv ChangeLog: created session instance for installable drivers now properly freeing library upon driver exit License: X11 GenDate: 2002/05/10 20:43:50 UTC ModifiedFiles: dlls/winmm/driver.c AddedFiles: =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/dlls/winmm/driver.c,v retrieving revision 1.14 diff -u -u -r1.14 driver.c --- dlls/winmm/driver.c 9 Mar 2002 23:44:33 -0000 1.14 +++ dlls/winmm/driver.c 23 Apr 2002 19:16:57 -0000 @@ -34,25 +34,22 @@ static LPWINE_DRIVER lpDrvItemList = NULL; -/* TODO list : - * - LoadModule count and clean up is not handled correctly (it's not a - * problem as long as FreeLibrary is not working correctly) - */ - /************************************************************************** * DRIVER_GetNumberOfModuleRefs [internal] * * Returns the number of open drivers which share the same module. */ -static WORD DRIVER_GetNumberOfModuleRefs(LPWINE_DRIVER lpNewDrv) +static unsigned DRIVER_GetNumberOfModuleRefs(HMODULE hModule, WINE_DRIVER** found) { LPWINE_DRIVER lpDrv; - WORD count = 0; + unsigned count = 0; - if (lpNewDrv->dwFlags & WINE_GDF_16BIT) ERR("OOOch\n"); - for (lpDrv = lpDrvItemList; lpDrv; lpDrv = lpDrv->lpNextItem) { - if (!(lpDrv->dwFlags & WINE_GDF_16BIT) && - lpDrv->d.d32.hModule == lpNewDrv->d.d32.hModule) { + if (found) *found = NULL; + for (lpDrv = lpDrvItemList; lpDrv; lpDrv = lpDrv->lpNextItem) + { + if (!(lpDrv->dwFlags & WINE_GDF_16BIT) && lpDrv->d.d32.hModule == hModule) + { + if (found && !*found) *found = lpDrv; count++; } } @@ -253,7 +309,8 @@ static BOOL DRIVER_RemoveFromList(LPWINE_DRIVER lpDrv) { if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) { - if (DRIVER_GetNumberOfModuleRefs(lpDrv) == 1) { + /* last of this driver in list ? */ + if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 1) { DRIVER_SendMessage(lpDrv, DRV_DISABLE, 0L, 0L); DRIVER_SendMessage(lpDrv, DRV_FREE, 0L, 0L); } @@ -265,6 +322,8 @@ lpDrvItemList = lpDrv->lpNextItem; if (lpDrv->lpNextItem) lpDrv->lpNextItem->lpPrevItem = lpDrv->lpPrevItem; + /* trash magic number */ + lpDrv->dwMagic ^= 0xa5a5a5a5; return TRUE; } @@ -280,7 +339,8 @@ lpNewDrv->dwMagic = WINE_DI_MAGIC; /* First driver to be loaded for this module, need to load correctly the module */ if (!(lpNewDrv->dwFlags & WINE_GDF_16BIT)) { - if (DRIVER_GetNumberOfModuleRefs(lpNewDrv) == 0) { + /* first of this driver in list ? */ + if (DRIVER_GetNumberOfModuleRefs(lpNewDrv->d.d32.hModule, NULL) == 0) { if (DRIVER_SendMessage(lpNewDrv, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) { TRACE("DRV_LOAD failed on driver 0x%08lx\n", (DWORD)lpNewDrv); return FALSE; @@ -358,7 +418,31 @@ lpDrv->d.d32.hModule = hModule; lpDrv->d.d32.dwDriverID = 0; - if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, lParam2)) {cause = "load failed"; goto exit;} + /* Win32 installable drivers must support a two phase opening scheme: + * + first open with NULL as lParam2 (session instance), + * + then do a second open with the real non null lParam2) + */ + if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 0 && lParam2) + { + LPWINE_DRIVER ret; + + if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, 0L)) + { + cause = "load0 failed"; + goto exit; + } + ret = DRIVER_TryOpenDriver32(fn, lParam2); + if (!ret) + { + CloseDriver((HDRVR)lpDrv, 0L, 0L); + cause = "load1 failed"; + goto exit; + } + return ret; + } + + if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, lParam2)) + {cause = "load failed"; goto exit;} TRACE("=> %p\n", lpDrv); return lpDrv; @@ -461,15 +545,34 @@ TRACE("(%04x, %08lX, %08lX);\n", hDrvr, lParam1, lParam2); - if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) { + if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) + { if (lpDrv->dwFlags & WINE_GDF_16BIT) CloseDriver16(lpDrv->d.d16.hDriver16, lParam1, lParam2); else + { DRIVER_SendMessage(lpDrv, DRV_CLOSE, lParam1, lParam2); + lpDrv->d.d32.dwDriverID = 0; + } if (DRIVER_RemoveFromList(lpDrv)) { - HeapFree(GetProcessHeap(), 0, lpDrv); - return TRUE; - } + if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) + { + LPWINE_DRIVER lpDrv0; + + /* if driver has an opened session instance, we have to close it too */ + if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, &lpDrv0) == 1) + { + DRIVER_SendMessage(lpDrv0, DRV_CLOSE, 0L, 0L); + lpDrv0->d.d32.dwDriverID = 0; + DRIVER_RemoveFromList(lpDrv0); + FreeLibrary(lpDrv->d.d32.hModule); + HeapFree(GetProcessHeap(), 0, lpDrv0); + } + FreeLibrary(lpDrv->d.d32.hModule); + } + HeapFree(GetProcessHeap(), 0, lpDrv); + return TRUE; + } } WARN("Failed to close driver\n"); return FALSE;