Commit in reactos/lib/ole32 on MAIN
compobj.c+109-541.10 -> 1.11
ifs.c+2-21.8 -> 1.9
marshal.c+7-91.4 -> 1.5
regsvr.c-31.3 -> 1.4
rpc.c+11.2 -> 1.3
+119-68
5 modified files
Sync to Wine-20040716:
Mike McCormack <mike@codeweavers.com>
- Fix a few serious race conditions in the OLE object pipe server.
- Add some explanations to compobj.c, implement flushing message queue
  on shutdown.
Francois Gouget <fgouget@free.fr>
- Assorted spelling fixes.
Marcus Meissner <marcus@jet.franken.de>
- IMalloc vtables are static.
- IID_IObjectWithSite is already in libuuid, no need to declare here.
Aric Stewart <aric@codeweavers.com>
- Return an error in CoMarshalInterface if the IUnknown pointer is NULL
  and don't crash.
Ivan Leo Puoti <puoti@inwind.it>
- Removed the winedefault.reg message.
Robert Shearman <rob@codeweavers.com>
- Add static to non-exported marshal functions.
- Remove unused marshal functions.
- Rename several RPC functions.

reactos/lib/ole32
compobj.c 1.10 -> 1.11
diff -u -r1.10 -r1.11
--- compobj.c	16 Jun 2004 07:06:49 -0000	1.10
+++ compobj.c	8 Aug 2004 20:42:46 -0000	1.11
@@ -4,8 +4,9 @@
  *	Copyright 1995	Martin von Loewis
  *	Copyright 1998	Justin Bradford
  *      Copyright 1999  Francis Beaudet
- *  Copyright 1999  Sylvain St-Germain
- *  Copyright 2002  Marcus Meissner
+ *      Copyright 1999  Sylvain St-Germain
+ *      Copyright 2002  Marcus Meissner
+ *      Copyright 2004  Mike Hearn
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -118,10 +119,10 @@
  * This section contains OpenDllList definitions
  *
  * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
- * other functions what do LoadLibrary _without_ giving back a HMODULE.
- * Without this list these handles would be freed never.
+ * other functions that do LoadLibrary _without_ giving back a HMODULE.
+ * Without this list these handles would never be freed.
  *
- * FIXME: a DLL what says OK whenn asked for unloading is unloaded in the
+ * FIXME: a DLL that says OK when asked for unloading is unloaded in the
  * next unload-call but not before 600 sec.
  */
 
@@ -147,14 +148,17 @@
 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
 static void COMPOBJ_DllList_FreeUnused(int Timeout);
 
-
-/******************************************************************************
- * Initialize/Unitialize threading stuff.
- */
 void COMPOBJ_InitProcess( void )
 {
     WNDCLASSA wclass;
 
+    /* Inter-thread RPCs are done through window messages rather than pipes. When
+       an interface is marshalled into another apartment in the same process,
+       a window of the following class is created. The *caller* of CoMarshalInterface
+       (ie the application) is responsible for pumping the message loop in that thread,
+       the WM_USER messages which point to the RPCs are then dispatched to COM_AptWndProc
+       by the users code.
+     */
     memset(&wclass, 0, sizeof(wclass));
     wclass.lpfnWndProc = &COM_AptWndProc;
     wclass.hInstance = OLE32_hInstance;
@@ -170,10 +174,22 @@
 /******************************************************************************
  * Manage apartments.
  */
+
+
+/* The multi-threaded apartment (MTA) contains zero or more threads interacting
+   with free threaded (ie thread safe) COM objects. There is only ever one MTA
+   in a process - you can enter it by calling CoInitializeEx(COINIT_MULTITHREADED)
+ */
 static void COM_InitMTA(void)
 {
-    /* FIXME: how does windoze create OXIDs?
-     * this method will only work for local RPC */
+    /* OXIDs are object exporter IDs. Each apartment has an OXID, which is unique
+       within a network. That is, two different MTAs on different machines will have
+       different OXIDs.
+
+       This method of generating an OXID is therefore wrong as it doesn't work across
+       a network, but for local RPC only it's OK. We can distinguish between MTAs and
+       STAs because STAs use the thread ID as well, and no thread can have an ID of zero.
+     */
     MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
     InitializeCriticalSection(&MTA.cs);
 }
@@ -204,6 +220,7 @@
     }
     else
         apt = NtCurrentTeb()->ReservedForOle;
+
     apt->model = model;
     if (model & COINIT_APARTMENTTHREADED) {
       /* FIXME: how does windoze create OXIDs? */
@@ -245,6 +262,8 @@
     HeapFree(GetProcessHeap(), 0, apt);
 }
 
+/* The given OXID must be local to this process: you cannot use apartment
+   windows to send RPCs to other processes */
 HWND COM_GetApartmentWin(OXID oxid)
 {
     APARTMENT *apt;
@@ -258,6 +277,7 @@
     return win;
 }
 
+/* Currently inter-thread marshalling is not fully implemented, so this does nothing */
 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
   return DefWindowProcA(hWnd, msg, wParam, lParam);
@@ -378,8 +398,8 @@
  * RETURNS
  *  S_OK               if successful,
  *  S_FALSE            if this function was called already.
- *  RPC_E_CHANGED_MODE if a previous call to CoInitialize specified another
- *                      threading model.
+ *  RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
+ *                     threading model.
  */
 HRESULT WINAPI CoInitializeEx(
 	LPVOID lpReserved,	/* [in] pointer to win32 malloc interface
@@ -402,7 +422,9 @@
   {
     if (dwCoInit != apt->model)
     {
-      WARN("Apartment threading model already initialized with another model\n");
+      /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
+         code then we are probably using the wrong threading model to implement that API. */
+      WARN("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
       return RPC_E_CHANGED_MODE;
     }
     hr = S_FALSE;
@@ -436,6 +458,25 @@
   return hr;
 }
 
+/* On COM finalization for a STA thread, the message queue is flushed to ensure no
+   pending RPCs are ignored. Non-COM messages are discarded at this point.
+ */
+void COM_FlushMessageQueue(void)
+{
+    MSG message;
+    APARTMENT *apt = NtCurrentTeb()->ReservedForOle;
+
+    if (!apt || !apt->win) return;
+
+    TRACE("Flushing STA message queue\n");
+
+    while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) {
+        if (message.hwnd != apt->win) continue;
+        TranslateMessage(&message);
+        DispatchMessageA(&message);
+    }
+}
+
 /***********************************************************************
  *           CoUninitialize   [OLE32.@]
  *
@@ -466,27 +507,22 @@
   lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
   if (lCOMRefCnt==1)
   {
-    /*
-     * Release the various COM libraries and data structures.
-     */
     TRACE("() - Releasing the COM libraries\n");
 
     RunningObjectTableImpl_UnInitialize();
-    /*
-     * Release the references to the registered class objects.
-     */
+
+    /* Release the references to the registered class objects */
     COM_RevokeAllClasses();
 
-    /*
-     * This will free the loaded COM Dlls.
-     */
+    /* This will free the loaded COM Dlls  */
     CoFreeAllLibraries();
 
-    /*
-     * This will free list of external references to COM objects.
-     */
+    /* This will free list of external references to COM objects */
     COM_ExternalLockFreeList();
 
+    /* This ensures we deal with any pending RPCs */
+    COM_FlushMessageQueue();
+
     COM_UninitMTA();
   }
   else if (lCOMRefCnt<1) {
@@ -498,10 +534,17 @@
 /******************************************************************************
  *		CoDisconnectObject	[COMPOBJ.15]
  *		CoDisconnectObject	[OLE32.@]
+ *
+ * Disconnects all connections to this object from remote processes. Dispatches
+ * pending RPCs while blocking new RPCs from occurring, and then calls
+ * IMarshal::DisconnectObject on the given object.
+ *
+ * Typically called when the object server is forced to shut down, for instance by
+ * the user.
  */
 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
 {
-    TRACE("(%p, %lx)\n",lpUnk,reserved);
+    FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
     return S_OK;
 }
 
@@ -821,10 +864,14 @@
 /*****************************************************************************
  *             CoGetPSClsid [OLE32.@]
  *
- * This function returns the CLSID of the DLL that implements the proxy and stub
+ * This function returns the CLSID of the proxy/stub factory that implements IPSFactoryBuffer
  * for the specified interface.
  *
- * It determines this by searching the
+ * The standard marshaller activates the object with the CLSID returned and uses the
+ * CreateProxy and CreateStub methods on its IPSFactoryBuffer interface to construct
+ * the proxies and stubs for a given object.
+ *
+ * CoGetPSClsid determines this CLSID by searching the
  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
  * and any interface id registered by CoRegisterPSClsid within the current process.
  *
@@ -1047,36 +1094,41 @@
     }
     IStream_Release(pStm);
 
+    hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX,
+               PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
+               4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL );
+    if (hPipe == INVALID_HANDLE_VALUE) {
+        FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
+        return 1;
+    }
     while (1) {
-	hPipe = CreateNamedPipeA(
-	    pipefn,
-	    PIPE_ACCESS_DUPLEX,
-	    PIPE_TYPE_BYTE|PIPE_WAIT,
-	    PIPE_UNLIMITED_INSTANCES,
-	    4096,
-	    4096,
-	    NMPWAIT_USE_DEFAULT_WAIT,
-	    NULL
-	);
-	if (hPipe == INVALID_HANDLE_VALUE) {
-	    FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
-	    return 1;
-	}
-	if (!ConnectNamedPipe(hPipe,NULL)) {
-	    ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
-	    CloseHandle(hPipe);
-	    continue;
-	}
-	WriteFile(hPipe,buffer,buflen,&res,NULL);
-	CloseHandle(hPipe);
+        if (!ConnectNamedPipe(hPipe,NULL)) {
+            ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
+            break;
+        }
+        WriteFile(hPipe,buffer,buflen,&res,NULL);
+        FlushFileBuffers(hPipe);
+        DisconnectNamedPipe(hPipe);
     }
+    CloseHandle(hPipe);
     return 0;
 }
 
 /******************************************************************************
  *		CoRegisterClassObject	[OLE32.@]
  *
- * This method will register the class object for a given class ID.
+ * This method will register the class object for a given class ID. Servers housed
+ * in EXE files use this method instead of exporting DllGetClassObject to allow other
+ * code to connect to their objects.
+ *
+ * When a class object (an object which implements IClassFactory) is registered in
+ * this way, a new thread is started which listens for connections on a named pipe
+ * specific to the registered CLSID. When something else connects to it, it writes
+ * out the marshalled IClassFactory interface to the pipe. The code on the other end
+ * uses this buffer to unmarshal the class factory, and can then call methods on it.
+ *
+ * In Windows, such objects are registered with the RPC endpoint mapper, not with
+ * a unique named pipe.
  *
  * See the Windows documentation for more details.
  */
@@ -1103,6 +1155,9 @@
   /*
    * First, check if the class is already registered.
    * If it is, this should cause an error.
+   *
+   * MSDN claims that multiple interface registrations are legal, but we can't do that with
+   * our current implementation.
    */
   hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
   if (hr == S_OK) {
@@ -1323,7 +1378,7 @@
         return create_marshalled_proxy(rclsid,iid,ppv);
     }
 
-    /* Finally try remote */
+    /* Finally try remote: this requires networked DCOM (a lot of work) */
     if (CLSCTX_REMOTE_SERVER & dwClsContext)
     {
         FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
@@ -1339,7 +1394,7 @@
  */
 HRESULT WINAPI CoResumeClassObjects(void)
 {
-	FIXME("\n");
+       FIXME("stub\n");
 	return S_OK;
 }
 
@@ -1396,7 +1451,7 @@
         }
      */
 
-    /* if the obove strategies fail then search for the extension key in the registry */
+    /* if the above strategies fail then search for the extension key in the registry */
 
     /* get the last element (absolute file) in the path name */
     nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);

reactos/lib/ole32
ifs.c 1.8 -> 1.9
diff -u -r1.8 -r1.9
--- ifs.c	16 Jun 2004 07:06:50 -0000	1.8
+++ ifs.c	8 Aug 2004 20:42:47 -0000	1.9
@@ -45,7 +45,7 @@
  *
  *****************************************************************************/
 /* set the vtable later */
-extern ICOM_VTABLE(IMalloc) VT_IMalloc32;
+static ICOM_VTABLE(IMalloc) VT_IMalloc32;
 
 typedef struct {
         ICOM_VFIELD(IMalloc);
@@ -361,7 +361,7 @@
  *****************************************************************************/
 
 /* set the vtable later */
-extern ICOM_VTABLE(IMallocSpy) VT_IMallocSpy;
+static ICOM_VTABLE(IMallocSpy) VT_IMallocSpy;
 
 typedef struct {
         ICOM_VFIELD(IMallocSpy);

reactos/lib/ole32
marshal.c 1.4 -> 1.5
diff -u -r1.4 -r1.5
--- marshal.c	16 Jun 2004 07:06:50 -0000	1.4
+++ marshal.c	8 Aug 2004 20:42:47 -0000	1.5
@@ -453,6 +453,10 @@
   TRACE("(%p, %s, %p, %lx, %p, %lx)\n",
     pStm,debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags
   );
+
+  if (pUnk == NULL)
+    return E_INVALIDARG;
+
   STUBMGR_Start(); /* Just to be sure we have one running. */
   mid.processid = GetCurrentProcessId();
   IUnknown_QueryInterface(pUnk,&IID_IUnknown,(LPVOID*)&pUnknown);
@@ -482,17 +486,11 @@
   }
   hres = IMarshal_MarshalInterface(pMarshal,pStm,riid,pUnk,dwDestContext,pvDestContext,mshlflags);
   if (hres) {
-    if (IsEqualGUID(riid,&IID_IClassFactory)) {
-	MESSAGE("\nERROR: You need to merge the 'winedefault.reg' file into your\n");
-	MESSAGE("       Wine registry by running: `regedit winedefault.reg'\n\n");
+    if (IsEqualGUID(riid,&IID_IOleObject)) {
+      ERR("WINE currently cannot marshal IOleObject interfaces. This means you cannot embed/link OLE objects between applications.\n");
     } else {
-    	if (IsEqualGUID(riid,&IID_IOleObject)) {
-	    ERR("WINE currently cannot marshal IOleObject interfaces. This means you cannot embed/link OLE objects between applications.\n");
-	} else {
-	    FIXME("Failed to marshal the interface %s, %lx?\n",debugstr_guid(riid),hres);
-	}
+      FIXME("Failed to marshal the interface %s, %lx?\n",debugstr_guid(riid),hres);
     }
-    goto release_marshal;
   }
 release_marshal:
   IMarshal_Release(pMarshal);

reactos/lib/ole32
regsvr.c 1.3 -> 1.4
diff -u -r1.3 -r1.4
--- regsvr.c	11 Mar 2004 21:46:41 -0000	1.3
+++ regsvr.c	8 Aug 2004 20:42:47 -0000	1.4
@@ -466,9 +466,6 @@
 static IID const IID_IProvideMultipleClassInfo = {
     0xA7ABA9C1, 0x8983, 0x11CF, {0x8F,0x20,0x00,0x80,0x5F,0x2C,0xD0,0x64} };
 
-static IID const IID_IObjectWithSite = {
-    0xFC4801A3, 0x2BA9, 0x11CF, {0xA2,0x29,0x00,0xAA,0x00,0x3D,0x73,0x52} };
-
 static struct regsvr_interface const interface_list[] = {
     {   &IID_IUnknown,
 	"IUnknown",

reactos/lib/ole32
rpc.c 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- rpc.c	2 Jan 2004 19:49:45 -0000	1.2
+++ rpc.c	8 Aug 2004 20:42:47 -0000	1.3
@@ -512,6 +512,7 @@
   WINE_StringFromCLSID(rclsid,pipefn+strlen(PIPEPREF));
 
   while (tries++<MAXTRIES) {
+      WaitNamedPipeA( pipefn, NMPWAIT_WAIT_FOREVER );
       hPipe	= CreateFileA(
 	      pipefn,
 	      GENERIC_READ|GENERIC_WRITE,
CVSspam 0.2.8