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
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
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
66 struct response_header
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
86 HANDLE hPipe
; /* temp copy of handle */
87 struct request_header reqh
;
88 struct response_header resph
;
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.
101 wine_marshal_id mid
; /* target mid */
102 DWORD tid
; /* thread which owns this pipe */
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
;
124 static HRESULT WINAPI
125 read_pipe(HANDLE hf
, LPVOID ptr
, DWORD size
) {
127 if (!ReadFile(hf
,ptr
,size
,&res
,NULL
)) {
128 FIXME("Failed to read from %p, le is %ld\n",hf
,GetLastError());
132 FIXME("Read only %ld of %ld bytes from %p.\n",res
,size
,hf
);
138 static HRESULT WINAPI
139 write_pipe(HANDLE hf
, LPVOID ptr
, DWORD size
) {
141 if (!WriteFile(hf
,ptr
,size
,&res
,NULL
)) {
142 FIXME("Failed to write to %p, le is %ld\n",hf
,GetLastError());
146 FIXME("Wrote only %ld of %ld bytes to %p.\n",res
,size
,hf
);
152 static DWORD WINAPI
stub_dispatch_thread(LPVOID
);
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.
163 for (i
=0;i
<nrofpipes
;i
++)
164 if (pipes
[i
].mid
.oxid
==mid
->oxid
)
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
));
180 pipes
[nrofpipes
-1].hThread
= CreateThread(NULL
,0,stub_dispatch_thread
,(LPVOID
)(pipes
+(nrofpipes
-1)),0,&(pipes
[nrofpipes
-1].tid
));
182 pipes
[nrofpipes
-1].tid
= GetCurrentThreadId();
188 PIPE_FindByMID(wine_marshal_id
*mid
) {
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
;
199 PIPE_GetFromIPID(const IPID
*ipid
) {
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
))
208 /* special case for IRemUnknown IPID */
209 else if ((pipes
[i
].mid
.oxid
== *(OXID
*)ipid
->Data4
) &&
210 (GetCurrentThreadId() == pipes
[i
].tid
))
217 RPC_GetRequest(struct rpc
**req
) {
218 static int reqid
= 0xdeadbeef;
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
;
227 reqs
[i
]->state
= REQSTATE_START
;
233 reqs
= (struct rpc
**)HeapReAlloc(
237 sizeof(struct rpc
*)*(nrofreqs
+1)
240 reqs
= (struct rpc
**)HeapAlloc(
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
;
258 RPC_FreeRequest(struct rpc
*req
) {
259 req
->state
= REQSTATE_DONE
; /* Just reuse slot. */
263 static HRESULT WINAPI
264 PipeBuf_QueryInterface(
265 LPRPCCHANNELBUFFER iface
,REFIID riid
,LPVOID
*ppv
268 if (IsEqualIID(riid
,&IID_IRpcChannelBuffer
) || IsEqualIID(riid
,&IID_IUnknown
)) {
269 *ppv
= (LPVOID
)iface
;
270 IUnknown_AddRef(iface
);
273 return E_NOINTERFACE
;
277 PipeBuf_AddRef(LPRPCCHANNELBUFFER iface
) {
278 PipeBuf
*This
= (PipeBuf
*)iface
;
279 return InterlockedIncrement(&This
->ref
);
283 PipeBuf_Release(LPRPCCHANNELBUFFER iface
) {
284 PipeBuf
*This
= (PipeBuf
*)iface
;
287 ref
= InterlockedDecrement(&This
->ref
);
291 HeapFree(GetProcessHeap(),0,This
);
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
);
306 COM_InvokeAndRpcSend(struct rpc
*req
) {
307 IRpcStubBuffer
*stub
;
312 if (!(stub
= ipid_to_stubbuffer(&(req
->reqh
.ipid
))))
314 ERR("Stub not found?\n");
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
;
339 static HRESULT
COM_RpcReceive(struct pipe
*xpipe
);
342 RPC_QueueRequestAndWait(struct rpc
*req
) {
347 struct pipe
*xpipe
= PIPE_GetFromIPID(&(req
->reqh
.ipid
));
350 FIXME("no pipe found.\n");
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. */
366 hres
= COM_RpcReceive(xpipe
);
369 for (i
=0;i
<nrofreqs
;i
++) {
371 if ((xreq
->state
==REQSTATE_REQ_GOT
) && (xreq
->hPipe
==req
->hPipe
)) {
372 hres
= COM_InvokeAndRpcSend(xreq
);
376 if (req
->state
== REQSTATE_RESP_GOT
)
380 WARN("-- 0x%08lx\n", hres
);
384 static HRESULT WINAPI
385 PipeBuf_SendReceive(LPRPCCHANNELBUFFER iface
,RPCOLEMESSAGE
* msg
,ULONG
*status
)
387 PipeBuf
*This
= (PipeBuf
*)iface
;
393 if (This
->mid
.oxid
== COM_CurrentApt()->oxid
) {
394 ERR("Need to call directly!\n");
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
);
406 RPC_FreeRequest(req
);
409 msg
->cbBuffer
= req
->resph
.cbBuffer
;
410 msg
->Buffer
= req
->Buffer
;
411 *status
= req
->resph
.retval
;
412 RPC_FreeRequest(req
);
417 static HRESULT WINAPI
418 PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface
,RPCOLEMESSAGE
* msg
)
420 FIXME("(%p), stub!\n",msg
);
424 static HRESULT WINAPI
425 PipeBuf_GetDestCtx(LPRPCCHANNELBUFFER iface
,DWORD
* pdwDestContext
,void** ppvDestContext
)
427 FIXME("(%p,%p), stub!\n",pdwDestContext
,ppvDestContext
);
431 static HRESULT WINAPI
432 PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface
)
434 FIXME("(), stub!\n");
438 static IRpcChannelBufferVtbl pipebufvt
= {
439 PipeBuf_QueryInterface
,
449 HRESULT
PIPE_GetNewPipeBuf(wine_marshal_id
*mid
, IRpcChannelBuffer
**pipebuf
)
451 wine_marshal_id ourid
;
457 hPipe
= PIPE_FindByMID(mid
);
458 if (hPipe
== INVALID_HANDLE_VALUE
) {
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());
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");
482 pbuf
= (PipeBuf
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(PipeBuf
));
483 pbuf
->lpVtbl
= &pipebufvt
;
485 memcpy(&(pbuf
->mid
),mid
,sizeof(*mid
));
487 *pipebuf
= (IRpcChannelBuffer
*)pbuf
;
493 create_server(REFCLSID rclsid
)
495 static const WCHAR embedding
[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
498 HRESULT hres
= E_UNEXPECTED
;
500 WCHAR exe
[MAX_PATH
+1];
501 DWORD exelen
= sizeof(exe
);
502 WCHAR command
[MAX_PATH
+sizeof(embedding
)/sizeof(WCHAR
)];
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
);
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
));
545 * start_local_service() - start a service given its name and parameters
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
);
558 hsvc
= OpenServiceW(handle
, name
, SC_MANAGER_ALL_ACCESS
);
561 if(StartServiceW(hsvc
, num
, (LPCWSTR
*)params
))
565 if (r
== ERROR_SERVICE_ALREADY_RUNNING
)
567 CloseServiceHandle(hsvc
);
569 CloseServiceHandle(handle
);
571 TRACE("StartService returned error %ld (%s)\n", r
, r
?"ok":"failed");
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
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};
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
)
608 r
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &sz
);
610 if (r
!=ERROR_SUCCESS
|| type
!=REG_SZ
)
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
)
620 r
= RegQueryValueExW(hkey
, szLocalService
, NULL
, &type
, (LPBYTE
)buf
, &sz
);
621 if (r
==ERROR_SUCCESS
&& type
==REG_SZ
)
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
);
639 RegQueryValueExW(hkey
, szServiceParams
, NULL
, &type
, (LPBYTE
)args
[0], &sz
);
641 r
= start_local_service(buf
, num_args
, args
);
642 if (r
==ERROR_SUCCESS
)
644 HeapFree(GetProcessHeap(),0,args
[0]);
651 /* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */
653 create_marshalled_proxy(REFCLSID rclsid
, REFIID iid
, LPVOID
*ppv
)
658 DWORD res
, bufferlen
;
659 char marshalbuffer
[200];
661 LARGE_INTEGER seekto
;
662 ULARGE_INTEGER newpos
;
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
) {
679 if ( (hres
= create_server(rclsid
)) &&
680 (hres
= create_local_service(rclsid
)) )
684 WARN("Could not open named pipe to broker %s, le is %lx\n",pipefn
,GetLastError());
690 if (!ReadFile(hPipe
,marshalbuffer
,sizeof(marshalbuffer
),&bufferlen
,NULL
)) {
691 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid
));
695 TRACE("read marshal id from pipe\n");
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
);
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
);
713 IStream_Release(pStm
);
719 PIPE_StartRequestThread(HANDLE xhPipe
)
721 wine_marshal_id remoteid
;
724 hres
= read_pipe(xhPipe
,&remoteid
,sizeof(remoteid
));
726 ERR("Failed to read remote mid!\n");
729 PIPE_RegisterPipe(&remoteid
,xhPipe
, TRUE
);
733 COM_RpcReceive(struct pipe
*xpipe
) {
736 HANDLE xhPipe
= xpipe
->hPipe
;
738 hres
= read_pipe(xhPipe
,&reqtype
,sizeof(reqtype
));
740 EnterCriticalSection(&(xpipe
->crit
));
742 /* only received by servers */
743 if (reqtype
== REQTYPE_REQUEST
) {
746 RPC_GetRequest(&xreq
);
747 xreq
->hPipe
= xhPipe
;
748 hres
= read_pipe(xhPipe
,&(xreq
->reqh
),sizeof(xreq
->reqh
));
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
);
756 xreq
->state
= REQSTATE_REQ_GOT
;
758 } else if (reqtype
== REQTYPE_RESPONSE
) {
759 struct response_header resph
;
762 hres
= read_pipe(xhPipe
,&resph
,sizeof(resph
));
765 for (i
=nrofreqs
;i
--;) {
766 struct rpc
*xreq
= reqs
[i
];
767 if (xreq
->state
!= REQSTATE_REQ_WAITING_FOR_REPLY
)
769 if (xreq
->reqh
.reqid
== resph
.reqid
) {
770 memcpy(&(xreq
->resph
),&resph
,sizeof(resph
));
773 xreq
->Buffer
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,xreq
->Buffer
,xreq
->resph
.cbBuffer
);
775 xreq
->Buffer
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,xreq
->resph
.cbBuffer
);
777 hres
= read_pipe(xhPipe
,xreq
->Buffer
,xreq
->resph
.cbBuffer
);
779 xreq
->state
= REQSTATE_RESP_GOT
;
780 /*PulseEvent(hRpcChanged);*/
785 ERR("Did not find request for id %lx\n",resph
.reqid
);
790 ERR("Unknown reqtype %ld\n",reqtype
);
793 LeaveCriticalSection(&(xpipe
->crit
));
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
;
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
;
812 hres
= COM_RpcReceive(xpipe
);
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
);
824 /* fixme: this thread never quits naturally */
825 WARN("exiting with hres %lx\n",hres
);
830 struct apartment_listener_params
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
841 * This architecture is different in native DCOM.
843 static DWORD WINAPI
apartment_listener_thread(LPVOID p
)
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
);
860 listenPipe
= CreateNamedPipeA(
863 PIPE_TYPE_BYTE
|PIPE_WAIT
,
864 PIPE_UNLIMITED_INSTANCES
,
867 NMPWAIT_USE_DEFAULT_WAIT
,
871 /* tell function that started this thread that we have attempted to created the
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
);
891 PIPE_StartRequestThread(listenPipe
);
896 void start_apartment_listener_thread()
898 APARTMENT
*apt
= COM_CurrentApt();
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
)
915 HANDLE event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
916 struct apartment_listener_params
* params
= HeapAlloc(GetProcessHeap(), 0, sizeof(*params
));
919 params
->event
= event
;
920 thread
= CreateThread(NULL
, 0, apartment_listener_thread
, params
, 0, &apt
->listenertid
);
922 /* wait for pipe to be created before returning, otherwise we
923 * might try to use it and fail */
924 WaitForSingleObject(event
, INFINITE
);
929 struct local_server_params
935 static DWORD WINAPI
local_server_thread(LPVOID param
)
937 struct local_server_params
* lsp
= (struct local_server_params
*)param
;
941 IStream
*pStm
= lsp
->stream
;
943 unsigned char *buffer
;
945 LARGE_INTEGER seekto
;
946 ULARGE_INTEGER newpos
;
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());
964 if (!ConnectNamedPipe(hPipe
,NULL
)) {
965 ERR("Failure during ConnectNamedPipe %ld, ABORT!\n",GetLastError());
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
);
980 FIXME("IStream_Seek failed, %lx\n",hres
);
984 hres
= IStream_Read(pStm
,buffer
,buflen
,&res
);
986 FIXME("Stream Read failed, %lx\n",hres
);
990 IStream_Release(pStm
);
992 WriteFile(hPipe
,buffer
,buflen
,&res
,NULL
);
993 FlushFileBuffers(hPipe
);
994 DisconnectNamedPipe(hPipe
);
996 TRACE("done marshalling IClassFactory\n");
1002 void RPC_StartLocalServer(REFCLSID clsid
, IStream
*stream
)
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 */