[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