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