From 6fe69b538c7e4e32c2b05ca6cce7bdc05137c672 Mon Sep 17 00:00:00 2001 From: cjee21 <77721854+cjee21@users.noreply.github.com> Date: Sat, 4 Jan 2025 19:03:15 +0800 Subject: [PATCH] ShellExt: Add shortcut (*.lnk) handling --- Source/WindowsShellExtension/dllmain.cpp | 72 +++++++++++++++++++++++- Source/WindowsShellExtension/pch.h | 2 + 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/Source/WindowsShellExtension/dllmain.cpp b/Source/WindowsShellExtension/dllmain.cpp index 11688be9a..bcad537ae 100644 --- a/Source/WindowsShellExtension/dllmain.cpp +++ b/Source/WindowsShellExtension/dllmain.cpp @@ -297,6 +297,58 @@ namespace { }; return std::any_of(supported_extensions.begin(), supported_extensions.end(), [extension](const std::string& extension_iter) {return (extension_iter.compare(extension) == 0); }); } + + // ResolveIt - Uses the Shell's IShellLink and IPersistFile interfaces + // to retrieve the path and description from an existing shortcut. + // Adapted from: https://learn.microsoft.com/en-us/windows/win32/shell/links#resolving-a-shortcut + // + // Returns the result of calling the member functions of the interfaces. + // + // Parameters: + // hwnd - A handle to the parent window. The Shell uses this window to + // display a dialog box if it needs to prompt the user for more + // information while resolving the link. + // lpszLinkFile - Address of a buffer that contains the path of the link, + // including the file name. + // lpszPath - Address of a buffer that receives the path of the link + // target, including the file name. + HRESULT ResolveIt(_In_opt_ HWND hwnd, _In_ LPCWSTR lpszLinkFile, _Out_ LPWSTR lpszPath, _In_ int iPathBufferSize) { + HRESULT hres; + IShellLink* psl = nullptr; + WCHAR szGotPath[MAX_PATH]; + WIN32_FIND_DATA wfd{}; + + *lpszPath = 0; // Assume failure + + // Get a pointer to the IShellLink interface. It is assumed that CoInitialize + // has already been called. + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, reinterpret_cast(&psl)); + if (SUCCEEDED(hres)) { + IPersistFile* ppf = nullptr; + // Get a pointer to the IPersistFile interface. + hres = psl->QueryInterface(IID_IPersistFile, reinterpret_cast(&ppf)); + if (SUCCEEDED(hres)) { + // Load the shortcut. + hres = ppf->Load(lpszLinkFile, STGM_READ); + if (SUCCEEDED(hres)) { + // Resolve the link. + hres = psl->Resolve(hwnd, 0); + if (SUCCEEDED(hres)) { + // Get the path to the link target. + hres = psl->GetPath(szGotPath, MAX_PATH, reinterpret_cast(&wfd), SLGP_SHORTPATH); + if (SUCCEEDED(hres)) { + hres = StringCbCopy(lpszPath, iPathBufferSize, szGotPath); + } + } + } + // Release the pointer to the IPersistFile interface. + ppf->Release(); + } + // Release the pointer to the IShellLink interface. + psl->Release(); + } + return hres; + } } struct ExplorerCommandHandler : public winrt::implements { @@ -352,7 +404,16 @@ struct ExplorerCommandHandler : public winrt::implementsGetDisplayName(SIGDN_FILESYSPATH, &path))) { std::filesystem::path filepath = path.get(); - is_supported_extension = IsSupportedFileExtension(filepath.extension().string()); + // resolve shortcuts + if (filepath.extension().string().compare(".lnk") == 0) { + WCHAR target_path[MAX_PATH]; + if (SUCCEEDED(ResolveIt(nullptr, filepath.wstring().c_str(), target_path, sizeof(target_path)))) + filepath = target_path; + } + if (std::filesystem::is_directory(filepath)) + is_folder = true; + else + is_supported_extension = IsSupportedFileExtension(filepath.extension().string()); } } } @@ -435,8 +496,15 @@ struct ExplorerCommandHandler : public winrt::implementsGetDisplayName(SIGDN_FILESYSPATH, &path); if (SUCCEEDED(result)) { + std::filesystem::path filepath = path.get(); + // Resolve shortcuts + if (filepath.extension().string().compare(".lnk") == 0) { + WCHAR target_path[MAX_PATH]; + if (SUCCEEDED(ResolveIt(nullptr, filepath.wstring().c_str(), target_path, sizeof(target_path)))) + filepath = target_path; + } // Append the item path to the existing command, adding quotes and escapes as needed - command = wil::str_printf(LR"-(%s %s)-", command.c_str(), QuoteForCommandLineArg(path.get()).c_str()); + command = wil::str_printf(LR"-(%s %s)-", command.c_str(), QuoteForCommandLineArg(filepath.wstring()).c_str()); } } } diff --git a/Source/WindowsShellExtension/pch.h b/Source/WindowsShellExtension/pch.h index 17677c3d0..634b3cc89 100644 --- a/Source/WindowsShellExtension/pch.h +++ b/Source/WindowsShellExtension/pch.h @@ -13,6 +13,8 @@ #include #include +#include + #include #include #pragma comment(lib, "shlwapi.lib")