4 * Copyright 2002 Marcus Meissner
23 #include "wine/unicode.h"
24 #include "wine/obj_base.h"
25 #include "wine/obj_clientserver.h"
26 #include "wine/obj_misc.h"
27 #include "wine/obj_marshal.h"
28 #include "wine/obj_storage.h"
29 #include "wine/obj_channel.h"
30 #include "wine/winbase16.h"
31 #include "compobj_private.h"
34 #include "compobj_private.h"
36 #include "debugtools.h"
38 DEFAULT_DEBUG_CHANNEL(ole);
40 typedef struct _wine_rpc_request {
42 HANDLE hPipe; /* temp copy of handle */
43 wine_rpc_request_header reqh;
44 wine_rpc_response_header resph;
48 static wine_rpc_request **reqs = NULL;
49 static int nrofreqs = 0;
51 /* This pipe is _thread_ based */
52 typedef struct _wine_pipe {
53 wine_marshal_id mid; /* target mid */
54 DWORD tid; /* thread in which we execute */
59 CRITICAL_SECTION crit;
62 static wine_pipe *pipes = NULL;
63 static int nrofpipes = 0;
65 typedef struct _PipeBuf {
66 ICOM_VTABLE(IRpcChannelBuffer) *lpVtbl;
73 static int nrofreaders = 0;
76 _xread(HANDLE hf, LPVOID ptr, DWORD size) {
78 if (!ReadFile(hf,ptr,size,&res,NULL)) {
79 FIXME("Failed to read from %x, le is %lx\n",hf,GetLastError());
83 FIXME("Read only %ld of %ld bytes.\n",res,size);
95 memset(states,0,sizeof(states));
97 states[reqs[i]->state]++;
98 FIXME("%lx/%s/%d: rq %d, w %d, rg %d, rsq %d, rsg %d, d %d\n",
99 GetCurrentProcessId(),
102 states[REQSTATE_REQ_QUEUED],
103 states[REQSTATE_REQ_WAITING_FOR_REPLY],
104 states[REQSTATE_REQ_GOT],
105 states[REQSTATE_RESP_QUEUED],
106 states[REQSTATE_RESP_GOT],
107 states[REQSTATE_DONE]
111 static HRESULT WINAPI
112 _xwrite(HANDLE hf, LPVOID ptr, DWORD size) {
114 if (!WriteFile(hf,ptr,size,&res,NULL)) {
115 FIXME("Failed to write to %x, le is %lx\n",hf,GetLastError());
119 FIXME("Wrote only %ld of %ld bytes.\n",res,size);
125 static DWORD WINAPI _StubReaderThread(LPVOID);
128 PIPE_RegisterPipe(wine_marshal_id *mid, HANDLE hPipe, BOOL startreader) {
132 for (i=0;i<nrofpipes;i++)
133 if (pipes[i].mid.processid==mid->processid)
136 pipes=(wine_pipe*)HeapReAlloc(GetProcessHeap(),0,pipes,sizeof(pipes[0])*(nrofpipes+1));
138 pipes=(wine_pipe*)HeapAlloc(GetProcessHeap(),0,sizeof(pipes[0]));
139 if (!pipes) return E_OUTOFMEMORY;
140 sprintf(pipefn,OLESTUBMGR"_%08lx",mid->processid);
141 memcpy(&(pipes[nrofpipes].mid),mid,sizeof(*mid));
142 pipes[nrofpipes].hPipe = hPipe;
143 InitializeCriticalSection(&(pipes[nrofpipes].crit));
146 pipes[nrofpipes-1].hThread = CreateThread(NULL,0,_StubReaderThread,(LPVOID)pipes+(nrofpipes-1),0,&(pipes[nrofpipes-1].tid));
148 pipes[nrofpipes-1].tid = GetCurrentThreadId();
154 PIPE_FindByMID(wine_marshal_id *mid) {
156 for (i=0;i<nrofpipes;i++)
157 if ((pipes[i].mid.processid==mid->processid) &&
158 (GetCurrentThreadId()==pipes[i].tid)
160 return pipes[i].hPipe;
161 return INVALID_HANDLE_VALUE;
165 PIPE_GetFromMID(wine_marshal_id *mid) {
167 for (i=0;i<nrofpipes;i++) {
168 if ((pipes[i].mid.processid==mid->processid) &&
169 (GetCurrentThreadId()==pipes[i].tid)
177 RPC_GetRequest(wine_rpc_request **req) {
178 static int reqid = 0xdeadbeef;
181 for (i=0;i<nrofreqs;i++) { /* try to reuse */
182 if (reqs[i]->state == REQSTATE_DONE) {
183 reqs[i]->reqh.reqid = reqid++;
184 reqs[i]->resph.reqid = reqs[i]->reqh.reqid;
185 reqs[i]->hPipe = INVALID_HANDLE_VALUE;
187 reqs[i]->state = REQSTATE_START;
193 reqs = (wine_rpc_request**)HeapReAlloc(
197 sizeof(wine_rpc_request*)*(nrofreqs+1)
200 reqs = (wine_rpc_request**)HeapAlloc(
203 sizeof(wine_rpc_request*)
206 return E_OUTOFMEMORY;
207 reqs[nrofreqs] = (wine_rpc_request*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(wine_rpc_request));
208 reqs[nrofreqs]->reqh.reqid = reqid++;
209 reqs[nrofreqs]->resph.reqid = reqs[nrofreqs]->reqh.reqid;
210 reqs[nrofreqs]->hPipe = INVALID_HANDLE_VALUE;
211 *req = reqs[nrofreqs];
212 reqs[nrofreqs]->state = REQSTATE_START;
218 RPC_FreeRequest(wine_rpc_request *req) {
219 req->state = REQSTATE_DONE; /* Just reuse slot. */
223 static HRESULT WINAPI
224 PipeBuf_QueryInterface(
225 LPRPCCHANNELBUFFER iface,REFIID riid,LPVOID *ppv
228 if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown)) {
229 *ppv = (LPVOID)iface;
230 IUnknown_AddRef(iface);
233 return E_NOINTERFACE;
237 PipeBuf_AddRef(LPRPCCHANNELBUFFER iface) {
238 ICOM_THIS(PipeBuf,iface);
244 PipeBuf_Release(LPRPCCHANNELBUFFER iface) {
245 ICOM_THIS(PipeBuf,iface);
249 ERR("Free all stuff.\n");
250 HeapFree(GetProcessHeap(),0,This);
254 static HRESULT WINAPI
256 LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,REFIID riid
258 /*ICOM_THIS(PipeBuf,iface);*/
260 TRACE("(%p,%s), slightly wrong.\n",msg,debugstr_guid(riid));
261 /* probably reuses IID in real. */
262 if (msg->cbBuffer && (msg->Buffer == NULL))
263 msg->Buffer = HeapAlloc(GetProcessHeap(),0,msg->cbBuffer);
268 _invoke_onereq(wine_rpc_request *req) {
269 IRpcStubBuffer *stub;
274 hres = MARSHAL_Find_Stub_Buffer(&(req->reqh.mid),&stub);
276 ERR("Stub not found?\n");
279 msg.Buffer = req->Buffer;
280 msg.iMethod = req->reqh.iMethod;
281 msg.cbBuffer = req->reqh.cbBuffer;
282 req->state = REQSTATE_INVOKING;
283 req->resph.retval = IRpcStubBuffer_Invoke(stub,&msg,NULL);
284 req->Buffer = msg.Buffer;
285 req->resph.cbBuffer = msg.cbBuffer;
286 reqtype = REQTYPE_RESPONSE;
287 hres = _xwrite(req->hPipe,&reqtype,sizeof(reqtype));
288 if (hres) return hres;
289 hres = _xwrite(req->hPipe,&(req->resph),sizeof(req->resph));
290 if (hres) return hres;
291 hres = _xwrite(req->hPipe,req->Buffer,req->resph.cbBuffer);
292 if (hres) return hres;
293 req->state = REQSTATE_DONE;
298 static HRESULT _read_one(wine_pipe *xpipe);
301 RPC_QueueRequestAndWait(wine_rpc_request *req) {
303 wine_rpc_request *xreq;
306 wine_pipe *xpipe = PIPE_GetFromMID(&(req->reqh.mid));
309 FIXME("no pipe found.\n");
312 if (GetCurrentProcessId() == req->reqh.mid.processid) {
313 ERR("In current process?\n");
316 req->hPipe = xpipe->hPipe;
317 req->state = REQSTATE_REQ_WAITING_FOR_REPLY;
318 reqtype = REQTYPE_REQUEST;
319 hres = _xwrite(req->hPipe,&reqtype,sizeof(reqtype));
320 if (hres) return hres;
321 hres = _xwrite(req->hPipe,&(req->reqh),sizeof(req->reqh));
322 if (hres) return hres;
323 hres = _xwrite(req->hPipe,req->Buffer,req->reqh.cbBuffer);
324 if (hres) return hres;
327 /*WaitForSingleObject(hRpcChanged,INFINITE);*/
328 hres = _read_one(xpipe);
331 for (i=0;i<nrofreqs;i++) {
333 if ((xreq->state==REQSTATE_REQ_GOT) && (xreq->hPipe==req->hPipe)) {
334 _invoke_onereq(xreq);
337 if (req->state == REQSTATE_RESP_GOT)
343 static HRESULT WINAPI
345 LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,ULONG *status
347 ICOM_THIS(PipeBuf,iface);
348 wine_rpc_request *req;
353 if (This->mid.processid == GetCurrentProcessId()) {
354 ERR("Need to call directly!\n");
358 hres = RPC_GetRequest(&req);
359 if (hres) return hres;
360 req->reqh.iMethod = msg->iMethod;
361 req->reqh.cbBuffer = msg->cbBuffer;
362 memcpy(&(req->reqh.mid),&(This->mid),sizeof(This->mid));
363 req->Buffer = msg->Buffer;
364 hres = RPC_QueueRequestAndWait(req);
366 RPC_FreeRequest(req);
369 msg->cbBuffer = req->resph.cbBuffer;
370 msg->Buffer = req->Buffer;
371 *status = req->resph.retval;
372 RPC_FreeRequest(req);
377 static HRESULT WINAPI
378 PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg) {
379 FIXME("(%p), stub!\n",msg);
383 static HRESULT WINAPI
385 LPRPCCHANNELBUFFER iface,DWORD* pdwDestContext,void** ppvDestContext
387 FIXME("(%p,%p), stub!\n",pdwDestContext,ppvDestContext);
391 static HRESULT WINAPI
392 PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface) {
393 FIXME("(), stub!\n");
397 static ICOM_VTABLE(IRpcChannelBuffer) pipebufvt = {
398 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
399 PipeBuf_QueryInterface,
410 PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf) {
411 wine_marshal_id ourid;
417 hPipe = PIPE_FindByMID(mid);
418 if (hPipe == INVALID_HANDLE_VALUE) {
420 sprintf(pipefn,OLESTUBMGR"_%08lx",mid->processid);
423 GENERIC_READ|GENERIC_WRITE,
430 if (hPipe == INVALID_HANDLE_VALUE) {
431 FIXME("Could not open named pipe %s, le is %lx\n",pipefn,GetLastError());
434 hres = PIPE_RegisterPipe(mid, hPipe, FALSE);
435 if (hres) return hres;
436 memset(&ourid,0,sizeof(ourid));
437 ourid.processid = GetCurrentProcessId();
438 if (!WriteFile(hPipe,&ourid,sizeof(ourid),&res,NULL)||(res!=sizeof(ourid))) {
439 ERR("Failed writing startup mid!\n");
443 pbuf = (PipeBuf*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PipeBuf));
444 pbuf->lpVtbl = &pipebufvt;
446 memcpy(&(pbuf->mid),mid,sizeof(*mid));
447 *pipebuf = (IRpcChannelBuffer*)pbuf;
452 create_server(REFCLSID rclsid) {
455 HRESULT hres = E_UNEXPECTED;
457 WCHAR dllName[MAX_PATH+1];
458 DWORD dllNameLen = sizeof(dllName);
460 PROCESS_INFORMATION pinfo;
462 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
464 sprintf(buf,"CLSID\\%s\\LocalServer32",xclsid);
465 hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key);
467 if (hres != ERROR_SUCCESS)
468 return REGDB_E_CLASSNOTREG;
470 memset(dllName,0,sizeof(dllName));
471 hres= RegQueryValueExW(key,NULL,NULL,NULL,(LPBYTE)dllName,&dllNameLen);
473 return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
475 memset(&sinfo,0,sizeof(sinfo));
476 sinfo.cb = sizeof(sinfo);
477 if (!CreateProcessW(NULL,dllName,NULL,NULL,FALSE,0,NULL,NULL,&sinfo,&pinfo))
481 /* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */
482 HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) {
487 char marshalbuffer[200];
489 LARGE_INTEGER seekto;
490 ULARGE_INTEGER newpos;
492 #define MAXTRIES 10000
494 strcpy(pipefn,PIPEPREF);
495 WINE_StringFromCLSID(rclsid,pipefn+strlen(PIPEPREF));
497 while (tries++<MAXTRIES) {
500 GENERIC_READ|GENERIC_WRITE,
507 if (hPipe == INVALID_HANDLE_VALUE) {
509 if ((hres = create_server(rclsid)))
513 WARN("Could not open named pipe to broker %s, le is %lx\n",pipefn,GetLastError());
519 if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
520 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
528 return E_NOINTERFACE;
529 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
530 if (hres) return hres;
531 hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
533 seekto.s.LowPart = 0;seekto.s.HighPart = 0;
534 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
535 hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
537 IStream_Release(pStm);
543 PIPE_StartRequestThread(HANDLE xhPipe) {
544 wine_marshal_id remoteid;
547 hres = _xread(xhPipe,&remoteid,sizeof(remoteid));
549 ERR("Failed to read remote mid!\n");
552 PIPE_RegisterPipe(&remoteid,xhPipe, TRUE);
556 _read_one(wine_pipe *xpipe) {
559 HANDLE xhPipe = xpipe->hPipe;
561 /*FIXME("%lx %d reading reqtype\n",GetCurrentProcessId(),xhPipe);*/
562 hres = _xread(xhPipe,&reqtype,sizeof(reqtype));
564 EnterCriticalSection(&(xpipe->crit));
565 /*FIXME("%lx got reqtype %ld\n",GetCurrentProcessId(),reqtype);*/
567 if (reqtype == REQTYPE_REQUEST) {
568 wine_rpc_request *xreq;
569 RPC_GetRequest(&xreq);
570 xreq->hPipe = xhPipe;
571 hres = _xread(xhPipe,&(xreq->reqh),sizeof(xreq->reqh));
573 xreq->resph.reqid = xreq->reqh.reqid;
574 xreq->Buffer = HeapAlloc(GetProcessHeap(),0, xreq->reqh.cbBuffer);
575 hres = _xread(xhPipe,xreq->Buffer,xreq->reqh.cbBuffer);
577 xreq->state = REQSTATE_REQ_GOT;
580 if (reqtype == REQTYPE_RESPONSE) {
581 wine_rpc_response_header resph;
584 hres = _xread(xhPipe,&resph,sizeof(resph));
586 for (i=nrofreqs;i--;) {
587 wine_rpc_request *xreq = reqs[i];
588 if (xreq->state != REQSTATE_REQ_WAITING_FOR_REPLY)
590 if (xreq->reqh.reqid == resph.reqid) {
591 memcpy(&(xreq->resph),&resph,sizeof(resph));
592 xreq->Buffer = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->Buffer,xreq->resph.cbBuffer);
593 hres = _xread(xhPipe,xreq->Buffer,xreq->resph.cbBuffer);
595 xreq->state = REQSTATE_RESP_GOT;
596 /*PulseEvent(hRpcChanged);*/
600 ERR("Did not find request for id %lx\n",resph.reqid);
604 ERR("Unknown reqtype %ld\n",reqtype);
607 LeaveCriticalSection(&(xpipe->crit));
612 _StubReaderThread(LPVOID param) {
613 wine_pipe *xpipe = (wine_pipe*)param;
614 HANDLE xhPipe = xpipe->hPipe;
617 TRACE("STUB reader thread %lx\n",GetCurrentProcessId());
620 hres = _read_one(xpipe);
623 for (i=nrofreqs;i--;) {
624 wine_rpc_request *xreq = reqs[i];
625 if ((xreq->state == REQSTATE_REQ_GOT) && (xreq->hPipe == xhPipe)) {
626 _invoke_onereq(xreq);
630 FIXME("Failed with hres %lx\n",hres);
636 _StubMgrThread(LPVOID param) {
640 sprintf(pipefn,OLESTUBMGR"_%08lx",GetCurrentProcessId());
641 TRACE("Stub Manager Thread starting on (%s)\n",pipefn);
643 listenPipe = CreateNamedPipeA(
646 PIPE_TYPE_BYTE|PIPE_WAIT,
647 PIPE_UNLIMITED_INSTANCES,
650 NMPWAIT_USE_DEFAULT_WAIT,
653 if (listenPipe == INVALID_HANDLE_VALUE) {
654 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
655 return 1; /* permanent failure, so quit stubmgr thread */
659 if (!ConnectNamedPipe(listenPipe,NULL)) {
660 ERR("Failure during ConnectNamedPipe %lx!\n",GetLastError());
661 CloseHandle(listenPipe);
664 PIPE_StartRequestThread(listenPipe);
665 listenPipe = CreateNamedPipeA(
668 PIPE_TYPE_BYTE|PIPE_WAIT,
669 PIPE_UNLIMITED_INSTANCES,
672 NMPWAIT_USE_DEFAULT_WAIT,
675 if (listenPipe == INVALID_HANDLE_VALUE) {
676 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
677 return 1; /* permanent failure, so quit stubmgr thread */
685 static BOOL stubMgrRunning = FALSE;
688 if (!stubMgrRunning) {
689 stubMgrRunning = TRUE;
690 CreateThread(NULL,0,_StubMgrThread,NULL,0,&tid);
691 Sleep(2000); /* actually we just try opening the pipe until it succeeds */