Multimedia "session instance" session for drivers [1/3]

Eric Pouech eric.pouech at wanadoo.fr
Fri May 10 16:08:42 CDT 2002


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+
-------------- next part --------------
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;


More information about the wine-patches mailing list