Add support for HCBT_SYSCOMMAND hook, add logging for HCBT_SYSCOMMAND
[wine.git] / dlls / ole32 / rpc.c
blob511bc341483ef852c1354663e65ca20ea6c0d5e1
1 /*
2 * (Local) RPC Stuff
4 * Copyright 2002 Marcus Meissner
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.
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.
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
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"
47 #include "compobj_private.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(ole);
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;
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;
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;
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
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;
93 static wine_rpc_request **reqs = NULL;
94 static int nrofreqs = 0;
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;
103 int pending;
104 HANDLE hThread;
105 CRITICAL_SECTION crit;
106 } wine_pipe;
108 static wine_pipe *pipes = NULL;
109 static int nrofpipes = 0;
111 typedef struct _PipeBuf {
112 IRpcChannelBufferVtbl *lpVtbl;
113 DWORD ref;
115 wine_marshal_id mid;
116 wine_pipe *pipe;
117 } PipeBuf;
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;
126 if (res!=size) {
127 FIXME("Read only %ld of %ld bytes from %p.\n",res,size,hf);
128 return E_FAIL;
130 return S_OK;
133 static void
134 drs(LPCSTR where) {
135 #if 0
136 static int nrofreaders = 0;
138 int i, states[10];
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]
154 #endif
156 return ;
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;
166 if (res!=size) {
167 FIXME("Wrote only %ld of %ld bytes to %p.\n",res,size,hf);
168 return E_FAIL;
170 return S_OK;
173 static DWORD WINAPI _StubReaderThread(LPVOID);
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;
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();
200 return S_OK;
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)
210 return pipes[i].hPipe;
211 return INVALID_HANDLE_VALUE;
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)
221 return pipes+i;
223 return NULL;
226 static HRESULT
227 RPC_GetRequest(wine_rpc_request **req) {
228 static int reqid = 0xdeadbeef;
229 int i;
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;
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)
249 else
250 reqs = (wine_rpc_request**)HeapAlloc(
251 GetProcessHeap(),
252 HEAP_ZERO_MEMORY,
253 sizeof(wine_rpc_request*)
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;
267 static void
268 RPC_FreeRequest(wine_rpc_request *req) {
269 req->state = REQSTATE_DONE; /* Just reuse slot. */
270 return;
273 static HRESULT WINAPI
274 PipeBuf_QueryInterface(
275 LPRPCCHANNELBUFFER iface,REFIID riid,LPVOID *ppv
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;
283 return E_NOINTERFACE;
286 static ULONG WINAPI
287 PipeBuf_AddRef(LPRPCCHANNELBUFFER iface) {
288 PipeBuf *This = (PipeBuf *)iface;
289 This->ref++;
290 return This->ref;
293 static ULONG WINAPI
294 PipeBuf_Release(LPRPCCHANNELBUFFER iface) {
295 PipeBuf *This = (PipeBuf *)iface;
296 wine_rpc_disconnect_header header;
297 HANDLE pipe;
298 DWORD reqtype = REQTYPE_DISCONNECT;
300 This->ref--;
301 if (This->ref)
302 return This->ref;
304 FIXME("Free all stuff\n");
306 memcpy(&header.mid, &This->mid, sizeof(wine_marshal_id));
308 pipe = PIPE_FindByMID(&This->mid);
310 write_pipe(pipe, &reqtype, sizeof(reqtype));
311 write_pipe(pipe, &header, sizeof(wine_rpc_disconnect_header));
313 TRACE("written disconnect packet\n");
315 HeapFree(GetProcessHeap(),0,This);
316 return 0;
319 static HRESULT WINAPI
320 PipeBuf_GetBuffer(
321 LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,REFIID riid
323 /*PipeBuf *This = (PipeBuf *)iface;*/
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;
332 static HRESULT
333 COM_InvokeAndRpcSend(wine_rpc_request *req) {
334 IRpcStubBuffer *stub;
335 RPCOLEMESSAGE msg;
336 HRESULT hres;
337 DWORD reqtype;
339 hres = MARSHAL_Find_Stub_Buffer(&(req->reqh.mid),&stub);
340 if (hres) {
341 ERR("Stub not found?\n");
342 return hres;
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;
365 static HRESULT COM_RpcReceive(wine_pipe *xpipe);
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));
375 if (!xpipe) {
376 FIXME("no pipe found.\n");
377 return E_POINTER;
379 if (GetCurrentProcessId() == req->reqh.mid.processid) {
380 ERR("In current process?\n");
381 return E_FAIL;
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;
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;
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;
406 if (req->state == REQSTATE_RESP_GOT)
407 return S_OK;
409 if (FAILED(hres))
410 WARN("-- 0x%08lx\n", hres);
411 return hres;
414 static HRESULT WINAPI
415 PipeBuf_SendReceive(
416 LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,ULONG *status
418 PipeBuf *This = (PipeBuf *)iface;
419 wine_rpc_request *req;
420 HRESULT hres;
422 TRACE("()\n");
424 if (This->mid.processid == GetCurrentProcessId()) {
425 ERR("Need to call directly!\n");
426 return E_FAIL;
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;
440 msg->cbBuffer = req->resph.cbBuffer;
441 msg->Buffer = req->Buffer;
442 *status = req->resph.retval;
443 RPC_FreeRequest(req);
444 return S_OK;
448 static HRESULT WINAPI
449 PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg) {
450 FIXME("(%p), stub!\n",msg);
451 return E_FAIL;
454 static HRESULT WINAPI
455 PipeBuf_GetDestCtx(
456 LPRPCCHANNELBUFFER iface,DWORD* pdwDestContext,void** ppvDestContext
458 FIXME("(%p,%p), stub!\n",pdwDestContext,ppvDestContext);
459 return E_FAIL;
462 static HRESULT WINAPI
463 PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface) {
464 FIXME("(), stub!\n");
465 return S_OK;
468 static IRpcChannelBufferVtbl pipebufvt = {
469 PipeBuf_QueryInterface,
470 PipeBuf_AddRef,
471 PipeBuf_Release,
472 PipeBuf_GetBuffer,
473 PipeBuf_SendReceive,
474 PipeBuf_FreeBuffer,
475 PipeBuf_GetDestCtx,
476 PipeBuf_IsConnected
479 HRESULT
480 PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf) {
481 wine_marshal_id ourid;
482 DWORD res;
483 HANDLE hPipe;
484 HRESULT hres;
485 PipeBuf *pbuf;
487 hPipe = PIPE_FindByMID(mid);
488 if (hPipe == INVALID_HANDLE_VALUE) {
489 char pipefn[200];
490 sprintf(pipefn,OLESTUBMGR"_%08lx",mid->processid);
491 hPipe = CreateFileA(
492 pipefn,
493 GENERIC_READ|GENERIC_WRITE,
495 NULL,
496 OPEN_EXISTING,
500 if (hPipe == INVALID_HANDLE_VALUE) {
501 FIXME("Could not open named pipe %s, le is %lx\n",pipefn,GetLastError());
502 return E_FAIL;
504 hres = PIPE_RegisterPipe(mid, hPipe, FALSE);
505 if (hres) return hres;
506 memset(&ourid,0,sizeof(ourid));
507 ourid.processid = GetCurrentProcessId();
508 if (!WriteFile(hPipe,&ourid,sizeof(ourid),&res,NULL)||(res!=sizeof(ourid))) {
509 ERR("Failed writing startup mid!\n");
510 return E_FAIL;
513 pbuf = (PipeBuf*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PipeBuf));
514 pbuf->lpVtbl = &pipebufvt;
515 pbuf->ref = 1;
516 memcpy(&(pbuf->mid),mid,sizeof(*mid));
517 *pipebuf = (IRpcChannelBuffer*)pbuf;
518 return S_OK;
521 static HRESULT
522 create_server(REFCLSID rclsid) {
523 static const WCHAR embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
524 HKEY key;
525 char buf[200];
526 HRESULT hres = E_UNEXPECTED;
527 char xclsid[80];
528 WCHAR exe[MAX_PATH+1];
529 DWORD exelen = sizeof(exe);
530 WCHAR command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)];
531 STARTUPINFOW sinfo;
532 PROCESS_INFORMATION pinfo;
534 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
536 sprintf(buf,"CLSID\\%s\\LocalServer32",xclsid);
537 hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key);
539 if (hres != ERROR_SUCCESS) {
540 WARN("CLSID %s not registered as LocalServer32\n", xclsid);
541 return REGDB_E_READREGDB; /* Probably */
544 memset(exe,0,sizeof(exe));
545 hres= RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)exe, &exelen);
546 RegCloseKey(key);
547 if (hres) {
548 WARN("No default value for LocalServer32 key\n");
549 return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
552 memset(&sinfo,0,sizeof(sinfo));
553 sinfo.cb = sizeof(sinfo);
555 /* EXE servers are started with the -Embedding switch. MSDN also claims /Embedding is used,
556 9x does -Embedding, perhaps an 9x/NT difference? */
558 strcpyW(command, exe);
559 strcatW(command, embedding);
561 TRACE("activating local server '%s' for %s\n", debugstr_w(command), xclsid);
563 if (!CreateProcessW(exe, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) {
564 WARN("failed to run local server %s\n", debugstr_w(exe));
565 return E_FAIL;
568 return S_OK;
570 /* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */
571 HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) {
572 HRESULT hres;
573 HANDLE hPipe;
574 char pipefn[200];
575 DWORD res,bufferlen;
576 char marshalbuffer[200];
577 IStream *pStm;
578 LARGE_INTEGER seekto;
579 ULARGE_INTEGER newpos;
580 int tries = 0;
581 #define MAXTRIES 10000
583 TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
585 strcpy(pipefn,PIPEPREF);
586 WINE_StringFromCLSID(rclsid,pipefn+strlen(PIPEPREF));
588 while (tries++<MAXTRIES) {
589 WaitNamedPipeA( pipefn, NMPWAIT_WAIT_FOREVER );
590 hPipe = CreateFileA(
591 pipefn,
592 GENERIC_READ|GENERIC_WRITE,
594 NULL,
595 OPEN_EXISTING,
599 if (hPipe == INVALID_HANDLE_VALUE) {
600 if (tries == 1) {
601 if ((hres = create_server(rclsid)))
602 return hres;
603 Sleep(1000);
604 } else {
605 WARN("Could not open named pipe to broker %s, le is %lx\n",pipefn,GetLastError());
606 Sleep(1000);
608 continue;
610 bufferlen = 0;
611 if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
612 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
613 Sleep(1000);
614 continue;
616 CloseHandle(hPipe);
617 break;
619 if (tries>=MAXTRIES)
620 return E_NOINTERFACE;
621 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
622 if (hres) return hres;
623 hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
624 if (hres) goto out;
625 seekto.u.LowPart = 0;seekto.u.HighPart = 0;
626 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
627 hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
628 out:
629 IStream_Release(pStm);
630 return hres;
634 static void WINAPI
635 PIPE_StartRequestThread(HANDLE xhPipe) {
636 wine_marshal_id remoteid;
637 HRESULT hres;
639 hres = read_pipe(xhPipe,&remoteid,sizeof(remoteid));
640 if (hres) {
641 ERR("Failed to read remote mid!\n");
642 return;
644 PIPE_RegisterPipe(&remoteid,xhPipe, TRUE);
647 static HRESULT
648 COM_RpcReceive(wine_pipe *xpipe) {
649 DWORD reqtype;
650 HRESULT hres = S_OK;
651 HANDLE xhPipe = xpipe->hPipe;
653 /*FIXME("%lx %d reading reqtype\n",GetCurrentProcessId(),xhPipe);*/
654 hres = read_pipe(xhPipe,&reqtype,sizeof(reqtype));
655 if (hres) goto end;
656 EnterCriticalSection(&(xpipe->crit));
657 /*FIXME("%lx got reqtype %ld\n",GetCurrentProcessId(),reqtype);*/
659 if (reqtype == REQTYPE_DISCONNECT) { /* only received by servers */
660 wine_rpc_disconnect_header header;
661 IRpcStubBuffer *stub;
662 ULONG ret;
664 hres = read_pipe(xhPipe, &header, sizeof(header));
665 if (hres) {
666 ERR("could not read disconnect header\n");
667 goto end;
670 TRACE("read disconnect header\n");
672 hres = MARSHAL_Find_Stub_Buffer(&header.mid, &stub);
673 if (hres) {
674 ERR("could not locate stub to disconnect, mid.objectid=%p\n", (void*)header.mid.objectid);
675 goto end;
679 /* release reference added by MARSHAL_Find_Stub_Buffer call */
680 IRpcStubBuffer_Release(stub);
681 /* release it for real */
682 ret = IRpcStubBuffer_Release(stub);
683 /* FIXME: race */
684 if (ret == 0)
685 MARSHAL_Invalidate_Stub_From_MID(&header.mid);
686 goto end;
687 } else if (reqtype == REQTYPE_REQUEST) {
688 wine_rpc_request *xreq;
689 RPC_GetRequest(&xreq);
690 xreq->hPipe = xhPipe;
691 hres = read_pipe(xhPipe,&(xreq->reqh),sizeof(xreq->reqh));
692 if (hres) goto end;
693 xreq->resph.reqid = xreq->reqh.reqid;
694 xreq->Buffer = HeapAlloc(GetProcessHeap(),0, xreq->reqh.cbBuffer);
695 hres = read_pipe(xhPipe,xreq->Buffer,xreq->reqh.cbBuffer);
696 if (hres) goto end;
697 xreq->state = REQSTATE_REQ_GOT;
698 goto end;
699 } else if (reqtype == REQTYPE_RESPONSE) {
700 wine_rpc_response_header resph;
701 int i;
703 hres = read_pipe(xhPipe,&resph,sizeof(resph));
704 if (hres) goto end;
705 for (i=nrofreqs;i--;) {
706 wine_rpc_request *xreq = reqs[i];
707 if (xreq->state != REQSTATE_REQ_WAITING_FOR_REPLY)
708 continue;
709 if (xreq->reqh.reqid == resph.reqid) {
710 memcpy(&(xreq->resph),&resph,sizeof(resph));
712 if (xreq->Buffer)
713 xreq->Buffer = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->Buffer,xreq->resph.cbBuffer);
714 else
715 xreq->Buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->resph.cbBuffer);
717 hres = read_pipe(xhPipe,xreq->Buffer,xreq->resph.cbBuffer);
718 if (hres) goto end;
719 xreq->state = REQSTATE_RESP_GOT;
720 /*PulseEvent(hRpcChanged);*/
721 goto end;
724 ERR("Did not find request for id %lx\n",resph.reqid);
725 hres = S_OK;
726 goto end;
728 ERR("Unknown reqtype %ld\n",reqtype);
729 hres = E_FAIL;
730 end:
731 LeaveCriticalSection(&(xpipe->crit));
732 return hres;
735 static DWORD WINAPI
736 _StubReaderThread(LPVOID param) {
737 wine_pipe *xpipe = (wine_pipe*)param;
738 HANDLE xhPipe = xpipe->hPipe;
739 HRESULT hres = S_OK;
741 TRACE("STUB reader thread %lx\n",GetCurrentProcessId());
742 while (!hres) {
743 int i;
744 hres = COM_RpcReceive(xpipe);
745 if (hres) break;
747 for (i=nrofreqs;i--;) {
748 wine_rpc_request *xreq = reqs[i];
749 if ((xreq->state == REQSTATE_REQ_GOT) && (xreq->hPipe == xhPipe)) {
750 hres = COM_InvokeAndRpcSend(xreq);
751 if (!hres) break;
755 FIXME("Failed with hres %lx\n",hres);
756 CloseHandle(xhPipe);
757 return 0;
760 static DWORD WINAPI
761 _StubMgrThread(LPVOID param) {
762 char pipefn[200];
763 HANDLE listenPipe;
765 sprintf(pipefn,OLESTUBMGR"_%08lx",GetCurrentProcessId());
766 TRACE("Stub Manager Thread starting on (%s)\n",pipefn);
768 while (1) {
769 listenPipe = CreateNamedPipeA(
770 pipefn,
771 PIPE_ACCESS_DUPLEX,
772 PIPE_TYPE_BYTE|PIPE_WAIT,
773 PIPE_UNLIMITED_INSTANCES,
774 4096,
775 4096,
776 NMPWAIT_USE_DEFAULT_WAIT,
777 NULL
779 if (listenPipe == INVALID_HANDLE_VALUE) {
780 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
781 return 1; /* permanent failure, so quit stubmgr thread */
783 if (!ConnectNamedPipe(listenPipe,NULL)) {
784 ERR("Failure during ConnectNamedPipe %lx!\n",GetLastError());
785 CloseHandle(listenPipe);
786 continue;
788 PIPE_StartRequestThread(listenPipe);
790 return 0;
793 void
794 STUBMGR_Start() {
795 static BOOL stubMgrRunning = FALSE;
796 DWORD tid;
798 if (!stubMgrRunning) {
799 stubMgrRunning = TRUE;
800 CreateThread(NULL,0,_StubMgrThread,NULL,0,&tid);
801 Sleep(2000); /* actually we just try opening the pipe until it succeeds */