[PATCH v4 1/3] shell32: Add ShellLinkObject stubs.

Myah Caron qsniyg at protonmail.com
Mon Sep 14 10:05:32 CDT 2020


Signed-off-by: Myah Caron <qsniyg at protonmail.com>
---
v4:
 - Remove shell_link and persist_file from the structure.
   shell_link is added back in #2.

 dlls/shell32/shell32_main.h        |   1 +
 dlls/shell32/shelldispatch.c       | 263 ++++++++++++++++++++++++++++-
 dlls/shell32/tests/shelldispatch.c | 149 ++++++++++++++++
 3 files changed, 412 insertions(+), 1 deletion(-)

diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h
index 11a96309e8b..3465a3c8445 100644
--- a/dlls/shell32/shell32_main.h
+++ b/dlls/shell32/shell32_main.h
@@ -222,6 +222,7 @@ enum tid_t {
     FolderItems3_tid,
     FolderItemVerb_tid,
     FolderItemVerbs_tid,
+    IShellLinkDual2_tid,
     LAST_tid
 };

diff --git a/dlls/shell32/shelldispatch.c b/dlls/shell32/shelldispatch.c
index c6d1dab7f62..afe1348bdec 100644
--- a/dlls/shell32/shelldispatch.c
+++ b/dlls/shell32/shelldispatch.c
@@ -51,7 +51,8 @@ static const IID * const tid_ids[] =
     &IID_FolderItem2,
     &IID_FolderItems3,
     &IID_FolderItemVerb,
-    &IID_FolderItemVerbs
+    &IID_FolderItemVerbs,
+    &IID_IShellLinkDual2
 };
 static ITypeInfo *typeinfos[LAST_tid];

@@ -102,6 +103,11 @@ typedef struct {
     BSTR name;
 } FolderItemVerbImpl;

+typedef struct {
+    IShellLinkDual2 IShellLinkDual2_iface;
+    LONG ref;
+} ShellLinkObjectImpl;
+
 static inline ShellDispatch *impl_from_IShellDispatch6(IShellDispatch6 *iface)
 {
     return CONTAINING_RECORD(iface, ShellDispatch, IShellDispatch6_iface);
@@ -132,6 +138,11 @@ static inline FolderItemVerbImpl *impl_from_FolderItemVerb(FolderItemVerb *iface
     return CONTAINING_RECORD(iface, FolderItemVerbImpl, FolderItemVerb_iface);
 }

+static inline ShellLinkObjectImpl *impl_from_IShellLinkDual(IShellLinkDual2 *iface)
+{
+    return CONTAINING_RECORD(iface, ShellLinkObjectImpl, IShellLinkDual2_iface);
+}
+
 static HRESULT load_typelib(void)
 {
     ITypeLib *tl;
@@ -617,6 +628,256 @@ failed:
     return hr;
 }

+static HRESULT WINAPI ShellLinkObject_QueryInterface(IShellLinkDual2 *iface, REFIID riid,
+        LPVOID *ppv)
+{
+    ShellLinkObjectImpl *This = impl_from_IShellLinkDual(iface);
+
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, riid) ||
+        IsEqualIID(&IID_IDispatch, riid) ||
+        IsEqualIID(&IID_IShellLinkDual, riid) ||
+        IsEqualIID(&IID_IShellLinkDual2, riid))
+        *ppv = &This->IShellLinkDual2_iface;
+    else
+    {
+        WARN("not implemented for %s\n", debugstr_guid(riid));
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI ShellLinkObject_AddRef(IShellLinkDual2 *iface)
+{
+    ShellLinkObjectImpl *This = impl_from_IShellLinkDual(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p), new refcount=%i\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI ShellLinkObject_Release(IShellLinkDual2 *iface)
+{
+    ShellLinkObjectImpl *This = impl_from_IShellLinkDual(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p), new refcount=%i\n", iface, ref);
+
+    if (!ref)
+    {
+        heap_free(This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI ShellLinkObject_GetTypeInfoCount(IShellLinkDual2 *iface, UINT *pctinfo)
+{
+    TRACE("(%p,%p)\n", iface, pctinfo);
+
+    *pctinfo = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI ShellLinkObject_GetTypeInfo(IShellLinkDual2 *iface, UINT iTInfo,
+        LCID lcid, ITypeInfo **ppTInfo)
+{
+    HRESULT hr;
+
+    TRACE("(%p,%u,%d,%p)\n", iface, iTInfo, lcid, ppTInfo);
+
+    hr = get_typeinfo(IShellLinkDual2_tid, ppTInfo);
+    if (SUCCEEDED(hr))
+        ITypeInfo_AddRef(*ppTInfo);
+
+    return hr;
+}
+
+static HRESULT WINAPI ShellLinkObject_GetIDsOfNames(IShellLinkDual2 *iface, REFIID riid,
+        LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
+{
+    ITypeInfo *ti;
+    HRESULT hr;
+
+    TRACE("(%p,%s,%p,%u,%d,%p)\n", iface, shdebugstr_guid(riid), rgszNames, cNames, lcid,
+            rgDispId);
+
+    hr = get_typeinfo(IShellLinkDual2_tid, &ti);
+    if (SUCCEEDED(hr))
+        hr = ITypeInfo_GetIDsOfNames(ti, rgszNames, cNames, rgDispId);
+    return hr;
+}
+
+static HRESULT WINAPI ShellLinkObject_Invoke(IShellLinkDual2 *iface, DISPID dispIdMember,
+        REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
+        VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+    ShellLinkObjectImpl *This = impl_from_IShellLinkDual(iface);
+    ITypeInfo *ti;
+    HRESULT hr;
+
+    TRACE("(%p,%d,%s,%d,%u,%p,%p,%p,%p)\n", iface, dispIdMember, shdebugstr_guid(riid), lcid,
+            wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+
+    hr = get_typeinfo(IShellLinkDual2_tid, &ti);
+    if (SUCCEEDED(hr))
+        hr = ITypeInfo_Invoke(ti, This, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+    return hr;
+}
+
+static HRESULT WINAPI ShellLinkObject_get_Path(IShellLinkDual2 *iface, BSTR *pbs)
+{
+    FIXME("(%p, %p)\n", iface, pbs);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_put_Path(IShellLinkDual2 *iface, BSTR bs)
+{
+    FIXME("(%p, %s)\n", iface, debugstr_w(bs));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_get_Description(IShellLinkDual2 *iface, BSTR *pbs)
+{
+    FIXME("(%p, %p)\n", iface, pbs);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_put_Description(IShellLinkDual2 *iface, BSTR bs)
+{
+    FIXME("(%p, %s)\n", iface, debugstr_w(bs));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_get_WorkingDirectory(IShellLinkDual2 *iface, BSTR *pbs)
+{
+    FIXME("(%p, %p)\n", iface, pbs);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_put_WorkingDirectory(IShellLinkDual2 *iface, BSTR bs)
+{
+    FIXME("(%p, %s)\n", iface, debugstr_w(bs));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_get_Arguments(IShellLinkDual2 *iface, BSTR *pbs)
+{
+    FIXME("(%p, %p)\n", iface, pbs);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_put_Arguments(IShellLinkDual2 *iface, BSTR bs)
+{
+    FIXME("(%p, %s)\n", iface, debugstr_w(bs));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_get_Hotkey(IShellLinkDual2 *iface, int *piHK)
+{
+    FIXME("(%p, %p)\n", iface, piHK);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_put_Hotkey(IShellLinkDual2 *iface, int iHK)
+{
+    FIXME("(%p, %d)\n", iface, iHK);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_get_ShowCommand(IShellLinkDual2 *iface, int *piShowCommand)
+{
+    FIXME("(%p, %p)\n", iface, piShowCommand);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_put_ShowCommand(IShellLinkDual2 *iface, int iShowCommand)
+{
+    FIXME("(%p, %d)\n", iface, iShowCommand);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_Resolve(IShellLinkDual2 *iface, int fFlags)
+{
+    FIXME("(%p, %d)\n", iface, fFlags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_GetIconLocation(IShellLinkDual2 *iface, BSTR *pbs,
+                                                      int *piIcon)
+{
+    FIXME("(%p, %p, %p)\n", iface, pbs, piIcon);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_SetIconLocation(IShellLinkDual2 *iface, BSTR bs,
+                                                      int iIcon)
+{
+    FIXME("(%p, %s, %d)\n", iface, debugstr_w(bs), iIcon);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_Save(IShellLinkDual2 *iface, VARIANT vWhere)
+{
+    FIXME("(%p, %s)\n", iface, debugstr_variant(&vWhere));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ShellLinkObject_get_Target(IShellLinkDual2 *iface, FolderItem **ppfi)
+{
+    FIXME("(%p, %p)\n", iface, ppfi);
+
+    return E_NOTIMPL;
+}
+
+static const IShellLinkDual2Vtbl ShellLinkObjectVtbl = {
+    ShellLinkObject_QueryInterface,
+    ShellLinkObject_AddRef,
+    ShellLinkObject_Release,
+    ShellLinkObject_GetTypeInfoCount,
+    ShellLinkObject_GetTypeInfo,
+    ShellLinkObject_GetIDsOfNames,
+    ShellLinkObject_Invoke,
+    ShellLinkObject_get_Path,
+    ShellLinkObject_put_Path,
+    ShellLinkObject_get_Description,
+    ShellLinkObject_put_Description,
+    ShellLinkObject_get_WorkingDirectory,
+    ShellLinkObject_put_WorkingDirectory,
+    ShellLinkObject_get_Arguments,
+    ShellLinkObject_put_Arguments,
+    ShellLinkObject_get_Hotkey,
+    ShellLinkObject_put_Hotkey,
+    ShellLinkObject_get_ShowCommand,
+    ShellLinkObject_put_ShowCommand,
+    ShellLinkObject_Resolve,
+    ShellLinkObject_GetIconLocation,
+    ShellLinkObject_SetIconLocation,
+    ShellLinkObject_Save,
+    ShellLinkObject_get_Target,
+};
+
 static HRESULT WINAPI FolderItemImpl_QueryInterface(FolderItem2 *iface,
         REFIID riid, LPVOID *ppv)
 {
diff --git a/dlls/shell32/tests/shelldispatch.c b/dlls/shell32/tests/shelldispatch.c
index 54957875615..28b0b186b8e 100644
--- a/dlls/shell32/tests/shelldispatch.c
+++ b/dlls/shell32/tests/shelldispatch.c
@@ -1408,6 +1408,154 @@ if (0) { /* crashes on winxp/win2k3 */
     IShellDispatch_Release(sd);
 }

+static void test_ShellLinkObject(void)
+{
+    HRESULT hr;
+    IShellDispatch *sd;
+    WCHAR path[MAX_PATH],
+        empty_path[MAX_PATH],
+        link_path[MAX_PATH];
+    VARIANT v;
+    Folder2 *folder2;
+    Folder *folder;
+    FolderItem *item;
+    IDispatch *dispatch;
+    IShellLinkW *sl;
+    IShellLinkDual2* sld;
+    IPersistFile *pf;
+    BOOL ret;
+    BSTR str;
+    HANDLE file;
+    int hk;
+
+    hr = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
+        &IID_IShellDispatch, (void**)&sd);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    GetTempPathW(MAX_PATH, path);
+    V_VT(&v) = VT_BSTR;
+    V_BSTR(&v) = SysAllocString(path);
+    hr = IShellDispatch_NameSpace(sd, v, &folder);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    VariantClear(&v);
+
+    hr = Folder_QueryInterface(folder, &IID_Folder2, (void**)&folder2);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    Folder_Release(folder);
+
+    hr = Folder2_get_Self(folder2, &item);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    dispatch = (IDispatch*)0xdeadbeef;
+    hr = FolderItem_get_GetLink(item, &dispatch);
+    ok(hr == E_NOTIMPL, "got 0x%08x\n", hr);
+    ok(dispatch == NULL, "got %p\n", dispatch);
+
+    FolderItem_Release(item);
+
+    PathCombineW(empty_path, path, L"winetest_empty_file.txt");
+    file = CreateFileW(empty_path, 0, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %08x\n", GetLastError());
+    CloseHandle(file);
+
+    hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    hr = IShellLinkW_SetPath(sl, empty_path);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    hr = IShellLinkW_GetPath(sl, empty_path, MAX_PATH, NULL, 0);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    hr = IShellLinkW_SetDescription(sl, L"description");
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    hr = IShellLinkW_SetWorkingDirectory(sl, L"working directory");
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    hr = IShellLinkW_SetArguments(sl, L"arguments");
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    hr = IShellLinkW_SetHotkey(sl, 1234);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    hr = IShellLinkW_SetShowCmd(sl, 1);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = IShellLinkW_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    PathCombineW(link_path, path, L"winetest_filled.lnk");
+    hr = IPersistFile_Save(pf, link_path, TRUE);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    IPersistFile_Release(pf);
+    IShellLinkW_Release(sl);
+
+    str = SysAllocString(L"winetest_filled.lnk");
+    hr = Folder2_ParseName(folder2, str, &item);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    SysFreeString(str);
+
+    dispatch = NULL;
+    hr = FolderItem_get_GetLink(item, &dispatch);
+    todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
+    todo_wine ok(dispatch != NULL, "got %p\n", dispatch);
+
+    if (dispatch) {
+        sld = (IShellLinkDual2*)dispatch;
+
+        str = NULL;
+        hr = IShellLinkDual2_get_Path(sld, &str);
+        todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
+        if (hr == S_OK) {
+            ok(!wcscmp(str, empty_path), "got %s (wanted %s)\n",
+               wine_dbgstr_w(str), wine_dbgstr_w(empty_path));
+            SysFreeString(str);
+        }
+
+        str = NULL;
+        hr = IShellLinkDual2_get_Description(sld, &str);
+        todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
+        if (hr == S_OK) {
+            ok(!wcscmp(str, L"description"), "got %s\n", wine_dbgstr_w(str));
+            SysFreeString(str);
+        }
+
+        str = NULL;
+        hr = IShellLinkDual2_get_WorkingDirectory(sld, &str);
+        todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
+        if (hr == S_OK) {
+            ok(!wcscmp(str, L"working directory"), "got %s\n", wine_dbgstr_w(str));
+            SysFreeString(str);
+        }
+
+        str = NULL;
+        hr = IShellLinkDual2_get_Arguments(sld, &str);
+        todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
+        if (hr == S_OK) {
+            ok(!wcscmp(str, L"arguments"), "got %s\n", wine_dbgstr_w(str));
+            SysFreeString(str);
+        }
+
+        hk = 0;
+        hr = IShellLinkDual2_get_Hotkey(sld, &hk);
+        todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
+        todo_wine ok(hk == 1234, "got %i\n", hk);
+
+        hk = 0;
+        hr = IShellLinkDual2_get_ShowCommand(sld, &hk);
+        todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
+        todo_wine ok(hk == 1, "got %i\n", hk);
+
+        IShellLinkDual2_Release(sld);
+    }
+
+    FolderItem_Release(item);
+
+    ret = DeleteFileW(link_path);
+    ok(ret, "DeleteFile failed: %08x\n", GetLastError());
+    ret = DeleteFileW(empty_path);
+    ok(ret, "DeleteFile failed: %08x\n", GetLastError());
+
+    Folder2_Release(folder2);
+
+    IShellDispatch_Release(sd);
+}
+
 static void test_ShellExecute(void)
 {
     HRESULT hr;
@@ -1466,6 +1614,7 @@ START_TEST(shelldispatch)
     test_ShellWindows();
     test_ParseName();
     test_Verbs();
+    test_ShellLinkObject();
     test_ShellExecute();

     CoUninitialize();
--
2.28.0





More information about the wine-devel mailing list