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
37 #include "wine/unicode.h"
38 #include "wine/obj_base.h"
39 #include "wine/obj_clientserver.h"
40 #include "wine/obj_misc.h"
41 #include "wine/obj_marshal.h"
42 #include "wine/obj_storage.h"
43 #include "wine/obj_channel.h"
44 #include "wine/winbase16.h"
45 #include "compobj_private.h"
48 #include "compobj_private.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
54 typedef struct _wine_rpc_request
{
56 HANDLE hPipe
; /* temp copy of handle */
57 wine_rpc_request_header reqh
;
58 wine_rpc_response_header resph
;
62 static wine_rpc_request
**reqs
= NULL
;
63 static int nrofreqs
= 0;
65 /* This pipe is _thread_ based */
66 typedef struct _wine_pipe
{
67 wine_marshal_id mid
; /* target mid */
68 DWORD tid
; /* thread in which we execute */
73 CRITICAL_SECTION crit
;
76 static wine_pipe
*pipes
= NULL
;
77 static int nrofpipes
= 0;
79 typedef struct _PipeBuf
{
80 ICOM_VTABLE(IRpcChannelBuffer
) *lpVtbl
;
87 static int nrofreaders
= 0;
90 _xread(HANDLE hf
, LPVOID ptr
, DWORD size
) {
92 if (!ReadFile(hf
,ptr
,size
,&res
,NULL
)) {
93 FIXME("Failed to read from %x, le is %lx\n",hf
,GetLastError());
97 FIXME("Read only %ld of %ld bytes.\n",res
,size
);
109 memset(states
,0,sizeof(states
));
110 for (i
=nrofreqs
;i
--;)
111 states
[reqs
[i
]->state
]++;
112 FIXME("%lx/%s/%d: rq %d, w %d, rg %d, rsq %d, rsg %d, d %d\n",
113 GetCurrentProcessId(),
116 states
[REQSTATE_REQ_QUEUED
],
117 states
[REQSTATE_REQ_WAITING_FOR_REPLY
],
118 states
[REQSTATE_REQ_GOT
],
119 states
[REQSTATE_RESP_QUEUED
],
120 states
[REQSTATE_RESP_GOT
],
121 states
[REQSTATE_DONE
]
125 static HRESULT WINAPI
126 _xwrite(HANDLE hf
, LPVOID ptr
, DWORD size
) {
128 if (!WriteFile(hf
,ptr
,size
,&res
,NULL
)) {
129 FIXME("Failed to write to %x, le is %lx\n",hf
,GetLastError());
133 FIXME("Wrote only %ld of %ld bytes.\n",res
,size
);
139 static DWORD WINAPI
_StubReaderThread(LPVOID
);
142 PIPE_RegisterPipe(wine_marshal_id
*mid
, HANDLE hPipe
, BOOL startreader
) {
146 for (i
=0;i
<nrofpipes
;i
++)
147 if (pipes
[i
].mid
.processid
==mid
->processid
)
150 pipes
=(wine_pipe
*)HeapReAlloc(GetProcessHeap(),0,pipes
,sizeof(pipes
[0])*(nrofpipes
+1));
152 pipes
=(wine_pipe
*)HeapAlloc(GetProcessHeap(),0,sizeof(pipes
[0]));
153 if (!pipes
) return E_OUTOFMEMORY
;
154 sprintf(pipefn
,OLESTUBMGR
"_%08lx",mid
->processid
);
155 memcpy(&(pipes
[nrofpipes
].mid
),mid
,sizeof(*mid
));
156 pipes
[nrofpipes
].hPipe
= hPipe
;
157 InitializeCriticalSection(&(pipes
[nrofpipes
].crit
));
160 pipes
[nrofpipes
-1].hThread
= CreateThread(NULL
,0,_StubReaderThread
,(LPVOID
)pipes
+(nrofpipes
-1),0,&(pipes
[nrofpipes
-1].tid
));
162 pipes
[nrofpipes
-1].tid
= GetCurrentThreadId();
168 PIPE_FindByMID(wine_marshal_id
*mid
) {
170 for (i
=0;i
<nrofpipes
;i
++)
171 if ((pipes
[i
].mid
.processid
==mid
->processid
) &&
172 (GetCurrentThreadId()==pipes
[i
].tid
)
174 return pipes
[i
].hPipe
;
175 return INVALID_HANDLE_VALUE
;
179 PIPE_GetFromMID(wine_marshal_id
*mid
) {
181 for (i
=0;i
<nrofpipes
;i
++) {
182 if ((pipes
[i
].mid
.processid
==mid
->processid
) &&
183 (GetCurrentThreadId()==pipes
[i
].tid
)
191 RPC_GetRequest(wine_rpc_request
**req
) {
192 static int reqid
= 0xdeadbeef;
195 for (i
=0;i
<nrofreqs
;i
++) { /* try to reuse */
196 if (reqs
[i
]->state
== REQSTATE_DONE
) {
197 reqs
[i
]->reqh
.reqid
= reqid
++;
198 reqs
[i
]->resph
.reqid
= reqs
[i
]->reqh
.reqid
;
199 reqs
[i
]->hPipe
= INVALID_HANDLE_VALUE
;
201 reqs
[i
]->state
= REQSTATE_START
;
207 reqs
= (wine_rpc_request
**)HeapReAlloc(
211 sizeof(wine_rpc_request
*)*(nrofreqs
+1)
214 reqs
= (wine_rpc_request
**)HeapAlloc(
217 sizeof(wine_rpc_request
*)
220 return E_OUTOFMEMORY
;
221 reqs
[nrofreqs
] = (wine_rpc_request
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(wine_rpc_request
));
222 reqs
[nrofreqs
]->reqh
.reqid
= reqid
++;
223 reqs
[nrofreqs
]->resph
.reqid
= reqs
[nrofreqs
]->reqh
.reqid
;
224 reqs
[nrofreqs
]->hPipe
= INVALID_HANDLE_VALUE
;
225 *req
= reqs
[nrofreqs
];
226 reqs
[nrofreqs
]->state
= REQSTATE_START
;
232 RPC_FreeRequest(wine_rpc_request
*req
) {
233 req
->state
= REQSTATE_DONE
; /* Just reuse slot. */
237 static HRESULT WINAPI
238 PipeBuf_QueryInterface(
239 LPRPCCHANNELBUFFER iface
,REFIID riid
,LPVOID
*ppv
242 if (IsEqualIID(riid
,&IID_IRpcChannelBuffer
) || IsEqualIID(riid
,&IID_IUnknown
)) {
243 *ppv
= (LPVOID
)iface
;
244 IUnknown_AddRef(iface
);
247 return E_NOINTERFACE
;
251 PipeBuf_AddRef(LPRPCCHANNELBUFFER iface
) {
252 ICOM_THIS(PipeBuf
,iface
);
258 PipeBuf_Release(LPRPCCHANNELBUFFER iface
) {
259 ICOM_THIS(PipeBuf
,iface
);
263 ERR("Free all stuff.\n");
264 HeapFree(GetProcessHeap(),0,This
);
268 static HRESULT WINAPI
270 LPRPCCHANNELBUFFER iface
,RPCOLEMESSAGE
* msg
,REFIID riid
272 /*ICOM_THIS(PipeBuf,iface);*/
274 TRACE("(%p,%s), slightly wrong.\n",msg
,debugstr_guid(riid
));
275 /* probably reuses IID in real. */
276 if (msg
->cbBuffer
&& (msg
->Buffer
== NULL
))
277 msg
->Buffer
= HeapAlloc(GetProcessHeap(),0,msg
->cbBuffer
);
282 _invoke_onereq(wine_rpc_request
*req
) {
283 IRpcStubBuffer
*stub
;
288 hres
= MARSHAL_Find_Stub_Buffer(&(req
->reqh
.mid
),&stub
);
290 ERR("Stub not found?\n");
293 msg
.Buffer
= req
->Buffer
;
294 msg
.iMethod
= req
->reqh
.iMethod
;
295 msg
.cbBuffer
= req
->reqh
.cbBuffer
;
296 req
->state
= REQSTATE_INVOKING
;
297 req
->resph
.retval
= IRpcStubBuffer_Invoke(stub
,&msg
,NULL
);
298 req
->Buffer
= msg
.Buffer
;
299 req
->resph
.cbBuffer
= msg
.cbBuffer
;
300 reqtype
= REQTYPE_RESPONSE
;
301 hres
= _xwrite(req
->hPipe
,&reqtype
,sizeof(reqtype
));
302 if (hres
) return hres
;
303 hres
= _xwrite(req
->hPipe
,&(req
->resph
),sizeof(req
->resph
));
304 if (hres
) return hres
;
305 hres
= _xwrite(req
->hPipe
,req
->Buffer
,req
->resph
.cbBuffer
);
306 if (hres
) return hres
;
307 req
->state
= REQSTATE_DONE
;
312 static HRESULT
_read_one(wine_pipe
*xpipe
);
315 RPC_QueueRequestAndWait(wine_rpc_request
*req
) {
317 wine_rpc_request
*xreq
;
320 wine_pipe
*xpipe
= PIPE_GetFromMID(&(req
->reqh
.mid
));
323 FIXME("no pipe found.\n");
326 if (GetCurrentProcessId() == req
->reqh
.mid
.processid
) {
327 ERR("In current process?\n");
330 req
->hPipe
= xpipe
->hPipe
;
331 req
->state
= REQSTATE_REQ_WAITING_FOR_REPLY
;
332 reqtype
= REQTYPE_REQUEST
;
333 hres
= _xwrite(req
->hPipe
,&reqtype
,sizeof(reqtype
));
334 if (hres
) return hres
;
335 hres
= _xwrite(req
->hPipe
,&(req
->reqh
),sizeof(req
->reqh
));
336 if (hres
) return hres
;
337 hres
= _xwrite(req
->hPipe
,req
->Buffer
,req
->reqh
.cbBuffer
);
338 if (hres
) return hres
;
341 /*WaitForSingleObject(hRpcChanged,INFINITE);*/
342 hres
= _read_one(xpipe
);
345 for (i
=0;i
<nrofreqs
;i
++) {
347 if ((xreq
->state
==REQSTATE_REQ_GOT
) && (xreq
->hPipe
==req
->hPipe
)) {
348 _invoke_onereq(xreq
);
351 if (req
->state
== REQSTATE_RESP_GOT
)
357 static HRESULT WINAPI
359 LPRPCCHANNELBUFFER iface
,RPCOLEMESSAGE
* msg
,ULONG
*status
361 ICOM_THIS(PipeBuf
,iface
);
362 wine_rpc_request
*req
;
367 if (This
->mid
.processid
== GetCurrentProcessId()) {
368 ERR("Need to call directly!\n");
372 hres
= RPC_GetRequest(&req
);
373 if (hres
) return hres
;
374 req
->reqh
.iMethod
= msg
->iMethod
;
375 req
->reqh
.cbBuffer
= msg
->cbBuffer
;
376 memcpy(&(req
->reqh
.mid
),&(This
->mid
),sizeof(This
->mid
));
377 req
->Buffer
= msg
->Buffer
;
378 hres
= RPC_QueueRequestAndWait(req
);
380 RPC_FreeRequest(req
);
383 msg
->cbBuffer
= req
->resph
.cbBuffer
;
384 msg
->Buffer
= req
->Buffer
;
385 *status
= req
->resph
.retval
;
386 RPC_FreeRequest(req
);
391 static HRESULT WINAPI
392 PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface
,RPCOLEMESSAGE
* msg
) {
393 FIXME("(%p), stub!\n",msg
);
397 static HRESULT WINAPI
399 LPRPCCHANNELBUFFER iface
,DWORD
* pdwDestContext
,void** ppvDestContext
401 FIXME("(%p,%p), stub!\n",pdwDestContext
,ppvDestContext
);
405 static HRESULT WINAPI
406 PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface
) {
407 FIXME("(), stub!\n");
411 static ICOM_VTABLE(IRpcChannelBuffer
) pipebufvt
= {
412 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
413 PipeBuf_QueryInterface
,
424 PIPE_GetNewPipeBuf(wine_marshal_id
*mid
, IRpcChannelBuffer
**pipebuf
) {
425 wine_marshal_id ourid
;
431 hPipe
= PIPE_FindByMID(mid
);
432 if (hPipe
== INVALID_HANDLE_VALUE
) {
434 sprintf(pipefn
,OLESTUBMGR
"_%08lx",mid
->processid
);
437 GENERIC_READ
|GENERIC_WRITE
,
444 if (hPipe
== INVALID_HANDLE_VALUE
) {
445 FIXME("Could not open named pipe %s, le is %lx\n",pipefn
,GetLastError());
448 hres
= PIPE_RegisterPipe(mid
, hPipe
, FALSE
);
449 if (hres
) return hres
;
450 memset(&ourid
,0,sizeof(ourid
));
451 ourid
.processid
= GetCurrentProcessId();
452 if (!WriteFile(hPipe
,&ourid
,sizeof(ourid
),&res
,NULL
)||(res
!=sizeof(ourid
))) {
453 ERR("Failed writing startup mid!\n");
457 pbuf
= (PipeBuf
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(PipeBuf
));
458 pbuf
->lpVtbl
= &pipebufvt
;
460 memcpy(&(pbuf
->mid
),mid
,sizeof(*mid
));
461 *pipebuf
= (IRpcChannelBuffer
*)pbuf
;
466 create_server(REFCLSID rclsid
) {
469 HRESULT hres
= E_UNEXPECTED
;
471 WCHAR dllName
[MAX_PATH
+1];
472 DWORD dllNameLen
= sizeof(dllName
);
474 PROCESS_INFORMATION pinfo
;
476 WINE_StringFromCLSID((LPCLSID
)rclsid
,xclsid
);
478 sprintf(buf
,"CLSID\\%s\\LocalServer32",xclsid
);
479 hres
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, buf
, 0, KEY_READ
, &key
);
481 if (hres
!= ERROR_SUCCESS
)
482 return REGDB_E_CLASSNOTREG
;
484 memset(dllName
,0,sizeof(dllName
));
485 hres
= RegQueryValueExW(key
,NULL
,NULL
,NULL
,(LPBYTE
)dllName
,&dllNameLen
);
487 return REGDB_E_CLASSNOTREG
; /* FIXME: check retval */
489 memset(&sinfo
,0,sizeof(sinfo
));
490 sinfo
.cb
= sizeof(sinfo
);
491 if (!CreateProcessW(NULL
,dllName
,NULL
,NULL
,FALSE
,0,NULL
,NULL
,&sinfo
,&pinfo
))
495 /* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */
496 HRESULT
create_marshalled_proxy(REFCLSID rclsid
, REFIID iid
, LPVOID
*ppv
) {
501 char marshalbuffer
[200];
503 LARGE_INTEGER seekto
;
504 ULARGE_INTEGER newpos
;
506 #define MAXTRIES 10000
508 strcpy(pipefn
,PIPEPREF
);
509 WINE_StringFromCLSID(rclsid
,pipefn
+strlen(PIPEPREF
));
511 while (tries
++<MAXTRIES
) {
514 GENERIC_READ
|GENERIC_WRITE
,
521 if (hPipe
== INVALID_HANDLE_VALUE
) {
523 if ((hres
= create_server(rclsid
)))
527 WARN("Could not open named pipe to broker %s, le is %lx\n",pipefn
,GetLastError());
533 if (!ReadFile(hPipe
,marshalbuffer
,sizeof(marshalbuffer
),&bufferlen
,NULL
)) {
534 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid
));
542 return E_NOINTERFACE
;
543 hres
= CreateStreamOnHGlobal(0,TRUE
,&pStm
);
544 if (hres
) return hres
;
545 hres
= IStream_Write(pStm
,marshalbuffer
,bufferlen
,&res
);
547 seekto
.s
.LowPart
= 0;seekto
.s
.HighPart
= 0;
548 hres
= IStream_Seek(pStm
,seekto
,SEEK_SET
,&newpos
);
549 hres
= CoUnmarshalInterface(pStm
,&IID_IClassFactory
,ppv
);
551 IStream_Release(pStm
);
557 PIPE_StartRequestThread(HANDLE xhPipe
) {
558 wine_marshal_id remoteid
;
561 hres
= _xread(xhPipe
,&remoteid
,sizeof(remoteid
));
563 ERR("Failed to read remote mid!\n");
566 PIPE_RegisterPipe(&remoteid
,xhPipe
, TRUE
);
570 _read_one(wine_pipe
*xpipe
) {
573 HANDLE xhPipe
= xpipe
->hPipe
;
575 /*FIXME("%lx %d reading reqtype\n",GetCurrentProcessId(),xhPipe);*/
576 hres
= _xread(xhPipe
,&reqtype
,sizeof(reqtype
));
578 EnterCriticalSection(&(xpipe
->crit
));
579 /*FIXME("%lx got reqtype %ld\n",GetCurrentProcessId(),reqtype);*/
581 if (reqtype
== REQTYPE_REQUEST
) {
582 wine_rpc_request
*xreq
;
583 RPC_GetRequest(&xreq
);
584 xreq
->hPipe
= xhPipe
;
585 hres
= _xread(xhPipe
,&(xreq
->reqh
),sizeof(xreq
->reqh
));
587 xreq
->resph
.reqid
= xreq
->reqh
.reqid
;
588 xreq
->Buffer
= HeapAlloc(GetProcessHeap(),0, xreq
->reqh
.cbBuffer
);
589 hres
= _xread(xhPipe
,xreq
->Buffer
,xreq
->reqh
.cbBuffer
);
591 xreq
->state
= REQSTATE_REQ_GOT
;
594 if (reqtype
== REQTYPE_RESPONSE
) {
595 wine_rpc_response_header resph
;
598 hres
= _xread(xhPipe
,&resph
,sizeof(resph
));
600 for (i
=nrofreqs
;i
--;) {
601 wine_rpc_request
*xreq
= reqs
[i
];
602 if (xreq
->state
!= REQSTATE_REQ_WAITING_FOR_REPLY
)
604 if (xreq
->reqh
.reqid
== resph
.reqid
) {
605 memcpy(&(xreq
->resph
),&resph
,sizeof(resph
));
606 xreq
->Buffer
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,xreq
->Buffer
,xreq
->resph
.cbBuffer
);
607 hres
= _xread(xhPipe
,xreq
->Buffer
,xreq
->resph
.cbBuffer
);
609 xreq
->state
= REQSTATE_RESP_GOT
;
610 /*PulseEvent(hRpcChanged);*/
614 ERR("Did not find request for id %lx\n",resph
.reqid
);
618 ERR("Unknown reqtype %ld\n",reqtype
);
621 LeaveCriticalSection(&(xpipe
->crit
));
626 _StubReaderThread(LPVOID param
) {
627 wine_pipe
*xpipe
= (wine_pipe
*)param
;
628 HANDLE xhPipe
= xpipe
->hPipe
;
631 TRACE("STUB reader thread %lx\n",GetCurrentProcessId());
634 hres
= _read_one(xpipe
);
637 for (i
=nrofreqs
;i
--;) {
638 wine_rpc_request
*xreq
= reqs
[i
];
639 if ((xreq
->state
== REQSTATE_REQ_GOT
) && (xreq
->hPipe
== xhPipe
)) {
640 _invoke_onereq(xreq
);
644 FIXME("Failed with hres %lx\n",hres
);
650 _StubMgrThread(LPVOID param
) {
654 sprintf(pipefn
,OLESTUBMGR
"_%08lx",GetCurrentProcessId());
655 TRACE("Stub Manager Thread starting on (%s)\n",pipefn
);
657 listenPipe
= CreateNamedPipeA(
660 PIPE_TYPE_BYTE
|PIPE_WAIT
,
661 PIPE_UNLIMITED_INSTANCES
,
664 NMPWAIT_USE_DEFAULT_WAIT
,
667 if (listenPipe
== INVALID_HANDLE_VALUE
) {
668 FIXME("pipe creation failed for %s, le is %lx\n",pipefn
,GetLastError());
669 return 1; /* permanent failure, so quit stubmgr thread */
673 if (!ConnectNamedPipe(listenPipe
,NULL
)) {
674 ERR("Failure during ConnectNamedPipe %lx!\n",GetLastError());
675 CloseHandle(listenPipe
);
678 PIPE_StartRequestThread(listenPipe
);
679 listenPipe
= CreateNamedPipeA(
682 PIPE_TYPE_BYTE
|PIPE_WAIT
,
683 PIPE_UNLIMITED_INSTANCES
,
686 NMPWAIT_USE_DEFAULT_WAIT
,
689 if (listenPipe
== INVALID_HANDLE_VALUE
) {
690 FIXME("pipe creation failed for %s, le is %lx\n",pipefn
,GetLastError());
691 return 1; /* permanent failure, so quit stubmgr thread */
699 static BOOL stubMgrRunning
= FALSE
;
702 if (!stubMgrRunning
) {
703 stubMgrRunning
= TRUE
;
704 CreateThread(NULL
,0,_StubMgrThread
,NULL
,0,&tid
);
705 Sleep(2000); /* actually we just try opening the pipe until it succeeds */