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