From 68e3fb7e6f4d6c51595af69d51fe11552fea9869 Mon Sep 17 00:00:00 2001 From: cjee21 <77721854+cjee21@users.noreply.github.com> Date: Sat, 4 Jan 2025 20:10:15 +0800 Subject: [PATCH 1/2] ShellExt: Move file extensions list from XML to DLL --- Source/WindowsQtPackage/AppxManifest.xml | 463 +----------------- Source/WindowsShellExtension/dllmain.cpp | 190 ++++++- .../MSIX/AppxManifest.xml | 463 +----------------- 3 files changed, 187 insertions(+), 929 deletions(-) diff --git a/Source/WindowsQtPackage/AppxManifest.xml b/Source/WindowsQtPackage/AppxManifest.xml index 3b8bf8941..6b26632a5 100644 --- a/Source/WindowsQtPackage/AppxManifest.xml +++ b/Source/WindowsQtPackage/AppxManifest.xml @@ -35,469 +35,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/Source/WindowsShellExtension/dllmain.cpp b/Source/WindowsShellExtension/dllmain.cpp index 5ea95b1c4..8dcd6ee9d 100644 --- a/Source/WindowsShellExtension/dllmain.cpp +++ b/Source/WindowsShellExtension/dllmain.cpp @@ -82,7 +82,7 @@ namespace { // Extracted from // https://learn.microsoft.com/en-us/archive/msdn-magazine/2017/may/c-use-modern-c-to-access-the-windows-registry#reading-a-dword-value-from-the-registry - DWORD RegGetDword(HKEY hKey, const std::wstring& subKey, const std::wstring& value) { + DWORD RegGetDword(_In_ HKEY hKey, _In_ const std::wstring& subKey, _In_ const std::wstring& value) { DWORD data{}; DWORD dataSize = sizeof(data); LONG retCode = RegGetValue( @@ -101,7 +101,7 @@ namespace { // Adapted from // https://learn.microsoft.com/en-us/archive/msdn-magazine/2017/may/c-use-modern-c-to-access-the-windows-registry#reading-a-string-value-from-the-registry - bool RegGetBool(HKEY hKey, const std::wstring& subKey, const std::wstring& value) { + bool RegGetBool(_In_ HKEY hKey, _In_ const std::wstring& subKey, _In_ const std::wstring& value) { DWORD dataSize{}; LONG retCode = RegGetValue( hKey, @@ -136,6 +136,169 @@ namespace { return false; throw std::runtime_error("Not a boolean."); } + + // Function to check for supported file extensions + bool IsSupportedFileExtension(_In_ const std::string& extension) { + const std::vector supported_extensions{ + ".264", + ".3g2", + ".3ga", + ".3gp", + ".3gpa", + ".3gpp", + ".aa3", + ".aac", + ".aacp", + ".adts", + ".ac3", + ".act", + ".aif", + ".aifc", + ".aiff", + ".amr", + ".ape", + ".asf", + ".at3", + ".au", + ".aud", + ".aue", + ".avi", + ".avif", + ".avs", + ".bdmv", + ".bmp", + ".bms", + ".braw", + ".caf", + ".clpi", + ".dat", + ".dde", + ".divx", + ".dpg", + ".dff", + ".dsd", + ".dsf", + ".dts", + ".dtshd", + ".dv", + ".dvr", + ".dvr-ms", + ".eac3", + ".evo", + ".f4a", + ".f4b", + ".f4v", + ".fla", + ".flc", + ".fli", + ".flac", + ".flv", + ".gvi", + ".gif", + ".gis", + ".h264", + ".h3d", + ".hdmov", + ".heic", + ".heif", + ".iamf", + ".ico", + ".ifo", + ".ism", + ".isma", + ".ismv", + ".j2k", + ".jp2", + ".jpeg", + ".jpg", + ".jps", + ".jxl", + ".m1s", + ".m1t", + ".m1v", + ".m2p", + ".m2s", + ".m2t", + ".m2ts", + ".m2v", + ".m4a", + ".m4b", + ".m4v", + ".mac", + ".mk3d", + ".mka", + ".mks", + ".mkv", + ".mlp", + ".mod", + ".mov", + ".mp+", + ".mp2", + ".mp3", + ".mp4", + ".mpc", + ".mpd", + ".mpe", + ".mpeg", + ".mpg", + ".mpgv", + ".mpgx", + ".mpls", + ".mpm", + ".mpo", + ".mpv", + ".mts", + ".mxf", + ".oga", + ".ogg", + ".ogm", + ".ogv", + ".ogx", + ".oma", + ".opus", + ".png", + ".pns", + ".qcp", + ".qt", + ".ra", + ".rm", + ".rmvb", + ".shn", + ".smv", + ".spdif", + ".spx", + ".stl", + ".swf", + ".tak", + ".thd", + ".thd+ac3", + ".tif", + ".tiff", + ".tmf", + ".tp", + ".trec", + ".trp", + ".ts", + ".tta", + ".ty", + ".vob", + ".vqf", + ".vro", + ".w64", + ".wav", + ".webm", + ".webp", + ".wma", + ".wmv", + ".wtv", + ".wv", + ".wvc", + ".y4m" + }; + std::string extension_lower{ extension }; + std::for_each(extension_lower.begin(), extension_lower.end(), [](char& c) { c = static_cast(tolower(c)); }); + return std::any_of(supported_extensions.begin(), supported_extensions.end(), [extension_lower](const std::string& extension_iter) { return (extension_iter.compare(extension_lower) == 0); }); + } } struct ExplorerCommandHandler : public winrt::implements { @@ -174,23 +337,36 @@ struct ExplorerCommandHandler : public winrt::implementsGetCount(&count)); if (count > 0) { winrt::com_ptr item; if (SUCCEEDED(items->GetItemAt(0, item.put()))) { - SFGAOF attribute = 0; - if (SUCCEEDED(item->GetAttributes(SFGAO_FOLDER, &attribute))) - if (attribute & SFGAO_FOLDER) + SFGAOF attribute{}; + if (SUCCEEDED(item->GetAttributes(SFGAO_FOLDER | SFGAO_STREAM, &attribute))) { + if ((attribute & SFGAO_FOLDER) && !(attribute & SFGAO_STREAM)) is_folder = true; + else { + 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()); + } + } + } } } } // Check for files + if (!is_supported_extension && !is_folder) { + *cmdState = ECS_HIDDEN; + return S_OK; + } try { #ifdef MEDIAINFO_QT if (!RegGetBool(HKEY_CURRENT_USER, L"Software\\MediaArea.net\\MediaInfo", L"shellExtension")) diff --git a/Source/WindowsSparsePackage/MSIX/AppxManifest.xml b/Source/WindowsSparsePackage/MSIX/AppxManifest.xml index c2b373e3d..100f577c7 100644 --- a/Source/WindowsSparsePackage/MSIX/AppxManifest.xml +++ b/Source/WindowsSparsePackage/MSIX/AppxManifest.xml @@ -40,469 +40,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + From cb65a3c75d95d700c5abb1eac2da71f8edb5adbe Mon Sep 17 00:00:00 2001 From: cjee21 <77721854+cjee21@users.noreply.github.com> Date: Sat, 4 Jan 2025 20:31:28 +0800 Subject: [PATCH 2/2] ShellExt: Add shortcut (*.lnk) handling --- Source/WindowsShellExtension/dllmain.cpp | 68 +++++++++++++++++++++++- Source/WindowsShellExtension/pch.h | 2 + 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/Source/WindowsShellExtension/dllmain.cpp b/Source/WindowsShellExtension/dllmain.cpp index 8dcd6ee9d..cc2e5f8d4 100644 --- a/Source/WindowsShellExtension/dllmain.cpp +++ b/Source/WindowsShellExtension/dllmain.cpp @@ -137,6 +137,54 @@ namespace { throw std::runtime_error("Not a boolean."); } + // 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. + _Check_return_ + HRESULT ResolveIt(_In_opt_ HWND hwnd, _In_ LPCWSTR lpszLinkFile, _Out_ LPWSTR lpszPath, _In_ int iPathBufferSize) { + HRESULT hres; + winrt::com_ptr psl; + + *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)) { + winrt::com_ptr ppf; + // 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)) { + WCHAR szGotPath[MAX_PATH]; + // Get the path to the link target. + hres = psl->GetPath(szGotPath, ARRAYSIZE(szGotPath), nullptr, SLGP_RAWPATH); + if (SUCCEEDED(hres)) { + hres = StringCbCopy(lpszPath, iPathBufferSize, szGotPath); + } + } + } + } + } + return hres; + } + // Function to check for supported file extensions bool IsSupportedFileExtension(_In_ const std::string& extension) { const std::vector supported_extensions{ @@ -354,7 +402,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()); } } } @@ -437,8 +494,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")