[PATCH 6/6] ole32: Implement MkParseDisplayName.

Robert Shearman rob at codeweavers.com
Tue Mar 27 12:21:23 CDT 2007


---
  dlls/ole32/classmoniker.c  |   83 ++++++++++++++++++++++++++++++-
  dlls/ole32/compobj.c       |    2 +
  dlls/ole32/filemoniker.c   |  100 +++++++++++++++++++++++++++++++++++++
  dlls/ole32/moniker.c       |  119 
+++++++++++++++++++++++++++++++++++++++++++-
  dlls/ole32/moniker.h       |    5 ++
  dlls/ole32/tests/moniker.c |   18 +++----
  6 files changed, 314 insertions(+), 13 deletions(-)
-------------- next part --------------
diff --git a/dlls/ole32/classmoniker.c b/dlls/ole32/classmoniker.c
index 66677d6..07db622 100644
--- a/dlls/ole32/classmoniker.c
+++ b/dlls/ole32/classmoniker.c
@@ -2,7 +2,7 @@
  *	                      Class Monikers
  *
  *           Copyright 1999  Noomen Hamza
- *           Copyright 2005  Robert Shearman
+ *           Copyright 2005-2007  Robert Shearman
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -734,6 +734,87 @@ HRESULT WINAPI CreateClassMoniker(REFCLS
     return ClassMoniker_QueryInterface((IMoniker *)newClassMoniker, &IID_IMoniker, (void**)ppmk);
 }
 
+HRESULT ClassMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
+                                           LPDWORD pchEaten, LPMONIKER *ppmk)
+{
+    HRESULT hr;
+    LPCWSTR s = strchrW(szDisplayName, ':');
+    LPCWSTR end;
+    CLSID clsid;
+    BYTE table[256];
+    int i;
+
+    if (!s)
+        return MK_E_SYNTAX;
+
+    s++;
+
+    for (end = s; *end && (*end != ':'); end++)
+        ;
+
+    TRACE("parsing %s\n", debugstr_wn(s, end - s));
+
+    /* validate the CLSID string */
+    if (s[0] == '{')
+    {
+        if ((end - s != 38) || (s[37] != '}'))
+            return MK_E_SYNTAX;
+        s++;
+    }
+    else
+    {
+        if (end - s != 36)
+            return MK_E_SYNTAX;
+    }
+
+    for (i=0; i<36; i++)
+    {
+        if ((i == 8)||(i == 13)||(i == 18)||(i == 23))
+        {
+            if (s[i] != '-')
+                return MK_E_SYNTAX;
+            continue;
+        }
+        if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
+              ((s[i] >= 'a') && (s[i] <= 'f'))  ||
+              ((s[i] >= 'A') && (s[i] <= 'F'))))
+            return MK_E_SYNTAX;
+    }
+
+    /* quick lookup table */
+    memset(table, 0, 256);
+
+    for (i = 0; i < 10; i++)
+        table['0' + i] = i;
+    for (i = 0; i < 6; i++)
+    {
+        table['A' + i] = i+10;
+        table['a' + i] = i+10;
+    }
+
+    /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */
+
+    clsid.Data1 = (table[s[0]] << 28 | table[s[1]] << 24 | table[s[2]] << 20 | table[s[3]] << 16 |
+                   table[s[4]] << 12 | table[s[5]] << 8  | table[s[6]] << 4  | table[s[7]]);
+    clsid.Data2 = table[s[9]] << 12  | table[s[10]] << 8 | table[s[11]] << 4 | table[s[12]];
+    clsid.Data3 = table[s[14]] << 12 | table[s[15]] << 8 | table[s[16]] << 4 | table[s[17]];
+
+    /* these are just sequential bytes */
+    clsid.Data4[0] = table[s[19]] << 4 | table[s[20]];
+    clsid.Data4[1] = table[s[21]] << 4 | table[s[22]];
+    clsid.Data4[2] = table[s[24]] << 4 | table[s[25]];
+    clsid.Data4[3] = table[s[26]] << 4 | table[s[27]];
+    clsid.Data4[4] = table[s[28]] << 4 | table[s[29]];
+    clsid.Data4[5] = table[s[30]] << 4 | table[s[31]];
+    clsid.Data4[6] = table[s[32]] << 4 | table[s[33]];
+    clsid.Data4[7] = table[s[34]] << 4 | table[s[35]];
+
+    hr = CreateClassMoniker(&clsid, ppmk);
+    if (SUCCEEDED(hr))
+        *pchEaten = (*end == ':' ? end + 1 : end) - szDisplayName;
+    return hr;
+}
+
 static HRESULT WINAPI ClassMonikerCF_QueryInterface(LPCLASSFACTORY iface,
                                                   REFIID riid, LPVOID *ppv)
 {
diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c
index ec37043..28bd184 100644
--- a/dlls/ole32/compobj.c
+++ b/dlls/ole32/compobj.c
@@ -1246,6 +1246,7 @@ HRESULT WINAPI CLSIDFromProgID(LPCOLESTR
     if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
     {
         HeapFree(GetProcessHeap(),0,buf);
+        WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
         return CO_E_CLASSSTRING;
     }
     HeapFree(GetProcessHeap(),0,buf);
@@ -1253,6 +1254,7 @@ HRESULT WINAPI CLSIDFromProgID(LPCOLESTR
     if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
     {
         RegCloseKey(xhkey);
+        WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
         return CO_E_CLASSSTRING;
     }
     RegCloseKey(xhkey);
diff --git a/dlls/ole32/filemoniker.c b/dlls/ole32/filemoniker.c
index 562c92f..7578836 100644
--- a/dlls/ole32/filemoniker.c
+++ b/dlls/ole32/filemoniker.c
@@ -2,6 +2,7 @@
  * FileMonikers implementation
  *
  * Copyright 1999  Noomen Hamza
+ * Copyright 2007  Robert Shearman
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -1405,6 +1406,105 @@ HRESULT WINAPI CreateFileMoniker(LPCOLES
     return hr;
 }
 
+/* find a character from a set in reverse without the string having to be null-terminated */
+static inline WCHAR *memrpbrkW(const WCHAR *ptr, size_t n, const WCHAR *accept)
+{
+    const WCHAR *end, *ret = NULL;
+    for (end = ptr + n; ptr < end; ptr++) if (strchrW(accept, *ptr)) ret = ptr;
+    return (WCHAR *)ret;
+}
+
+HRESULT FileMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
+                                          LPDWORD pchEaten, LPMONIKER *ppmk)
+{
+    LPCWSTR end;
+    static const WCHAR wszSeparators[] = {':','\\','/','!',0};
+
+    for (end = szDisplayName + strlenW(szDisplayName);
+         end && (end != szDisplayName);
+         end = memrpbrkW(szDisplayName, end - szDisplayName, wszSeparators))
+    {
+        HRESULT hr;
+        IRunningObjectTable *rot;
+        IMoniker *file_moniker;
+        LPWSTR file_display_name;
+        LPWSTR full_path_name;
+        DWORD full_path_name_len;
+        int len = end - szDisplayName;
+
+        file_display_name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+        if (!file_display_name) return E_OUTOFMEMORY;
+        memcpy(file_display_name, szDisplayName, len * sizeof(WCHAR));
+        file_display_name[len] = '\0';
+
+        hr = CreateFileMoniker(file_display_name, &file_moniker);
+        if (FAILED(hr))
+        {
+            HeapFree(GetProcessHeap(), 0, file_display_name);
+            return hr;
+        }
+
+        hr = IBindCtx_GetRunningObjectTable(pbc, &rot);
+        if (FAILED(hr))
+        {
+            HeapFree(GetProcessHeap(), 0, file_display_name);
+            IMoniker_Release(file_moniker);
+            return hr;
+        }
+
+        hr = IRunningObjectTable_IsRunning(rot, file_moniker);
+        IRunningObjectTable_Release(rot);
+        if (FAILED(hr))
+        {
+            HeapFree(GetProcessHeap(), 0, file_display_name);
+            IMoniker_Release(file_moniker);
+            return hr;
+        }
+        if (hr == S_OK)
+        {
+            TRACE("found running file moniker for %s\n", debugstr_w(file_display_name));
+            *pchEaten = len;
+            *ppmk = file_moniker;
+            HeapFree(GetProcessHeap(), 0, file_display_name);
+            return S_OK;
+        }
+
+        full_path_name_len = GetFullPathNameW(file_display_name, 0, NULL, NULL);
+        if (!full_path_name_len)
+        {
+            HeapFree(GetProcessHeap(), 0, file_display_name);
+            IMoniker_Release(file_moniker);
+            return MK_E_SYNTAX;
+        }
+        full_path_name = HeapAlloc(GetProcessHeap(), 0, full_path_name_len * sizeof(WCHAR));
+        if (!full_path_name)
+        {
+            HeapFree(GetProcessHeap(), 0, file_display_name);
+            IMoniker_Release(file_moniker);
+            return E_OUTOFMEMORY;
+        }
+        GetFullPathNameW(file_display_name, full_path_name_len, full_path_name, NULL);
+
+        if (GetFileAttributesW(full_path_name) == INVALID_FILE_ATTRIBUTES)
+            TRACE("couldn't open file %s\n", debugstr_w(full_path_name));
+        else
+        {
+            TRACE("got file moniker for %s\n", debugstr_w(szDisplayName));
+            *pchEaten = len;
+            *ppmk = file_moniker;
+            HeapFree(GetProcessHeap(), 0, file_display_name);
+            HeapFree(GetProcessHeap(), 0, full_path_name);
+            return S_OK;
+        }
+        HeapFree(GetProcessHeap(), 0, file_display_name);
+        HeapFree(GetProcessHeap(), 0, full_path_name);
+        IMoniker_Release(file_moniker);
+    }
+
+    return MK_E_CANTOPENFILE;
+}
+
+
 static HRESULT WINAPI FileMonikerCF_QueryInterface(LPCLASSFACTORY iface,
                                                   REFIID riid, LPVOID *ppv)
 {
diff --git a/dlls/ole32/moniker.c b/dlls/ole32/moniker.c
index 99ab450..a4d2a5e 100644
--- a/dlls/ole32/moniker.c
+++ b/dlls/ole32/moniker.c
@@ -4,6 +4,7 @@
  *	Copyright 1998	Marcus Meissner
  *      Copyright 1999  Noomen Hamza
  *      Copyright 2005  Robert Shearman (for CodeWeavers)
+ *      Copyright 2007  Robert Shearman
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -43,6 +44,7 @@ #include "wine/debug.h"
 #include "wine/unicode.h"
 
 #include "compobj_private.h"
+#include "moniker.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 
@@ -826,18 +828,129 @@ GetRunningObjectTable(DWORD reserved, LP
     return res;
 }
 
+static HRESULT get_moniker_for_progid_display_name(LPBC pbc,
+                                                   LPCOLESTR szDisplayName,
+                                                   LPDWORD pchEaten,
+                                                   LPMONIKER *ppmk)
+{
+    CLSID clsid;
+    HRESULT hr;
+    LPWSTR progid;
+    LPCWSTR start = szDisplayName;
+    LPCWSTR end;
+    int len;
+    IMoniker *class_moniker;
+
+    if (*start == '@')
+        start++;
+
+    /* find end delimiter */
+    for (end = start; *end; end++)
+        if (*end == ':')
+            break;
+
+    len = end - start;
+
+    /* must start with '@' or have a ':' somewhere and mustn't be one character
+     * long (since that looks like an absolute path) */
+    if (((start == szDisplayName) && (*end == '\0')) || (len <= 1))
+        return MK_E_SYNTAX;
+
+    progid = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+    if (progid)
+    {
+        memcpy(progid, start, len * sizeof(WCHAR));
+        progid[len] = '\0';
+    }
+    hr = CLSIDFromProgID(progid, &clsid);
+    HeapFree(GetProcessHeap(), 0, progid);
+    if (FAILED(hr))
+        return MK_E_SYNTAX;
+
+    hr = CreateClassMoniker(&clsid, &class_moniker);
+    if (SUCCEEDED(hr))
+    {
+        IParseDisplayName *pdn;
+        hr = IMoniker_BindToObject(class_moniker, pbc, NULL,
+                                   &IID_IParseDisplayName, (void **)&pdn);
+        IMoniker_Release(class_moniker);
+        if (SUCCEEDED(hr))
+        {
+            hr = IParseDisplayName_ParseDisplayName(pdn, pbc,
+                                                    (LPOLESTR)szDisplayName,
+                                                    pchEaten, ppmk);
+            IParseDisplayName_Release(pdn);
+        }
+    }
+    return hr;
+}
+
 /******************************************************************************
  *              MkParseDisplayName        [OLE32.@]
  */
-HRESULT WINAPI MkParseDisplayName(LPBC pbc, LPCOLESTR szUserName,
+HRESULT WINAPI MkParseDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
 				LPDWORD pchEaten, LPMONIKER *ppmk)
 {
-    FIXME("(%p, %s, %p, %p): stub.\n", pbc, debugstr_w(szUserName), pchEaten, *ppmk);
+    HRESULT hr = MK_E_SYNTAX;
+    static const WCHAR wszClsidColon[] = {'c','l','s','i','d',':'};
+    IMoniker *moniker;
+    DWORD chEaten;
+
+    TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(szDisplayName), pchEaten, ppmk);
 
     if (!(IsValidInterface((LPUNKNOWN) pbc)))
         return E_INVALIDARG;
 
-    return MK_E_SYNTAX;
+    *pchEaten = 0;
+    *ppmk = NULL;
+
+    if (!strncmpiW(szDisplayName, wszClsidColon, sizeof(wszClsidColon)/sizeof(wszClsidColon[0])))
+    {
+        hr = ClassMoniker_CreateFromDisplayName(pbc, szDisplayName, &chEaten, &moniker);
+        if (FAILED(hr) && (hr != MK_E_SYNTAX))
+            return hr;
+    }
+    else
+    {
+        hr = get_moniker_for_progid_display_name(pbc, szDisplayName, &chEaten, &moniker);
+        if (FAILED(hr) && (hr != MK_E_SYNTAX))
+            return hr;
+    }
+
+    if (FAILED(hr))
+    {
+        hr = FileMoniker_CreateFromDisplayName(pbc, szDisplayName, &chEaten, &moniker);
+        if (FAILED(hr) && (hr != MK_E_SYNTAX))
+            return hr;
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        while (TRUE)
+        {
+            IMoniker *next_moniker;
+            *pchEaten += chEaten;
+            szDisplayName += chEaten;
+            if (!*szDisplayName)
+            {
+                *ppmk = moniker;
+                return S_OK;
+            }
+            chEaten = 0;
+            hr = IMoniker_ParseDisplayName(moniker, pbc, NULL,
+                                           (LPOLESTR)szDisplayName, &chEaten,
+                                           &next_moniker);
+            IMoniker_Release(moniker);
+            if (FAILED(hr))
+            {
+                *pchEaten = 0;
+                break;
+            }
+            moniker = next_moniker;
+        }
+    }
+
+    return hr;
 }
 
 /***********************************************************************
diff --git a/dlls/ole32/moniker.h b/dlls/ole32/moniker.h
index fa009cf..3398b0e 100644
--- a/dlls/ole32/moniker.h
+++ b/dlls/ole32/moniker.h
@@ -35,6 +35,11 @@ HRESULT AntiMonikerCF_Create(REFIID riid
 HRESULT CompositeMonikerCF_Create(REFIID riid, LPVOID *ppv);
 HRESULT ClassMonikerCF_Create(REFIID riid, LPVOID *ppv);
 
+HRESULT FileMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
+                                          LPDWORD pchEaten, LPMONIKER *ppmk);
+HRESULT ClassMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
+                                           LPDWORD pchEaten, LPMONIKER *ppmk);
+
 HRESULT MonikerMarshal_Create(IMoniker *inner, IUnknown **outer);
 
 
diff --git a/dlls/ole32/tests/moniker.c b/dlls/ole32/tests/moniker.c
index 3319961..544cedf 100644
--- a/dlls/ole32/tests/moniker.c
+++ b/dlls/ole32/tests/moniker.c
@@ -777,12 +777,12 @@ static void test_MkParseDisplayName(void
     ok_ole_success(hr, CreateBindCtx);
 
     hr = MkParseDisplayName(pbc, wszNonExistantProgId, &eaten, &pmk);
-    todo_wine { ok(hr == MK_E_CANTOPENFILE, "MkParseDisplayName should have failed with MK_E_CANTOPENFILE instead of 0x%08x\n", hr); }
+    ok(hr == MK_E_CANTOPENFILE, "MkParseDisplayName should have failed with MK_E_CANTOPENFILE instead of 0x%08x\n", hr);
 
     /* no special handling of "clsid:" without the string form of the clsid
      * following */
     hr = MkParseDisplayName(pbc, wszDisplayNameClsid, &eaten, &pmk);
-    todo_wine { ok(hr == MK_E_CANTOPENFILE, "MkParseDisplayName should have failed with MK_E_CANTOPENFILE instead of 0x%08x\n", hr); }
+    ok(hr == MK_E_CANTOPENFILE, "MkParseDisplayName should have failed with MK_E_CANTOPENFILE instead of 0x%08x\n", hr);
 
     /* shows clsid has higher precedence than a running object */
     hr = CreateFileMoniker(wszDisplayName, &pmk);
@@ -794,7 +794,7 @@ static void test_MkParseDisplayName(void
     IMoniker_Release(pmk);
     pmk = NULL;
     hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk);
-    todo_wine { ok_ole_success(hr, MkParseDisplayName); }
+    ok_ole_success(hr, MkParseDisplayName);
     if (pmk)
     {
         IMoniker_IsSystemMoniker(pmk, &moniker_type);
@@ -814,7 +814,7 @@ static void test_MkParseDisplayName(void
     IMoniker_Release(pmk);
     pmk = NULL;
     hr = MkParseDisplayName(pbc, wszDisplayNameRunning, &eaten, &pmk);
-    todo_wine { ok_ole_success(hr, MkParseDisplayName); }
+    ok_ole_success(hr, MkParseDisplayName);
     if (pmk)
     {
         IMoniker_IsSystemMoniker(pmk, &moniker_type);
@@ -830,7 +830,7 @@ static void test_MkParseDisplayName(void
 
     expected_display_name = wszDisplayNameProgId1;
     hr = MkParseDisplayName(pbc, wszDisplayNameProgId1, &eaten, &pmk);
-    todo_wine { ok_ole_success(hr, MkParseDisplayName); }
+    ok_ole_success(hr, MkParseDisplayName);
     if (pmk)
     {
         IMoniker_IsSystemMoniker(pmk, &moniker_type);
@@ -840,7 +840,7 @@ static void test_MkParseDisplayName(void
     
     expected_display_name = wszDisplayNameProgId2;
     hr = MkParseDisplayName(pbc, wszDisplayNameProgId2, &eaten, &pmk);
-    todo_wine { ok_ole_success(hr, MkParseDisplayName); }
+    ok_ole_success(hr, MkParseDisplayName);
     if (pmk)
     {
         IMoniker_IsSystemMoniker(pmk, &moniker_type);
@@ -849,7 +849,7 @@ static void test_MkParseDisplayName(void
     }
 
     hr = MkParseDisplayName(pbc, wszDisplayNameProgIdFail, &eaten, &pmk);
-    todo_wine { ok(hr == MK_E_CANTOPENFILE, "MkParseDisplayName with ProgId without marker should fail with MK_E_CANTOPENFILE instead of 0x%08x\n", hr); }
+    ok(hr == MK_E_CANTOPENFILE, "MkParseDisplayName with ProgId without marker should fail with MK_E_CANTOPENFILE instead of 0x%08x\n", hr);
 
     hr = CoRevokeClassObject(pdwReg1);
     ok_ole_success(hr, CoRevokeClassObject);
@@ -858,7 +858,7 @@ static void test_MkParseDisplayName(void
     strcat(szDisplayNameFile, "\\kernel32.dll");
     MultiByteToWideChar(CP_ACP, 0, szDisplayNameFile, -1, wszDisplayNameFile, sizeof(wszDisplayNameFile)/sizeof(wszDisplayNameFile[0]));
     hr = MkParseDisplayName(pbc, wszDisplayNameFile, &eaten, &pmk);
-    todo_wine { ok_ole_success(hr, MkParseDisplayName); }
+    ok_ole_success(hr, MkParseDisplayName);
     if (pmk)
     {
         IMoniker_IsSystemMoniker(pmk, &moniker_type);
@@ -867,7 +867,7 @@ static void test_MkParseDisplayName(void
     }
     
     hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk);
-    todo_wine { ok_ole_success(hr, MkParseDisplayName); }
+    ok_ole_success(hr, MkParseDisplayName);
 
     if (pmk)
     {


More information about the wine-patches mailing list