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..cc2e5f8d4 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,217 @@ namespace {
return false;
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{
+ ".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 +385,45 @@ 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() };
+ // 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());
+ }
+ }
+ }
}
}
}
// 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"))
@@ -261,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")
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 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+