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