OLE32: allows COM to start services containing COM servers
Mike McCormack
mike at codeweavers.com
Sun Jan 2 23:57:16 CST 2005
In Windows NT, a COM server can be started via the Service API as well
as just in a seperate process. This patch allows COM to start services
containing COM servers.
Mike
ChangeLog:
* allows COM to start services containing COM servers
-------------- next part --------------
Index: dlls/ole32/rpc.c
===================================================================
RCS file: /home/wine/wine/dlls/ole32/rpc.c,v
retrieving revision 1.35
diff -u -r1.35 rpc.c
--- dlls/ole32/rpc.c 27 Dec 2004 19:27:57 -0000 1.35
+++ dlls/ole32/rpc.c 3 Jan 2005 05:47:54 -0000
@@ -33,6 +33,7 @@
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
+#include "winsvc.h"
#include "objbase.h"
#include "ole2.h"
#include "rpc.h"
@@ -571,6 +572,116 @@
return S_OK;
}
+
+/*
+ * start_local_service() - start a service given its name and parameters
+ */
+static DWORD
+start_local_service(LPCWSTR name, DWORD num, LPWSTR *params)
+{
+ SC_HANDLE handle, hsvc;
+ DWORD r = ERROR_FUNCTION_FAILED;
+
+ TRACE("Starting service %s %ld params\n", debugstr_w(name), num);
+
+ handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (!handle)
+ return r;
+ hsvc = OpenServiceW(handle, name, SC_MANAGER_ALL_ACCESS);
+ if (hsvc)
+ {
+ if(StartServiceW(hsvc, num, (LPCWSTR*)params))
+ r = ERROR_SUCCESS;
+ else
+ r = GetLastError();
+ if (r==ERROR_SERVICE_ALREADY_RUNNING)
+ r = ERROR_SUCCESS;
+ CloseServiceHandle(hsvc);
+ }
+ CloseServiceHandle(handle);
+
+ TRACE("StartService returned error %ld (%s)\n", r, r?"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 = REGDB_E_READREGDB;
+ WCHAR buf[40], keyname[50];
+ static const WCHAR szClsId[] = { 'C','L','S','I','D','\\',0 };
+ static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
+ static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
+ 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));
+
+ /* read the AppID value under the class's key */
+ strcpyW(keyname,szClsId);
+ StringFromGUID2(rclsid,&keyname[6],39);
+ r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey);
+ if (r!=ERROR_SUCCESS)
+ return hres;
+ sz = sizeof buf;
+ r = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &sz);
+ RegCloseKey(hkey);
+ if (r!=ERROR_SUCCESS || type!=REG_SZ)
+ return hres;
+
+ /* read the LocalService and ServiceParameters values from the AppID key */
+ strcpyW(keyname, szAppIdKey);
+ strcatW(keyname, buf);
+ r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey);
+ if (r!=ERROR_SUCCESS)
+ return hres;
+ 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, args);
+ if (r==ERROR_SUCCESS)
+ hres = S_OK;
+ HeapFree(GetProcessHeap(),0,args[0]);
+ }
+ RegCloseKey(hkey);
+
+ return hres;
+}
+
/* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */
HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) {
HRESULT hres;
@@ -604,7 +715,8 @@
);
if (hPipe == INVALID_HANDLE_VALUE) {
if (tries == 1) {
- if ((hres = create_server(rclsid)))
+ if ( (hres = create_server(rclsid)) &&
+ (hres = create_local_service(rclsid)) )
return hres;
Sleep(1000);
} else {
More information about the wine-patches
mailing list