Various cosmetic changes.
[wine] / dlls / ole32 / rpc.c
1 /*
2  *      (Local) RPC Stuff
3  *
4  *  Copyright 2002  Marcus Meissner
5  */
6
7 #include "config.h"
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <assert.h>
13
14 #include "windef.h"
15 #include "objbase.h"
16 #include "ole2.h"
17 #include "ole2ver.h"
18 #include "rpc.h"
19 #include "winerror.h"
20 #include "winreg.h"
21 #include "wownt32.h"
22 #include "wtypes.h"
23 #include "wine/unicode.h"
24 #include "wine/obj_base.h"
25 #include "wine/obj_clientserver.h"
26 #include "wine/obj_misc.h"
27 #include "wine/obj_marshal.h"
28 #include "wine/obj_storage.h"
29 #include "wine/obj_channel.h"
30 #include "wine/winbase16.h"
31 #include "compobj_private.h"
32 #include "ifs.h"
33
34 #include "compobj_private.h"
35
36 #include "debugtools.h"
37
38 DEFAULT_DEBUG_CHANNEL(ole);
39
40 typedef struct _wine_rpc_request {
41     int                         state;
42     HANDLE                      hPipe;  /* temp copy of handle */
43     wine_rpc_request_header     reqh;
44     wine_rpc_response_header    resph;
45     LPBYTE                      Buffer;
46 } wine_rpc_request;
47
48 static wine_rpc_request **reqs = NULL;
49 static int nrofreqs = 0;
50
51 /* This pipe is _thread_ based */
52 typedef struct _wine_pipe {
53     wine_marshal_id     mid;    /* target mid */
54     DWORD               tid;    /* thread in which we execute */
55     HANDLE              hPipe;
56
57     int                 pending;
58     HANDLE              hThread;
59     CRITICAL_SECTION    crit;
60 } wine_pipe;
61
62 static wine_pipe *pipes = NULL;
63 static int nrofpipes = 0;
64
65 typedef struct _PipeBuf {
66     ICOM_VTABLE(IRpcChannelBuffer)      *lpVtbl;
67     DWORD                               ref;
68
69     wine_marshal_id                     mid;
70     wine_pipe                           *pipe;
71 } PipeBuf;
72
73 static int nrofreaders = 0;
74
75 static HRESULT WINAPI
76 _xread(HANDLE hf, LPVOID ptr, DWORD size) {
77     DWORD res;
78     if (!ReadFile(hf,ptr,size,&res,NULL)) {
79         FIXME("Failed to read from %x, le is %lx\n",hf,GetLastError());
80         return E_FAIL;
81     }
82     if (res!=size) {
83         FIXME("Read only %ld of %ld bytes.\n",res,size);
84         return E_FAIL;
85     }
86     return S_OK;
87 }
88
89 static void
90 drs(LPCSTR where) {
91     int i, states[10];
92
93     return ;
94
95     memset(states,0,sizeof(states));
96     for (i=nrofreqs;i--;)
97         states[reqs[i]->state]++;
98     FIXME("%lx/%s/%d: rq %d, w %d, rg %d, rsq %d, rsg %d, d %d\n",
99             GetCurrentProcessId(),
100             where,
101             nrofreaders,
102             states[REQSTATE_REQ_QUEUED],
103             states[REQSTATE_REQ_WAITING_FOR_REPLY],
104             states[REQSTATE_REQ_GOT],
105             states[REQSTATE_RESP_QUEUED],
106             states[REQSTATE_RESP_GOT],
107             states[REQSTATE_DONE]
108     );
109 }
110
111 static HRESULT WINAPI
112 _xwrite(HANDLE hf, LPVOID ptr, DWORD size) {
113     DWORD res;
114     if (!WriteFile(hf,ptr,size,&res,NULL)) {
115         FIXME("Failed to write to %x, le is %lx\n",hf,GetLastError());
116         return E_FAIL;
117     }
118     if (res!=size) {
119         FIXME("Wrote only %ld of %ld bytes.\n",res,size);
120         return E_FAIL;
121     }
122     return S_OK;
123 }
124
125 static DWORD WINAPI _StubReaderThread(LPVOID);
126
127 static HRESULT
128 PIPE_RegisterPipe(wine_marshal_id *mid, HANDLE hPipe, BOOL startreader) {
129   int   i;
130   char  pipefn[100];
131
132   for (i=0;i<nrofpipes;i++)
133     if (pipes[i].mid.processid==mid->processid)
134       return S_OK;
135   if (pipes)
136     pipes=(wine_pipe*)HeapReAlloc(GetProcessHeap(),0,pipes,sizeof(pipes[0])*(nrofpipes+1));
137   else
138     pipes=(wine_pipe*)HeapAlloc(GetProcessHeap(),0,sizeof(pipes[0]));
139   if (!pipes) return E_OUTOFMEMORY;
140   sprintf(pipefn,OLESTUBMGR"_%08lx",mid->processid);
141   memcpy(&(pipes[nrofpipes].mid),mid,sizeof(*mid));
142   pipes[nrofpipes].hPipe        = hPipe;
143   InitializeCriticalSection(&(pipes[nrofpipes].crit));
144   nrofpipes++;
145   if (startreader) {
146       pipes[nrofpipes-1].hThread = CreateThread(NULL,0,_StubReaderThread,(LPVOID)pipes+(nrofpipes-1),0,&(pipes[nrofpipes-1].tid));
147   } else {
148       pipes[nrofpipes-1].tid     = GetCurrentThreadId();
149   }
150   return S_OK;
151 }
152
153 static HANDLE
154 PIPE_FindByMID(wine_marshal_id *mid) {
155   int i;
156   for (i=0;i<nrofpipes;i++)
157     if ((pipes[i].mid.processid==mid->processid) &&
158         (GetCurrentThreadId()==pipes[i].tid)
159     )
160       return pipes[i].hPipe;
161   return INVALID_HANDLE_VALUE;
162 }
163
164 static wine_pipe*
165 PIPE_GetFromMID(wine_marshal_id *mid) {
166   int i;
167   for (i=0;i<nrofpipes;i++) {
168     if ((pipes[i].mid.processid==mid->processid) &&
169         (GetCurrentThreadId()==pipes[i].tid)
170     )
171       return pipes+i;
172   }
173   return NULL;
174 }
175
176 static HRESULT 
177 RPC_GetRequest(wine_rpc_request **req) {
178     static int reqid = 0xdeadbeef;
179     int i;
180
181     for (i=0;i<nrofreqs;i++) { /* try to reuse */
182         if (reqs[i]->state == REQSTATE_DONE) {
183             reqs[i]->reqh.reqid = reqid++;
184             reqs[i]->resph.reqid = reqs[i]->reqh.reqid;
185             reqs[i]->hPipe = INVALID_HANDLE_VALUE;
186             *req = reqs[i];
187             reqs[i]->state = REQSTATE_START;
188             return S_OK;
189         }
190     }
191     /* create new */
192     if (reqs)
193         reqs = (wine_rpc_request**)HeapReAlloc(
194                         GetProcessHeap(),
195                         HEAP_ZERO_MEMORY,
196                         reqs,
197                         sizeof(wine_rpc_request*)*(nrofreqs+1)
198                 );
199     else
200         reqs = (wine_rpc_request**)HeapAlloc(
201                         GetProcessHeap(),
202                         HEAP_ZERO_MEMORY,
203                         sizeof(wine_rpc_request*)
204                 );
205     if (!reqs)
206         return E_OUTOFMEMORY;
207     reqs[nrofreqs] = (wine_rpc_request*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(wine_rpc_request));
208     reqs[nrofreqs]->reqh.reqid = reqid++;
209     reqs[nrofreqs]->resph.reqid = reqs[nrofreqs]->reqh.reqid;
210     reqs[nrofreqs]->hPipe = INVALID_HANDLE_VALUE;
211     *req = reqs[nrofreqs];
212     reqs[nrofreqs]->state = REQSTATE_START;
213     nrofreqs++;
214     return S_OK;
215 }
216
217 static void
218 RPC_FreeRequest(wine_rpc_request *req) {
219     req->state = REQSTATE_DONE; /* Just reuse slot. */
220     return;
221 }
222
223 static HRESULT WINAPI
224 PipeBuf_QueryInterface(
225     LPRPCCHANNELBUFFER iface,REFIID riid,LPVOID *ppv
226 ) {
227     *ppv = NULL;
228     if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown)) {
229         *ppv = (LPVOID)iface;
230         IUnknown_AddRef(iface);
231         return S_OK;
232     }
233     return E_NOINTERFACE;
234 }
235
236 static ULONG WINAPI
237 PipeBuf_AddRef(LPRPCCHANNELBUFFER iface) {
238     ICOM_THIS(PipeBuf,iface);
239     This->ref++;
240     return This->ref;
241 }
242
243 static ULONG WINAPI
244 PipeBuf_Release(LPRPCCHANNELBUFFER iface) {
245     ICOM_THIS(PipeBuf,iface);
246     This->ref--;
247     if (This->ref)
248         return This->ref;
249     ERR("Free all stuff.\n");
250     HeapFree(GetProcessHeap(),0,This);
251     return 0;
252 }
253
254 static HRESULT WINAPI
255 PipeBuf_GetBuffer(
256     LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,REFIID riid
257 ) {
258     /*ICOM_THIS(PipeBuf,iface);*/
259
260     TRACE("(%p,%s), slightly wrong.\n",msg,debugstr_guid(riid));
261     /* probably reuses IID in real. */
262     if (msg->cbBuffer && (msg->Buffer == NULL))
263         msg->Buffer = HeapAlloc(GetProcessHeap(),0,msg->cbBuffer);
264     return S_OK;
265 }
266
267 static HRESULT
268 _invoke_onereq(wine_rpc_request *req) {
269     IRpcStubBuffer      *stub;
270     RPCOLEMESSAGE       msg;
271     HRESULT             hres;
272     DWORD               reqtype;
273
274     hres = MARSHAL_Find_Stub_Buffer(&(req->reqh.mid),&stub);
275     if (hres) {
276         ERR("Stub not found?\n");
277         return hres;
278     }
279     msg.Buffer          = req->Buffer;
280     msg.iMethod         = req->reqh.iMethod;
281     msg.cbBuffer        = req->reqh.cbBuffer;
282     req->state          = REQSTATE_INVOKING;
283     req->resph.retval   = IRpcStubBuffer_Invoke(stub,&msg,NULL);
284     req->Buffer         = msg.Buffer;
285     req->resph.cbBuffer = msg.cbBuffer;
286     reqtype             = REQTYPE_RESPONSE;
287     hres = _xwrite(req->hPipe,&reqtype,sizeof(reqtype));
288     if (hres) return hres;
289     hres = _xwrite(req->hPipe,&(req->resph),sizeof(req->resph));
290     if (hres) return hres;
291     hres = _xwrite(req->hPipe,req->Buffer,req->resph.cbBuffer);
292     if (hres) return hres;
293     req->state = REQSTATE_DONE;
294     drs("invoke");
295     return S_OK;
296 }
297
298 static HRESULT _read_one(wine_pipe *xpipe);
299
300 static HRESULT
301 RPC_QueueRequestAndWait(wine_rpc_request *req) {
302     int                 i;
303     wine_rpc_request    *xreq;
304     HRESULT             hres;
305     DWORD               reqtype;
306     wine_pipe           *xpipe = PIPE_GetFromMID(&(req->reqh.mid));
307
308     if (!xpipe) {
309         FIXME("no pipe found.\n");
310         return E_POINTER;
311     }
312     if (GetCurrentProcessId() == req->reqh.mid.processid) {
313         ERR("In current process?\n");
314         return E_FAIL;
315     }
316     req->hPipe = xpipe->hPipe;
317     req->state = REQSTATE_REQ_WAITING_FOR_REPLY;
318     reqtype = REQTYPE_REQUEST;
319     hres = _xwrite(req->hPipe,&reqtype,sizeof(reqtype));
320     if (hres) return hres;
321     hres = _xwrite(req->hPipe,&(req->reqh),sizeof(req->reqh));
322     if (hres) return hres;
323     hres = _xwrite(req->hPipe,req->Buffer,req->reqh.cbBuffer);
324     if (hres) return hres;
325
326     while (1) {
327         /*WaitForSingleObject(hRpcChanged,INFINITE);*/
328         hres = _read_one(xpipe);
329         if (hres) break;
330
331         for (i=0;i<nrofreqs;i++) {
332             xreq = reqs[i];
333             if ((xreq->state==REQSTATE_REQ_GOT) && (xreq->hPipe==req->hPipe)) {
334                 _invoke_onereq(xreq);
335             }
336         }
337         if (req->state == REQSTATE_RESP_GOT)
338             return S_OK;
339     }
340     return hres;
341 }
342
343 static HRESULT WINAPI
344 PipeBuf_SendReceive(
345     LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,ULONG *status
346 ) {
347     ICOM_THIS(PipeBuf,iface);
348     wine_rpc_request    *req;
349     HRESULT             hres;
350
351     TRACE("()\n");
352
353     if (This->mid.processid == GetCurrentProcessId()) {
354         ERR("Need to call directly!\n");
355         return E_FAIL;
356     }
357
358     hres = RPC_GetRequest(&req);
359     if (hres) return hres;
360     req->reqh.iMethod   = msg->iMethod;
361     req->reqh.cbBuffer  = msg->cbBuffer;
362     memcpy(&(req->reqh.mid),&(This->mid),sizeof(This->mid));
363     req->Buffer = msg->Buffer;
364     hres = RPC_QueueRequestAndWait(req);
365     if (hres) {
366         RPC_FreeRequest(req);
367         return hres;
368     }
369     msg->cbBuffer       = req->resph.cbBuffer;
370     msg->Buffer         = req->Buffer;
371     *status             = req->resph.retval;
372     RPC_FreeRequest(req);
373     return S_OK;
374 }
375
376
377 static HRESULT WINAPI
378 PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg) {
379     FIXME("(%p), stub!\n",msg);
380     return E_FAIL;
381 }
382
383 static HRESULT WINAPI
384 PipeBuf_GetDestCtx(
385     LPRPCCHANNELBUFFER iface,DWORD* pdwDestContext,void** ppvDestContext
386 ) {
387     FIXME("(%p,%p), stub!\n",pdwDestContext,ppvDestContext);
388     return E_FAIL;
389 }
390
391 static HRESULT WINAPI
392 PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface) {
393     FIXME("(), stub!\n");
394     return S_OK;
395 }
396
397 static ICOM_VTABLE(IRpcChannelBuffer) pipebufvt = {
398     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
399     PipeBuf_QueryInterface,
400     PipeBuf_AddRef,
401     PipeBuf_Release,
402     PipeBuf_GetBuffer,
403     PipeBuf_SendReceive,
404     PipeBuf_FreeBuffer,
405     PipeBuf_GetDestCtx,
406     PipeBuf_IsConnected
407 };
408
409 HRESULT
410 PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf) {
411   wine_marshal_id       ourid;
412   DWORD                 res;
413   HANDLE                hPipe;
414   HRESULT               hres;
415   PipeBuf               *pbuf;
416
417   hPipe = PIPE_FindByMID(mid);
418   if (hPipe == INVALID_HANDLE_VALUE) {
419       char                      pipefn[200];
420       sprintf(pipefn,OLESTUBMGR"_%08lx",mid->processid);
421       hPipe = CreateFileA(
422               pipefn,
423               GENERIC_READ|GENERIC_WRITE,
424               0,
425               NULL,
426               OPEN_EXISTING,
427               0,
428               -1
429       );
430       if (hPipe == INVALID_HANDLE_VALUE) {
431           FIXME("Could not open named pipe %s, le is %lx\n",pipefn,GetLastError());
432           return E_FAIL;
433       }
434       hres = PIPE_RegisterPipe(mid, hPipe, FALSE);
435       if (hres) return hres;
436       memset(&ourid,0,sizeof(ourid));
437       ourid.processid = GetCurrentProcessId();
438       if (!WriteFile(hPipe,&ourid,sizeof(ourid),&res,NULL)||(res!=sizeof(ourid))) {
439           ERR("Failed writing startup mid!\n");
440           return E_FAIL;
441       }
442   }
443   pbuf = (PipeBuf*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PipeBuf));
444   pbuf->lpVtbl  = &pipebufvt;
445   pbuf->ref     = 1;
446   memcpy(&(pbuf->mid),mid,sizeof(*mid));
447   *pipebuf = (IRpcChannelBuffer*)pbuf;
448   return S_OK;
449 }
450
451 static HRESULT
452 create_server(REFCLSID rclsid) {
453   HKEY          key;
454   char          buf[200];
455   HRESULT       hres = E_UNEXPECTED;
456   char          xclsid[80];
457   WCHAR         dllName[MAX_PATH+1];
458   DWORD         dllNameLen = sizeof(dllName);
459   STARTUPINFOW  sinfo;
460   PROCESS_INFORMATION   pinfo;
461
462   WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
463
464   sprintf(buf,"CLSID\\%s\\LocalServer32",xclsid);
465   hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key);
466
467   if (hres != ERROR_SUCCESS)
468       return REGDB_E_CLASSNOTREG;
469
470   memset(dllName,0,sizeof(dllName));
471   hres= RegQueryValueExW(key,NULL,NULL,NULL,(LPBYTE)dllName,&dllNameLen);
472   if (hres)
473           return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
474   RegCloseKey(key);
475   memset(&sinfo,0,sizeof(sinfo));
476   sinfo.cb = sizeof(sinfo);
477   if (!CreateProcessW(NULL,dllName,NULL,NULL,FALSE,0,NULL,NULL,&sinfo,&pinfo))
478       return E_FAIL;
479   return S_OK;
480 }
481 /* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */
482 HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) {
483   HRESULT       hres;
484   HANDLE        hPipe;
485   char          pipefn[200];
486   DWORD         res,bufferlen;
487   char          marshalbuffer[200];
488   IStream       *pStm;
489   LARGE_INTEGER seekto;
490   ULARGE_INTEGER newpos;
491   int           tries = 0;
492 #define MAXTRIES 10000
493
494   strcpy(pipefn,PIPEPREF);
495   WINE_StringFromCLSID(rclsid,pipefn+strlen(PIPEPREF));
496
497   while (tries++<MAXTRIES) {
498       hPipe     = CreateFileA(
499               pipefn,
500               GENERIC_READ|GENERIC_WRITE,
501               0,
502               NULL,
503               OPEN_EXISTING,
504               0,
505               -1
506       );
507       if (hPipe == INVALID_HANDLE_VALUE) {
508           if (tries == 1) {
509               if ((hres = create_server(rclsid)))
510                   return hres;
511               Sleep(1000);
512           } else {
513               WARN("Could not open named pipe to broker %s, le is %lx\n",pipefn,GetLastError());
514               Sleep(1000);
515           }
516           continue;
517       }
518       bufferlen = 0;
519       if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
520           FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
521           Sleep(1000);
522           continue;
523       }
524       CloseHandle(hPipe);
525       break;
526   }
527   if (tries>=MAXTRIES) 
528       return E_NOINTERFACE;
529   hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
530   if (hres) return hres;
531   hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
532   if (hres) goto out;
533   seekto.s.LowPart = 0;seekto.s.HighPart = 0;
534   hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
535   hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
536 out:
537   IStream_Release(pStm);
538   return hres;
539 }
540
541
542 static void WINAPI
543 PIPE_StartRequestThread(HANDLE xhPipe) {
544     wine_marshal_id     remoteid;
545     HRESULT             hres;
546
547     hres = _xread(xhPipe,&remoteid,sizeof(remoteid));
548     if (hres) {
549         ERR("Failed to read remote mid!\n");
550         return;
551     }
552     PIPE_RegisterPipe(&remoteid,xhPipe, TRUE);
553 }
554
555 static HRESULT
556 _read_one(wine_pipe *xpipe) {
557     DWORD       reqtype;
558     HRESULT     hres = S_OK;
559     HANDLE      xhPipe = xpipe->hPipe;
560
561     /*FIXME("%lx %d reading reqtype\n",GetCurrentProcessId(),xhPipe);*/
562     hres = _xread(xhPipe,&reqtype,sizeof(reqtype));
563     if (hres) goto end;
564     EnterCriticalSection(&(xpipe->crit));
565     /*FIXME("%lx got reqtype %ld\n",GetCurrentProcessId(),reqtype);*/
566
567     if (reqtype == REQTYPE_REQUEST) {
568         wine_rpc_request        *xreq;
569         RPC_GetRequest(&xreq);
570         xreq->hPipe = xhPipe;
571         hres = _xread(xhPipe,&(xreq->reqh),sizeof(xreq->reqh));
572         if (hres) goto end;
573         xreq->resph.reqid = xreq->reqh.reqid;
574         xreq->Buffer = HeapAlloc(GetProcessHeap(),0, xreq->reqh.cbBuffer);
575         hres = _xread(xhPipe,xreq->Buffer,xreq->reqh.cbBuffer);
576         if (hres) goto end;
577         xreq->state = REQSTATE_REQ_GOT;
578         goto end;
579     }
580     if (reqtype == REQTYPE_RESPONSE) {
581         wine_rpc_response_header        resph;
582         int i;
583
584         hres = _xread(xhPipe,&resph,sizeof(resph));
585         if (hres) goto end;
586         for (i=nrofreqs;i--;) {
587             wine_rpc_request *xreq = reqs[i];
588             if (xreq->state != REQSTATE_REQ_WAITING_FOR_REPLY)
589                 continue;
590             if (xreq->reqh.reqid == resph.reqid) {
591                 memcpy(&(xreq->resph),&resph,sizeof(resph));
592                 xreq->Buffer = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->Buffer,xreq->resph.cbBuffer);
593                 hres = _xread(xhPipe,xreq->Buffer,xreq->resph.cbBuffer);
594                 if (hres) goto end;
595                 xreq->state = REQSTATE_RESP_GOT;
596                 /*PulseEvent(hRpcChanged);*/
597                 goto end;
598             }
599         }
600         ERR("Did not find request for id %lx\n",resph.reqid);
601         hres = S_OK;
602         goto end;
603     }
604     ERR("Unknown reqtype %ld\n",reqtype);
605     hres = E_FAIL;
606 end:
607     LeaveCriticalSection(&(xpipe->crit));
608     return hres;
609 }
610
611 static DWORD WINAPI
612 _StubReaderThread(LPVOID param) {
613     wine_pipe           *xpipe = (wine_pipe*)param;
614     HANDLE              xhPipe = xpipe->hPipe;
615     HRESULT             hres;
616
617     TRACE("STUB reader thread %lx\n",GetCurrentProcessId());
618     while (1) {
619         int i;
620         hres = _read_one(xpipe);
621         if (hres) break;
622
623         for (i=nrofreqs;i--;) {
624             wine_rpc_request *xreq = reqs[i];
625             if ((xreq->state == REQSTATE_REQ_GOT) && (xreq->hPipe == xhPipe)) {
626                 _invoke_onereq(xreq);
627             }
628         }
629     }
630     FIXME("Failed with hres %lx\n",hres);
631     CloseHandle(xhPipe);
632     return 0;
633 }
634
635 static DWORD WINAPI
636 _StubMgrThread(LPVOID param) {
637     char                pipefn[200];
638     HANDLE              listenPipe;
639
640     sprintf(pipefn,OLESTUBMGR"_%08lx",GetCurrentProcessId());
641     TRACE("Stub Manager Thread starting on (%s)\n",pipefn);
642
643     listenPipe = CreateNamedPipeA(
644         pipefn,
645         PIPE_ACCESS_DUPLEX,
646         PIPE_TYPE_BYTE|PIPE_WAIT,
647         PIPE_UNLIMITED_INSTANCES,
648         4096,
649         4096,
650         NMPWAIT_USE_DEFAULT_WAIT,
651         NULL
652     );
653     if (listenPipe == INVALID_HANDLE_VALUE) {
654         FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
655         return 1; /* permanent failure, so quit stubmgr thread */
656     }
657
658     while (1) {
659         if (!ConnectNamedPipe(listenPipe,NULL)) {
660             ERR("Failure during ConnectNamedPipe %lx!\n",GetLastError());
661             CloseHandle(listenPipe);
662             continue;
663         }
664         PIPE_StartRequestThread(listenPipe);
665         listenPipe = CreateNamedPipeA(
666             pipefn,
667             PIPE_ACCESS_DUPLEX,
668             PIPE_TYPE_BYTE|PIPE_WAIT,
669             PIPE_UNLIMITED_INSTANCES,
670             4096,
671             4096,
672             NMPWAIT_USE_DEFAULT_WAIT,
673             NULL
674         );
675         if (listenPipe == INVALID_HANDLE_VALUE) {
676             FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
677             return 1; /* permanent failure, so quit stubmgr thread */
678         }
679     }
680     return 0;
681 }
682
683 void
684 STUBMGR_Start() {
685   static BOOL stubMgrRunning = FALSE;
686   DWORD tid;
687
688   if (!stubMgrRunning) {
689       stubMgrRunning = TRUE;
690       CreateThread(NULL,0,_StubMgrThread,NULL,0,&tid);
691       Sleep(2000); /* actually we just try opening the pipe until it succeeds */
692   }
693 }