dpnphupnp: Implement Class Factory

Maarten Lankhorst m.b.lankhorst at gmail.com
Sat May 26 07:02:03 CDT 2007


Based on the existing one from qcap, only trimmed down a little.
-------------- next part --------------
>From c0fc1847202a784d73df4c030571470f6e54e935 Mon Sep 17 00:00:00 2001
From: Maarten Lankhorst <m.b.lankhorst at gmail.com>
Date: Sat, 26 May 2007 12:49:37 +0200
Subject: [PATCH 3/4] dpnhupnp: Implement ClassFactory and Dll(Un)RegisterServer

---
 dlls/dpnhupnp/dpnhupnp_main.c |  304 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 296 insertions(+), 8 deletions(-)

diff --git a/dlls/dpnhupnp/dpnhupnp_main.c b/dlls/dpnhupnp/dpnhupnp_main.c
index 51e97fc..d056952 100644
--- a/dlls/dpnhupnp/dpnhupnp_main.c
+++ b/dlls/dpnhupnp/dpnhupnp_main.c
@@ -46,11 +46,27 @@
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(upnp);
+	
+/*
+ * defines and constants
+ */
+#define MAX_KEY_LEN  260
+
+static WCHAR const clsid_keyname[6] = {'C','L','S','I','D',0 };
+static WCHAR const ips32_keyname[15] = {'I','n','P','r','o','c','S','e','r','v','e','r','3','2',0};
+static WCHAR const tmodel_keyname[15] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
+static WCHAR const tmodel_both[] = {'B','o','t','h',0};
+static LONG objects_ref;
+static LONG server_locks;
+/*
+static WCHAR const nathelperupnp[] = { 'D','i','r','e','c','t','P','l','a','y',' ','N','A','T',' ',
+                                       'H','e','l','p','e','r',' ','U','P','n','P',' ','O','b','j','e','c','t',0};
+ */
+
 
 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
 {
     TRACE("(%p, %08x, %p)\n", hInstDLL, fdwReason, lpv);
-
     switch (fdwReason)
     {
         case DLL_PROCESS_ATTACH:
@@ -64,28 +80,300 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
 
 HRESULT WINAPI DllCanUnloadNow(void)
 {
-    FIXME("stub\n");
+    TRACE("\n");
+
+    if (!objects_ref && !server_locks)
+        return S_OK;
     return S_FALSE;
 }
 
+typedef IUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr);
+
+typedef struct tagCFactoryTemplate {
+    const WCHAR *m_Name;
+    const CLSID *m_ClsID;
+    LPFNNewCOMObject m_lpfnNew;
+} CFactoryTemplate;
+
+static CFactoryTemplate const g_cTemplates[] = {
+#if 0
+    {
+        nathelperupnp,
+        &CLSID_DirectPlayNATHelpUPnP,
+        Create_UPNP
+    },
+#endif
+};
+
+static const int g_numTemplates = sizeof(g_cTemplates) / sizeof(g_cTemplates[0]);
+
+typedef struct {
+    IClassFactory ITF_IClassFactory;
+
+    LONG ref;
+    LPFNNewCOMObject pfnCreateInstance;
+} IClassFactoryImpl;
+
+static HRESULT WINAPI
+DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+        IsEqualGUID(riid, &IID_IClassFactory))
+    {
+        IClassFactory_AddRef(iface);
+        *ppobj = This;
+        return S_OK;
+    }
+
+    WARN("(%p)->(%s,%p), not found\n", This, debugstr_guid(riid), ppobj);
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI DSCF_AddRef(LPCLASSFACTORY iface)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    if (ref == 0)
+        HeapFree(GetProcessHeap(), 0, This);
+
+    return ref;
+}
+
+static HRESULT WINAPI DSCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
+                                          REFIID riid, LPVOID *ppobj)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    HRESULT hres = ERROR_SUCCESS;
+    LPUNKNOWN punk;
+
+    TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj);
+
+    if (!ppobj)
+        return E_POINTER;
+
+    /* Enforce the normal OLE rules regarding interfaces and delegation */
+    if (pOuter && !IsEqualGUID(riid, &IID_IUnknown))
+        return E_NOINTERFACE;
+
+    *ppobj = NULL;
+    punk = This->pfnCreateInstance(pOuter, &hres);
+    if (!punk)
+    {
+        /* No object created, update error if it isn't done already and return */
+        if (!FAILED(hres))
+            hres = E_OUTOFMEMORY;
+        return hres;
+    }
+
+    if (SUCCEEDED(hres))
+        hres = IUnknown_QueryInterface(punk, riid, ppobj);
+
+    /* Releasing the object. If everything was successful, QueryInterface
+       should have incremented the refcount once more, otherwise this will
+       purge the object. */
+    IUnknown_Release(punk);
+    return hres;
+}
+
+static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    TRACE("(%p)->(%d)\n",This, dolock);
+
+    if (dolock)
+        InterlockedIncrement(&server_locks);
+    else
+        InterlockedDecrement(&server_locks);
+    return S_OK;
+}
+
+static const IClassFactoryVtbl DSCF_Vtbl =
+{
+    DSCF_QueryInterface,
+    DSCF_AddRef,
+    DSCF_Release,
+    DSCF_CreateInstance,
+    DSCF_LockServer
+};
+
 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
 {
-    FIXME("stub\n");
-    return E_FAIL;
+    const CFactoryTemplate *pList = g_cTemplates;
+    IClassFactoryImpl *factory;
+    int i;
+
+    TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+
+    if (!ppv)
+        return E_POINTER;
+
+    *ppv = NULL;
+
+    if (!IsEqualGUID(&IID_IClassFactory, riid) &&
+        !IsEqualGUID(&IID_IUnknown, riid))
+        return E_NOINTERFACE;
+
+    for (i = 0; i < g_numTemplates; i++, pList++)
+    {
+        if (IsEqualGUID(pList->m_ClsID, rclsid))
+            break;
+    }
+
+    if (i == g_numTemplates)
+    {
+        FIXME("%s: no class found.\n", debugstr_guid(rclsid));
+        return CLASS_E_CLASSNOTAVAILABLE;
+    }
+
+    factory = HeapAlloc(GetProcessHeap(), 0, sizeof(IClassFactoryImpl));
+    if (!factory)
+        return E_OUTOFMEMORY;
+
+    factory->ITF_IClassFactory.lpVtbl = &DSCF_Vtbl;
+    factory->ref = 1;
+
+    factory->pfnCreateInstance = pList->m_lpfnNew;
+
+    *ppv = &(factory->ITF_IClassFactory);
+    return S_OK;
+}
+
+/*
+ * Delete a key and all its subkeys
+ */
+static HRESULT DeleteEntireSubKey(HKEY hkey, LPWSTR strSubKey)
+{
+    WCHAR buffer[MAX_KEY_LEN];
+    DWORD dw = MAX_KEY_LEN;
+    FILETIME ft;
+    HKEY hk;
+    LONG ret = RegOpenKeyExW(hkey, strSubKey, 0, MAXIMUM_ALLOWED, &hk);
+
+    if (ERROR_SUCCESS == ret)
+    {
+        /* Keep on enumerating the first key and deleting that */
+        for( ; ; )
+        {
+            dw = MAX_KEY_LEN;
+
+            ret = RegEnumKeyExW(hk, 0, buffer, &dw, NULL, NULL, NULL, &ft);
+
+            if (ERROR_SUCCESS == ret)
+                DeleteEntireSubKey(hk, buffer);
+            else
+                break;
+        }
+        RegCloseKey(hk);
+        RegDeleteKeyW(hkey, strSubKey);
+    }
+    return NOERROR;
+}
+
+/*
+ * SetupRegisterClass()
+ */
+static HRESULT SetupRegisterClass(HKEY clsid, LPCWSTR szCLSID,
+                                  LPCWSTR szDescription,
+                                  LPCWSTR szFileName,
+                                  LPCWSTR szServerType,
+                                  LPCWSTR szThreadingModel)
+{
+    HKEY hkey, hsubkey = NULL;
+    LONG ret = RegCreateKeyW(clsid, szCLSID, &hkey);
+    if (ERROR_SUCCESS != ret)
+        return HRESULT_FROM_WIN32(ret);
+
+    /* set description string */
+    ret = RegSetValueW(hkey, NULL, REG_SZ, szDescription,
+                       sizeof(WCHAR) * (lstrlenW(szDescription) + 1));
+    if (ERROR_SUCCESS != ret)
+        goto err_out;
+
+    /* create CLSID\\{"CLSID"}\\"ServerType" key, using key to CLSID\\{"CLSID"}
+       passed back by last call to RegCreateKeyW(). */
+    ret = RegCreateKeyW(hkey,  szServerType, &hsubkey);
+    if (ERROR_SUCCESS != ret)
+        goto err_out;
+
+    /* set server path */
+    ret = RegSetValueW(hsubkey, NULL, REG_SZ, szFileName,
+                       sizeof(WCHAR) * (lstrlenW(szFileName) + 1));
+    if (ERROR_SUCCESS != ret)
+        goto err_out;
+
+    /* set threading model */
+    ret = RegSetValueExW(hsubkey, tmodel_keyname, 0L, REG_SZ,
+                         (const BYTE*)szThreadingModel, 
+                         sizeof(WCHAR) * (lstrlenW(szThreadingModel) + 1));
+err_out:
+    if (hsubkey)
+        RegCloseKey(hsubkey);
+    RegCloseKey(hkey);
+    return HRESULT_FROM_WIN32(ret);
+}
+
+/****************************************************************************
+ * SetupRegisterServers
+ *
+ * This function is table driven using the static members of the
+ * CFactoryTemplate class defined in the Dll.
+ *
+ * It registers the Dll as the InprocServer32 for all the classes in
+ * CFactoryTemplate
+ *
+ ****************************************************************************/
+static HRESULT SetupRegisterServers(const CFactoryTemplate * pList, int num,
+                             BOOL bRegister)
+{
+    static const WCHAR szFileName[] = {'d','p','n','h','u','p','n','p','.','d','l','l', 0};
+    HRESULT hr = NOERROR;
+    HKEY hkey;
+    OLECHAR szCLSID[CHARS_IN_GUID];
+    LONG i, ret;
+    ret = RegCreateKeyW(HKEY_CLASSES_ROOT, clsid_keyname, &hkey);
+    if (ret != ERROR_SUCCESS)
+        return HRESULT_FROM_WIN32(ret);
+
+    for (i = 0; i < num; i++, pList++)
+    {
+        /* (un)register CLSID and InprocServer32 */
+        hr = StringFromGUID2(pList->m_ClsID, szCLSID, CHARS_IN_GUID);
+        if (SUCCEEDED(hr))
+        {
+            if (bRegister )
+                hr = SetupRegisterClass(hkey, szCLSID,
+                                        pList->m_Name, szFileName,
+                                        ips32_keyname, tmodel_both);
+            else
+                hr = DeleteEntireSubKey(hkey, szCLSID);
+        }
+    }
+    RegCloseKey(hkey);
+    return hr;
 }
 
 HRESULT WINAPI DllRegisterServer(void)
 {
-    FIXME("stub\n");
+    TRACE("()\n");
 
-    return S_FALSE;
+    return SetupRegisterServers(g_cTemplates, g_numTemplates, TRUE);
 }
 
 HRESULT WINAPI DllUnregisterServer(void)
 {
-    FIXME("stub\n");
+    TRACE("\n");
 
-    return S_FALSE;
+    return SetupRegisterServers(g_cTemplates, g_numTemplates, FALSE);
 }
 
 HRESULT WINAPI DirectPlayNATHelpCreate(const LPGUID pIID, void ** ppvInterface)
-- 
1.4.4.2



More information about the wine-patches mailing list