- Use InterlockedIncrement for the ipid counter instead of a critical
[wine/multimedia.git] / dlls / ole32 / rpc.c
blobf440c6e520149de47ec61753ecb114bda026360b
1 /*
2 * (Local) RPC Stuff
4 * Copyright 2002 Marcus Meissner
5 * Copyright 2005 Mike Hearn, Rob Shearman for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <assert.h>
30 #define COBJMACROS
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winuser.h"
37 #include "winsvc.h"
38 #include "objbase.h"
39 #include "ole2.h"
40 #include "rpc.h"
41 #include "winerror.h"
42 #include "winreg.h"
43 #include "wtypes.h"
44 #include "wine/unicode.h"
46 #include "compobj_private.h"
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(ole);
52 #define PIPEPREF "\\\\.\\pipe\\"
53 #define OLESTUBMGR PIPEPREF"WINE_OLE_StubMgr"
55 #define REQTYPE_REQUEST 0
56 #define REQTYPE_RESPONSE 1
58 struct request_header
60 DWORD reqid;
61 IPID ipid;
62 DWORD iMethod;
63 DWORD cbBuffer;
66 struct response_header
68 DWORD reqid;
69 DWORD cbBuffer;
70 DWORD retval;
74 #define REQSTATE_START 0
75 #define REQSTATE_REQ_QUEUED 1
76 #define REQSTATE_REQ_WAITING_FOR_REPLY 2
77 #define REQSTATE_REQ_GOT 3
78 #define REQSTATE_INVOKING 4
79 #define REQSTATE_RESP_QUEUED 5
80 #define REQSTATE_RESP_GOT 6
81 #define REQSTATE_DONE 6
83 struct rpc
85 int state;
86 HANDLE hPipe; /* temp copy of handle */
87 struct request_header reqh;
88 struct response_header resph;
89 LPBYTE Buffer;
92 static struct rpc **reqs = NULL;
93 static int nrofreqs = 0;
95 /* This pipe is _thread_ based, each thread which talks to a remote
96 * apartment (mid) has its own pipe. The same structure is used both
97 * for outgoing and incoming RPCs.
99 struct pipe
101 wine_marshal_id mid; /* target mid */
102 DWORD tid; /* thread which owns this pipe */
103 HANDLE hPipe;
105 int pending;
106 HANDLE hThread;
107 CRITICAL_SECTION crit;
109 APARTMENT *apt; /* apartment of the marshalling thread for the stub dispatch case */
112 #define MAX_WINE_PIPES 256
114 static struct pipe pipes[MAX_WINE_PIPES];
115 static int nrofpipes = 0;
117 typedef struct _PipeBuf {
118 IRpcChannelBufferVtbl *lpVtbl;
119 DWORD ref;
121 wine_marshal_id mid;
122 } PipeBuf;
124 static HRESULT WINAPI
125 read_pipe(HANDLE hf, LPVOID ptr, DWORD size) {
126 DWORD res;
127 if (!ReadFile(hf,ptr,size,&res,NULL)) {
128 FIXME("Failed to read from %p, le is %ld\n",hf,GetLastError());
129 return E_FAIL;
131 if (res!=size) {
132 FIXME("Read only %ld of %ld bytes from %p.\n",res,size,hf);
133 return E_FAIL;
135 return S_OK;
138 static HRESULT WINAPI
139 write_pipe(HANDLE hf, LPVOID ptr, DWORD size) {
140 DWORD res;
141 if (!WriteFile(hf,ptr,size,&res,NULL)) {
142 FIXME("Failed to write to %p, le is %ld\n",hf,GetLastError());
143 return E_FAIL;
145 if (res!=size) {
146 FIXME("Wrote only %ld of %ld bytes to %p.\n",res,size,hf);
147 return E_FAIL;
149 return S_OK;
152 static DWORD WINAPI stub_dispatch_thread(LPVOID);
154 static HRESULT
155 PIPE_RegisterPipe(wine_marshal_id *mid, HANDLE hPipe, BOOL startreader)
157 /* FIXME: this pipe caching code is commented out because it is breaks the
158 * tests, causing them hang due to writing to or reading from the wrong pipe.
160 #if 0
161 int i;
163 for (i=0;i<nrofpipes;i++)
164 if (pipes[i].mid.oxid==mid->oxid)
165 return S_OK;
166 #endif
168 if (nrofpipes + 1 >= MAX_WINE_PIPES)
170 FIXME("Out of pipes, please increase MAX_WINE_PIPES\n");
171 return E_OUTOFMEMORY;
173 memcpy(&(pipes[nrofpipes].mid),mid,sizeof(*mid));
174 pipes[nrofpipes].hPipe = hPipe;
175 pipes[nrofpipes].apt = COM_CurrentApt();
176 assert( pipes[nrofpipes].apt );
177 InitializeCriticalSection(&(pipes[nrofpipes].crit));
178 nrofpipes++;
179 if (startreader) {
180 pipes[nrofpipes-1].hThread = CreateThread(NULL,0,stub_dispatch_thread,(LPVOID)(pipes+(nrofpipes-1)),0,&(pipes[nrofpipes-1].tid));
181 } else {
182 pipes[nrofpipes-1].tid = GetCurrentThreadId();
184 return S_OK;
187 static HANDLE
188 PIPE_FindByMID(wine_marshal_id *mid) {
189 int i;
190 for (i=0;i<nrofpipes;i++)
191 if ((pipes[i].mid.oxid==mid->oxid) &&
192 (GetCurrentThreadId()==pipes[i].tid)
194 return pipes[i].hPipe;
195 return INVALID_HANDLE_VALUE;
198 static struct pipe*
199 PIPE_GetFromIPID(const IPID *ipid) {
200 int i;
201 for (i=0; i<nrofpipes; i++)
203 /* compare TID and PID fields */
204 if ((pipes[i].mid.ipid.Data2 == ipid->Data2) &&
205 (pipes[i].mid.ipid.Data3 == ipid->Data3) &&
206 (GetCurrentThreadId() == pipes[i].tid))
207 return pipes+i;
208 /* special case for IRemUnknown IPID */
209 else if ((pipes[i].mid.oxid == *(OXID *)ipid->Data4) &&
210 (GetCurrentThreadId() == pipes[i].tid))
211 return pipes+i;
213 return NULL;
216 static HRESULT
217 RPC_GetRequest(struct rpc **req) {
218 static int reqid = 0xdeadbeef;
219 int i;
221 for (i=0;i<nrofreqs;i++) { /* try to reuse */
222 if (reqs[i]->state == REQSTATE_DONE) {
223 reqs[i]->reqh.reqid = reqid++;
224 reqs[i]->resph.reqid = reqs[i]->reqh.reqid;
225 reqs[i]->hPipe = INVALID_HANDLE_VALUE;
226 *req = reqs[i];
227 reqs[i]->state = REQSTATE_START;
228 return S_OK;
231 /* create new */
232 if (reqs)
233 reqs = (struct rpc**)HeapReAlloc(
234 GetProcessHeap(),
235 HEAP_ZERO_MEMORY,
236 reqs,
237 sizeof(struct rpc*)*(nrofreqs+1)
239 else
240 reqs = (struct rpc**)HeapAlloc(
241 GetProcessHeap(),
242 HEAP_ZERO_MEMORY,
243 sizeof(struct rpc*)
245 if (!reqs)
246 return E_OUTOFMEMORY;
247 reqs[nrofreqs] = (struct rpc*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(struct rpc));
248 reqs[nrofreqs]->reqh.reqid = reqid++;
249 reqs[nrofreqs]->resph.reqid = reqs[nrofreqs]->reqh.reqid;
250 reqs[nrofreqs]->hPipe = INVALID_HANDLE_VALUE;
251 *req = reqs[nrofreqs];
252 reqs[nrofreqs]->state = REQSTATE_START;
253 nrofreqs++;
254 return S_OK;
257 static void
258 RPC_FreeRequest(struct rpc *req) {
259 req->state = REQSTATE_DONE; /* Just reuse slot. */
260 return;
263 static HRESULT WINAPI
264 PipeBuf_QueryInterface(
265 LPRPCCHANNELBUFFER iface,REFIID riid,LPVOID *ppv
267 *ppv = NULL;
268 if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown)) {
269 *ppv = (LPVOID)iface;
270 IUnknown_AddRef(iface);
271 return S_OK;
273 return E_NOINTERFACE;
276 static ULONG WINAPI
277 PipeBuf_AddRef(LPRPCCHANNELBUFFER iface) {
278 PipeBuf *This = (PipeBuf *)iface;
279 return InterlockedIncrement(&This->ref);
282 static ULONG WINAPI
283 PipeBuf_Release(LPRPCCHANNELBUFFER iface) {
284 PipeBuf *This = (PipeBuf *)iface;
285 ULONG ref;
287 ref = InterlockedDecrement(&This->ref);
288 if (ref)
289 return ref;
291 HeapFree(GetProcessHeap(),0,This);
292 return 0;
295 static HRESULT WINAPI
296 PipeBuf_GetBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,REFIID riid)
298 TRACE("(%p,%s)\n",msg,debugstr_guid(riid));
299 /* probably reuses IID in real. */
300 if (msg->cbBuffer && (msg->Buffer == NULL))
301 msg->Buffer = HeapAlloc(GetProcessHeap(),0,msg->cbBuffer);
302 return S_OK;
305 static HRESULT
306 COM_InvokeAndRpcSend(struct rpc *req) {
307 IRpcStubBuffer *stub;
308 RPCOLEMESSAGE msg;
309 HRESULT hres;
310 DWORD reqtype;
312 if (!(stub = ipid_to_stubbuffer(&(req->reqh.ipid))))
314 ERR("Stub not found?\n");
315 return E_FAIL;
318 IUnknown_AddRef(stub);
319 msg.Buffer = req->Buffer;
320 msg.iMethod = req->reqh.iMethod;
321 msg.cbBuffer = req->reqh.cbBuffer;
322 msg.dataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
323 req->state = REQSTATE_INVOKING;
324 req->resph.retval = IRpcStubBuffer_Invoke(stub,&msg,NULL);
325 IUnknown_Release(stub);
326 req->Buffer = msg.Buffer;
327 req->resph.cbBuffer = msg.cbBuffer;
328 reqtype = REQTYPE_RESPONSE;
329 hres = write_pipe(req->hPipe,&reqtype,sizeof(reqtype));
330 if (hres) return hres;
331 hres = write_pipe(req->hPipe,&(req->resph),sizeof(req->resph));
332 if (hres) return hres;
333 hres = write_pipe(req->hPipe,req->Buffer,req->resph.cbBuffer);
334 if (hres) return hres;
335 req->state = REQSTATE_DONE;
336 return S_OK;
339 static HRESULT COM_RpcReceive(struct pipe *xpipe);
341 static HRESULT
342 RPC_QueueRequestAndWait(struct rpc *req) {
343 int i;
344 struct rpc *xreq;
345 HRESULT hres;
346 DWORD reqtype;
347 struct pipe *xpipe = PIPE_GetFromIPID(&(req->reqh.ipid));
349 if (!xpipe) {
350 FIXME("no pipe found.\n");
351 return E_POINTER;
353 req->hPipe = xpipe->hPipe;
354 req->state = REQSTATE_REQ_WAITING_FOR_REPLY;
355 reqtype = REQTYPE_REQUEST;
356 hres = write_pipe(req->hPipe,&reqtype,sizeof(reqtype));
357 if (hres) return hres;
358 hres = write_pipe(req->hPipe,&(req->reqh),sizeof(req->reqh));
359 if (hres) return hres;
360 hres = write_pipe(req->hPipe,req->Buffer,req->reqh.cbBuffer);
361 if (hres) return hres;
363 /* This loop is about allowing re-entrancy. While waiting for the
364 * response to one RPC we may receive a request starting another. */
365 while (!hres) {
366 hres = COM_RpcReceive(xpipe);
367 if (hres) break;
369 for (i=0;i<nrofreqs;i++) {
370 xreq = reqs[i];
371 if ((xreq->state==REQSTATE_REQ_GOT) && (xreq->hPipe==req->hPipe)) {
372 hres = COM_InvokeAndRpcSend(xreq);
373 if (hres) break;
376 if (req->state == REQSTATE_RESP_GOT)
377 return S_OK;
379 if (FAILED(hres))
380 WARN("-- 0x%08lx\n", hres);
381 return hres;
384 static HRESULT WINAPI
385 PipeBuf_SendReceive(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,ULONG *status)
387 PipeBuf *This = (PipeBuf *)iface;
388 struct rpc *req;
389 HRESULT hres;
391 TRACE("()\n");
393 if (This->mid.oxid == COM_CurrentApt()->oxid) {
394 ERR("Need to call directly!\n");
395 return E_FAIL;
398 hres = RPC_GetRequest(&req);
399 if (hres) return hres;
400 req->reqh.iMethod = msg->iMethod;
401 req->reqh.cbBuffer = msg->cbBuffer;
402 req->reqh.ipid = This->mid.ipid;
403 req->Buffer = msg->Buffer;
404 hres = RPC_QueueRequestAndWait(req);
405 if (hres) {
406 RPC_FreeRequest(req);
407 return hres;
409 msg->cbBuffer = req->resph.cbBuffer;
410 msg->Buffer = req->Buffer;
411 *status = req->resph.retval;
412 RPC_FreeRequest(req);
413 return S_OK;
417 static HRESULT WINAPI
418 PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg)
420 FIXME("(%p), stub!\n",msg);
421 return E_FAIL;
424 static HRESULT WINAPI
425 PipeBuf_GetDestCtx(LPRPCCHANNELBUFFER iface,DWORD* pdwDestContext,void** ppvDestContext)
427 FIXME("(%p,%p), stub!\n",pdwDestContext,ppvDestContext);
428 return E_FAIL;
431 static HRESULT WINAPI
432 PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface)
434 FIXME("(), stub!\n");
435 return S_OK;
438 static IRpcChannelBufferVtbl pipebufvt = {
439 PipeBuf_QueryInterface,
440 PipeBuf_AddRef,
441 PipeBuf_Release,
442 PipeBuf_GetBuffer,
443 PipeBuf_SendReceive,
444 PipeBuf_FreeBuffer,
445 PipeBuf_GetDestCtx,
446 PipeBuf_IsConnected
449 HRESULT PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf)
451 wine_marshal_id ourid;
452 DWORD res;
453 HANDLE hPipe;
454 HRESULT hres;
455 PipeBuf *pbuf;
457 hPipe = PIPE_FindByMID(mid);
458 if (hPipe == INVALID_HANDLE_VALUE) {
459 char pipefn[200];
461 sprintf(pipefn,OLESTUBMGR"_%08lx%08lx",(DWORD)(mid->oxid >> 32),(DWORD)mid->oxid);
462 hPipe = CreateFileA(pipefn, GENERIC_READ | GENERIC_WRITE,
463 0, NULL, OPEN_EXISTING, 0, 0);
465 if (hPipe == INVALID_HANDLE_VALUE) {
466 FIXME("Could not open named pipe %s, le is %lx\n",pipefn,GetLastError());
467 return E_FAIL;
470 hres = PIPE_RegisterPipe(mid, hPipe, FALSE);
471 if (hres) return hres;
473 memset(&ourid,0,sizeof(ourid));
474 ourid.oxid = COM_CurrentApt()->oxid;
476 if (!WriteFile(hPipe,&ourid,sizeof(ourid),&res,NULL)||(res!=sizeof(ourid))) {
477 ERR("Failed writing startup mid!\n");
478 return E_FAIL;
482 pbuf = (PipeBuf*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PipeBuf));
483 pbuf->lpVtbl = &pipebufvt;
484 pbuf->ref = 1;
485 memcpy(&(pbuf->mid),mid,sizeof(*mid));
487 *pipebuf = (IRpcChannelBuffer*)pbuf;
489 return S_OK;
492 static HRESULT
493 create_server(REFCLSID rclsid)
495 static const WCHAR embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
496 HKEY key;
497 char buf[200];
498 HRESULT hres = E_UNEXPECTED;
499 char xclsid[80];
500 WCHAR exe[MAX_PATH+1];
501 DWORD exelen = sizeof(exe);
502 WCHAR command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)];
503 STARTUPINFOW sinfo;
504 PROCESS_INFORMATION pinfo;
506 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
508 sprintf(buf,"CLSID\\%s\\LocalServer32",xclsid);
509 hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key);
511 if (hres != ERROR_SUCCESS) {
512 WARN("CLSID %s not registered as LocalServer32\n", xclsid);
513 return REGDB_E_READREGDB; /* Probably */
516 memset(exe,0,sizeof(exe));
517 hres= RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)exe, &exelen);
518 RegCloseKey(key);
519 if (hres) {
520 WARN("No default value for LocalServer32 key\n");
521 return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
524 memset(&sinfo,0,sizeof(sinfo));
525 sinfo.cb = sizeof(sinfo);
527 /* EXE servers are started with the -Embedding switch. MSDN also claims /Embedding is used,
528 * 9x does -Embedding, perhaps an 9x/NT difference?
531 strcpyW(command, exe);
532 strcatW(command, embedding);
534 TRACE("activating local server '%s' for %s\n", debugstr_w(command), xclsid);
536 if (!CreateProcessW(exe, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) {
537 WARN("failed to run local server %s\n", debugstr_w(exe));
538 return E_FAIL;
541 return S_OK;
545 * start_local_service() - start a service given its name and parameters
547 static DWORD
548 start_local_service(LPCWSTR name, DWORD num, LPWSTR *params)
550 SC_HANDLE handle, hsvc;
551 DWORD r = ERROR_FUNCTION_FAILED;
553 TRACE("Starting service %s %ld params\n", debugstr_w(name), num);
555 handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
556 if (!handle)
557 return r;
558 hsvc = OpenServiceW(handle, name, SC_MANAGER_ALL_ACCESS);
559 if (hsvc)
561 if(StartServiceW(hsvc, num, (LPCWSTR*)params))
562 r = ERROR_SUCCESS;
563 else
564 r = GetLastError();
565 if (r == ERROR_SERVICE_ALREADY_RUNNING)
566 r = ERROR_SUCCESS;
567 CloseServiceHandle(hsvc);
569 CloseServiceHandle(handle);
571 TRACE("StartService returned error %ld (%s)\n", r, r?"ok":"failed");
573 return r;
577 * create_local_service() - start a COM server in a service
579 * To start a Local Service, we read the AppID value under
580 * the class's CLSID key, then open the HKCR\\AppId key specified
581 * there and check for a LocalService value.
583 * Note: Local Services are not supported under Windows 9x
585 static HRESULT
586 create_local_service(REFCLSID rclsid)
588 HRESULT hres = REGDB_E_READREGDB;
589 WCHAR buf[40], keyname[50];
590 static const WCHAR szClsId[] = { 'C','L','S','I','D','\\',0 };
591 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
592 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
593 static const WCHAR szLocalService[] = { 'L','o','c','a','l','S','e','r','v','i','c','e',0 };
594 static const WCHAR szServiceParams[] = {'S','e','r','v','i','c','e','P','a','r','a','m','s',0};
595 HKEY hkey;
596 LONG r;
597 DWORD type, sz;
599 TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid));
601 /* read the AppID value under the class's key */
602 strcpyW(keyname,szClsId);
603 StringFromGUID2(rclsid,&keyname[6],39);
604 r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey);
605 if (r!=ERROR_SUCCESS)
606 return hres;
607 sz = sizeof buf;
608 r = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &sz);
609 RegCloseKey(hkey);
610 if (r!=ERROR_SUCCESS || type!=REG_SZ)
611 return hres;
613 /* read the LocalService and ServiceParameters values from the AppID key */
614 strcpyW(keyname, szAppIdKey);
615 strcatW(keyname, buf);
616 r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey);
617 if (r!=ERROR_SUCCESS)
618 return hres;
619 sz = sizeof buf;
620 r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz);
621 if (r==ERROR_SUCCESS && type==REG_SZ)
623 DWORD num_args = 0;
624 LPWSTR args[1] = { NULL };
627 * FIXME: I'm not really sure how to deal with the service parameters.
628 * I suspect that the string returned from RegQueryValueExW
629 * should be split into a number of arguments by spaces.
630 * It would make more sense if ServiceParams contained a
631 * REG_MULTI_SZ here, but it's a REG_SZ for the services
632 * that I'm interested in for the moment.
634 r = RegQueryValueExW(hkey, szServiceParams, NULL, &type, NULL, &sz);
635 if (r == ERROR_SUCCESS && type == REG_SZ && sz)
637 args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz);
638 num_args++;
639 RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz);
641 r = start_local_service(buf, num_args, args);
642 if (r==ERROR_SUCCESS)
643 hres = S_OK;
644 HeapFree(GetProcessHeap(),0,args[0]);
646 RegCloseKey(hkey);
648 return hres;
651 /* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */
652 HRESULT
653 create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
655 HRESULT hres;
656 HANDLE hPipe;
657 char pipefn[200];
658 DWORD res, bufferlen;
659 char marshalbuffer[200];
660 IStream *pStm;
661 LARGE_INTEGER seekto;
662 ULARGE_INTEGER newpos;
663 int tries = 0;
665 static const int MAXTRIES = 10000;
667 TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
669 strcpy(pipefn,PIPEPREF);
670 WINE_StringFromCLSID(rclsid,pipefn+strlen(PIPEPREF));
672 while (tries++ < MAXTRIES) {
673 TRACE("waiting for %s\n", pipefn);
675 WaitNamedPipeA( pipefn, NMPWAIT_WAIT_FOREVER );
676 hPipe = CreateFileA(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
677 if (hPipe == INVALID_HANDLE_VALUE) {
678 if (tries == 1) {
679 if ( (hres = create_server(rclsid)) &&
680 (hres = create_local_service(rclsid)) )
681 return hres;
682 Sleep(1000);
683 } else {
684 WARN("Could not open named pipe to broker %s, le is %lx\n",pipefn,GetLastError());
685 Sleep(1000);
687 continue;
689 bufferlen = 0;
690 if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
691 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
692 Sleep(1000);
693 continue;
695 TRACE("read marshal id from pipe\n");
696 CloseHandle(hPipe);
697 break;
700 if (tries >= MAXTRIES)
701 return E_NOINTERFACE;
703 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
704 if (hres) return hres;
705 hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
706 if (hres) goto out;
707 seekto.u.LowPart = 0;seekto.u.HighPart = 0;
708 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
710 TRACE("unmarshalling classfactory\n");
711 hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
712 out:
713 IStream_Release(pStm);
714 return hres;
718 static void WINAPI
719 PIPE_StartRequestThread(HANDLE xhPipe)
721 wine_marshal_id remoteid;
722 HRESULT hres;
724 hres = read_pipe(xhPipe,&remoteid,sizeof(remoteid));
725 if (hres) {
726 ERR("Failed to read remote mid!\n");
727 return;
729 PIPE_RegisterPipe(&remoteid,xhPipe, TRUE);
732 static HRESULT
733 COM_RpcReceive(struct pipe *xpipe) {
734 DWORD reqtype;
735 HRESULT hres = S_OK;
736 HANDLE xhPipe = xpipe->hPipe;
738 hres = read_pipe(xhPipe,&reqtype,sizeof(reqtype));
739 if (hres) goto end;
740 EnterCriticalSection(&(xpipe->crit));
742 /* only received by servers */
743 if (reqtype == REQTYPE_REQUEST) {
744 struct rpc *xreq;
746 RPC_GetRequest(&xreq);
747 xreq->hPipe = xhPipe;
748 hres = read_pipe(xhPipe,&(xreq->reqh),sizeof(xreq->reqh));
749 if (hres) goto end;
751 xreq->resph.reqid = xreq->reqh.reqid;
752 xreq->Buffer = HeapAlloc(GetProcessHeap(),0, xreq->reqh.cbBuffer);
753 hres = read_pipe(xhPipe,xreq->Buffer,xreq->reqh.cbBuffer);
754 if (hres) goto end;
756 xreq->state = REQSTATE_REQ_GOT;
757 goto end;
758 } else if (reqtype == REQTYPE_RESPONSE) {
759 struct response_header resph;
760 int i;
762 hres = read_pipe(xhPipe,&resph,sizeof(resph));
763 if (hres) goto end;
765 for (i=nrofreqs;i--;) {
766 struct rpc *xreq = reqs[i];
767 if (xreq->state != REQSTATE_REQ_WAITING_FOR_REPLY)
768 continue;
769 if (xreq->reqh.reqid == resph.reqid) {
770 memcpy(&(xreq->resph),&resph,sizeof(resph));
772 if (xreq->Buffer)
773 xreq->Buffer = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->Buffer,xreq->resph.cbBuffer);
774 else
775 xreq->Buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->resph.cbBuffer);
777 hres = read_pipe(xhPipe,xreq->Buffer,xreq->resph.cbBuffer);
778 if (hres) goto end;
779 xreq->state = REQSTATE_RESP_GOT;
780 /*PulseEvent(hRpcChanged);*/
781 goto end;
785 ERR("Did not find request for id %lx\n",resph.reqid);
786 hres = S_OK;
787 goto end;
790 ERR("Unknown reqtype %ld\n",reqtype);
791 hres = E_FAIL;
792 end:
793 LeaveCriticalSection(&(xpipe->crit));
794 return hres;
797 /* This thread listens on the given pipe for requests to a particular stub manager */
798 static DWORD WINAPI stub_dispatch_thread(LPVOID param)
800 struct pipe *xpipe = (struct pipe*)param;
801 HANDLE xhPipe = xpipe->hPipe;
802 HRESULT hres = S_OK;
804 TRACE("starting for apartment OXID %08lx%08lx\n", (DWORD)(xpipe->mid.oxid >> 32), (DWORD)(xpipe->mid.oxid));
806 /* join marshalling apartment. fixme: this stuff is all very wrong, threading needs to work like native */
807 COM_CurrentInfo()->apt = xpipe->apt;
809 while (!hres) {
810 int i;
812 hres = COM_RpcReceive(xpipe);
813 if (hres) break;
815 for (i=nrofreqs;i--;) {
816 struct rpc *xreq = reqs[i];
817 if ((xreq->state == REQSTATE_REQ_GOT) && (xreq->hPipe == xhPipe)) {
818 hres = COM_InvokeAndRpcSend(xreq);
819 if (!hres) break;
824 /* fixme: this thread never quits naturally */
825 WARN("exiting with hres %lx\n",hres);
826 CloseHandle(xhPipe);
827 return 0;
830 struct apartment_listener_params
832 APARTMENT *apt;
833 HANDLE event;
836 /* This thread listens on a named pipe for each apartment that exports
837 * objects. It deals with incoming connection requests. Each time a
838 * client connects a separate thread is spawned for that particular
839 * connection.
841 * This architecture is different in native DCOM.
843 static DWORD WINAPI apartment_listener_thread(LPVOID p)
845 char pipefn[200];
846 HANDLE listenPipe;
847 struct apartment_listener_params * params = (struct apartment_listener_params *)p;
848 APARTMENT *apt = params->apt;
849 HANDLE event = params->event;
851 HeapFree(GetProcessHeap(), 0, params);
853 /* we must join the marshalling threads apartment. we already have a ref here */
854 COM_CurrentInfo()->apt = apt;
856 sprintf(pipefn,OLESTUBMGR"_%08lx%08lx", (DWORD)(apt->oxid >> 32), (DWORD)(apt->oxid));
857 TRACE("Apartment listener thread starting on (%s)\n",pipefn);
859 while (1) {
860 listenPipe = CreateNamedPipeA(
861 pipefn,
862 PIPE_ACCESS_DUPLEX,
863 PIPE_TYPE_BYTE|PIPE_WAIT,
864 PIPE_UNLIMITED_INSTANCES,
865 4096,
866 4096,
867 NMPWAIT_USE_DEFAULT_WAIT,
868 NULL
871 /* tell function that started this thread that we have attempted to created the
872 * named pipe. */
873 if (event) {
874 SetEvent(event);
875 event = NULL;
878 if (listenPipe == INVALID_HANDLE_VALUE) {
879 FIXME("pipe creation failed for %s, error %ld\n",pipefn,GetLastError());
880 return 1; /* permanent failure, so quit stubmgr thread */
883 /* an already connected pipe is not an error */
884 if (!ConnectNamedPipe(listenPipe,NULL) &&
885 (GetLastError() != ERROR_PIPE_CONNECTED)) {
886 ERR("Failure during ConnectNamedPipe %ld!\n",GetLastError());
887 CloseHandle(listenPipe);
888 continue;
891 PIPE_StartRequestThread(listenPipe);
893 return 0;
896 void start_apartment_listener_thread()
898 APARTMENT *apt = COM_CurrentApt();
900 assert( apt );
902 TRACE("apt->listenertid=%ld\n", apt->listenertid);
904 /* apt->listenertid is a hack which needs to die at some point, as
905 * it leaks information into the apartment structure. in fact,
906 * this thread isn't quite correct anyway as native RPC doesn't
907 * use a thread per apartment at all, instead the dispatch thread
908 * either enters the apartment to perform the RPC (for MTAs, RTAs)
909 * or does a context switch into it for STAs.
912 if (!apt->listenertid)
914 HANDLE thread;
915 HANDLE event = CreateEventW(NULL, TRUE, FALSE, NULL);
916 struct apartment_listener_params * params = HeapAlloc(GetProcessHeap(), 0, sizeof(*params));
918 params->apt = apt;
919 params->event = event;
920 thread = CreateThread(NULL, 0, apartment_listener_thread, params, 0, &apt->listenertid);
921 CloseHandle(thread);
922 /* wait for pipe to be created before returning, otherwise we
923 * might try to use it and fail */
924 WaitForSingleObject(event, INFINITE);
925 CloseHandle(event);
929 struct local_server_params
931 CLSID clsid;
932 IStream *stream;
935 static DWORD WINAPI local_server_thread(LPVOID param)
937 struct local_server_params * lsp = (struct local_server_params *)param;
938 HANDLE hPipe;
939 char pipefn[200];
940 HRESULT hres;
941 IStream *pStm = lsp->stream;
942 STATSTG ststg;
943 unsigned char *buffer;
944 int buflen;
945 LARGE_INTEGER seekto;
946 ULARGE_INTEGER newpos;
947 ULONG res;
949 TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
951 strcpy(pipefn,PIPEPREF);
952 WINE_StringFromCLSID(&lsp->clsid,pipefn+strlen(PIPEPREF));
954 HeapFree(GetProcessHeap(), 0, lsp);
956 hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX,
957 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
958 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL );
959 if (hPipe == INVALID_HANDLE_VALUE) {
960 FIXME("pipe creation failed for %s, le is %ld\n",pipefn,GetLastError());
961 return 1;
963 while (1) {
964 if (!ConnectNamedPipe(hPipe,NULL)) {
965 ERR("Failure during ConnectNamedPipe %ld, ABORT!\n",GetLastError());
966 break;
969 TRACE("marshalling IClassFactory to client\n");
971 hres = IStream_Stat(pStm,&ststg,0);
972 if (hres) return hres;
974 buflen = ststg.cbSize.u.LowPart;
975 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
976 seekto.u.LowPart = 0;
977 seekto.u.HighPart = 0;
978 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
979 if (hres) {
980 FIXME("IStream_Seek failed, %lx\n",hres);
981 return hres;
984 hres = IStream_Read(pStm,buffer,buflen,&res);
985 if (hres) {
986 FIXME("Stream Read failed, %lx\n",hres);
987 return hres;
990 IStream_Release(pStm);
992 WriteFile(hPipe,buffer,buflen,&res,NULL);
993 FlushFileBuffers(hPipe);
994 DisconnectNamedPipe(hPipe);
996 TRACE("done marshalling IClassFactory\n");
998 CloseHandle(hPipe);
999 return 0;
1002 void RPC_StartLocalServer(REFCLSID clsid, IStream *stream)
1004 DWORD tid;
1005 HANDLE thread;
1006 struct local_server_params *lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
1008 lsp->clsid = *clsid;
1009 lsp->stream = stream;
1011 thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
1012 CloseHandle(thread);
1013 /* FIXME: failure handling */