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
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
39 #include "wine/unicode.h"
40 #include "wine/winbase16.h"
41 #include "compobj_private.h"
44 #include "compobj_private.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(ole);
50 typedef struct _wine_rpc_request {
52 HANDLE hPipe; /* temp copy of handle */
53 wine_rpc_request_header reqh;
54 wine_rpc_response_header resph;
58 static wine_rpc_request **reqs = NULL;
59 static int nrofreqs = 0;
61 /* This pipe is _thread_ based */
62 typedef struct _wine_pipe {
63 wine_marshal_id mid; /* target mid */
64 DWORD tid; /* thread in which we execute */
69 CRITICAL_SECTION crit;
72 static wine_pipe *pipes = NULL;
73 static int nrofpipes = 0;
75 typedef struct _PipeBuf {
76 ICOM_VTABLE(IRpcChannelBuffer) *lpVtbl;
83 static int nrofreaders = 0;
86 _xread(HANDLE hf, LPVOID ptr, DWORD size) {
88 if (!ReadFile(hf,ptr,size,&res,NULL)) {
89 FIXME("Failed to read from %p, le is %lx\n",hf,GetLastError());
93 FIXME("Read only %ld of %ld bytes from %p.\n",res,size,hf);
105 memset(states,0,sizeof(states));
106 for (i=nrofreqs;i--;)
107 states[reqs[i]->state]++;
108 FIXME("%lx/%s/%d: rq %d, w %d, rg %d, rsq %d, rsg %d, d %d\n",
109 GetCurrentProcessId(),
112 states[REQSTATE_REQ_QUEUED],
113 states[REQSTATE_REQ_WAITING_FOR_REPLY],
114 states[REQSTATE_REQ_GOT],
115 states[REQSTATE_RESP_QUEUED],
116 states[REQSTATE_RESP_GOT],
117 states[REQSTATE_DONE]
121 static HRESULT WINAPI
122 _xwrite(HANDLE hf, LPVOID ptr, DWORD size) {
124 if (!WriteFile(hf,ptr,size,&res,NULL)) {
125 FIXME("Failed to write to %p, le is %lx\n",hf,GetLastError());
129 FIXME("Wrote only %ld of %ld bytes to %p.\n",res,size,hf);
135 static DWORD WINAPI _StubReaderThread(LPVOID);
138 PIPE_RegisterPipe(wine_marshal_id *mid, HANDLE hPipe, BOOL startreader) {
141 wine_pipe *new_pipes;
143 for (i=0;i<nrofpipes;i++)
144 if (pipes[i].mid.processid==mid->processid)
147 new_pipes=(wine_pipe*)HeapReAlloc(GetProcessHeap(),0,pipes,sizeof(pipes[0])*(nrofpipes+1));
149 new_pipes=(wine_pipe*)HeapAlloc(GetProcessHeap(),0,sizeof(pipes[0]));
150 if (!new_pipes) return E_OUTOFMEMORY;
152 sprintf(pipefn,OLESTUBMGR"_%08lx",mid->processid);
153 memcpy(&(pipes[nrofpipes].mid),mid,sizeof(*mid));
154 pipes[nrofpipes].hPipe = hPipe;
155 InitializeCriticalSection(&(pipes[nrofpipes].crit));
158 pipes[nrofpipes-1].hThread = CreateThread(NULL,0,_StubReaderThread,(LPVOID)(pipes+(nrofpipes-1)),0,&(pipes[nrofpipes-1].tid));
160 pipes[nrofpipes-1].tid = GetCurrentThreadId();
166 PIPE_FindByMID(wine_marshal_id *mid) {
168 for (i=0;i<nrofpipes;i++)
169 if ((pipes[i].mid.processid==mid->processid) &&
170 (GetCurrentThreadId()==pipes[i].tid)
172 return pipes[i].hPipe;
173 return INVALID_HANDLE_VALUE;
177 PIPE_GetFromMID(wine_marshal_id *mid) {
179 for (i=0;i<nrofpipes;i++) {
180 if ((pipes[i].mid.processid==mid->processid) &&
181 (GetCurrentThreadId()==pipes[i].tid)
189 RPC_GetRequest(wine_rpc_request **req) {
190 static int reqid = 0xdeadbeef;
193 for (i=0;i<nrofreqs;i++) { /* try to reuse */
194 if (reqs[i]->state == REQSTATE_DONE) {
195 reqs[i]->reqh.reqid = reqid++;
196 reqs[i]->resph.reqid = reqs[i]->reqh.reqid;
197 reqs[i]->hPipe = INVALID_HANDLE_VALUE;
199 reqs[i]->state = REQSTATE_START;
205 reqs = (wine_rpc_request**)HeapReAlloc(
209 sizeof(wine_rpc_request*)*(nrofreqs+1)
212 reqs = (wine_rpc_request**)HeapAlloc(
215 sizeof(wine_rpc_request*)
218 return E_OUTOFMEMORY;
219 reqs[nrofreqs] = (wine_rpc_request*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(wine_rpc_request));
220 reqs[nrofreqs]->reqh.reqid = reqid++;
221 reqs[nrofreqs]->resph.reqid = reqs[nrofreqs]->reqh.reqid;
222 reqs[nrofreqs]->hPipe = INVALID_HANDLE_VALUE;
223 *req = reqs[nrofreqs];
224 reqs[nrofreqs]->state = REQSTATE_START;
230 RPC_FreeRequest(wine_rpc_request *req) {
231 req->state = REQSTATE_DONE; /* Just reuse slot. */
235 static HRESULT WINAPI
236 PipeBuf_QueryInterface(
237 LPRPCCHANNELBUFFER iface,REFIID riid,LPVOID *ppv
240 if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown)) {
241 *ppv = (LPVOID)iface;
242 IUnknown_AddRef(iface);
245 return E_NOINTERFACE;
249 PipeBuf_AddRef(LPRPCCHANNELBUFFER iface) {
250 ICOM_THIS(PipeBuf,iface);
256 PipeBuf_Release(LPRPCCHANNELBUFFER iface) {
257 ICOM_THIS(PipeBuf,iface);
261 ERR("Free all stuff.\n");
262 HeapFree(GetProcessHeap(),0,This);
266 static HRESULT WINAPI
268 LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,REFIID riid
270 /*ICOM_THIS(PipeBuf,iface);*/
272 TRACE("(%p,%s), slightly wrong.\n",msg,debugstr_guid(riid));
273 /* probably reuses IID in real. */
274 if (msg->cbBuffer && (msg->Buffer == NULL))
275 msg->Buffer = HeapAlloc(GetProcessHeap(),0,msg->cbBuffer);
280 _invoke_onereq(wine_rpc_request *req) {
281 IRpcStubBuffer *stub;
286 hres = MARSHAL_Find_Stub_Buffer(&(req->reqh.mid),&stub);
288 ERR("Stub not found?\n");
291 msg.Buffer = req->Buffer;
292 msg.iMethod = req->reqh.iMethod;
293 msg.cbBuffer = req->reqh.cbBuffer;
294 req->state = REQSTATE_INVOKING;
295 req->resph.retval = IRpcStubBuffer_Invoke(stub,&msg,NULL);
296 req->Buffer = msg.Buffer;
297 req->resph.cbBuffer = msg.cbBuffer;
298 reqtype = REQTYPE_RESPONSE;
299 hres = _xwrite(req->hPipe,&reqtype,sizeof(reqtype));
300 if (hres) return hres;
301 hres = _xwrite(req->hPipe,&(req->resph),sizeof(req->resph));
302 if (hres) return hres;
303 hres = _xwrite(req->hPipe,req->Buffer,req->resph.cbBuffer);
304 if (hres) return hres;
305 req->state = REQSTATE_DONE;
310 static HRESULT _read_one(wine_pipe *xpipe);
313 RPC_QueueRequestAndWait(wine_rpc_request *req) {
315 wine_rpc_request *xreq;
318 wine_pipe *xpipe = PIPE_GetFromMID(&(req->reqh.mid));
321 FIXME("no pipe found.\n");
324 if (GetCurrentProcessId() == req->reqh.mid.processid) {
325 ERR("In current process?\n");
328 req->hPipe = xpipe->hPipe;
329 req->state = REQSTATE_REQ_WAITING_FOR_REPLY;
330 reqtype = REQTYPE_REQUEST;
331 hres = _xwrite(req->hPipe,&reqtype,sizeof(reqtype));
332 if (hres) return hres;
333 hres = _xwrite(req->hPipe,&(req->reqh),sizeof(req->reqh));
334 if (hres) return hres;
335 hres = _xwrite(req->hPipe,req->Buffer,req->reqh.cbBuffer);
336 if (hres) return hres;
339 /*WaitForSingleObject(hRpcChanged,INFINITE);*/
340 hres = _read_one(xpipe);
343 for (i=0;i<nrofreqs;i++) {
345 if ((xreq->state==REQSTATE_REQ_GOT) && (xreq->hPipe==req->hPipe)) {
346 _invoke_onereq(xreq);
349 if (req->state == REQSTATE_RESP_GOT)
355 static HRESULT WINAPI
357 LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,ULONG *status
359 ICOM_THIS(PipeBuf,iface);
360 wine_rpc_request *req;
365 if (This->mid.processid == GetCurrentProcessId()) {
366 ERR("Need to call directly!\n");
370 hres = RPC_GetRequest(&req);
371 if (hres) return hres;
372 req->reqh.iMethod = msg->iMethod;
373 req->reqh.cbBuffer = msg->cbBuffer;
374 memcpy(&(req->reqh.mid),&(This->mid),sizeof(This->mid));
375 req->Buffer = msg->Buffer;
376 hres = RPC_QueueRequestAndWait(req);
378 RPC_FreeRequest(req);
381 msg->cbBuffer = req->resph.cbBuffer;
382 msg->Buffer = req->Buffer;
383 *status = req->resph.retval;
384 RPC_FreeRequest(req);
389 static HRESULT WINAPI
390 PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg) {
391 FIXME("(%p), stub!\n",msg);
395 static HRESULT WINAPI
397 LPRPCCHANNELBUFFER iface,DWORD* pdwDestContext,void** ppvDestContext
399 FIXME("(%p,%p), stub!\n",pdwDestContext,ppvDestContext);
403 static HRESULT WINAPI
404 PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface) {
405 FIXME("(), stub!\n");
409 static ICOM_VTABLE(IRpcChannelBuffer) pipebufvt = {
410 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
411 PipeBuf_QueryInterface,
422 PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf) {
423 wine_marshal_id ourid;
429 hPipe = PIPE_FindByMID(mid);
430 if (hPipe == INVALID_HANDLE_VALUE) {
432 sprintf(pipefn,OLESTUBMGR"_%08lx",mid->processid);
435 GENERIC_READ|GENERIC_WRITE,
442 if (hPipe == INVALID_HANDLE_VALUE) {
443 FIXME("Could not open named pipe %s, le is %lx\n",pipefn,GetLastError());
446 hres = PIPE_RegisterPipe(mid, hPipe, FALSE);
447 if (hres) return hres;
448 memset(&ourid,0,sizeof(ourid));
449 ourid.processid = GetCurrentProcessId();
450 if (!WriteFile(hPipe,&ourid,sizeof(ourid),&res,NULL)||(res!=sizeof(ourid))) {
451 ERR("Failed writing startup mid!\n");
455 pbuf = (PipeBuf*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PipeBuf));
456 pbuf->lpVtbl = &pipebufvt;
458 memcpy(&(pbuf->mid),mid,sizeof(*mid));
459 *pipebuf = (IRpcChannelBuffer*)pbuf;
464 create_server(REFCLSID rclsid) {
467 HRESULT hres = E_UNEXPECTED;
469 WCHAR dllName[MAX_PATH+1];
470 DWORD dllNameLen = sizeof(dllName);
472 PROCESS_INFORMATION pinfo;
474 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
476 sprintf(buf,"CLSID\\%s\\LocalServer32",xclsid);
477 hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key);
479 if (hres != ERROR_SUCCESS)
480 return REGDB_E_READREGDB; /* Probably */
482 memset(dllName,0,sizeof(dllName));
483 hres= RegQueryValueExW(key,NULL,NULL,NULL,(LPBYTE)dllName,&dllNameLen);
486 return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
487 memset(&sinfo,0,sizeof(sinfo));
488 sinfo.cb = sizeof(sinfo);
489 if (!CreateProcessW(NULL,dllName,NULL,NULL,FALSE,0,NULL,NULL,&sinfo,&pinfo))
493 /* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */
494 HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) {
499 char marshalbuffer[200];
501 LARGE_INTEGER seekto;
502 ULARGE_INTEGER newpos;
504 #define MAXTRIES 10000
506 strcpy(pipefn,PIPEPREF);
507 WINE_StringFromCLSID(rclsid,pipefn+strlen(PIPEPREF));
509 while (tries++<MAXTRIES) {
512 GENERIC_READ|GENERIC_WRITE,
519 if (hPipe == INVALID_HANDLE_VALUE) {
521 if ((hres = create_server(rclsid)))
525 WARN("Could not open named pipe to broker %s, le is %lx\n",pipefn,GetLastError());
531 if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
532 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
540 return E_NOINTERFACE;
541 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
542 if (hres) return hres;
543 hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
545 seekto.s.LowPart = 0;seekto.s.HighPart = 0;
546 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
547 hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
549 IStream_Release(pStm);
555 PIPE_StartRequestThread(HANDLE xhPipe) {
556 wine_marshal_id remoteid;
559 hres = _xread(xhPipe,&remoteid,sizeof(remoteid));
561 ERR("Failed to read remote mid!\n");
564 PIPE_RegisterPipe(&remoteid,xhPipe, TRUE);
568 _read_one(wine_pipe *xpipe) {
571 HANDLE xhPipe = xpipe->hPipe;
573 /*FIXME("%lx %d reading reqtype\n",GetCurrentProcessId(),xhPipe);*/
574 hres = _xread(xhPipe,&reqtype,sizeof(reqtype));
576 EnterCriticalSection(&(xpipe->crit));
577 /*FIXME("%lx got reqtype %ld\n",GetCurrentProcessId(),reqtype);*/
579 if (reqtype == REQTYPE_REQUEST) {
580 wine_rpc_request *xreq;
581 RPC_GetRequest(&xreq);
582 xreq->hPipe = xhPipe;
583 hres = _xread(xhPipe,&(xreq->reqh),sizeof(xreq->reqh));
585 xreq->resph.reqid = xreq->reqh.reqid;
586 xreq->Buffer = HeapAlloc(GetProcessHeap(),0, xreq->reqh.cbBuffer);
587 hres = _xread(xhPipe,xreq->Buffer,xreq->reqh.cbBuffer);
589 xreq->state = REQSTATE_REQ_GOT;
592 if (reqtype == REQTYPE_RESPONSE) {
593 wine_rpc_response_header resph;
596 hres = _xread(xhPipe,&resph,sizeof(resph));
598 for (i=nrofreqs;i--;) {
599 wine_rpc_request *xreq = reqs[i];
600 if (xreq->state != REQSTATE_REQ_WAITING_FOR_REPLY)
602 if (xreq->reqh.reqid == resph.reqid) {
603 memcpy(&(xreq->resph),&resph,sizeof(resph));
604 xreq->Buffer = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->Buffer,xreq->resph.cbBuffer);
605 hres = _xread(xhPipe,xreq->Buffer,xreq->resph.cbBuffer);
607 xreq->state = REQSTATE_RESP_GOT;
608 /*PulseEvent(hRpcChanged);*/
612 ERR("Did not find request for id %lx\n",resph.reqid);
616 ERR("Unknown reqtype %ld\n",reqtype);
619 LeaveCriticalSection(&(xpipe->crit));
624 _StubReaderThread(LPVOID param) {
625 wine_pipe *xpipe = (wine_pipe*)param;
626 HANDLE xhPipe = xpipe->hPipe;
629 TRACE("STUB reader thread %lx\n",GetCurrentProcessId());
632 hres = _read_one(xpipe);
635 for (i=nrofreqs;i--;) {
636 wine_rpc_request *xreq = reqs[i];
637 if ((xreq->state == REQSTATE_REQ_GOT) && (xreq->hPipe == xhPipe)) {
638 _invoke_onereq(xreq);
642 FIXME("Failed with hres %lx\n",hres);
648 _StubMgrThread(LPVOID param) {
652 sprintf(pipefn,OLESTUBMGR"_%08lx",GetCurrentProcessId());
653 TRACE("Stub Manager Thread starting on (%s)\n",pipefn);
655 listenPipe = CreateNamedPipeA(
658 PIPE_TYPE_BYTE|PIPE_WAIT,
659 PIPE_UNLIMITED_INSTANCES,
662 NMPWAIT_USE_DEFAULT_WAIT,
665 if (listenPipe == INVALID_HANDLE_VALUE) {
666 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
667 return 1; /* permanent failure, so quit stubmgr thread */
671 if (!ConnectNamedPipe(listenPipe,NULL)) {
672 ERR("Failure during ConnectNamedPipe %lx!\n",GetLastError());
673 CloseHandle(listenPipe);
676 PIPE_StartRequestThread(listenPipe);
677 listenPipe = CreateNamedPipeA(
680 PIPE_TYPE_BYTE|PIPE_WAIT,
681 PIPE_UNLIMITED_INSTANCES,
684 NMPWAIT_USE_DEFAULT_WAIT,
687 if (listenPipe == INVALID_HANDLE_VALUE) {
688 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
689 return 1; /* permanent failure, so quit stubmgr thread */
697 static BOOL stubMgrRunning = FALSE;
700 if (!stubMgrRunning) {
701 stubMgrRunning = TRUE;
702 CreateThread(NULL,0,_StubMgrThread,NULL,0,&tid);
703 Sleep(2000); /* actually we just try opening the pipe until it succeeds */