From f8789122aa7b6ed3894c61b4e74784650abfd0f7 Mon Sep 17 00:00:00 2001 From: Rob Shearman Date: Tue, 27 Mar 2007 18:21:23 +0100 Subject: [PATCH] ole32: Implement MkParseDisplayName. --- 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(-) diff --git a/dlls/ole32/classmoniker.c b/dlls/ole32/classmoniker.c index 66677d65eb9..07db6225b54 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(REFCLSID rclsid, IMoniker **ppmk) 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 ec3704301a8..28bd184d451 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -1246,6 +1246,7 @@ HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid) 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 progid, LPCLSID clsid) 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 562c92f0ad3..7578836dbcf 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(LPCOLESTR lpszPathName, LPMONIKER * ppmk) 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 99ab450efaf..a4d2a5efc59 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/unicode.h" #include "compobj_private.h" +#include "moniker.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -826,18 +828,129 @@ GetRunningObjectTable(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot) 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 fa009cf961f..3398b0ee5c3 100644 --- a/dlls/ole32/moniker.h +++ b/dlls/ole32/moniker.h @@ -35,6 +35,11 @@ HRESULT AntiMonikerCF_Create(REFIID riid, LPVOID *ppv); 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 d71cb260a35..0947b8786b5 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) {