Implement COM local servers using table marshaling to avoid doing the
marshaling in a child thread where COM has not been initialized.

diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c
index 1b16154..ab66d95 100644
--- a/dlls/ole32/compobj.c
+++ b/dlls/ole32/compobj.c
@@ -101,8 +101,7 @@
   DWORD     runContext;
   DWORD     connectFlags;
   DWORD     dwCookie;
-  HANDLE    hThread; /* only for localserver */
-  APARTMENT *apt;    /* owning apartment */
+  LPSTREAM  pMarshaledData; /* FIXME: only really need to store OXID and IPID */
   struct tagRegisteredClass* nextClass;
 } RegisteredClass;
 
@@ -1101,116 +1100,12 @@
   return hr;
 }
 
-static DWORD WINAPI
-_LocalServerThread(LPVOID param) {
-    HANDLE		hPipe;
-    char 		pipefn[200];
-    RegisteredClass *newClass = (RegisteredClass*)param;
-    HRESULT		hres;
-    IStream		*pStm;
-    STATSTG		ststg;
-    unsigned char	*buffer;
-    int 		buflen;
-    IClassFactory	*classfac;
-    LARGE_INTEGER	seekto;
-    ULARGE_INTEGER	newpos;
-    ULONG		res;
-
-    TRACE("Starting classfactory server thread for %s.\n",debugstr_guid(&newClass->classIdentifier));
-
-    /* we need to enter the apartment of the thread which registered
-     * the class object to perform the next stage
-     */
-
-    assert( newClass->apt );
-    NtCurrentTeb()->ReservedForOle = newClass->apt;
-
-    strcpy(pipefn,PIPEPREF);
-    WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
-
-    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) {
-        if (!ConnectNamedPipe(hPipe,NULL)) {
-            ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
-            break;
-        }
-
-        TRACE("marshalling IClassFactory to client\n");
-        
-        hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac);
-        if (hres) return hres;
-
-        hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
-        if (hres) {
-            FIXME("Failed to create stream on hglobal.\n");
-            return hres;
-        }
-        hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0);
-        if (hres) {
-            FIXME("CoMarshalInterface failed, %lx!\n",hres);
-            return hres;
-        }
-
-        IUnknown_Release(classfac); /* is this right? */
-
-        hres = IStream_Stat(pStm,&ststg,0);
-        if (hres) return hres;
-
-        buflen = ststg.cbSize.u.LowPart;
-        buffer = HeapAlloc(GetProcessHeap(),0,buflen);
-        seekto.u.LowPart = 0;
-        seekto.u.HighPart = 0;
-        hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
-        if (hres) {
-            FIXME("IStream_Seek failed, %lx\n",hres);
-            return hres;
-        }
-        
-        hres = IStream_Read(pStm,buffer,buflen,&res);
-        if (hres) {
-            FIXME("Stream Read failed, %lx\n",hres);
-            return hres;
-        }
-        
-        IStream_Release(pStm);
-
-        WriteFile(hPipe,buffer,buflen,&res,NULL);
-        FlushFileBuffers(hPipe);
-        DisconnectNamedPipe(hPipe);
-
-        TRACE("done marshalling IClassFactory\n");
-    }
-    CloseHandle(hPipe);
-    return 0;
-}
-
 /******************************************************************************
  *		CoRegisterClassObject	[OLE32.@]
  * 
- * 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.
- *
- * MSDN claims that multiple interface registrations are legal, but we
- * can't do that with our current implementation.
+ * Registers 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.
  *
  * RETURNS
  *   S_OK on success, 
@@ -1219,6 +1114,10 @@
  *
  * SEE ALSO
  *   CoRevokeClassObject, CoGetClassObject
+ *
+ * BUGS
+ *  MSDN claims that multiple interface registrations are legal, but we
+ *  can't do that with our current implementation.
  */
 HRESULT WINAPI CoRegisterClassObject(
         REFCLSID rclsid,       /* [in] CLSID of the object to register */
@@ -1264,10 +1163,9 @@
   newClass->classIdentifier = *rclsid;
   newClass->runContext      = dwClsContext;
   newClass->connectFlags    = flags;
-  newClass->apt             = COM_CurrentApt();
   /*
    * Use the address of the chain node as the cookie since we are sure it's
-   * unique.
+   * unique. FIXME: not on 64-bit platforms.
    */
   newClass->dwCookie        = (DWORD)newClass;
   newClass->nextClass       = firstRegisteredClass;
@@ -1285,10 +1183,30 @@
   *lpdwRegister = newClass->dwCookie;
 
   if (dwClsContext & CLSCTX_LOCAL_SERVER) {
-      DWORD tid;
+      IClassFactory *classfac;
 
-      start_apartment_listener_thread();
-      newClass->hThread = CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
+      hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory, 
+                                   (LPVOID*)&classfac);
+      if (hr) return hr;
+
+      hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
+      if (hr) {
+          FIXME("Failed to create stream on hglobal, %lx\n", hr);
+          IUnknown_Release(classfac);
+          return hr;
+      }
+      hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
+                              (LPVOID)classfac, MSHCTX_LOCAL, NULL,
+                              MSHLFLAGS_TABLESTRONG);
+      if (hr) {
+          FIXME("CoMarshalInterface failed, %lx!\n",hr);
+          IUnknown_Release(classfac);
+          return hr;
+      }
+
+      IUnknown_Release(classfac);
+
+      RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
   }
   return S_OK;
 }
@@ -1334,6 +1252,15 @@
        */
       IUnknown_Release(curClass->classObject);
 
+      if (curClass->pMarshaledData)
+      {
+        LARGE_INTEGER zero;
+        memset(&zero, 0, sizeof(zero));
+        /* FIXME: stop local server thread */
+        IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
+        CoReleaseMarshalData(curClass->pMarshaledData);
+      }
+
       /*
        * Free the memory used by the chain node.
        */
diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h
index 9da455e..6c5677f 100644
--- a/dlls/ole32/compobj_private.h
+++ b/dlls/ole32/compobj_private.h
@@ -194,6 +194,7 @@
 void start_apartment_listener_thread(void);
 
 extern HRESULT PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf);
+void RPC_StartLocalServer(REFCLSID clsid, IStream *stream);
 
 /* This function initialize the Running Object Table */
 HRESULT WINAPI RunningObjectTableImpl_Initialize(void);
diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c
index e8d62d3..f5acc92 100644
--- a/dlls/ole32/rpc.c
+++ b/dlls/ole32/rpc.c
@@ -829,3 +829,90 @@
         CreateThread(NULL, 0, apartment_listener_thread, apt, 0, &apt->listenertid);
     }
 }
+
+struct local_server_params
+{
+    CLSID clsid;
+    IStream *stream;
+};
+
+static DWORD WINAPI local_server_thread(LPVOID param)
+{
+    struct local_server_params * lsp = (struct local_server_params *)param;
+    HANDLE		hPipe;
+    char 		pipefn[200];
+    HRESULT		hres;
+    IStream		*pStm = lsp->stream;
+    STATSTG		ststg;
+    unsigned char	*buffer;
+    int 		buflen;
+    LARGE_INTEGER	seekto;
+    ULARGE_INTEGER	newpos;
+    ULONG		res;
+
+    TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
+
+    strcpy(pipefn,PIPEPREF);
+    WINE_StringFromCLSID(&lsp->clsid,pipefn+strlen(PIPEPREF));
+
+    HeapFree(GetProcessHeap(), 0, lsp);
+
+    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 %ld\n",pipefn,GetLastError());
+        return 1;
+    }
+    while (1) {
+        if (!ConnectNamedPipe(hPipe,NULL)) {
+            ERR("Failure during ConnectNamedPipe %ld, ABORT!\n",GetLastError());
+            break;
+        }
+
+        TRACE("marshalling IClassFactory to client\n");
+        
+        hres = IStream_Stat(pStm,&ststg,0);
+        if (hres) return hres;
+
+        buflen = ststg.cbSize.u.LowPart;
+        buffer = HeapAlloc(GetProcessHeap(),0,buflen);
+        seekto.u.LowPart = 0;
+        seekto.u.HighPart = 0;
+        hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
+        if (hres) {
+            FIXME("IStream_Seek failed, %lx\n",hres);
+            return hres;
+        }
+        
+        hres = IStream_Read(pStm,buffer,buflen,&res);
+        if (hres) {
+            FIXME("Stream Read failed, %lx\n",hres);
+            return hres;
+        }
+        
+        IStream_Release(pStm);
+
+        WriteFile(hPipe,buffer,buflen,&res,NULL);
+        FlushFileBuffers(hPipe);
+        DisconnectNamedPipe(hPipe);
+
+        TRACE("done marshalling IClassFactory\n");
+    }
+    CloseHandle(hPipe);
+    return 0;
+}
+
+void RPC_StartLocalServer(REFCLSID clsid, IStream *stream)
+{
+    DWORD tid;
+    HANDLE thread;
+    struct local_server_params *lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
+
+    lsp->clsid = *clsid;
+    lsp->stream = stream;
+
+    thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
+    CloseHandle(thread);
+    /* FIXME: failure handling */
+}