- Make the wine_marshal_id structure more like the DCOM OBJREF
[wine] / dlls / ole32 / rpc.c
1 /*
2  *      (Local) RPC Stuff
3  *
4  *  Copyright 2002  Marcus Meissner
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #define COBJMACROS
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winuser.h"
36 #include "objbase.h"
37 #include "ole2.h"
38 #include "ole2ver.h"
39 #include "rpc.h"
40 #include "winerror.h"
41 #include "winreg.h"
42 #include "wownt32.h"
43 #include "wtypes.h"
44 #include "wine/unicode.h"
45 #include "wine/winbase16.h"
46 #include "compobj_private.h"
47 #include "ifs.h"
48
49 #include "compobj_private.h"
50
51 #include "wine/debug.h"
52
53 WINE_DEFAULT_DEBUG_CHANNEL(ole);
54
55 #define REQTYPE_REQUEST         0
56 typedef struct _wine_rpc_request_header {
57     DWORD               reqid;
58     wine_marshal_id     mid;
59     DWORD               iMethod;
60     DWORD               cbBuffer;
61 } wine_rpc_request_header;
62
63 #define REQTYPE_RESPONSE        1
64 typedef struct _wine_rpc_response_header {
65     DWORD               reqid;
66     DWORD               cbBuffer;
67     DWORD               retval;
68 } wine_rpc_response_header;
69
70 /* used when shutting down a pipe, e.g. at the end of a process */
71 #define REQTYPE_DISCONNECT      2
72 typedef struct _wine_rpc_disconnect_header {
73   DWORD reqid;
74   wine_marshal_id mid; /* mid of stub to delete */
75 } wine_rpc_disconnect_header;
76
77
78 #define REQSTATE_START                  0
79 #define REQSTATE_REQ_QUEUED             1
80 #define REQSTATE_REQ_WAITING_FOR_REPLY  2
81 #define REQSTATE_REQ_GOT                3
82 #define REQSTATE_INVOKING               4
83 #define REQSTATE_RESP_QUEUED            5
84 #define REQSTATE_RESP_GOT               6
85 #define REQSTATE_DONE                   6
86
87 typedef struct _wine_rpc_request {
88     int                         state;
89     HANDLE                      hPipe;  /* temp copy of handle */
90     wine_rpc_request_header     reqh;
91     wine_rpc_response_header    resph;
92     LPBYTE                      Buffer;
93 } wine_rpc_request;
94
95 static wine_rpc_request **reqs = NULL;
96 static int nrofreqs = 0;
97
98 /* This pipe is _thread_ based, each thread which talks to a remote
99  * apartment (mid) has its own pipe */
100 typedef struct _wine_pipe {
101     wine_marshal_id     mid;    /* target mid */
102     DWORD               tid;    /* thread which owns this outgoing pipe */
103     HANDLE              hPipe;
104
105     int                 pending;
106     HANDLE              hThread;
107     CRITICAL_SECTION    crit;
108 } wine_pipe;
109
110 static wine_pipe *pipes = NULL;
111 static int nrofpipes = 0;
112
113 typedef struct _PipeBuf {
114     IRpcChannelBufferVtbl       *lpVtbl;
115     DWORD                               ref;
116
117     wine_marshal_id                     mid;
118     wine_pipe                           *pipe;
119 } PipeBuf;
120
121 static HRESULT WINAPI
122 read_pipe(HANDLE hf, LPVOID ptr, DWORD size) {
123     DWORD res;
124     if (!ReadFile(hf,ptr,size,&res,NULL)) {
125         FIXME("Failed to read from %p, le is %lx\n",hf,GetLastError());
126         return E_FAIL;
127     }
128     if (res!=size) {
129         FIXME("Read only %ld of %ld bytes from %p.\n",res,size,hf);
130         return E_FAIL;
131     }
132     return S_OK;
133 }
134
135 static void
136 drs(LPCSTR where) {
137 #if 0
138     static int nrofreaders = 0;
139
140     int i, states[10];
141
142     memset(states,0,sizeof(states));
143     for (i=nrofreqs;i--;)
144         states[reqs[i]->state]++;
145     FIXME("%lx/%s/%d: rq %d, w %d, rg %d, rsq %d, rsg %d, d %d\n",
146             GetCurrentProcessId(),
147             where,
148             nrofreaders,
149             states[REQSTATE_REQ_QUEUED],
150             states[REQSTATE_REQ_WAITING_FOR_REPLY],
151             states[REQSTATE_REQ_GOT],
152             states[REQSTATE_RESP_QUEUED],
153             states[REQSTATE_RESP_GOT],
154             states[REQSTATE_DONE]
155     );
156 #endif
157
158     return ;
159 }
160
161 static HRESULT WINAPI
162 write_pipe(HANDLE hf, LPVOID ptr, DWORD size) {
163     DWORD res;
164     if (!WriteFile(hf,ptr,size,&res,NULL)) {
165         FIXME("Failed to write to %p, le is %lx\n",hf,GetLastError());
166         return E_FAIL;
167     }
168     if (res!=size) {
169         FIXME("Wrote only %ld of %ld bytes to %p.\n",res,size,hf);
170         return E_FAIL;
171     }
172     return S_OK;
173 }
174
175 static DWORD WINAPI _StubReaderThread(LPVOID);
176
177 static HRESULT
178 PIPE_RegisterPipe(wine_marshal_id *mid, HANDLE hPipe, BOOL startreader) {
179   int   i;
180   char  pipefn[100];
181   wine_pipe *new_pipes;
182
183   for (i=0;i<nrofpipes;i++)
184     if (pipes[i].mid.oxid==mid->oxid)
185       return S_OK;
186   if (pipes)
187     new_pipes=(wine_pipe*)HeapReAlloc(GetProcessHeap(),0,pipes,sizeof(pipes[0])*(nrofpipes+1));
188   else
189     new_pipes=(wine_pipe*)HeapAlloc(GetProcessHeap(),0,sizeof(pipes[0]));
190   if (!new_pipes) return E_OUTOFMEMORY;
191   pipes = new_pipes;
192   sprintf(pipefn,OLESTUBMGR"_%08lx%08lx",(DWORD)(mid->oxid >> 32),(DWORD)mid->oxid);
193   memcpy(&(pipes[nrofpipes].mid),mid,sizeof(*mid));
194   pipes[nrofpipes].hPipe        = hPipe;
195   InitializeCriticalSection(&(pipes[nrofpipes].crit));
196   nrofpipes++;
197   if (startreader) {
198       pipes[nrofpipes-1].hThread = CreateThread(NULL,0,_StubReaderThread,(LPVOID)(pipes+(nrofpipes-1)),0,&(pipes[nrofpipes-1].tid));
199   } else {
200       pipes[nrofpipes-1].tid     = GetCurrentThreadId();
201   }
202   return S_OK;
203 }
204
205 static HANDLE
206 PIPE_FindByMID(wine_marshal_id *mid) {
207   int i;
208   for (i=0;i<nrofpipes;i++)
209     if ((pipes[i].mid.oxid==mid->oxid) &&
210         (GetCurrentThreadId()==pipes[i].tid)
211     )
212       return pipes[i].hPipe;
213   return INVALID_HANDLE_VALUE;
214 }
215
216 static wine_pipe*
217 PIPE_GetFromMID(wine_marshal_id *mid) {
218   int i;
219   for (i=0;i<nrofpipes;i++) {
220     if ((pipes[i].mid.oxid==mid->oxid) &&
221         (GetCurrentThreadId()==pipes[i].tid)
222     )
223       return pipes+i;
224   }
225   return NULL;
226 }
227
228 static HRESULT
229 RPC_GetRequest(wine_rpc_request **req) {
230     static int reqid = 0xdeadbeef;
231     int i;
232
233     for (i=0;i<nrofreqs;i++) { /* try to reuse */
234         if (reqs[i]->state == REQSTATE_DONE) {
235             reqs[i]->reqh.reqid = reqid++;
236             reqs[i]->resph.reqid = reqs[i]->reqh.reqid;
237             reqs[i]->hPipe = INVALID_HANDLE_VALUE;
238             *req = reqs[i];
239             reqs[i]->state = REQSTATE_START;
240             return S_OK;
241         }
242     }
243     /* create new */
244     if (reqs)
245         reqs = (wine_rpc_request**)HeapReAlloc(
246                         GetProcessHeap(),
247                         HEAP_ZERO_MEMORY,
248                         reqs,
249                         sizeof(wine_rpc_request*)*(nrofreqs+1)
250                 );
251     else
252         reqs = (wine_rpc_request**)HeapAlloc(
253                         GetProcessHeap(),
254                         HEAP_ZERO_MEMORY,
255                         sizeof(wine_rpc_request*)
256                 );
257     if (!reqs)
258         return E_OUTOFMEMORY;
259     reqs[nrofreqs] = (wine_rpc_request*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(wine_rpc_request));
260     reqs[nrofreqs]->reqh.reqid = reqid++;
261     reqs[nrofreqs]->resph.reqid = reqs[nrofreqs]->reqh.reqid;
262     reqs[nrofreqs]->hPipe = INVALID_HANDLE_VALUE;
263     *req = reqs[nrofreqs];
264     reqs[nrofreqs]->state = REQSTATE_START;
265     nrofreqs++;
266     return S_OK;
267 }
268
269 static void
270 RPC_FreeRequest(wine_rpc_request *req) {
271     req->state = REQSTATE_DONE; /* Just reuse slot. */
272     return;
273 }
274
275 static HRESULT WINAPI
276 PipeBuf_QueryInterface(
277     LPRPCCHANNELBUFFER iface,REFIID riid,LPVOID *ppv
278 ) {
279     *ppv = NULL;
280     if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown)) {
281         *ppv = (LPVOID)iface;
282         IUnknown_AddRef(iface);
283         return S_OK;
284     }
285     return E_NOINTERFACE;
286 }
287
288 static ULONG WINAPI
289 PipeBuf_AddRef(LPRPCCHANNELBUFFER iface) {
290     PipeBuf *This = (PipeBuf *)iface;
291     return InterlockedIncrement(&This->ref);
292 }
293
294 static ULONG WINAPI
295 PipeBuf_Release(LPRPCCHANNELBUFFER iface) {
296     PipeBuf *This = (PipeBuf *)iface;
297     ULONG ref;
298     wine_rpc_disconnect_header header;
299     HANDLE pipe;
300     DWORD reqtype = REQTYPE_DISCONNECT;
301
302     ref = InterlockedDecrement(&This->ref);
303     if (ref)
304         return ref;
305
306     FIXME("Free all stuff\n");
307
308     memcpy(&header.mid, &This->mid, sizeof(wine_marshal_id));
309
310     pipe = PIPE_FindByMID(&This->mid);
311
312     write_pipe(pipe, &reqtype, sizeof(reqtype));
313     write_pipe(pipe, &header, sizeof(wine_rpc_disconnect_header));
314
315     TRACE("written disconnect packet\n");
316
317     HeapFree(GetProcessHeap(),0,This);
318     return 0;
319 }
320
321 static HRESULT WINAPI
322 PipeBuf_GetBuffer(
323     LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,REFIID riid
324 ) {
325     /*PipeBuf *This = (PipeBuf *)iface;*/
326
327     TRACE("(%p,%s)\n",msg,debugstr_guid(riid));
328     /* probably reuses IID in real. */
329     if (msg->cbBuffer && (msg->Buffer == NULL))
330         msg->Buffer = HeapAlloc(GetProcessHeap(),0,msg->cbBuffer);
331     return S_OK;
332 }
333
334 static HRESULT
335 COM_InvokeAndRpcSend(wine_rpc_request *req) {
336     IRpcStubBuffer      *stub;
337     RPCOLEMESSAGE       msg;
338     HRESULT             hres;
339     DWORD               reqtype;
340
341     hres = MARSHAL_Find_Stub_Buffer(&(req->reqh.mid),&stub);
342     if (hres) {
343         ERR("Stub not found?\n");
344         return hres;
345     }
346     msg.Buffer          = req->Buffer;
347     msg.iMethod         = req->reqh.iMethod;
348     msg.cbBuffer        = req->reqh.cbBuffer;
349     msg.dataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
350     req->state          = REQSTATE_INVOKING;
351     req->resph.retval   = IRpcStubBuffer_Invoke(stub,&msg,NULL);
352     IUnknown_Release(stub);
353     req->Buffer         = msg.Buffer;
354     req->resph.cbBuffer = msg.cbBuffer;
355     reqtype             = REQTYPE_RESPONSE;
356     hres = write_pipe(req->hPipe,&reqtype,sizeof(reqtype));
357     if (hres) return hres;
358     hres = write_pipe(req->hPipe,&(req->resph),sizeof(req->resph));
359     if (hres) return hres;
360     hres = write_pipe(req->hPipe,req->Buffer,req->resph.cbBuffer);
361     if (hres) return hres;
362     req->state = REQSTATE_DONE;
363     drs("invoke");
364     return S_OK;
365 }
366
367 static HRESULT COM_RpcReceive(wine_pipe *xpipe);
368
369 static HRESULT
370 RPC_QueueRequestAndWait(wine_rpc_request *req) {
371     int                 i;
372     wine_rpc_request    *xreq;
373     HRESULT             hres;
374     DWORD               reqtype;
375     wine_pipe           *xpipe = PIPE_GetFromMID(&(req->reqh.mid));
376
377     if (!xpipe) {
378         FIXME("no pipe found.\n");
379         return E_POINTER;
380     }
381     req->hPipe = xpipe->hPipe;
382     req->state = REQSTATE_REQ_WAITING_FOR_REPLY;
383     reqtype = REQTYPE_REQUEST;
384     hres = write_pipe(req->hPipe,&reqtype,sizeof(reqtype));
385     if (hres) return hres;
386     hres = write_pipe(req->hPipe,&(req->reqh),sizeof(req->reqh));
387     if (hres) return hres;
388     hres = write_pipe(req->hPipe,req->Buffer,req->reqh.cbBuffer);
389     if (hres) return hres;
390
391     /* This loop is about allowing re-entrancy. While waiting for the
392      * response to one RPC we may receive a request starting another. */
393     while (!hres) {
394         hres = COM_RpcReceive(xpipe);
395         if (hres) break;
396
397         for (i=0;i<nrofreqs;i++) {
398             xreq = reqs[i];
399             if ((xreq->state==REQSTATE_REQ_GOT) && (xreq->hPipe==req->hPipe)) {
400                 hres = COM_InvokeAndRpcSend(xreq);
401                 if (hres) break;
402             }
403         }
404         if (req->state == REQSTATE_RESP_GOT)
405             return S_OK;
406     }
407     if (FAILED(hres))
408         WARN("-- 0x%08lx\n", hres);
409     return hres;
410 }
411
412 static HRESULT WINAPI
413 PipeBuf_SendReceive(
414     LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,ULONG *status
415 ) {
416     PipeBuf *This = (PipeBuf *)iface;
417     wine_rpc_request    *req;
418     HRESULT             hres;
419
420     TRACE("()\n");
421
422     if (This->mid.oxid == COM_CurrentApt()->oxid) {
423         ERR("Need to call directly!\n");
424         return E_FAIL;
425     }
426
427     hres = RPC_GetRequest(&req);
428     if (hres) return hres;
429     req->reqh.iMethod   = msg->iMethod;
430     req->reqh.cbBuffer  = msg->cbBuffer;
431     memcpy(&(req->reqh.mid),&(This->mid),sizeof(This->mid));
432     req->Buffer = msg->Buffer;
433     hres = RPC_QueueRequestAndWait(req);
434     if (hres) {
435         RPC_FreeRequest(req);
436         return hres;
437     }
438     msg->cbBuffer       = req->resph.cbBuffer;
439     msg->Buffer         = req->Buffer;
440     *status             = req->resph.retval;
441     RPC_FreeRequest(req);
442     return S_OK;
443 }
444
445
446 static HRESULT WINAPI
447 PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg) {
448     FIXME("(%p), stub!\n",msg);
449     return E_FAIL;
450 }
451
452 static HRESULT WINAPI
453 PipeBuf_GetDestCtx(
454     LPRPCCHANNELBUFFER iface,DWORD* pdwDestContext,void** ppvDestContext
455 ) {
456     FIXME("(%p,%p), stub!\n",pdwDestContext,ppvDestContext);
457     return E_FAIL;
458 }
459
460 static HRESULT WINAPI
461 PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface) {
462     FIXME("(), stub!\n");
463     return S_OK;
464 }
465
466 static IRpcChannelBufferVtbl pipebufvt = {
467     PipeBuf_QueryInterface,
468     PipeBuf_AddRef,
469     PipeBuf_Release,
470     PipeBuf_GetBuffer,
471     PipeBuf_SendReceive,
472     PipeBuf_FreeBuffer,
473     PipeBuf_GetDestCtx,
474     PipeBuf_IsConnected
475 };
476
477 HRESULT
478 PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf) {
479   wine_marshal_id       ourid;
480   DWORD                 res;
481   HANDLE                hPipe;
482   HRESULT               hres;
483   PipeBuf               *pbuf;
484
485   hPipe = PIPE_FindByMID(mid);
486   if (hPipe == INVALID_HANDLE_VALUE) {
487       char                      pipefn[200];
488       sprintf(pipefn,OLESTUBMGR"_%08lx%08lx",(DWORD)(mid->oxid >> 32),(DWORD)mid->oxid);
489       hPipe = CreateFileA(
490               pipefn,
491               GENERIC_READ|GENERIC_WRITE,
492               0,
493               NULL,
494               OPEN_EXISTING,
495               0,
496               0
497       );
498       if (hPipe == INVALID_HANDLE_VALUE) {
499           FIXME("Could not open named pipe %s, le is %lx\n",pipefn,GetLastError());
500           return E_FAIL;
501       }
502       hres = PIPE_RegisterPipe(mid, hPipe, FALSE);
503       if (hres) return hres;
504       memset(&ourid,0,sizeof(ourid));
505       ourid.oxid = COM_CurrentApt()->oxid;
506       if (!WriteFile(hPipe,&ourid,sizeof(ourid),&res,NULL)||(res!=sizeof(ourid))) {
507           ERR("Failed writing startup mid!\n");
508           return E_FAIL;
509       }
510   }
511   pbuf = (PipeBuf*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PipeBuf));
512   pbuf->lpVtbl  = &pipebufvt;
513   pbuf->ref     = 1;
514   memcpy(&(pbuf->mid),mid,sizeof(*mid));
515   *pipebuf = (IRpcChannelBuffer*)pbuf;
516   return S_OK;
517 }
518
519 static HRESULT
520 create_server(REFCLSID rclsid) {
521   static const WCHAR embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
522   HKEY          key;
523   char          buf[200];
524   HRESULT       hres = E_UNEXPECTED;
525   char          xclsid[80];
526   WCHAR        exe[MAX_PATH+1];
527   DWORD        exelen = sizeof(exe);
528   WCHAR         command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)];
529   STARTUPINFOW  sinfo;
530   PROCESS_INFORMATION   pinfo;
531
532   WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
533
534   sprintf(buf,"CLSID\\%s\\LocalServer32",xclsid);
535   hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key);
536
537   if (hres != ERROR_SUCCESS) {
538       WARN("CLSID %s not registered as LocalServer32\n", xclsid);
539       return REGDB_E_READREGDB; /* Probably */
540   }
541
542   memset(exe,0,sizeof(exe));
543   hres= RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)exe, &exelen);
544   RegCloseKey(key);
545   if (hres) {
546       WARN("No default value for LocalServer32 key\n");
547       return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
548   }
549
550   memset(&sinfo,0,sizeof(sinfo));
551   sinfo.cb = sizeof(sinfo);
552
553   /* EXE servers are started with the -Embedding switch. MSDN also claims /Embedding is used,
554      9x does -Embedding, perhaps an 9x/NT difference?  */
555
556   strcpyW(command, exe);
557   strcatW(command, embedding);
558
559   TRACE("activating local server '%s' for %s\n", debugstr_w(command), xclsid);
560
561   if (!CreateProcessW(exe, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) {
562       WARN("failed to run local server %s\n", debugstr_w(exe));
563       return E_FAIL;
564   }
565
566   return S_OK;
567 }
568 /* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */
569 HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) {
570   HRESULT       hres;
571   HANDLE        hPipe;
572   char          pipefn[200];
573   DWORD         res,bufferlen;
574   char          marshalbuffer[200];
575   IStream       *pStm;
576   LARGE_INTEGER seekto;
577   ULARGE_INTEGER newpos;
578   int           tries = 0;
579 #define MAXTRIES 10000
580
581   TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
582
583   strcpy(pipefn,PIPEPREF);
584   WINE_StringFromCLSID(rclsid,pipefn+strlen(PIPEPREF));
585
586   while (tries++<MAXTRIES) {
587       WaitNamedPipeA( pipefn, NMPWAIT_WAIT_FOREVER );
588       hPipe     = CreateFileA(
589               pipefn,
590               GENERIC_READ|GENERIC_WRITE,
591               0,
592               NULL,
593               OPEN_EXISTING,
594               0,
595               0
596       );
597       if (hPipe == INVALID_HANDLE_VALUE) {
598           if (tries == 1) {
599               if ((hres = create_server(rclsid)))
600                   return hres;
601               Sleep(1000);
602           } else {
603               WARN("Could not open named pipe to broker %s, le is %lx\n",pipefn,GetLastError());
604               Sleep(1000);
605           }
606           continue;
607       }
608       bufferlen = 0;
609       if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
610           FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
611           Sleep(1000);
612           continue;
613       }
614       CloseHandle(hPipe);
615       break;
616   }
617   if (tries>=MAXTRIES)
618       return E_NOINTERFACE;
619   hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
620   if (hres) return hres;
621   hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
622   if (hres) goto out;
623   seekto.u.LowPart = 0;seekto.u.HighPart = 0;
624   hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
625   hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
626 out:
627   IStream_Release(pStm);
628   return hres;
629 }
630
631
632 static void WINAPI
633 PIPE_StartRequestThread(HANDLE xhPipe) {
634     wine_marshal_id     remoteid;
635     HRESULT             hres;
636
637     hres = read_pipe(xhPipe,&remoteid,sizeof(remoteid));
638     if (hres) {
639         ERR("Failed to read remote mid!\n");
640         return;
641     }
642     PIPE_RegisterPipe(&remoteid,xhPipe, TRUE);
643 }
644
645 static HRESULT
646 COM_RpcReceive(wine_pipe *xpipe) {
647     DWORD       reqtype;
648     HRESULT     hres = S_OK;
649     HANDLE      xhPipe = xpipe->hPipe;
650
651     /*FIXME("%lx %d reading reqtype\n",GetCurrentProcessId(),xhPipe);*/
652     hres = read_pipe(xhPipe,&reqtype,sizeof(reqtype));
653     if (hres) goto end;
654     EnterCriticalSection(&(xpipe->crit));
655     /*FIXME("%lx got reqtype %ld\n",GetCurrentProcessId(),reqtype);*/
656
657     if (reqtype == REQTYPE_DISCONNECT) { /* only received by servers */
658         wine_rpc_disconnect_header header;
659         IRpcStubBuffer *stub;
660         ULONG ret;
661
662         hres = read_pipe(xhPipe, &header, sizeof(header));
663         if (hres) {
664             ERR("could not read disconnect header\n");
665             goto end;
666         }
667
668         TRACE("read disconnect header\n");
669
670         hres = MARSHAL_Find_Stub_Buffer(&header.mid, &stub);
671         if (hres) {
672             ERR("could not locate stub to disconnect, mid.oid=%s\n",
673                 wine_dbgstr_longlong(header.mid.oid));
674             goto end;
675         }
676
677
678         /* release reference added by MARSHAL_Find_Stub_Buffer call */
679         IRpcStubBuffer_Release(stub);
680         /* release it for real */
681         ret = IRpcStubBuffer_Release(stub);
682         /* FIXME: race */
683         if (ret == 0)
684             MARSHAL_Invalidate_Stub_From_MID(&header.mid);
685         goto end;
686     } else if (reqtype == REQTYPE_REQUEST) {
687         wine_rpc_request        *xreq;
688         RPC_GetRequest(&xreq);
689         xreq->hPipe = xhPipe;
690         hres = read_pipe(xhPipe,&(xreq->reqh),sizeof(xreq->reqh));
691         if (hres) goto end;
692         xreq->resph.reqid = xreq->reqh.reqid;
693         xreq->Buffer = HeapAlloc(GetProcessHeap(),0, xreq->reqh.cbBuffer);
694         hres = read_pipe(xhPipe,xreq->Buffer,xreq->reqh.cbBuffer);
695         if (hres) goto end;
696         xreq->state = REQSTATE_REQ_GOT;
697         goto end;
698     } else if (reqtype == REQTYPE_RESPONSE) {
699         wine_rpc_response_header        resph;
700         int i;
701
702         hres = read_pipe(xhPipe,&resph,sizeof(resph));
703         if (hres) goto end;
704         for (i=nrofreqs;i--;) {
705             wine_rpc_request *xreq = reqs[i];
706             if (xreq->state != REQSTATE_REQ_WAITING_FOR_REPLY)
707                 continue;
708             if (xreq->reqh.reqid == resph.reqid) {
709                 memcpy(&(xreq->resph),&resph,sizeof(resph));
710
711                 if (xreq->Buffer)
712                     xreq->Buffer = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->Buffer,xreq->resph.cbBuffer);
713                 else
714                     xreq->Buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->resph.cbBuffer);
715
716                 hres = read_pipe(xhPipe,xreq->Buffer,xreq->resph.cbBuffer);
717                 if (hres) goto end;
718                 xreq->state = REQSTATE_RESP_GOT;
719                 /*PulseEvent(hRpcChanged);*/
720                 goto end;
721             }
722         }
723         ERR("Did not find request for id %lx\n",resph.reqid);
724         hres = S_OK;
725         goto end;
726     }
727     ERR("Unknown reqtype %ld\n",reqtype);
728     hres = E_FAIL;
729 end:
730     LeaveCriticalSection(&(xpipe->crit));
731     return hres;
732 }
733
734 static DWORD WINAPI
735 _StubReaderThread(LPVOID param) {
736     wine_pipe           *xpipe = (wine_pipe*)param;
737     HANDLE              xhPipe = xpipe->hPipe;
738     HRESULT             hres = S_OK;
739
740     TRACE("STUB reader thread %lx\n",GetCurrentProcessId());
741     while (!hres) {
742         int i;
743         hres = COM_RpcReceive(xpipe);
744         if (hres) break;
745
746         for (i=nrofreqs;i--;) {
747             wine_rpc_request *xreq = reqs[i];
748             if ((xreq->state == REQSTATE_REQ_GOT) && (xreq->hPipe == xhPipe)) {
749                 hres = COM_InvokeAndRpcSend(xreq);
750                 if (!hres) break;
751             }
752         }
753     }
754     FIXME("Failed with hres %lx\n",hres);
755     CloseHandle(xhPipe);
756     return 0;
757 }
758
759 /* This thread listens on a named pipe for the entire process. It
760  * deals with incoming connection requests to objects.
761  */
762 static DWORD WINAPI listener_thread(LPVOID param)
763 {
764     char                pipefn[200];
765     HANDLE              listenPipe;
766
767     sprintf(pipefn,OLESTUBMGR"_%08lx",GetCurrentProcessId());
768     TRACE("Process listener thread starting on (%s)\n",pipefn);
769
770     while (1) {
771         listenPipe = CreateNamedPipeA(
772             pipefn,
773             PIPE_ACCESS_DUPLEX,
774             PIPE_TYPE_BYTE|PIPE_WAIT,
775             PIPE_UNLIMITED_INSTANCES,
776             4096,
777             4096,
778             NMPWAIT_USE_DEFAULT_WAIT,
779             NULL
780         );
781         if (listenPipe == INVALID_HANDLE_VALUE) {
782             FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
783             return 1; /* permanent failure, so quit stubmgr thread */
784         }
785         if (!ConnectNamedPipe(listenPipe,NULL)) {
786             ERR("Failure during ConnectNamedPipe %lx!\n",GetLastError());
787             CloseHandle(listenPipe);
788             continue;
789         }
790         PIPE_StartRequestThread(listenPipe);
791     }
792     return 0;
793 }
794
795 void start_listener_thread()
796 {
797   static BOOL running = FALSE;
798   DWORD tid;
799
800   if (!running)
801   {
802       running = TRUE;
803       CreateThread(NULL, 0, listener_thread, NULL, 0, &tid);
804       Sleep(2000); /* actually we just try opening the pipe until it succeeds */
805   }
806 }