#define COBJMACROS
#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#include "rpc.h"
#include "winerror.h"
#include "winreg.h"
+#include "servprov.h"
#include "wine/unicode.h"
#include "compobj_private.h"
OXID oxid; /* apartment in which the channel is valid */
DWORD server_pid; /* id of server process */
HANDLE event; /* cached event handle */
+ IID iid; /* IID of the proxy this belongs to */
} ClientRpcChannelBuffer;
struct dispatch_params
cif->Length = sizeof(RPC_CLIENT_INTERFACE);
/* RPC interface ID = COM interface ID */
- cif->InterfaceId.SyntaxGUID = *riid;
+ cif->InterfaceId.SyntaxGUID = This->iid;
/* COM objects always have a version of 0.0 */
cif->InterfaceId.SyntaxVersion.MajorVersion = 0;
cif->InterfaceId.SyntaxVersion.MinorVersion = 0;
message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
message_state->channel_hook_info.uCausality = COM_CurrentCausalityId();
message_state->channel_hook_info.dwServerPid = This->server_pid;
- message_state->channel_hook_info.iMethod = msg->ProcNum;
+ message_state->channel_hook_info.iMethod = msg->ProcNum & ~RPC_FLAGS_VALID_BIT;
message_state->channel_hook_info.pObject = NULL; /* only present on server-side */
message_state->target_hwnd = NULL;
message_state->target_tid = 0;
}
RpcBindingInqObject(message_state->binding_handle, &ipid);
- hr = ipid_get_dispatch_params(&ipid, &apt, &message_state->params.stub,
+ hr = ipid_get_dispatch_params(&ipid, &apt, NULL, &message_state->params.stub,
&message_state->params.chan,
&message_state->params.iid,
&message_state->params.iface);
ORPC_EXTENT_ARRAY orpc_ext_array;
WIRE_ORPC_EXTENT *first_wire_orpc_extent = NULL;
HRESULT hrFault = S_OK;
+ APARTMENT *apt = apartment_get_current_or_mta();
TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod);
- hr = ClientRpcChannelBuffer_IsCorrectApartment(This, COM_CurrentApt());
+ hr = ClientRpcChannelBuffer_IsCorrectApartment(This, apt);
if (hr != S_OK)
{
ERR("called from wrong apartment, should have been 0x%s\n",
wine_dbgstr_longlong(This->oxid));
+ if (apt) apartment_release(apt);
return RPC_E_WRONG_THREAD;
}
/* This situation should be impossible in multi-threaded apartments,
* Note: doing a COM call during the processing of a sent message is
* only disallowed if a client call is already being waited for
* completion */
- if (!COM_CurrentApt()->multi_threaded &&
+ if (!apt->multi_threaded &&
COM_CurrentInfo()->pending_call_count_client &&
InSendMessage())
{
ERR("can't make an outgoing COM call in response to a sent message\n");
+ apartment_release(apt);
return RPC_E_CANTCALLOUT_ININPUTSYNCCALL;
}
TRACE("-- 0x%08x\n", hr);
+ apartment_release(apt);
return hr;
}
/* returns a channel buffer for proxies */
HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
- const OXID_INFO *oxid_info,
+ const OXID_INFO *oxid_info, const IID *iid,
DWORD dest_context, void *dest_context_data,
- IRpcChannelBuffer **chan)
+ IRpcChannelBuffer **chan, APARTMENT *apt)
{
ClientRpcChannelBuffer *This;
WCHAR endpoint[200];
This->super.dest_context = dest_context;
This->super.dest_context_data = dest_context_data;
This->bind = bind;
- apartment_getoxid(COM_CurrentApt(), &This->oxid);
+ apartment_getoxid(apt, &This->oxid);
This->server_pid = oxid_info->dwPid;
This->event = NULL;
+ This->iid = *iid;
*chan = &This->super.IRpcChannelBuffer_iface;
static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
{
struct dispatch_params *params;
+ struct stub_manager *stub_manager;
APARTMENT *apt;
IPID ipid;
HRESULT hr;
return;
}
- hr = ipid_get_dispatch_params(&ipid, &apt, ¶ms->stub, ¶ms->chan,
+ hr = ipid_get_dispatch_params(&ipid, &apt, &stub_manager, ¶ms->stub, ¶ms->chan,
¶ms->iid, ¶ms->iface);
if (hr != S_OK)
{
else
{
BOOL joined = FALSE;
- if (!COM_CurrentInfo()->apt)
+ struct oletls *info = COM_CurrentInfo();
+
+ if (!info->apt)
{
- apartment_joinmta();
+ enter_apartment(info, COINIT_MULTITHREADED);
joined = TRUE;
}
RPC_ExecuteCall(params);
if (joined)
{
- apartment_release(COM_CurrentInfo()->apt);
- COM_CurrentInfo()->apt = NULL;
+ leave_apartment(info);
}
}
IRpcStubBuffer_Release(params->stub);
HeapFree(GetProcessHeap(), 0, params);
+ stub_manager_int_release(stub_manager);
apartment_release(apt);
/* if IRpcStubBuffer_Invoke fails, we should raise an exception to tell
* the RPC runtime that the call failed */
- if (hr) RpcRaiseException(hr);
+ if (hr != S_OK) RpcRaiseException(hr);
}
/* stub registration */
}
/* stub unregistration */
-void RPC_UnregisterInterface(REFIID riid)
+void RPC_UnregisterInterface(REFIID riid, BOOL wait)
{
struct registered_if *rif;
EnterCriticalSection(&csRegIf);
{
if (!--rif->refs)
{
- RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, TRUE);
+ RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, wait);
list_remove(&rif->entry);
HeapFree(GetProcessHeap(), 0, rif);
}
/* FIXME: move remote unknown exporting into this function */
}
- start_apartment_remote_unknown();
+ start_apartment_remote_unknown(apt);
}
static const WCHAR embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
HKEY key;
HRESULT hres;
- WCHAR command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)];
+ WCHAR command[MAX_PATH+ARRAY_SIZE(embedding)];
DWORD size = (MAX_PATH+1) * sizeof(WCHAR);
STARTUPINFOW sinfo;
PROCESS_INFORMATION pinfo;
+ LONG ret;
hres = COM_OpenKeyForCLSID(rclsid, wszLocalServer32, KEY_READ, &key);
if (FAILED(hres)) {
return hres;
}
- hres = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size);
+ ret = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size);
RegCloseKey(key);
- if (hres) {
+ if (ret) {
WARN("No default value for LocalServer32 key\n");
return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
}
/* FIXME: Win2003 supports a ServerExecutable value that is passed into
* CreateProcess */
- if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) {
+ if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &sinfo, &pinfo)) {
WARN("failed to run local server %s\n", debugstr_w(command));
return HRESULT_FROM_WIN32(GetLastError());
}
{
static const WCHAR wszPipeRef[] = {'\\','\\','.','\\','p','i','p','e','\\',0};
strcpyW(pipefn, wszPipeRef);
- StringFromGUID2(rclsid, pipefn + sizeof(wszPipeRef)/sizeof(wszPipeRef[0]) - 1, CHARS_IN_GUID);
+ StringFromGUID2(rclsid, pipefn + ARRAY_SIZE(wszPipeRef) - 1, CHARS_IN_GUID);
}
/* FIXME: should call to rpcss instead */
LARGE_INTEGER seekto;
ULARGE_INTEGER newpos;
int tries = 0;
+ IServiceProvider *local_server;
static const int MAXTRIES = 30; /* 30 seconds */
bufferlen = 0;
if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
+ CloseHandle(hPipe);
Sleep(1000);
continue;
}
return E_NOINTERFACE;
hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
- if (hres) return hres;
+ if (hres != S_OK) return hres;
hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
- if (hres) goto out;
+ if (hres != S_OK) goto out;
seekto.u.LowPart = 0;seekto.u.HighPart = 0;
hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos);
- TRACE("unmarshalling classfactory\n");
- hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
+ TRACE("unmarshalling local server\n");
+ hres = CoUnmarshalInterface(pStm, &IID_IServiceProvider, (void**)&local_server);
+ if(SUCCEEDED(hres))
+ hres = IServiceProvider_QueryService(local_server, rclsid, iid, ppv);
+ IServiceProvider_Release(local_server);
out:
IStream_Release(pStm);
return hres;
{
CLSID clsid;
IStream *stream;
- HANDLE ready_event;
+ HANDLE pipe;
HANDLE stop_event;
HANDLE thread;
BOOL multi_use;
ULONG res;
BOOL multi_use = lsp->multi_use;
OVERLAPPED ovl;
- HANDLE pipe_event, hPipe, new_pipe;
+ HANDLE pipe_event, hPipe = lsp->pipe, new_pipe;
DWORD bytes;
TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
get_localserver_pipe_name(pipefn, &lsp->clsid);
ovl.hEvent = pipe_event = CreateEventW(NULL, FALSE, FALSE, NULL);
- hPipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
- 4096, 4096, 500 /* 0.5 second timeout */, NULL );
- if (hPipe == INVALID_HANDLE_VALUE)
- {
- FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
- CloseHandle(pipe_event);
- return 1;
- }
-
- SetEvent(lsp->ready_event);
-
while (1) {
if (!ConnectNamedPipe(hPipe, &ovl))
{
DWORD ret;
ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
if (ret != WAIT_OBJECT_0)
- {
- CloseHandle(hPipe);
break;
- }
}
/* client already connected isn't an error */
else if (error != ERROR_PIPE_CONNECTED)
{
ERR("ConnectNamedPipe failed with error %d\n", GetLastError());
- CloseHandle(hPipe);
break;
}
}
- TRACE("marshalling IClassFactory to client\n");
+ TRACE("marshalling LocalServer to client\n");
hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME);
- if (hres)
- {
- CloseHandle(hPipe);
- CloseHandle(pipe_event);
- return hres;
- }
+ if (hres != S_OK)
+ break;
seekto.u.LowPart = 0;
seekto.u.HighPart = 0;
hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos);
- if (hres) {
+ if (hres != S_OK) {
FIXME("IStream_Seek failed, %x\n",hres);
- CloseHandle(hPipe);
- CloseHandle(pipe_event);
- return hres;
+ break;
}
buflen = ststg.cbSize.u.LowPart;
buffer = HeapAlloc(GetProcessHeap(),0,buflen);
hres = IStream_Read(pStm,buffer,buflen,&res);
- if (hres) {
+ if (hres != S_OK) {
FIXME("Stream Read failed, %x\n",hres);
- CloseHandle(hPipe);
- CloseHandle(pipe_event);
HeapFree(GetProcessHeap(),0,buffer);
- return hres;
+ break;
}
WriteFile(hPipe,buffer,buflen,&res,&ovl);
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
- TRACE("done marshalling IClassFactory\n");
+ TRACE("done marshalling LocalServer\n");
if (!multi_use)
{
TRACE("single use object, shutting down pipe %s\n", debugstr_w(pipefn));
- CloseHandle(hPipe);
break;
}
new_pipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
4096, 4096, 500 /* 0.5 second timeout */, NULL );
- CloseHandle(hPipe);
if (new_pipe == INVALID_HANDLE_VALUE)
{
FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
- CloseHandle(pipe_event);
- return 1;
+ break;
}
+ CloseHandle(hPipe);
hPipe = new_pipe;
}
+
CloseHandle(pipe_event);
+ CloseHandle(hPipe);
return 0;
}
/* starts listening for a local server */
HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration)
{
- DWORD tid;
+ DWORD tid, err;
struct local_server_params *lsp;
+ WCHAR pipefn[100];
lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
if (!lsp)
lsp->clsid = *clsid;
lsp->stream = stream;
IStream_AddRef(stream);
- lsp->ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
- if (!lsp->ready_event)
- {
- HeapFree(GetProcessHeap(), 0, lsp);
- return HRESULT_FROM_WIN32(GetLastError());
- }
lsp->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!lsp->stop_event)
{
- CloseHandle(lsp->ready_event);
HeapFree(GetProcessHeap(), 0, lsp);
return HRESULT_FROM_WIN32(GetLastError());
}
lsp->multi_use = multi_use;
+ get_localserver_pipe_name(pipefn, &lsp->clsid);
+ lsp->pipe = CreateNamedPipeW(pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
+ 4096, 4096, 500 /* 0.5 second timeout */, NULL);
+ if (lsp->pipe == INVALID_HANDLE_VALUE)
+ {
+ err = GetLastError();
+ FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
+ CloseHandle(lsp->stop_event);
+ HeapFree(GetProcessHeap(), 0, lsp);
+ return HRESULT_FROM_WIN32(err);
+ }
+
lsp->thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
if (!lsp->thread)
{
- CloseHandle(lsp->ready_event);
+ CloseHandle(lsp->pipe);
CloseHandle(lsp->stop_event);
HeapFree(GetProcessHeap(), 0, lsp);
return HRESULT_FROM_WIN32(GetLastError());
}
- WaitForSingleObject(lsp->ready_event, INFINITE);
- CloseHandle(lsp->ready_event);
- lsp->ready_event = NULL;
-
*registration = lsp;
return S_OK;
}