📄 rpc.c
字号:
return S_OK;
}
/* make the apartment reachable by other threads and processes and create the
* IRemUnknown object */
void RPC_StartRemoting(struct apartment *apt)
{
if (!InterlockedExchange(&apt->remoting_started, TRUE))
{
WCHAR endpoint[200];
RPC_STATUS status;
get_rpc_endpoint(endpoint, &apt->oxid);
status = RpcServerUseProtseqEpW(
wszRpcTransport,
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
endpoint,
NULL);
if (status != RPC_S_OK)
ERR("Couldn't register endpoint %s\n", debugstr_w(endpoint));
/* FIXME: move remote unknown exporting into this function */
}
start_apartment_remote_unknown();
}
static HRESULT create_server(REFCLSID rclsid)
{
static const WCHAR wszLocalServer32[] = { 'L','o','c','a','l','S','e','r','v','e','r','3','2',0 };
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)];
DWORD size = (MAX_PATH+1) * sizeof(WCHAR);
STARTUPINFOW sinfo;
PROCESS_INFORMATION pinfo;
hres = COM_OpenKeyForCLSID(rclsid, wszLocalServer32, KEY_READ, &key);
if (FAILED(hres)) {
ERR("class %s not registered\n", debugstr_guid(rclsid));
return hres;
}
hres = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size);
RegCloseKey(key);
if (hres) {
WARN("No default value for LocalServer32 key\n");
return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
}
memset(&sinfo,0,sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
/* EXE servers are started with the -Embedding switch. */
strcatW(command, embedding);
TRACE("activating local server %s for %s\n", debugstr_w(command), debugstr_guid(rclsid));
/* FIXME: Win2003 supports a ServerExecutable value that is passed into
* CreateProcess */
if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) {
WARN("failed to run local server %s\n", debugstr_w(command));
return HRESULT_FROM_WIN32(GetLastError());
}
CloseHandle(pinfo.hProcess);
CloseHandle(pinfo.hThread);
return S_OK;
}
/*
* start_local_service() - start a service given its name and parameters
*/
static DWORD start_local_service(LPCWSTR name, DWORD num, LPCWSTR *params)
{
SC_HANDLE handle, hsvc;
DWORD r = ERROR_FUNCTION_FAILED;
TRACE("Starting service %s %d params\n", debugstr_w(name), num);
handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
if (!handle)
return r;
hsvc = OpenServiceW(handle, name, SERVICE_START);
if (hsvc)
{
if(StartServiceW(hsvc, num, params))
r = ERROR_SUCCESS;
else
r = GetLastError();
if (r == ERROR_SERVICE_ALREADY_RUNNING)
r = ERROR_SUCCESS;
CloseServiceHandle(hsvc);
}
else
r = GetLastError();
CloseServiceHandle(handle);
TRACE("StartService returned error %u (%s)\n", r, (r == ERROR_SUCCESS) ? "ok":"failed");
return r;
}
/*
* create_local_service() - start a COM server in a service
*
* To start a Local Service, we read the AppID value under
* the class's CLSID key, then open the HKCR\\AppId key specified
* there and check for a LocalService value.
*
* Note: Local Services are not supported under Windows 9x
*/
static HRESULT create_local_service(REFCLSID rclsid)
{
HRESULT hres;
WCHAR buf[CHARS_IN_GUID];
static const WCHAR szLocalService[] = { 'L','o','c','a','l','S','e','r','v','i','c','e',0 };
static const WCHAR szServiceParams[] = {'S','e','r','v','i','c','e','P','a','r','a','m','s',0};
HKEY hkey;
LONG r;
DWORD type, sz;
TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid));
hres = COM_OpenKeyForAppIdFromCLSID(rclsid, KEY_READ, &hkey);
if (FAILED(hres))
return hres;
/* read the LocalService and ServiceParameters values from the AppID key */
sz = sizeof buf;
r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz);
if (r==ERROR_SUCCESS && type==REG_SZ)
{
DWORD num_args = 0;
LPWSTR args[1] = { NULL };
/*
* FIXME: I'm not really sure how to deal with the service parameters.
* I suspect that the string returned from RegQueryValueExW
* should be split into a number of arguments by spaces.
* It would make more sense if ServiceParams contained a
* REG_MULTI_SZ here, but it's a REG_SZ for the services
* that I'm interested in for the moment.
*/
r = RegQueryValueExW(hkey, szServiceParams, NULL, &type, NULL, &sz);
if (r == ERROR_SUCCESS && type == REG_SZ && sz)
{
args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz);
num_args++;
RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz);
}
r = start_local_service(buf, num_args, (LPCWSTR *)args);
if (r != ERROR_SUCCESS)
hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
HeapFree(GetProcessHeap(),0,args[0]);
}
else
{
WARN("No LocalService value\n");
hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
}
RegCloseKey(hkey);
return hres;
}
static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid)
{
static const WCHAR wszPipeRef[] = {'\\','\\','.','\\','p','i','p','e','\\',0};
strcpyW(pipefn, wszPipeRef);
StringFromGUID2(rclsid, pipefn + sizeof(wszPipeRef)/sizeof(wszPipeRef[0]) - 1, CHARS_IN_GUID);
}
/* FIXME: should call to rpcss instead */
HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
{
HRESULT hres;
HANDLE hPipe;
WCHAR pipefn[100];
DWORD res, bufferlen;
char marshalbuffer[200];
IStream *pStm;
LARGE_INTEGER seekto;
ULARGE_INTEGER newpos;
int tries = 0;
static const int MAXTRIES = 30; /* 30 seconds */
TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
get_localserver_pipe_name(pipefn, rclsid);
while (tries++ < MAXTRIES) {
TRACE("waiting for %s\n", debugstr_w(pipefn));
WaitNamedPipeW( pipefn, NMPWAIT_WAIT_FOREVER );
hPipe = CreateFileW(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
if (hPipe == INVALID_HANDLE_VALUE) {
if (tries == 1) {
if ( (hres = create_local_service(rclsid)) &&
(hres = create_server(rclsid)) )
return hres;
Sleep(1000);
} else {
WARN("Connecting to %s, no response yet, retrying: le is %u\n", debugstr_w(pipefn), GetLastError());
Sleep(1000);
}
continue;
}
bufferlen = 0;
if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
Sleep(1000);
continue;
}
TRACE("read marshal id from pipe\n");
CloseHandle(hPipe);
break;
}
if (tries >= MAXTRIES)
return E_NOINTERFACE;
hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
if (hres) return hres;
hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
if (hres) goto out;
seekto.u.LowPart = 0;seekto.u.HighPart = 0;
hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
TRACE("unmarshalling classfactory\n");
hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
out:
IStream_Release(pStm);
return hres;
}
struct local_server_params
{
CLSID clsid;
IStream *stream;
HANDLE ready_event;
BOOL multi_use;
HANDLE pipe;
};
/* FIXME: should call to rpcss instead */
static DWORD WINAPI local_server_thread(LPVOID param)
{
struct local_server_params * lsp = (struct local_server_params *)param;
HANDLE hPipe;
WCHAR pipefn[100];
HRESULT hres;
IStream *pStm = lsp->stream;
STATSTG ststg;
unsigned char *buffer;
int buflen;
LARGE_INTEGER seekto;
ULARGE_INTEGER newpos;
ULONG res;
BOOL multi_use = lsp->multi_use;
TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
get_localserver_pipe_name(pipefn, &lsp->clsid);
hPipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
4096, 4096, 500 /* 0.5 second timeout */, NULL );
lsp->pipe = hPipe;
SetEvent(lsp->ready_event);
HeapFree(GetProcessHeap(), 0, lsp);
if (hPipe == INVALID_HANDLE_VALUE)
{
FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
return 1;
}
while (1) {
if (!ConnectNamedPipe(hPipe,NULL))
{
DWORD error = GetLastError();
/* client already connected isn't an error */
if (error != ERROR_PIPE_CONNECTED)
{
/* if error wasn't caused by RPC_StopLocalServer closing the
* pipe for us */
if (error != ERROR_INVALID_HANDLE)
{
ERR("Failure during ConnectNamedPipe %u\n", error);
CloseHandle(hPipe);
}
break;
}
}
TRACE("marshalling IClassFactory to client\n");
hres = IStream_Stat(pStm,&ststg,0);
if (hres) return hres;
seekto.u.LowPart = 0;
seekto.u.HighPart = 0;
hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
if (hres) {
FIXME("IStream_Seek failed, %x\n",hres);
return hres;
}
buflen = ststg.cbSize.u.LowPart;
buffer = HeapAlloc(GetProcessHeap(),0,buflen);
hres = IStream_Read(pStm,buffer,buflen,&res);
if (hres) {
FIXME("Stream Read failed, %x\n",hres);
HeapFree(GetProcessHeap(),0,buffer);
return hres;
}
WriteFile(hPipe,buffer,buflen,&res,NULL);
HeapFree(GetProcessHeap(),0,buffer);
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
TRACE("done marshalling IClassFactory\n");
if (!multi_use)
{
TRACE("single use object, shutting down pipe %s\n", debugstr_w(pipefn));
CloseHandle(hPipe);
break;
}
}
IStream_Release(pStm);
return 0;
}
/* starts listening for a local server */
HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration)
{
DWORD tid;
HANDLE thread, ready_event;
struct local_server_params *lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
lsp->clsid = *clsid;
lsp->stream = stream;
IStream_AddRef(stream);
lsp->ready_event = ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
lsp->multi_use = multi_use;
thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
if (!thread)
return HRESULT_FROM_WIN32(GetLastError());
CloseHandle(thread);
WaitForSingleObject(ready_event, INFINITE);
CloseHandle(ready_event);
*registration = lsp->pipe;
return S_OK;
}
/* stops listening for a local server */
void RPC_StopLocalServer(void *registration)
{
HANDLE pipe = registration;
CloseHandle(pipe);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -