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
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
43 #include "wine/unicode.h"
45 #include "compobj_private.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(ole);
51 #define PIPEPREF "\\\\.\\pipe\\"
52 #define OLESTUBMGR PIPEPREF"WINE_OLE_StubMgr"
54 #define REQTYPE_REQUEST 0
55 typedef struct _wine_rpc_request_header {
60 } wine_rpc_request_header;
62 #define REQTYPE_RESPONSE 1
63 typedef struct _wine_rpc_response_header {
67 } wine_rpc_response_header;
69 /* used when shutting down a pipe, e.g. at the end of a process */
70 #define REQTYPE_DISCONNECT 2
71 typedef struct _wine_rpc_disconnect_header {
73 wine_marshal_id mid; /* mid of stub to delete */
74 } wine_rpc_disconnect_header;
77 #define REQSTATE_START 0
78 #define REQSTATE_REQ_QUEUED 1
79 #define REQSTATE_REQ_WAITING_FOR_REPLY 2
80 #define REQSTATE_REQ_GOT 3
81 #define REQSTATE_INVOKING 4
82 #define REQSTATE_RESP_QUEUED 5
83 #define REQSTATE_RESP_GOT 6
84 #define REQSTATE_DONE 6
86 typedef struct _wine_rpc_request {
88 HANDLE hPipe; /* temp copy of handle */
89 wine_rpc_request_header reqh;
90 wine_rpc_response_header resph;
94 static wine_rpc_request **reqs = NULL;
95 static int nrofreqs = 0;
97 /* This pipe is _thread_ based, each thread which talks to a remote
98 * apartment (mid) has its own pipe. The same structure is used both
99 * for outgoing and incoming RPCs.
101 typedef struct _wine_pipe {
102 wine_marshal_id mid; /* target mid */
103 DWORD tid; /* thread which owns this pipe */
108 CRITICAL_SECTION crit;
110 APARTMENT *apt; /* apartment of the marshalling thread for the stub dispatch case */
113 #define MAX_WINE_PIPES 256
115 static wine_pipe pipes[MAX_WINE_PIPES];
116 static int nrofpipes = 0;
118 typedef struct _PipeBuf {
119 IRpcChannelBufferVtbl *lpVtbl;
125 static HRESULT WINAPI
126 read_pipe(HANDLE hf, LPVOID ptr, DWORD size) {
128 if (!ReadFile(hf,ptr,size,&res,NULL)) {
129 FIXME("Failed to read from %p, le is %ld\n",hf,GetLastError());
133 FIXME("Read only %ld of %ld bytes from %p.\n",res,size,hf);
142 static int nrofreaders = 0;
146 memset(states,0,sizeof(states));
147 for (i=nrofreqs;i--;)
148 states[reqs[i]->state]++;
149 FIXME("%lx/%s/%d: rq %d, w %d, rg %d, rsq %d, rsg %d, d %d\n",
150 GetCurrentProcessId(),
153 states[REQSTATE_REQ_QUEUED],
154 states[REQSTATE_REQ_WAITING_FOR_REPLY],
155 states[REQSTATE_REQ_GOT],
156 states[REQSTATE_RESP_QUEUED],
157 states[REQSTATE_RESP_GOT],
158 states[REQSTATE_DONE]
165 static HRESULT WINAPI
166 write_pipe(HANDLE hf, LPVOID ptr, DWORD size) {
168 if (!WriteFile(hf,ptr,size,&res,NULL)) {
169 FIXME("Failed to write to %p, le is %ld\n",hf,GetLastError());
173 FIXME("Wrote only %ld of %ld bytes to %p.\n",res,size,hf);
179 static DWORD WINAPI stub_dispatch_thread(LPVOID);
182 PIPE_RegisterPipe(wine_marshal_id *mid, HANDLE hPipe, BOOL startreader) {
184 /* FIXME: this pipe caching code is commented out because it is breaks the
185 * tests, causing them hang due to writing to or reading from the wrong pipe.
190 for (i=0;i<nrofpipes;i++)
191 if (pipes[i].mid.oxid==mid->oxid)
195 if (nrofpipes + 1 >= MAX_WINE_PIPES)
197 FIXME("Out of pipes, please increase MAX_WINE_PIPES\n");
198 return E_OUTOFMEMORY;
200 memcpy(&(pipes[nrofpipes].mid),mid,sizeof(*mid));
201 pipes[nrofpipes].hPipe = hPipe;
202 pipes[nrofpipes].apt = COM_CurrentApt();
203 assert( pipes[nrofpipes].apt );
204 InitializeCriticalSection(&(pipes[nrofpipes].crit));
207 pipes[nrofpipes-1].hThread = CreateThread(NULL,0,stub_dispatch_thread,(LPVOID)(pipes+(nrofpipes-1)),0,&(pipes[nrofpipes-1].tid));
209 pipes[nrofpipes-1].tid = GetCurrentThreadId();
215 PIPE_FindByMID(wine_marshal_id *mid) {
217 for (i=0;i<nrofpipes;i++)
218 if ((pipes[i].mid.oxid==mid->oxid) &&
219 (GetCurrentThreadId()==pipes[i].tid)
221 return pipes[i].hPipe;
222 return INVALID_HANDLE_VALUE;
226 PIPE_GetFromMID(wine_marshal_id *mid) {
228 for (i=0;i<nrofpipes;i++) {
229 if ((pipes[i].mid.oxid==mid->oxid) &&
230 (GetCurrentThreadId()==pipes[i].tid)
238 RPC_GetRequest(wine_rpc_request **req) {
239 static int reqid = 0xdeadbeef;
242 for (i=0;i<nrofreqs;i++) { /* try to reuse */
243 if (reqs[i]->state == REQSTATE_DONE) {
244 reqs[i]->reqh.reqid = reqid++;
245 reqs[i]->resph.reqid = reqs[i]->reqh.reqid;
246 reqs[i]->hPipe = INVALID_HANDLE_VALUE;
248 reqs[i]->state = REQSTATE_START;
254 reqs = (wine_rpc_request**)HeapReAlloc(
258 sizeof(wine_rpc_request*)*(nrofreqs+1)
261 reqs = (wine_rpc_request**)HeapAlloc(
264 sizeof(wine_rpc_request*)
267 return E_OUTOFMEMORY;
268 reqs[nrofreqs] = (wine_rpc_request*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(wine_rpc_request));
269 reqs[nrofreqs]->reqh.reqid = reqid++;
270 reqs[nrofreqs]->resph.reqid = reqs[nrofreqs]->reqh.reqid;
271 reqs[nrofreqs]->hPipe = INVALID_HANDLE_VALUE;
272 *req = reqs[nrofreqs];
273 reqs[nrofreqs]->state = REQSTATE_START;
279 RPC_FreeRequest(wine_rpc_request *req) {
280 req->state = REQSTATE_DONE; /* Just reuse slot. */
284 static HRESULT WINAPI
285 PipeBuf_QueryInterface(
286 LPRPCCHANNELBUFFER iface,REFIID riid,LPVOID *ppv
289 if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown)) {
290 *ppv = (LPVOID)iface;
291 IUnknown_AddRef(iface);
294 return E_NOINTERFACE;
298 PipeBuf_AddRef(LPRPCCHANNELBUFFER iface) {
299 PipeBuf *This = (PipeBuf *)iface;
300 return InterlockedIncrement(&This->ref);
304 PipeBuf_Release(LPRPCCHANNELBUFFER iface) {
305 PipeBuf *This = (PipeBuf *)iface;
307 wine_rpc_disconnect_header header;
309 DWORD reqtype = REQTYPE_DISCONNECT;
312 ref = InterlockedDecrement(&This->ref);
316 memcpy(&header.mid, &This->mid, sizeof(wine_marshal_id));
318 pipe = PIPE_FindByMID(&This->mid);
320 write_pipe(pipe, &reqtype, sizeof(reqtype));
321 write_pipe(pipe, &header, sizeof(wine_rpc_disconnect_header));
323 TRACE("written disconnect packet\n");
325 /* prevent a disconnect race with the other side: this isn't
326 * necessary for real dcom but the test suite needs it */
328 read_pipe(pipe, &magic, sizeof(magic));
329 if (magic != 0xcafebabe) ERR("bad disconnection magic: expecting 0xcafebabe but got 0x%lx", magic);
331 HeapFree(GetProcessHeap(),0,This);
335 static HRESULT WINAPI
337 LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,REFIID riid
339 /*PipeBuf *This = (PipeBuf *)iface;*/
341 TRACE("(%p,%s)\n",msg,debugstr_guid(riid));
342 /* probably reuses IID in real. */
343 if (msg->cbBuffer && (msg->Buffer == NULL))
344 msg->Buffer = HeapAlloc(GetProcessHeap(),0,msg->cbBuffer);
349 COM_InvokeAndRpcSend(wine_rpc_request *req) {
350 IRpcStubBuffer *stub;
355 if (!(stub = mid_to_stubbuffer(&(req->reqh.mid))))
357 ERR("Stub not found?\n");
361 IUnknown_AddRef(stub);
362 msg.Buffer = req->Buffer;
363 msg.iMethod = req->reqh.iMethod;
364 msg.cbBuffer = req->reqh.cbBuffer;
365 msg.dataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
366 req->state = REQSTATE_INVOKING;
367 req->resph.retval = IRpcStubBuffer_Invoke(stub,&msg,NULL);
368 IUnknown_Release(stub);
369 req->Buffer = msg.Buffer;
370 req->resph.cbBuffer = msg.cbBuffer;
371 reqtype = REQTYPE_RESPONSE;
372 hres = write_pipe(req->hPipe,&reqtype,sizeof(reqtype));
373 if (hres) return hres;
374 hres = write_pipe(req->hPipe,&(req->resph),sizeof(req->resph));
375 if (hres) return hres;
376 hres = write_pipe(req->hPipe,req->Buffer,req->resph.cbBuffer);
377 if (hres) return hres;
378 req->state = REQSTATE_DONE;
383 static HRESULT COM_RpcReceive(wine_pipe *xpipe);
386 RPC_QueueRequestAndWait(wine_rpc_request *req) {
388 wine_rpc_request *xreq;
391 wine_pipe *xpipe = PIPE_GetFromMID(&(req->reqh.mid));
394 FIXME("no pipe found.\n");
397 req->hPipe = xpipe->hPipe;
398 req->state = REQSTATE_REQ_WAITING_FOR_REPLY;
399 reqtype = REQTYPE_REQUEST;
400 hres = write_pipe(req->hPipe,&reqtype,sizeof(reqtype));
401 if (hres) return hres;
402 hres = write_pipe(req->hPipe,&(req->reqh),sizeof(req->reqh));
403 if (hres) return hres;
404 hres = write_pipe(req->hPipe,req->Buffer,req->reqh.cbBuffer);
405 if (hres) return hres;
407 /* This loop is about allowing re-entrancy. While waiting for the
408 * response to one RPC we may receive a request starting another. */
410 hres = COM_RpcReceive(xpipe);
413 for (i=0;i<nrofreqs;i++) {
415 if ((xreq->state==REQSTATE_REQ_GOT) && (xreq->hPipe==req->hPipe)) {
416 hres = COM_InvokeAndRpcSend(xreq);
420 if (req->state == REQSTATE_RESP_GOT)
424 WARN("-- 0x%08lx\n", hres);
428 static HRESULT WINAPI
430 LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,ULONG *status
432 PipeBuf *This = (PipeBuf *)iface;
433 wine_rpc_request *req;
438 if (This->mid.oxid == COM_CurrentApt()->oxid) {
439 ERR("Need to call directly!\n");
443 hres = RPC_GetRequest(&req);
444 if (hres) return hres;
445 req->reqh.iMethod = msg->iMethod;
446 req->reqh.cbBuffer = msg->cbBuffer;
447 memcpy(&(req->reqh.mid),&(This->mid),sizeof(This->mid));
448 req->Buffer = msg->Buffer;
449 hres = RPC_QueueRequestAndWait(req);
451 RPC_FreeRequest(req);
454 msg->cbBuffer = req->resph.cbBuffer;
455 msg->Buffer = req->Buffer;
456 *status = req->resph.retval;
457 RPC_FreeRequest(req);
462 static HRESULT WINAPI
463 PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg) {
464 FIXME("(%p), stub!\n",msg);
468 static HRESULT WINAPI
470 LPRPCCHANNELBUFFER iface,DWORD* pdwDestContext,void** ppvDestContext
472 FIXME("(%p,%p), stub!\n",pdwDestContext,ppvDestContext);
476 static HRESULT WINAPI
477 PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface) {
478 FIXME("(), stub!\n");
482 static IRpcChannelBufferVtbl pipebufvt = {
483 PipeBuf_QueryInterface,
494 PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf) {
495 wine_marshal_id ourid;
501 hPipe = PIPE_FindByMID(mid);
502 if (hPipe == INVALID_HANDLE_VALUE) {
504 sprintf(pipefn,OLESTUBMGR"_%08lx%08lx",(DWORD)(mid->oxid >> 32),(DWORD)mid->oxid);
507 GENERIC_READ|GENERIC_WRITE,
514 if (hPipe == INVALID_HANDLE_VALUE) {
515 FIXME("Could not open named pipe %s, le is %lx\n",pipefn,GetLastError());
518 hres = PIPE_RegisterPipe(mid, hPipe, FALSE);
519 if (hres) return hres;
520 memset(&ourid,0,sizeof(ourid));
521 ourid.oxid = COM_CurrentApt()->oxid;
522 if (!WriteFile(hPipe,&ourid,sizeof(ourid),&res,NULL)||(res!=sizeof(ourid))) {
523 ERR("Failed writing startup mid!\n");
527 pbuf = (PipeBuf*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PipeBuf));
528 pbuf->lpVtbl = &pipebufvt;
530 memcpy(&(pbuf->mid),mid,sizeof(*mid));
531 *pipebuf = (IRpcChannelBuffer*)pbuf;
536 create_server(REFCLSID rclsid) {
537 static const WCHAR embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
540 HRESULT hres = E_UNEXPECTED;
542 WCHAR exe[MAX_PATH+1];
543 DWORD exelen = sizeof(exe);
544 WCHAR command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)];
546 PROCESS_INFORMATION pinfo;
548 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
550 sprintf(buf,"CLSID\\%s\\LocalServer32",xclsid);
551 hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key);
553 if (hres != ERROR_SUCCESS) {
554 WARN("CLSID %s not registered as LocalServer32\n", xclsid);
555 return REGDB_E_READREGDB; /* Probably */
558 memset(exe,0,sizeof(exe));
559 hres= RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)exe, &exelen);
562 WARN("No default value for LocalServer32 key\n");
563 return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
566 memset(&sinfo,0,sizeof(sinfo));
567 sinfo.cb = sizeof(sinfo);
569 /* EXE servers are started with the -Embedding switch. MSDN also claims /Embedding is used,
570 9x does -Embedding, perhaps an 9x/NT difference? */
572 strcpyW(command, exe);
573 strcatW(command, embedding);
575 TRACE("activating local server '%s' for %s\n", debugstr_w(command), xclsid);
577 if (!CreateProcessW(exe, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) {
578 WARN("failed to run local server %s\n", debugstr_w(exe));
586 * start_local_service() - start a service given its name and parameters
589 start_local_service(LPCWSTR name, DWORD num, LPWSTR *params)
591 SC_HANDLE handle, hsvc;
592 DWORD r = ERROR_FUNCTION_FAILED;
594 TRACE("Starting service %s %ld params\n", debugstr_w(name), num);
596 handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
599 hsvc = OpenServiceW(handle, name, SC_MANAGER_ALL_ACCESS);
602 if(StartServiceW(hsvc, num, (LPCWSTR*)params))
606 if (r==ERROR_SERVICE_ALREADY_RUNNING)
608 CloseServiceHandle(hsvc);
610 CloseServiceHandle(handle);
612 TRACE("StartService returned error %ld (%s)\n", r, r?"ok":"failed");
618 * create_local_service() - start a COM server in a service
620 * To start a Local Service, we read the AppID value under
621 * the class's CLSID key, then open the HKCR\\AppId key specified
622 * there and check for a LocalService value.
624 * Note: Local Services are not supported under Windows 9x
627 create_local_service(REFCLSID rclsid)
629 HRESULT hres = REGDB_E_READREGDB;
630 WCHAR buf[40], keyname[50];
631 static const WCHAR szClsId[] = { 'C','L','S','I','D','\\',0 };
632 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
633 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
634 static const WCHAR szLocalService[] = {
635 'L','o','c','a','l','S','e','r','v','i','c','e',0 };
636 static const WCHAR szServiceParams[] = {
637 'S','e','r','v','i','c','e','P','a','r','a','m','s',0};
642 TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid));
644 /* read the AppID value under the class's key */
645 strcpyW(keyname,szClsId);
646 StringFromGUID2(rclsid,&keyname[6],39);
647 r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey);
648 if (r!=ERROR_SUCCESS)
651 r = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &sz);
653 if (r!=ERROR_SUCCESS || type!=REG_SZ)
656 /* read the LocalService and ServiceParameters values from the AppID key */
657 strcpyW(keyname, szAppIdKey);
658 strcatW(keyname, buf);
659 r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey);
660 if (r!=ERROR_SUCCESS)
663 r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz);
664 if (r==ERROR_SUCCESS && type==REG_SZ)
667 LPWSTR args[1] = { NULL };
670 * FIXME: I'm not really sure how to deal with the service parameters.
671 * I suspect that the string returned from RegQueryValueExW
672 * should be split into a number of arguments by spaces.
673 * It would make more sense if ServiceParams contained a
674 * REG_MULTI_SZ here, but it's a REG_SZ for the services
675 * that I'm interested in for the moment.
677 r = RegQueryValueExW(hkey, szServiceParams, NULL, &type, NULL, &sz);
678 if (r == ERROR_SUCCESS && type == REG_SZ && sz)
680 args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz);
682 RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz);
684 r = start_local_service(buf, num_args, args);
685 if (r==ERROR_SUCCESS)
687 HeapFree(GetProcessHeap(),0,args[0]);
694 /* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */
695 HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) {
700 char marshalbuffer[200];
702 LARGE_INTEGER seekto;
703 ULARGE_INTEGER newpos;
705 #define MAXTRIES 10000
707 TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
709 strcpy(pipefn,PIPEPREF);
710 WINE_StringFromCLSID(rclsid,pipefn+strlen(PIPEPREF));
712 while (tries++<MAXTRIES) {
713 TRACE("waiting for %s\n", pipefn);
715 WaitNamedPipeA( pipefn, NMPWAIT_WAIT_FOREVER );
718 GENERIC_READ|GENERIC_WRITE,
725 if (hPipe == INVALID_HANDLE_VALUE) {
727 if ( (hres = create_server(rclsid)) &&
728 (hres = create_local_service(rclsid)) )
732 WARN("Could not open named pipe to broker %s, le is %lx\n",pipefn,GetLastError());
738 if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
739 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
743 TRACE("read marshal id from pipe\n");
748 return E_NOINTERFACE;
749 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
750 if (hres) return hres;
751 hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
753 seekto.u.LowPart = 0;seekto.u.HighPart = 0;
754 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
755 TRACE("unmarshalling classfactory\n");
756 hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
758 IStream_Release(pStm);
764 PIPE_StartRequestThread(HANDLE xhPipe) {
765 wine_marshal_id remoteid;
768 hres = read_pipe(xhPipe,&remoteid,sizeof(remoteid));
770 ERR("Failed to read remote mid!\n");
773 PIPE_RegisterPipe(&remoteid,xhPipe, TRUE);
777 COM_RpcReceive(wine_pipe *xpipe) {
780 HANDLE xhPipe = xpipe->hPipe;
782 /*FIXME("%lx %d reading reqtype\n",GetCurrentProcessId(),xhPipe);*/
783 hres = read_pipe(xhPipe,&reqtype,sizeof(reqtype));
785 EnterCriticalSection(&(xpipe->crit));
786 /*FIXME("%lx got reqtype %ld\n",GetCurrentProcessId(),reqtype);*/
788 if (reqtype == REQTYPE_DISCONNECT) { /* only received by servers */
789 wine_rpc_disconnect_header header;
790 struct stub_manager *stubmgr;
791 DWORD magic = 0xcafebabe;
794 hres = read_pipe(xhPipe, &header, sizeof(header));
796 ERR("could not read disconnect header\n");
800 TRACE("read disconnect header\n");
802 if (!(apt = COM_ApartmentFromOXID(header.mid.oxid, TRUE)))
804 ERR("Could not map OXID %s to apartment object in disconnect\n", wine_dbgstr_longlong(header.mid.oxid));
808 if (!(stubmgr = get_stub_manager(apt, header.mid.oid)))
810 ERR("could not locate stub to disconnect, mid.oid=%s\n", wine_dbgstr_longlong(header.mid.oid));
811 COM_ApartmentRelease(apt);
815 stub_manager_ext_release(stubmgr, 1);
817 stub_manager_int_release(stubmgr);
818 COM_ApartmentRelease(apt);
821 write_pipe(xhPipe, &magic, sizeof(magic));
823 } else if (reqtype == REQTYPE_REQUEST) {
824 wine_rpc_request *xreq;
825 RPC_GetRequest(&xreq);
826 xreq->hPipe = xhPipe;
827 hres = read_pipe(xhPipe,&(xreq->reqh),sizeof(xreq->reqh));
829 xreq->resph.reqid = xreq->reqh.reqid;
830 xreq->Buffer = HeapAlloc(GetProcessHeap(),0, xreq->reqh.cbBuffer);
831 hres = read_pipe(xhPipe,xreq->Buffer,xreq->reqh.cbBuffer);
833 xreq->state = REQSTATE_REQ_GOT;
835 } else if (reqtype == REQTYPE_RESPONSE) {
836 wine_rpc_response_header resph;
839 hres = read_pipe(xhPipe,&resph,sizeof(resph));
841 for (i=nrofreqs;i--;) {
842 wine_rpc_request *xreq = reqs[i];
843 if (xreq->state != REQSTATE_REQ_WAITING_FOR_REPLY)
845 if (xreq->reqh.reqid == resph.reqid) {
846 memcpy(&(xreq->resph),&resph,sizeof(resph));
849 xreq->Buffer = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->Buffer,xreq->resph.cbBuffer);
851 xreq->Buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->resph.cbBuffer);
853 hres = read_pipe(xhPipe,xreq->Buffer,xreq->resph.cbBuffer);
855 xreq->state = REQSTATE_RESP_GOT;
856 /*PulseEvent(hRpcChanged);*/
860 ERR("Did not find request for id %lx\n",resph.reqid);
864 ERR("Unknown reqtype %ld\n",reqtype);
867 LeaveCriticalSection(&(xpipe->crit));
871 /* This thread listens on the given pipe for requests to a particular stub manager */
872 static DWORD WINAPI stub_dispatch_thread(LPVOID param)
874 wine_pipe *xpipe = (wine_pipe*)param;
875 HANDLE xhPipe = xpipe->hPipe;
878 TRACE("starting for apartment OXID %08lx%08lx\n", (DWORD)(xpipe->mid.oxid >> 32), (DWORD)(xpipe->mid.oxid));
880 /* join marshalling apartment. fixme: this stuff is all very wrong, threading needs to work like native */
881 COM_CurrentInfo()->apt = xpipe->apt;
886 hres = COM_RpcReceive(xpipe);
889 for (i=nrofreqs;i--;) {
890 wine_rpc_request *xreq = reqs[i];
891 if ((xreq->state == REQSTATE_REQ_GOT) && (xreq->hPipe == xhPipe)) {
892 hres = COM_InvokeAndRpcSend(xreq);
898 /* fixme: this thread never quits naturally */
899 WARN("exiting with hres %lx\n",hres);
904 struct apartment_listener_params
910 /* This thread listens on a named pipe for each apartment that exports
911 * objects. It deals with incoming connection requests. Each time a
912 * client connects a separate thread is spawned for that particular
915 * This architecture is different in native DCOM.
917 static DWORD WINAPI apartment_listener_thread(LPVOID p)
921 struct apartment_listener_params * params = (struct apartment_listener_params *)p;
922 APARTMENT *apt = params->apt;
923 HANDLE event = params->event;
925 HeapFree(GetProcessHeap(), 0, params);
927 /* we must join the marshalling threads apartment. we already have a ref here */
928 COM_CurrentInfo()->apt = apt;
930 sprintf(pipefn,OLESTUBMGR"_%08lx%08lx", (DWORD)(apt->oxid >> 32), (DWORD)(apt->oxid));
931 TRACE("Apartment listener thread starting on (%s)\n",pipefn);
934 listenPipe = CreateNamedPipeA(
937 PIPE_TYPE_BYTE|PIPE_WAIT,
938 PIPE_UNLIMITED_INSTANCES,
941 NMPWAIT_USE_DEFAULT_WAIT,
945 /* tell function that started this thread that we have attempted to created the
952 if (listenPipe == INVALID_HANDLE_VALUE) {
953 FIXME("pipe creation failed for %s, error %ld\n",pipefn,GetLastError());
954 return 1; /* permanent failure, so quit stubmgr thread */
957 /* an already connected pipe is not an error */
958 if (!ConnectNamedPipe(listenPipe,NULL) &&
959 (GetLastError() != ERROR_PIPE_CONNECTED)) {
960 ERR("Failure during ConnectNamedPipe %ld!\n",GetLastError());
961 CloseHandle(listenPipe);
965 PIPE_StartRequestThread(listenPipe);
970 void start_apartment_listener_thread()
972 APARTMENT *apt = COM_CurrentApt();
976 TRACE("apt->listenertid=%ld\n", apt->listenertid);
978 /* apt->listenertid is a hack which needs to die at some point, as
979 * it leaks information into the apartment structure. in fact,
980 * this thread isn't quite correct anyway as native RPC doesn't
981 * use a thread per apartment at all, instead the dispatch thread
982 * either enters the apartment to perform the RPC (for MTAs, RTAs)
983 * or does a context switch into it for STAs.
986 if (!apt->listenertid)
989 HANDLE event = CreateEventW(NULL, TRUE, FALSE, NULL);
990 struct apartment_listener_params * params = HeapAlloc(GetProcessHeap(), 0, sizeof(*params));
993 params->event = event;
994 thread = CreateThread(NULL, 0, apartment_listener_thread, params, 0, &apt->listenertid);
996 /* wait for pipe to be created before returning, otherwise we
997 * might try to use it and fail */
998 WaitForSingleObject(event, INFINITE);
1003 struct local_server_params
1009 static DWORD WINAPI local_server_thread(LPVOID param)
1011 struct local_server_params * lsp = (struct local_server_params *)param;
1015 IStream *pStm = lsp->stream;
1017 unsigned char *buffer;
1019 LARGE_INTEGER seekto;
1020 ULARGE_INTEGER newpos;
1023 TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
1025 strcpy(pipefn,PIPEPREF);
1026 WINE_StringFromCLSID(&lsp->clsid,pipefn+strlen(PIPEPREF));
1028 HeapFree(GetProcessHeap(), 0, lsp);
1030 hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX,
1031 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
1032 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL );
1033 if (hPipe == INVALID_HANDLE_VALUE) {
1034 FIXME("pipe creation failed for %s, le is %ld\n",pipefn,GetLastError());
1038 if (!ConnectNamedPipe(hPipe,NULL)) {
1039 ERR("Failure during ConnectNamedPipe %ld, ABORT!\n",GetLastError());
1043 TRACE("marshalling IClassFactory to client\n");
1045 hres = IStream_Stat(pStm,&ststg,0);
1046 if (hres) return hres;
1048 buflen = ststg.cbSize.u.LowPart;
1049 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1050 seekto.u.LowPart = 0;
1051 seekto.u.HighPart = 0;
1052 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1054 FIXME("IStream_Seek failed, %lx\n",hres);
1058 hres = IStream_Read(pStm,buffer,buflen,&res);
1060 FIXME("Stream Read failed, %lx\n",hres);
1064 IStream_Release(pStm);
1066 WriteFile(hPipe,buffer,buflen,&res,NULL);
1067 FlushFileBuffers(hPipe);
1068 DisconnectNamedPipe(hPipe);
1070 TRACE("done marshalling IClassFactory\n");
1076 void RPC_StartLocalServer(REFCLSID clsid, IStream *stream)
1080 struct local_server_params *lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
1082 lsp->clsid = *clsid;
1083 lsp->stream = stream;
1085 thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
1086 CloseHandle(thread);
1087 /* FIXME: failure handling */