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
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
42 #include "wine/unicode.h"
43 #include "wine/winbase16.h"
44 #include "compobj_private.h"
47 #include "compobj_private.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
53 #define REQTYPE_REQUEST 0
54 typedef struct _wine_rpc_request_header
{
59 } wine_rpc_request_header
;
61 #define REQTYPE_RESPONSE 1
62 typedef struct _wine_rpc_response_header
{
66 } wine_rpc_response_header
;
68 /* used when shutting down a pipe, e.g. at the end of a process */
69 #define REQTYPE_DISCONNECT 2
70 typedef struct _wine_rpc_disconnect_header
{
72 wine_marshal_id mid
; /* mid of stub to delete */
73 } wine_rpc_disconnect_header
;
76 #define REQSTATE_START 0
77 #define REQSTATE_REQ_QUEUED 1
78 #define REQSTATE_REQ_WAITING_FOR_REPLY 2
79 #define REQSTATE_REQ_GOT 3
80 #define REQSTATE_INVOKING 4
81 #define REQSTATE_RESP_QUEUED 5
82 #define REQSTATE_RESP_GOT 6
83 #define REQSTATE_DONE 6
85 typedef struct _wine_rpc_request
{
87 HANDLE hPipe
; /* temp copy of handle */
88 wine_rpc_request_header reqh
;
89 wine_rpc_response_header resph
;
93 static wine_rpc_request
**reqs
= NULL
;
94 static int nrofreqs
= 0;
96 /* This pipe is _thread_ based, each thread which talks to a remote
97 * apartment (mid) has its own pipe */
98 typedef struct _wine_pipe
{
99 wine_marshal_id mid
; /* target mid */
100 DWORD tid
; /* thread which owns this outgoing pipe */
105 CRITICAL_SECTION crit
;
108 static wine_pipe
*pipes
= NULL
;
109 static int nrofpipes
= 0;
111 typedef struct _PipeBuf
{
112 IRpcChannelBufferVtbl
*lpVtbl
;
119 static HRESULT WINAPI
120 read_pipe(HANDLE hf
, LPVOID ptr
, DWORD size
) {
122 if (!ReadFile(hf
,ptr
,size
,&res
,NULL
)) {
123 FIXME("Failed to read from %p, le is %lx\n",hf
,GetLastError());
127 FIXME("Read only %ld of %ld bytes from %p.\n",res
,size
,hf
);
136 static int nrofreaders
= 0;
140 memset(states
,0,sizeof(states
));
141 for (i
=nrofreqs
;i
--;)
142 states
[reqs
[i
]->state
]++;
143 FIXME("%lx/%s/%d: rq %d, w %d, rg %d, rsq %d, rsg %d, d %d\n",
144 GetCurrentProcessId(),
147 states
[REQSTATE_REQ_QUEUED
],
148 states
[REQSTATE_REQ_WAITING_FOR_REPLY
],
149 states
[REQSTATE_REQ_GOT
],
150 states
[REQSTATE_RESP_QUEUED
],
151 states
[REQSTATE_RESP_GOT
],
152 states
[REQSTATE_DONE
]
159 static HRESULT WINAPI
160 write_pipe(HANDLE hf
, LPVOID ptr
, DWORD size
) {
162 if (!WriteFile(hf
,ptr
,size
,&res
,NULL
)) {
163 FIXME("Failed to write to %p, le is %lx\n",hf
,GetLastError());
167 FIXME("Wrote only %ld of %ld bytes to %p.\n",res
,size
,hf
);
173 static DWORD WINAPI
_StubReaderThread(LPVOID
);
176 PIPE_RegisterPipe(wine_marshal_id
*mid
, HANDLE hPipe
, BOOL startreader
) {
179 wine_pipe
*new_pipes
;
181 for (i
=0;i
<nrofpipes
;i
++)
182 if (pipes
[i
].mid
.processid
==mid
->processid
)
185 new_pipes
=(wine_pipe
*)HeapReAlloc(GetProcessHeap(),0,pipes
,sizeof(pipes
[0])*(nrofpipes
+1));
187 new_pipes
=(wine_pipe
*)HeapAlloc(GetProcessHeap(),0,sizeof(pipes
[0]));
188 if (!new_pipes
) return E_OUTOFMEMORY
;
190 sprintf(pipefn
,OLESTUBMGR
"_%08lx",mid
->processid
);
191 memcpy(&(pipes
[nrofpipes
].mid
),mid
,sizeof(*mid
));
192 pipes
[nrofpipes
].hPipe
= hPipe
;
193 InitializeCriticalSection(&(pipes
[nrofpipes
].crit
));
196 pipes
[nrofpipes
-1].hThread
= CreateThread(NULL
,0,_StubReaderThread
,(LPVOID
)(pipes
+(nrofpipes
-1)),0,&(pipes
[nrofpipes
-1].tid
));
198 pipes
[nrofpipes
-1].tid
= GetCurrentThreadId();
204 PIPE_FindByMID(wine_marshal_id
*mid
) {
206 for (i
=0;i
<nrofpipes
;i
++)
207 if ((pipes
[i
].mid
.processid
==mid
->processid
) &&
208 (GetCurrentThreadId()==pipes
[i
].tid
)
210 return pipes
[i
].hPipe
;
211 return INVALID_HANDLE_VALUE
;
215 PIPE_GetFromMID(wine_marshal_id
*mid
) {
217 for (i
=0;i
<nrofpipes
;i
++) {
218 if ((pipes
[i
].mid
.processid
==mid
->processid
) &&
219 (GetCurrentThreadId()==pipes
[i
].tid
)
227 RPC_GetRequest(wine_rpc_request
**req
) {
228 static int reqid
= 0xdeadbeef;
231 for (i
=0;i
<nrofreqs
;i
++) { /* try to reuse */
232 if (reqs
[i
]->state
== REQSTATE_DONE
) {
233 reqs
[i
]->reqh
.reqid
= reqid
++;
234 reqs
[i
]->resph
.reqid
= reqs
[i
]->reqh
.reqid
;
235 reqs
[i
]->hPipe
= INVALID_HANDLE_VALUE
;
237 reqs
[i
]->state
= REQSTATE_START
;
243 reqs
= (wine_rpc_request
**)HeapReAlloc(
247 sizeof(wine_rpc_request
*)*(nrofreqs
+1)
250 reqs
= (wine_rpc_request
**)HeapAlloc(
253 sizeof(wine_rpc_request
*)
256 return E_OUTOFMEMORY
;
257 reqs
[nrofreqs
] = (wine_rpc_request
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(wine_rpc_request
));
258 reqs
[nrofreqs
]->reqh
.reqid
= reqid
++;
259 reqs
[nrofreqs
]->resph
.reqid
= reqs
[nrofreqs
]->reqh
.reqid
;
260 reqs
[nrofreqs
]->hPipe
= INVALID_HANDLE_VALUE
;
261 *req
= reqs
[nrofreqs
];
262 reqs
[nrofreqs
]->state
= REQSTATE_START
;
268 RPC_FreeRequest(wine_rpc_request
*req
) {
269 req
->state
= REQSTATE_DONE
; /* Just reuse slot. */
273 static HRESULT WINAPI
274 PipeBuf_QueryInterface(
275 LPRPCCHANNELBUFFER iface
,REFIID riid
,LPVOID
*ppv
278 if (IsEqualIID(riid
,&IID_IRpcChannelBuffer
) || IsEqualIID(riid
,&IID_IUnknown
)) {
279 *ppv
= (LPVOID
)iface
;
280 IUnknown_AddRef(iface
);
283 return E_NOINTERFACE
;
287 PipeBuf_AddRef(LPRPCCHANNELBUFFER iface
) {
288 PipeBuf
*This
= (PipeBuf
*)iface
;
294 PipeBuf_Release(LPRPCCHANNELBUFFER iface
) {
295 PipeBuf
*This
= (PipeBuf
*)iface
;
296 wine_rpc_disconnect_header header
;
298 DWORD reqtype
= REQTYPE_DISCONNECT
;
304 FIXME("Free all stuff\n");
306 memcpy(&header
.mid
, &This
->mid
, sizeof(wine_marshal_id
));
308 pipe
= PIPE_FindByMID(&This
->mid
);
310 write_pipe(pipe
, &reqtype
, sizeof(reqtype
));
311 write_pipe(pipe
, &header
, sizeof(wine_rpc_disconnect_header
));
313 TRACE("written disconnect packet\n");
315 HeapFree(GetProcessHeap(),0,This
);
319 static HRESULT WINAPI
321 LPRPCCHANNELBUFFER iface
,RPCOLEMESSAGE
* msg
,REFIID riid
323 /*PipeBuf *This = (PipeBuf *)iface;*/
325 TRACE("(%p,%s)\n",msg
,debugstr_guid(riid
));
326 /* probably reuses IID in real. */
327 if (msg
->cbBuffer
&& (msg
->Buffer
== NULL
))
328 msg
->Buffer
= HeapAlloc(GetProcessHeap(),0,msg
->cbBuffer
);
333 COM_InvokeAndRpcSend(wine_rpc_request
*req
) {
334 IRpcStubBuffer
*stub
;
339 hres
= MARSHAL_Find_Stub_Buffer(&(req
->reqh
.mid
),&stub
);
341 ERR("Stub not found?\n");
344 msg
.Buffer
= req
->Buffer
;
345 msg
.iMethod
= req
->reqh
.iMethod
;
346 msg
.cbBuffer
= req
->reqh
.cbBuffer
;
347 msg
.dataRepresentation
= NDR_LOCAL_DATA_REPRESENTATION
;
348 req
->state
= REQSTATE_INVOKING
;
349 req
->resph
.retval
= IRpcStubBuffer_Invoke(stub
,&msg
,NULL
);
350 IUnknown_Release(stub
);
351 req
->Buffer
= msg
.Buffer
;
352 req
->resph
.cbBuffer
= msg
.cbBuffer
;
353 reqtype
= REQTYPE_RESPONSE
;
354 hres
= write_pipe(req
->hPipe
,&reqtype
,sizeof(reqtype
));
355 if (hres
) return hres
;
356 hres
= write_pipe(req
->hPipe
,&(req
->resph
),sizeof(req
->resph
));
357 if (hres
) return hres
;
358 hres
= write_pipe(req
->hPipe
,req
->Buffer
,req
->resph
.cbBuffer
);
359 if (hres
) return hres
;
360 req
->state
= REQSTATE_DONE
;
365 static HRESULT
COM_RpcReceive(wine_pipe
*xpipe
);
368 RPC_QueueRequestAndWait(wine_rpc_request
*req
) {
370 wine_rpc_request
*xreq
;
373 wine_pipe
*xpipe
= PIPE_GetFromMID(&(req
->reqh
.mid
));
376 FIXME("no pipe found.\n");
379 if (GetCurrentProcessId() == req
->reqh
.mid
.processid
) {
380 ERR("In current process?\n");
383 req
->hPipe
= xpipe
->hPipe
;
384 req
->state
= REQSTATE_REQ_WAITING_FOR_REPLY
;
385 reqtype
= REQTYPE_REQUEST
;
386 hres
= write_pipe(req
->hPipe
,&reqtype
,sizeof(reqtype
));
387 if (hres
) return hres
;
388 hres
= write_pipe(req
->hPipe
,&(req
->reqh
),sizeof(req
->reqh
));
389 if (hres
) return hres
;
390 hres
= write_pipe(req
->hPipe
,req
->Buffer
,req
->reqh
.cbBuffer
);
391 if (hres
) return hres
;
393 /* This loop is about allowing re-entrancy. While waiting for the
394 * response to one RPC we may receive a request starting another. */
396 hres
= COM_RpcReceive(xpipe
);
399 for (i
=0;i
<nrofreqs
;i
++) {
401 if ((xreq
->state
==REQSTATE_REQ_GOT
) && (xreq
->hPipe
==req
->hPipe
)) {
402 hres
= COM_InvokeAndRpcSend(xreq
);
406 if (req
->state
== REQSTATE_RESP_GOT
)
410 WARN("-- 0x%08lx\n", hres
);
414 static HRESULT WINAPI
416 LPRPCCHANNELBUFFER iface
,RPCOLEMESSAGE
* msg
,ULONG
*status
418 PipeBuf
*This
= (PipeBuf
*)iface
;
419 wine_rpc_request
*req
;
424 if (This
->mid
.processid
== GetCurrentProcessId()) {
425 ERR("Need to call directly!\n");
429 hres
= RPC_GetRequest(&req
);
430 if (hres
) return hres
;
431 req
->reqh
.iMethod
= msg
->iMethod
;
432 req
->reqh
.cbBuffer
= msg
->cbBuffer
;
433 memcpy(&(req
->reqh
.mid
),&(This
->mid
),sizeof(This
->mid
));
434 req
->Buffer
= msg
->Buffer
;
435 hres
= RPC_QueueRequestAndWait(req
);
437 RPC_FreeRequest(req
);
440 msg
->cbBuffer
= req
->resph
.cbBuffer
;
441 msg
->Buffer
= req
->Buffer
;
442 *status
= req
->resph
.retval
;
443 RPC_FreeRequest(req
);
448 static HRESULT WINAPI
449 PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface
,RPCOLEMESSAGE
* msg
) {
450 FIXME("(%p), stub!\n",msg
);
454 static HRESULT WINAPI
456 LPRPCCHANNELBUFFER iface
,DWORD
* pdwDestContext
,void** ppvDestContext
458 FIXME("(%p,%p), stub!\n",pdwDestContext
,ppvDestContext
);
462 static HRESULT WINAPI
463 PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface
) {
464 FIXME("(), stub!\n");
468 static IRpcChannelBufferVtbl pipebufvt
= {
469 PipeBuf_QueryInterface
,
480 PIPE_GetNewPipeBuf(wine_marshal_id
*mid
, IRpcChannelBuffer
**pipebuf
) {
481 wine_marshal_id ourid
;
487 hPipe
= PIPE_FindByMID(mid
);
488 if (hPipe
== INVALID_HANDLE_VALUE
) {
490 sprintf(pipefn
,OLESTUBMGR
"_%08lx",mid
->processid
);
493 GENERIC_READ
|GENERIC_WRITE
,
500 if (hPipe
== INVALID_HANDLE_VALUE
) {
501 FIXME("Could not open named pipe %s, le is %lx\n",pipefn
,GetLastError());
504 hres
= PIPE_RegisterPipe(mid
, hPipe
, FALSE
);
505 if (hres
) return hres
;
506 memset(&ourid
,0,sizeof(ourid
));
507 ourid
.processid
= GetCurrentProcessId();
508 if (!WriteFile(hPipe
,&ourid
,sizeof(ourid
),&res
,NULL
)||(res
!=sizeof(ourid
))) {
509 ERR("Failed writing startup mid!\n");
513 pbuf
= (PipeBuf
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(PipeBuf
));
514 pbuf
->lpVtbl
= &pipebufvt
;
516 memcpy(&(pbuf
->mid
),mid
,sizeof(*mid
));
517 *pipebuf
= (IRpcChannelBuffer
*)pbuf
;
522 create_server(REFCLSID rclsid
) {
523 static const WCHAR embedding
[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
526 HRESULT hres
= E_UNEXPECTED
;
528 WCHAR exe
[MAX_PATH
+1];
529 DWORD exelen
= sizeof(exe
);
530 WCHAR command
[MAX_PATH
+sizeof(embedding
)/sizeof(WCHAR
)];
532 PROCESS_INFORMATION pinfo
;
534 WINE_StringFromCLSID((LPCLSID
)rclsid
,xclsid
);
536 sprintf(buf
,"CLSID\\%s\\LocalServer32",xclsid
);
537 hres
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, buf
, 0, KEY_READ
, &key
);
539 if (hres
!= ERROR_SUCCESS
) {
540 WARN("CLSID %s not registered as LocalServer32\n", xclsid
);
541 return REGDB_E_READREGDB
; /* Probably */
544 memset(exe
,0,sizeof(exe
));
545 hres
= RegQueryValueExW(key
, NULL
, NULL
, NULL
, (LPBYTE
)exe
, &exelen
);
548 WARN("No default value for LocalServer32 key\n");
549 return REGDB_E_CLASSNOTREG
; /* FIXME: check retval */
552 memset(&sinfo
,0,sizeof(sinfo
));
553 sinfo
.cb
= sizeof(sinfo
);
555 /* EXE servers are started with the -Embedding switch. MSDN also claims /Embedding is used,
556 9x does -Embedding, perhaps an 9x/NT difference? */
558 strcpyW(command
, exe
);
559 strcatW(command
, embedding
);
561 TRACE("activating local server '%s' for %s\n", debugstr_w(command
), xclsid
);
563 if (!CreateProcessW(exe
, command
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &sinfo
, &pinfo
)) {
564 WARN("failed to run local server %s\n", debugstr_w(exe
));
570 /* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */
571 HRESULT
create_marshalled_proxy(REFCLSID rclsid
, REFIID iid
, LPVOID
*ppv
) {
576 char marshalbuffer
[200];
578 LARGE_INTEGER seekto
;
579 ULARGE_INTEGER newpos
;
581 #define MAXTRIES 10000
583 TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
585 strcpy(pipefn
,PIPEPREF
);
586 WINE_StringFromCLSID(rclsid
,pipefn
+strlen(PIPEPREF
));
588 while (tries
++<MAXTRIES
) {
589 WaitNamedPipeA( pipefn
, NMPWAIT_WAIT_FOREVER
);
592 GENERIC_READ
|GENERIC_WRITE
,
599 if (hPipe
== INVALID_HANDLE_VALUE
) {
601 if ((hres
= create_server(rclsid
)))
605 WARN("Could not open named pipe to broker %s, le is %lx\n",pipefn
,GetLastError());
611 if (!ReadFile(hPipe
,marshalbuffer
,sizeof(marshalbuffer
),&bufferlen
,NULL
)) {
612 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid
));
620 return E_NOINTERFACE
;
621 hres
= CreateStreamOnHGlobal(0,TRUE
,&pStm
);
622 if (hres
) return hres
;
623 hres
= IStream_Write(pStm
,marshalbuffer
,bufferlen
,&res
);
625 seekto
.u
.LowPart
= 0;seekto
.u
.HighPart
= 0;
626 hres
= IStream_Seek(pStm
,seekto
,SEEK_SET
,&newpos
);
627 hres
= CoUnmarshalInterface(pStm
,&IID_IClassFactory
,ppv
);
629 IStream_Release(pStm
);
635 PIPE_StartRequestThread(HANDLE xhPipe
) {
636 wine_marshal_id remoteid
;
639 hres
= read_pipe(xhPipe
,&remoteid
,sizeof(remoteid
));
641 ERR("Failed to read remote mid!\n");
644 PIPE_RegisterPipe(&remoteid
,xhPipe
, TRUE
);
648 COM_RpcReceive(wine_pipe
*xpipe
) {
651 HANDLE xhPipe
= xpipe
->hPipe
;
653 /*FIXME("%lx %d reading reqtype\n",GetCurrentProcessId(),xhPipe);*/
654 hres
= read_pipe(xhPipe
,&reqtype
,sizeof(reqtype
));
656 EnterCriticalSection(&(xpipe
->crit
));
657 /*FIXME("%lx got reqtype %ld\n",GetCurrentProcessId(),reqtype);*/
659 if (reqtype
== REQTYPE_DISCONNECT
) { /* only received by servers */
660 wine_rpc_disconnect_header header
;
661 IRpcStubBuffer
*stub
;
664 hres
= read_pipe(xhPipe
, &header
, sizeof(header
));
666 ERR("could not read disconnect header\n");
670 TRACE("read disconnect header\n");
672 hres
= MARSHAL_Find_Stub_Buffer(&header
.mid
, &stub
);
674 ERR("could not locate stub to disconnect, mid.objectid=%p\n", (void*)header
.mid
.objectid
);
679 /* release reference added by MARSHAL_Find_Stub_Buffer call */
680 IRpcStubBuffer_Release(stub
);
681 /* release it for real */
682 ret
= IRpcStubBuffer_Release(stub
);
685 MARSHAL_Invalidate_Stub_From_MID(&header
.mid
);
687 } else if (reqtype
== REQTYPE_REQUEST
) {
688 wine_rpc_request
*xreq
;
689 RPC_GetRequest(&xreq
);
690 xreq
->hPipe
= xhPipe
;
691 hres
= read_pipe(xhPipe
,&(xreq
->reqh
),sizeof(xreq
->reqh
));
693 xreq
->resph
.reqid
= xreq
->reqh
.reqid
;
694 xreq
->Buffer
= HeapAlloc(GetProcessHeap(),0, xreq
->reqh
.cbBuffer
);
695 hres
= read_pipe(xhPipe
,xreq
->Buffer
,xreq
->reqh
.cbBuffer
);
697 xreq
->state
= REQSTATE_REQ_GOT
;
699 } else if (reqtype
== REQTYPE_RESPONSE
) {
700 wine_rpc_response_header resph
;
703 hres
= read_pipe(xhPipe
,&resph
,sizeof(resph
));
705 for (i
=nrofreqs
;i
--;) {
706 wine_rpc_request
*xreq
= reqs
[i
];
707 if (xreq
->state
!= REQSTATE_REQ_WAITING_FOR_REPLY
)
709 if (xreq
->reqh
.reqid
== resph
.reqid
) {
710 memcpy(&(xreq
->resph
),&resph
,sizeof(resph
));
713 xreq
->Buffer
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,xreq
->Buffer
,xreq
->resph
.cbBuffer
);
715 xreq
->Buffer
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,xreq
->resph
.cbBuffer
);
717 hres
= read_pipe(xhPipe
,xreq
->Buffer
,xreq
->resph
.cbBuffer
);
719 xreq
->state
= REQSTATE_RESP_GOT
;
720 /*PulseEvent(hRpcChanged);*/
724 ERR("Did not find request for id %lx\n",resph
.reqid
);
728 ERR("Unknown reqtype %ld\n",reqtype
);
731 LeaveCriticalSection(&(xpipe
->crit
));
736 _StubReaderThread(LPVOID param
) {
737 wine_pipe
*xpipe
= (wine_pipe
*)param
;
738 HANDLE xhPipe
= xpipe
->hPipe
;
741 TRACE("STUB reader thread %lx\n",GetCurrentProcessId());
744 hres
= COM_RpcReceive(xpipe
);
747 for (i
=nrofreqs
;i
--;) {
748 wine_rpc_request
*xreq
= reqs
[i
];
749 if ((xreq
->state
== REQSTATE_REQ_GOT
) && (xreq
->hPipe
== xhPipe
)) {
750 hres
= COM_InvokeAndRpcSend(xreq
);
755 FIXME("Failed with hres %lx\n",hres
);
761 _StubMgrThread(LPVOID param
) {
765 sprintf(pipefn
,OLESTUBMGR
"_%08lx",GetCurrentProcessId());
766 TRACE("Stub Manager Thread starting on (%s)\n",pipefn
);
769 listenPipe
= CreateNamedPipeA(
772 PIPE_TYPE_BYTE
|PIPE_WAIT
,
773 PIPE_UNLIMITED_INSTANCES
,
776 NMPWAIT_USE_DEFAULT_WAIT
,
779 if (listenPipe
== INVALID_HANDLE_VALUE
) {
780 FIXME("pipe creation failed for %s, le is %lx\n",pipefn
,GetLastError());
781 return 1; /* permanent failure, so quit stubmgr thread */
783 if (!ConnectNamedPipe(listenPipe
,NULL
)) {
784 ERR("Failure during ConnectNamedPipe %lx!\n",GetLastError());
785 CloseHandle(listenPipe
);
788 PIPE_StartRequestThread(listenPipe
);
795 static BOOL stubMgrRunning
= FALSE
;
798 if (!stubMgrRunning
) {
799 stubMgrRunning
= TRUE
;
800 CreateThread(NULL
,0,_StubMgrThread
,NULL
,0,&tid
);
801 Sleep(2000); /* actually we just try opening the pipe until it succeeds */