Skip to content

Commit

Permalink
ShellExt: Add shortcut (*.lnk) handling
Browse files Browse the repository at this point in the history
  • Loading branch information
cjee21 committed Jan 4, 2025
1 parent 9f136c2 commit 8967b36
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 2 deletions.
77 changes: 75 additions & 2 deletions Source/WindowsShellExtension/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,63 @@ 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];
WCHAR szDescription[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<LPVOID*>(&psl));
if (SUCCEEDED(hres)) {
IPersistFile* ppf = nullptr;
// Get a pointer to the IPersistFile interface.
hres = psl->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&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<WIN32_FIND_DATA*>(&wfd), SLGP_SHORTPATH);
if (SUCCEEDED(hres)) {
// Get the description of the target.
hres = psl->GetDescription(szDescription, MAX_PATH);
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<ExplorerCommandHandler, IExplorerCommand> {
Expand Down Expand Up @@ -352,7 +409,16 @@ struct ExplorerCommandHandler : public winrt::implements<ExplorerCommandHandler,
wil::unique_cotaskmem_string path;
if (SUCCEEDED(item->GetDisplayName(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());
}
}
}
Expand Down Expand Up @@ -435,8 +501,15 @@ struct ExplorerCommandHandler : public winrt::implements<ExplorerCommandHandler,
wil::unique_cotaskmem_string path;
result = item->GetDisplayName(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<std::wstring>(LR"-(%s %s)-", command.c_str(), QuoteForCommandLineArg(path.get()).c_str());
command = wil::str_printf<std::wstring>(LR"-(%s %s)-", command.c_str(), QuoteForCommandLineArg(filepath.wstring()).c_str());
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions Source/WindowsShellExtension/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <filesystem>
#include <string>

#include <strsafe.h>

#include <shlobj_core.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
Expand Down

0 comments on commit 8967b36

Please sign in to comment.