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