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
) {
186 for (i
=0;i
<nrofpipes
;i
++)
187 if (pipes
[i
].mid
.oxid
==mid
->oxid
)
189 if (nrofpipes
+ 1 >= MAX_WINE_PIPES
)
191 FIXME("Out of pipes, please increase MAX_WINE_PIPES\n");
192 return E_OUTOFMEMORY
;
194 sprintf(pipefn
,OLESTUBMGR
"_%08lx%08lx",(DWORD
)(mid
->oxid
>> 32),(DWORD
)mid
->oxid
);
195 memcpy(&(pipes
[nrofpipes
].mid
),mid
,sizeof(*mid
));
196 pipes
[nrofpipes
].hPipe
= hPipe
;
197 pipes
[nrofpipes
].apt
= COM_CurrentApt();
198 assert( pipes
[nrofpipes
].apt
);
199 InitializeCriticalSection(&(pipes
[nrofpipes
].crit
));
202 pipes
[nrofpipes
-1].hThread
= CreateThread(NULL
,0,stub_dispatch_thread
,(LPVOID
)(pipes
+(nrofpipes
-1)),0,&(pipes
[nrofpipes
-1].tid
));
204 pipes
[nrofpipes
-1].tid
= GetCurrentThreadId();
210 PIPE_FindByMID(wine_marshal_id
*mid
) {
212 for (i
=0;i
<nrofpipes
;i
++)
213 if ((pipes
[i
].mid
.oxid
==mid
->oxid
) &&
214 (GetCurrentThreadId()==pipes
[i
].tid
)
216 return pipes
[i
].hPipe
;
217 return INVALID_HANDLE_VALUE
;
221 PIPE_GetFromMID(wine_marshal_id
*mid
) {
223 for (i
=0;i
<nrofpipes
;i
++) {
224 if ((pipes
[i
].mid
.oxid
==mid
->oxid
) &&
225 (GetCurrentThreadId()==pipes
[i
].tid
)
233 RPC_GetRequest(wine_rpc_request
**req
) {
234 static int reqid
= 0xdeadbeef;
237 for (i
=0;i
<nrofreqs
;i
++) { /* try to reuse */
238 if (reqs
[i
]->state
== REQSTATE_DONE
) {
239 reqs
[i
]->reqh
.reqid
= reqid
++;
240 reqs
[i
]->resph
.reqid
= reqs
[i
]->reqh
.reqid
;
241 reqs
[i
]->hPipe
= INVALID_HANDLE_VALUE
;
243 reqs
[i
]->state
= REQSTATE_START
;
249 reqs
= (wine_rpc_request
**)HeapReAlloc(
253 sizeof(wine_rpc_request
*)*(nrofreqs
+1)
256 reqs
= (wine_rpc_request
**)HeapAlloc(
259 sizeof(wine_rpc_request
*)
262 return E_OUTOFMEMORY
;
263 reqs
[nrofreqs
] = (wine_rpc_request
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(wine_rpc_request
));
264 reqs
[nrofreqs
]->reqh
.reqid
= reqid
++;
265 reqs
[nrofreqs
]->resph
.reqid
= reqs
[nrofreqs
]->reqh
.reqid
;
266 reqs
[nrofreqs
]->hPipe
= INVALID_HANDLE_VALUE
;
267 *req
= reqs
[nrofreqs
];
268 reqs
[nrofreqs
]->state
= REQSTATE_START
;
274 RPC_FreeRequest(wine_rpc_request
*req
) {
275 req
->state
= REQSTATE_DONE
; /* Just reuse slot. */
279 static HRESULT WINAPI
280 PipeBuf_QueryInterface(
281 LPRPCCHANNELBUFFER iface
,REFIID riid
,LPVOID
*ppv
284 if (IsEqualIID(riid
,&IID_IRpcChannelBuffer
) || IsEqualIID(riid
,&IID_IUnknown
)) {
285 *ppv
= (LPVOID
)iface
;
286 IUnknown_AddRef(iface
);
289 return E_NOINTERFACE
;
293 PipeBuf_AddRef(LPRPCCHANNELBUFFER iface
) {
294 PipeBuf
*This
= (PipeBuf
*)iface
;
295 return InterlockedIncrement(&This
->ref
);
299 PipeBuf_Release(LPRPCCHANNELBUFFER iface
) {
300 PipeBuf
*This
= (PipeBuf
*)iface
;
302 wine_rpc_disconnect_header header
;
304 DWORD reqtype
= REQTYPE_DISCONNECT
;
307 ref
= InterlockedDecrement(&This
->ref
);
311 memcpy(&header
.mid
, &This
->mid
, sizeof(wine_marshal_id
));
313 pipe
= PIPE_FindByMID(&This
->mid
);
315 write_pipe(pipe
, &reqtype
, sizeof(reqtype
));
316 write_pipe(pipe
, &header
, sizeof(wine_rpc_disconnect_header
));
318 TRACE("written disconnect packet\n");
320 /* prevent a disconnect race with the other side: this isn't
321 * necessary for real dcom but the test suite needs it */
323 read_pipe(pipe
, &magic
, sizeof(magic
));
324 if (magic
!= 0xcafebabe) ERR("bad disconnection magic: expecting 0xcafebabe but got 0x%lx", magic
);
326 HeapFree(GetProcessHeap(),0,This
);
330 static HRESULT WINAPI
332 LPRPCCHANNELBUFFER iface
,RPCOLEMESSAGE
* msg
,REFIID riid
334 /*PipeBuf *This = (PipeBuf *)iface;*/
336 TRACE("(%p,%s)\n",msg
,debugstr_guid(riid
));
337 /* probably reuses IID in real. */
338 if (msg
->cbBuffer
&& (msg
->Buffer
== NULL
))
339 msg
->Buffer
= HeapAlloc(GetProcessHeap(),0,msg
->cbBuffer
);
344 COM_InvokeAndRpcSend(wine_rpc_request
*req
) {
345 IRpcStubBuffer
*stub
;
350 if (!(stub
= mid_to_stubbuffer(&(req
->reqh
.mid
))))
352 ERR("Stub not found?\n");
356 IUnknown_AddRef(stub
);
357 msg
.Buffer
= req
->Buffer
;
358 msg
.iMethod
= req
->reqh
.iMethod
;
359 msg
.cbBuffer
= req
->reqh
.cbBuffer
;
360 msg
.dataRepresentation
= NDR_LOCAL_DATA_REPRESENTATION
;
361 req
->state
= REQSTATE_INVOKING
;
362 req
->resph
.retval
= IRpcStubBuffer_Invoke(stub
,&msg
,NULL
);
363 IUnknown_Release(stub
);
364 req
->Buffer
= msg
.Buffer
;
365 req
->resph
.cbBuffer
= msg
.cbBuffer
;
366 reqtype
= REQTYPE_RESPONSE
;
367 hres
= write_pipe(req
->hPipe
,&reqtype
,sizeof(reqtype
));
368 if (hres
) return hres
;
369 hres
= write_pipe(req
->hPipe
,&(req
->resph
),sizeof(req
->resph
));
370 if (hres
) return hres
;
371 hres
= write_pipe(req
->hPipe
,req
->Buffer
,req
->resph
.cbBuffer
);
372 if (hres
) return hres
;
373 req
->state
= REQSTATE_DONE
;
378 static HRESULT
COM_RpcReceive(wine_pipe
*xpipe
);
381 RPC_QueueRequestAndWait(wine_rpc_request
*req
) {
383 wine_rpc_request
*xreq
;
386 wine_pipe
*xpipe
= PIPE_GetFromMID(&(req
->reqh
.mid
));
389 FIXME("no pipe found.\n");
392 req
->hPipe
= xpipe
->hPipe
;
393 req
->state
= REQSTATE_REQ_WAITING_FOR_REPLY
;
394 reqtype
= REQTYPE_REQUEST
;
395 hres
= write_pipe(req
->hPipe
,&reqtype
,sizeof(reqtype
));
396 if (hres
) return hres
;
397 hres
= write_pipe(req
->hPipe
,&(req
->reqh
),sizeof(req
->reqh
));
398 if (hres
) return hres
;
399 hres
= write_pipe(req
->hPipe
,req
->Buffer
,req
->reqh
.cbBuffer
);
400 if (hres
) return hres
;
402 /* This loop is about allowing re-entrancy. While waiting for the
403 * response to one RPC we may receive a request starting another. */
405 hres
= COM_RpcReceive(xpipe
);
408 for (i
=0;i
<nrofreqs
;i
++) {
410 if ((xreq
->state
==REQSTATE_REQ_GOT
) && (xreq
->hPipe
==req
->hPipe
)) {
411 hres
= COM_InvokeAndRpcSend(xreq
);
415 if (req
->state
== REQSTATE_RESP_GOT
)
419 WARN("-- 0x%08lx\n", hres
);
423 static HRESULT WINAPI
425 LPRPCCHANNELBUFFER iface
,RPCOLEMESSAGE
* msg
,ULONG
*status
427 PipeBuf
*This
= (PipeBuf
*)iface
;
428 wine_rpc_request
*req
;
433 if (This
->mid
.oxid
== COM_CurrentApt()->oxid
) {
434 ERR("Need to call directly!\n");
438 hres
= RPC_GetRequest(&req
);
439 if (hres
) return hres
;
440 req
->reqh
.iMethod
= msg
->iMethod
;
441 req
->reqh
.cbBuffer
= msg
->cbBuffer
;
442 memcpy(&(req
->reqh
.mid
),&(This
->mid
),sizeof(This
->mid
));
443 req
->Buffer
= msg
->Buffer
;
444 hres
= RPC_QueueRequestAndWait(req
);
446 RPC_FreeRequest(req
);
449 msg
->cbBuffer
= req
->resph
.cbBuffer
;
450 msg
->Buffer
= req
->Buffer
;
451 *status
= req
->resph
.retval
;
452 RPC_FreeRequest(req
);
457 static HRESULT WINAPI
458 PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface
,RPCOLEMESSAGE
* msg
) {
459 FIXME("(%p), stub!\n",msg
);
463 static HRESULT WINAPI
465 LPRPCCHANNELBUFFER iface
,DWORD
* pdwDestContext
,void** ppvDestContext
467 FIXME("(%p,%p), stub!\n",pdwDestContext
,ppvDestContext
);
471 static HRESULT WINAPI
472 PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface
) {
473 FIXME("(), stub!\n");
477 static IRpcChannelBufferVtbl pipebufvt
= {
478 PipeBuf_QueryInterface
,
489 PIPE_GetNewPipeBuf(wine_marshal_id
*mid
, IRpcChannelBuffer
**pipebuf
) {
490 wine_marshal_id ourid
;
496 hPipe
= PIPE_FindByMID(mid
);
497 if (hPipe
== INVALID_HANDLE_VALUE
) {
499 sprintf(pipefn
,OLESTUBMGR
"_%08lx%08lx",(DWORD
)(mid
->oxid
>> 32),(DWORD
)mid
->oxid
);
502 GENERIC_READ
|GENERIC_WRITE
,
509 if (hPipe
== INVALID_HANDLE_VALUE
) {
510 FIXME("Could not open named pipe %s, le is %lx\n",pipefn
,GetLastError());
513 hres
= PIPE_RegisterPipe(mid
, hPipe
, FALSE
);
514 if (hres
) return hres
;
515 memset(&ourid
,0,sizeof(ourid
));
516 ourid
.oxid
= COM_CurrentApt()->oxid
;
517 if (!WriteFile(hPipe
,&ourid
,sizeof(ourid
),&res
,NULL
)||(res
!=sizeof(ourid
))) {
518 ERR("Failed writing startup mid!\n");
522 pbuf
= (PipeBuf
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(PipeBuf
));
523 pbuf
->lpVtbl
= &pipebufvt
;
525 memcpy(&(pbuf
->mid
),mid
,sizeof(*mid
));
526 *pipebuf
= (IRpcChannelBuffer
*)pbuf
;
531 create_server(REFCLSID rclsid
) {
532 static const WCHAR embedding
[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
535 HRESULT hres
= E_UNEXPECTED
;
537 WCHAR exe
[MAX_PATH
+1];
538 DWORD exelen
= sizeof(exe
);
539 WCHAR command
[MAX_PATH
+sizeof(embedding
)/sizeof(WCHAR
)];
541 PROCESS_INFORMATION pinfo
;
543 WINE_StringFromCLSID((LPCLSID
)rclsid
,xclsid
);
545 sprintf(buf
,"CLSID\\%s\\LocalServer32",xclsid
);
546 hres
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, buf
, 0, KEY_READ
, &key
);
548 if (hres
!= ERROR_SUCCESS
) {
549 WARN("CLSID %s not registered as LocalServer32\n", xclsid
);
550 return REGDB_E_READREGDB
; /* Probably */
553 memset(exe
,0,sizeof(exe
));
554 hres
= RegQueryValueExW(key
, NULL
, NULL
, NULL
, (LPBYTE
)exe
, &exelen
);
557 WARN("No default value for LocalServer32 key\n");
558 return REGDB_E_CLASSNOTREG
; /* FIXME: check retval */
561 memset(&sinfo
,0,sizeof(sinfo
));
562 sinfo
.cb
= sizeof(sinfo
);
564 /* EXE servers are started with the -Embedding switch. MSDN also claims /Embedding is used,
565 9x does -Embedding, perhaps an 9x/NT difference? */
567 strcpyW(command
, exe
);
568 strcatW(command
, embedding
);
570 TRACE("activating local server '%s' for %s\n", debugstr_w(command
), xclsid
);
572 if (!CreateProcessW(exe
, command
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &sinfo
, &pinfo
)) {
573 WARN("failed to run local server %s\n", debugstr_w(exe
));
581 * start_local_service() - start a service given its name and parameters
584 start_local_service(LPCWSTR name
, DWORD num
, LPWSTR
*params
)
586 SC_HANDLE handle
, hsvc
;
587 DWORD r
= ERROR_FUNCTION_FAILED
;
589 TRACE("Starting service %s %ld params\n", debugstr_w(name
), num
);
591 handle
= OpenSCManagerW(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
594 hsvc
= OpenServiceW(handle
, name
, SC_MANAGER_ALL_ACCESS
);
597 if(StartServiceW(hsvc
, num
, (LPCWSTR
*)params
))
601 if (r
==ERROR_SERVICE_ALREADY_RUNNING
)
603 CloseServiceHandle(hsvc
);
605 CloseServiceHandle(handle
);
607 TRACE("StartService returned error %ld (%s)\n", r
, r
?"ok":"failed");
613 * create_local_service() - start a COM server in a service
615 * To start a Local Service, we read the AppID value under
616 * the class's CLSID key, then open the HKCR\\AppId key specified
617 * there and check for a LocalService value.
619 * Note: Local Services are not supported under Windows 9x
622 create_local_service(REFCLSID rclsid
)
624 HRESULT hres
= REGDB_E_READREGDB
;
625 WCHAR buf
[40], keyname
[50];
626 static const WCHAR szClsId
[] = { 'C','L','S','I','D','\\',0 };
627 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
628 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
629 static const WCHAR szLocalService
[] = {
630 'L','o','c','a','l','S','e','r','v','i','c','e',0 };
631 static const WCHAR szServiceParams
[] = {
632 'S','e','r','v','i','c','e','P','a','r','a','m','s',0};
637 TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid
));
639 /* read the AppID value under the class's key */
640 strcpyW(keyname
,szClsId
);
641 StringFromGUID2(rclsid
,&keyname
[6],39);
642 r
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &hkey
);
643 if (r
!=ERROR_SUCCESS
)
646 r
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &sz
);
648 if (r
!=ERROR_SUCCESS
|| type
!=REG_SZ
)
651 /* read the LocalService and ServiceParameters values from the AppID key */
652 strcpyW(keyname
, szAppIdKey
);
653 strcatW(keyname
, buf
);
654 r
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &hkey
);
655 if (r
!=ERROR_SUCCESS
)
658 r
= RegQueryValueExW(hkey
, szLocalService
, NULL
, &type
, (LPBYTE
)buf
, &sz
);
659 if (r
==ERROR_SUCCESS
&& type
==REG_SZ
)
662 LPWSTR args
[1] = { NULL
};
665 * FIXME: I'm not really sure how to deal with the service parameters.
666 * I suspect that the string returned from RegQueryValueExW
667 * should be split into a number of arguments by spaces.
668 * It would make more sense if ServiceParams contained a
669 * REG_MULTI_SZ here, but it's a REG_SZ for the services
670 * that I'm interested in for the moment.
672 r
= RegQueryValueExW(hkey
, szServiceParams
, NULL
, &type
, NULL
, &sz
);
673 if (r
== ERROR_SUCCESS
&& type
== REG_SZ
&& sz
)
675 args
[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sz
);
677 RegQueryValueExW(hkey
, szServiceParams
, NULL
, &type
, (LPBYTE
)args
[0], &sz
);
679 r
= start_local_service(buf
, num_args
, args
);
680 if (r
==ERROR_SUCCESS
)
682 HeapFree(GetProcessHeap(),0,args
[0]);
689 /* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */
690 HRESULT
create_marshalled_proxy(REFCLSID rclsid
, REFIID iid
, LPVOID
*ppv
) {
695 char marshalbuffer
[200];
697 LARGE_INTEGER seekto
;
698 ULARGE_INTEGER newpos
;
700 #define MAXTRIES 10000
702 TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
704 strcpy(pipefn
,PIPEPREF
);
705 WINE_StringFromCLSID(rclsid
,pipefn
+strlen(PIPEPREF
));
707 while (tries
++<MAXTRIES
) {
708 TRACE("waiting for %s\n", pipefn
);
710 WaitNamedPipeA( pipefn
, NMPWAIT_WAIT_FOREVER
);
713 GENERIC_READ
|GENERIC_WRITE
,
720 if (hPipe
== INVALID_HANDLE_VALUE
) {
722 if ( (hres
= create_server(rclsid
)) &&
723 (hres
= create_local_service(rclsid
)) )
727 WARN("Could not open named pipe to broker %s, le is %lx\n",pipefn
,GetLastError());
733 if (!ReadFile(hPipe
,marshalbuffer
,sizeof(marshalbuffer
),&bufferlen
,NULL
)) {
734 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid
));
738 TRACE("read marshal id from pipe\n");
743 return E_NOINTERFACE
;
744 hres
= CreateStreamOnHGlobal(0,TRUE
,&pStm
);
745 if (hres
) return hres
;
746 hres
= IStream_Write(pStm
,marshalbuffer
,bufferlen
,&res
);
748 seekto
.u
.LowPart
= 0;seekto
.u
.HighPart
= 0;
749 hres
= IStream_Seek(pStm
,seekto
,SEEK_SET
,&newpos
);
750 TRACE("unmarshalling classfactory\n");
751 hres
= CoUnmarshalInterface(pStm
,&IID_IClassFactory
,ppv
);
753 IStream_Release(pStm
);
759 PIPE_StartRequestThread(HANDLE xhPipe
) {
760 wine_marshal_id remoteid
;
763 hres
= read_pipe(xhPipe
,&remoteid
,sizeof(remoteid
));
765 ERR("Failed to read remote mid!\n");
768 PIPE_RegisterPipe(&remoteid
,xhPipe
, TRUE
);
772 COM_RpcReceive(wine_pipe
*xpipe
) {
775 HANDLE xhPipe
= xpipe
->hPipe
;
777 /*FIXME("%lx %d reading reqtype\n",GetCurrentProcessId(),xhPipe);*/
778 hres
= read_pipe(xhPipe
,&reqtype
,sizeof(reqtype
));
780 EnterCriticalSection(&(xpipe
->crit
));
781 /*FIXME("%lx got reqtype %ld\n",GetCurrentProcessId(),reqtype);*/
783 if (reqtype
== REQTYPE_DISCONNECT
) { /* only received by servers */
784 wine_rpc_disconnect_header header
;
785 struct stub_manager
*stubmgr
;
786 DWORD magic
= 0xcafebabe;
788 hres
= read_pipe(xhPipe
, &header
, sizeof(header
));
790 ERR("could not read disconnect header\n");
794 TRACE("read disconnect header\n");
796 if (!(stubmgr
= get_stub_manager(header
.mid
.oxid
, header
.mid
.oid
)))
798 ERR("could not locate stub to disconnect, mid.oid=%s\n", wine_dbgstr_longlong(header
.mid
.oid
));
802 stub_manager_ext_release(stubmgr
, 1);
804 stub_manager_int_release(stubmgr
);
806 write_pipe(xhPipe
, &magic
, sizeof(magic
));
809 } else if (reqtype
== REQTYPE_REQUEST
) {
810 wine_rpc_request
*xreq
;
811 RPC_GetRequest(&xreq
);
812 xreq
->hPipe
= xhPipe
;
813 hres
= read_pipe(xhPipe
,&(xreq
->reqh
),sizeof(xreq
->reqh
));
815 xreq
->resph
.reqid
= xreq
->reqh
.reqid
;
816 xreq
->Buffer
= HeapAlloc(GetProcessHeap(),0, xreq
->reqh
.cbBuffer
);
817 hres
= read_pipe(xhPipe
,xreq
->Buffer
,xreq
->reqh
.cbBuffer
);
819 xreq
->state
= REQSTATE_REQ_GOT
;
821 } else if (reqtype
== REQTYPE_RESPONSE
) {
822 wine_rpc_response_header resph
;
825 hres
= read_pipe(xhPipe
,&resph
,sizeof(resph
));
827 for (i
=nrofreqs
;i
--;) {
828 wine_rpc_request
*xreq
= reqs
[i
];
829 if (xreq
->state
!= REQSTATE_REQ_WAITING_FOR_REPLY
)
831 if (xreq
->reqh
.reqid
== resph
.reqid
) {
832 memcpy(&(xreq
->resph
),&resph
,sizeof(resph
));
835 xreq
->Buffer
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,xreq
->Buffer
,xreq
->resph
.cbBuffer
);
837 xreq
->Buffer
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,xreq
->resph
.cbBuffer
);
839 hres
= read_pipe(xhPipe
,xreq
->Buffer
,xreq
->resph
.cbBuffer
);
841 xreq
->state
= REQSTATE_RESP_GOT
;
842 /*PulseEvent(hRpcChanged);*/
846 ERR("Did not find request for id %lx\n",resph
.reqid
);
850 ERR("Unknown reqtype %ld\n",reqtype
);
853 LeaveCriticalSection(&(xpipe
->crit
));
857 /* This thread listens on the given pipe for requests to a particular stub manager */
858 static DWORD WINAPI
stub_dispatch_thread(LPVOID param
)
860 wine_pipe
*xpipe
= (wine_pipe
*)param
;
861 HANDLE xhPipe
= xpipe
->hPipe
;
864 TRACE("starting for apartment OXID %08lx%08lx\n", (DWORD
)(xpipe
->mid
.oxid
>> 32), (DWORD
)(xpipe
->mid
.oxid
));
866 /* join marshalling apartment. fixme: this stuff is all very wrong, threading needs to work like native */
867 COM_CurrentInfo()->apt
= xpipe
->apt
;
872 hres
= COM_RpcReceive(xpipe
);
875 for (i
=nrofreqs
;i
--;) {
876 wine_rpc_request
*xreq
= reqs
[i
];
877 if ((xreq
->state
== REQSTATE_REQ_GOT
) && (xreq
->hPipe
== xhPipe
)) {
878 hres
= COM_InvokeAndRpcSend(xreq
);
884 /* fixme: this thread never quits naturally */
885 WARN("exiting with hres %lx\n",hres
);
890 struct apartment_listener_params
896 /* This thread listens on a named pipe for each apartment that exports
897 * objects. It deals with incoming connection requests. Each time a
898 * client connects a separate thread is spawned for that particular
901 * This architecture is different in native DCOM.
903 static DWORD WINAPI
apartment_listener_thread(LPVOID p
)
907 struct apartment_listener_params
* params
= (struct apartment_listener_params
*)p
;
908 APARTMENT
*apt
= params
->apt
;
909 HANDLE event
= params
->event
;
911 HeapFree(GetProcessHeap(), 0, params
);
913 /* we must join the marshalling threads apartment. we already have a ref here */
914 COM_CurrentInfo()->apt
= apt
;
916 sprintf(pipefn
,OLESTUBMGR
"_%08lx%08lx", (DWORD
)(apt
->oxid
>> 32), (DWORD
)(apt
->oxid
));
917 TRACE("Apartment listener thread starting on (%s)\n",pipefn
);
920 listenPipe
= CreateNamedPipeA(
923 PIPE_TYPE_BYTE
|PIPE_WAIT
,
924 PIPE_UNLIMITED_INSTANCES
,
927 NMPWAIT_USE_DEFAULT_WAIT
,
931 /* tell function that started this thread that we have attempted to created the
938 if (listenPipe
== INVALID_HANDLE_VALUE
) {
939 FIXME("pipe creation failed for %s, error %ld\n",pipefn
,GetLastError());
940 return 1; /* permanent failure, so quit stubmgr thread */
943 /* an already connected pipe is not an error */
944 if (!ConnectNamedPipe(listenPipe
,NULL
) &&
945 (GetLastError() != ERROR_PIPE_CONNECTED
)) {
946 ERR("Failure during ConnectNamedPipe %ld!\n",GetLastError());
947 CloseHandle(listenPipe
);
951 PIPE_StartRequestThread(listenPipe
);
956 void start_apartment_listener_thread()
958 APARTMENT
*apt
= COM_CurrentApt();
962 TRACE("apt->listenertid=%ld\n", apt
->listenertid
);
964 /* apt->listenertid is a hack which needs to die at some point, as
965 * it leaks information into the apartment structure. in fact,
966 * this thread isn't quite correct anyway as native RPC doesn't
967 * use a thread per apartment at all, instead the dispatch thread
968 * either enters the apartment to perform the RPC (for MTAs, RTAs)
969 * or does a context switch into it for STAs.
972 if (!apt
->listenertid
)
975 HANDLE event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
976 struct apartment_listener_params
* params
= HeapAlloc(GetProcessHeap(), 0, sizeof(*params
));
979 params
->event
= event
;
980 thread
= CreateThread(NULL
, 0, apartment_listener_thread
, params
, 0, &apt
->listenertid
);
982 /* wait for pipe to be created before returning, otherwise we
983 * might try to use it and fail */
984 WaitForSingleObject(event
, INFINITE
);
989 struct local_server_params
995 static DWORD WINAPI
local_server_thread(LPVOID param
)
997 struct local_server_params
* lsp
= (struct local_server_params
*)param
;
1001 IStream
*pStm
= lsp
->stream
;
1003 unsigned char *buffer
;
1005 LARGE_INTEGER seekto
;
1006 ULARGE_INTEGER newpos
;
1009 TRACE("Starting threader for %s.\n",debugstr_guid(&lsp
->clsid
));
1011 strcpy(pipefn
,PIPEPREF
);
1012 WINE_StringFromCLSID(&lsp
->clsid
,pipefn
+strlen(PIPEPREF
));
1014 HeapFree(GetProcessHeap(), 0, lsp
);
1016 hPipe
= CreateNamedPipeA( pipefn
, PIPE_ACCESS_DUPLEX
,
1017 PIPE_TYPE_BYTE
|PIPE_WAIT
, PIPE_UNLIMITED_INSTANCES
,
1018 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT
, NULL
);
1019 if (hPipe
== INVALID_HANDLE_VALUE
) {
1020 FIXME("pipe creation failed for %s, le is %ld\n",pipefn
,GetLastError());
1024 if (!ConnectNamedPipe(hPipe
,NULL
)) {
1025 ERR("Failure during ConnectNamedPipe %ld, ABORT!\n",GetLastError());
1029 TRACE("marshalling IClassFactory to client\n");
1031 hres
= IStream_Stat(pStm
,&ststg
,0);
1032 if (hres
) return hres
;
1034 buflen
= ststg
.cbSize
.u
.LowPart
;
1035 buffer
= HeapAlloc(GetProcessHeap(),0,buflen
);
1036 seekto
.u
.LowPart
= 0;
1037 seekto
.u
.HighPart
= 0;
1038 hres
= IStream_Seek(pStm
,seekto
,SEEK_SET
,&newpos
);
1040 FIXME("IStream_Seek failed, %lx\n",hres
);
1044 hres
= IStream_Read(pStm
,buffer
,buflen
,&res
);
1046 FIXME("Stream Read failed, %lx\n",hres
);
1050 IStream_Release(pStm
);
1052 WriteFile(hPipe
,buffer
,buflen
,&res
,NULL
);
1053 FlushFileBuffers(hPipe
);
1054 DisconnectNamedPipe(hPipe
);
1056 TRACE("done marshalling IClassFactory\n");
1062 void RPC_StartLocalServer(REFCLSID clsid
, IStream
*stream
)
1066 struct local_server_params
*lsp
= HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp
));
1068 lsp
->clsid
= *clsid
;
1069 lsp
->stream
= stream
;
1071 thread
= CreateThread(NULL
, 0, local_server_thread
, lsp
, 0, &tid
);
1072 CloseHandle(thread
);
1073 /* FIXME: failure handling */