diff --git a/QuickLook.Native/QuickLook.Native32/DllExport.cpp b/QuickLook.Native/QuickLook.Native32/DllExport.cpp
index 29c669b..aab249b 100644
--- a/QuickLook.Native/QuickLook.Native32/DllExport.cpp
+++ b/QuickLook.Native/QuickLook.Native32/DllExport.cpp
@@ -21,6 +21,7 @@
#include "WoW64HookHelper.h"
#include "DOpus.h"
#include "MultiCommander.h"
+#include "IDMan.h"
#define EXPORT extern "C" __declspec(dllexport)
diff --git a/QuickLook.Native/QuickLook.Native32/IDMan.cpp b/QuickLook.Native/QuickLook.Native32/IDMan.cpp
new file mode 100644
index 0000000..801996a
--- /dev/null
+++ b/QuickLook.Native/QuickLook.Native32/IDMan.cpp
@@ -0,0 +1,268 @@
+// Copyright © 2017-2026 QL-Win Contributors
+//
+// This file is part of QuickLook program.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#include "stdafx.h"
+#include "IDMan.h"
+#include
+
+#pragma comment(lib, "UIAutomationCore.lib")
+
+void IDMan::GetSelected(PWCHAR buffer)
+{
+ // Step 1: Get the selected item name from the IDM list via UIAutomation
+ WCHAR selectedName[MAX_PATH] = { L'\0' };
+ if (!GetSelectedItemName(selectedName))
+ return;
+
+ // Step 2: Resolve the file path from the IDM registry
+ GetFilePath(selectedName, buffer);
+}
+
+bool IDMan::GetSelectedItemName(PWCHAR nameBuffer)
+{
+ HWND hwnd = GetForegroundWindow();
+ if (hwnd == nullptr)
+ return false;
+
+ IUIAutomation* pAutomation = nullptr;
+ HRESULT hr = CoCreateInstance(
+ __uuidof(CUIAutomation8),
+ nullptr,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(IUIAutomation),
+ reinterpret_cast(&pAutomation));
+
+ if (FAILED(hr))
+ {
+ // Fallback to older interface
+ hr = CoCreateInstance(
+ __uuidof(CUIAutomation),
+ nullptr,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(IUIAutomation),
+ reinterpret_cast(&pAutomation));
+ if (FAILED(hr))
+ return false;
+ }
+
+ // Get UIAutomation element from the IDM window handle
+ IUIAutomationElement* pIDMWindow = nullptr;
+ hr = pAutomation->ElementFromHandle(hwnd, &pIDMWindow);
+ if (FAILED(hr) || pIDMWindow == nullptr)
+ {
+ pAutomation->Release();
+ return false;
+ }
+
+ // Build OR condition: DataGrid || List
+ IUIAutomationCondition* pDataGridCond = nullptr;
+ VARIANT varDataGrid;
+ VariantInit(&varDataGrid);
+ varDataGrid.vt = VT_I4;
+ varDataGrid.intVal = UIA_DataGridControlTypeId;
+ pAutomation->CreatePropertyCondition(UIA_ControlTypePropertyId, varDataGrid, &pDataGridCond);
+
+ IUIAutomationCondition* pListCond = nullptr;
+ VARIANT varList;
+ VariantInit(&varList);
+ varList.vt = VT_I4;
+ varList.intVal = UIA_ListControlTypeId;
+ pAutomation->CreatePropertyCondition(UIA_ControlTypePropertyId, varList, &pListCond);
+
+ IUIAutomationCondition* pOrCond = nullptr;
+ pAutomation->CreateOrCondition(pDataGridCond, pListCond, &pOrCond);
+ pDataGridCond->Release();
+ pListCond->Release();
+
+ // Find the list view (DataGrid or List) inside the IDM window
+ IUIAutomationElement* pListView = nullptr;
+ pIDMWindow->FindFirst(TreeScope_Descendants, pOrCond, &pListView);
+ pOrCond->Release();
+ pIDMWindow->Release();
+
+ if (pListView == nullptr)
+ {
+ pAutomation->Release();
+ return false;
+ }
+
+ // Enumerate all children and find the selected item
+ IUIAutomationCondition* pTrueCond = nullptr;
+ pAutomation->CreateTrueCondition(&pTrueCond);
+
+ IUIAutomationElementArray* pChildren = nullptr;
+ pListView->FindAll(TreeScope_Children, pTrueCond, &pChildren);
+ pTrueCond->Release();
+ pListView->Release();
+
+ if (pChildren == nullptr)
+ {
+ pAutomation->Release();
+ return false;
+ }
+
+ bool found = false;
+ int count = 0;
+ pChildren->get_Length(&count);
+
+ for (int i = 0; i < count && !found; i++)
+ {
+ IUIAutomationElement* pItem = nullptr;
+ if (SUCCEEDED(pChildren->GetElement(i, &pItem)) && pItem != nullptr)
+ {
+ IUIAutomationSelectionItemPattern* pSelPattern = nullptr;
+ if (SUCCEEDED(pItem->GetCurrentPatternAs(
+ UIA_SelectionItemPatternId,
+ __uuidof(IUIAutomationSelectionItemPattern),
+ reinterpret_cast(&pSelPattern))) &&
+ pSelPattern != nullptr)
+ {
+ BOOL isSelected = FALSE;
+ pSelPattern->get_CurrentIsSelected(&isSelected);
+ pSelPattern->Release();
+
+ if (isSelected)
+ {
+ BSTR name = nullptr;
+ if (SUCCEEDED(pItem->get_CurrentName(&name)) && name != nullptr)
+ {
+ wcscpy_s(nameBuffer, MAX_PATH, name);
+ SysFreeString(name);
+ found = true;
+ }
+ }
+ }
+ pItem->Release();
+ }
+ }
+
+ pChildren->Release();
+ pAutomation->Release();
+ return found;
+}
+
+void IDMan::GetFilePath(PCWSTR name, PWCHAR buffer)
+{
+ // Extract the file extension (e.g. ".mp4")
+ WCHAR ext[64] = { L'\0' };
+ const WCHAR* dot = wcsrchr(name, L'.');
+ if (dot != nullptr)
+ wcscpy_s(ext, dot);
+
+ // Read the default download path from LocalPathW (stored as raw Unicode bytes)
+ WCHAR defaultPath[MAX_PATH] = { L'\0' };
+ {
+ HKEY hBase = nullptr;
+ if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\DownloadManager", 0, KEY_READ, &hBase) == ERROR_SUCCESS)
+ {
+ BYTE data[MAX_PATH * sizeof(WCHAR)] = {};
+ DWORD dataSize = sizeof(data);
+ DWORD dataType = 0;
+ if (RegQueryValueExW(hBase, L"LocalPathW", nullptr, &dataType, data, &dataSize) == ERROR_SUCCESS)
+ {
+ if (dataType == REG_BINARY)
+ wcsncpy_s(defaultPath, MAX_PATH, reinterpret_cast(data), dataSize / sizeof(WCHAR));
+ else if (dataType == REG_SZ)
+ wcsncpy_s(defaultPath, MAX_PATH, reinterpret_cast(data), MAX_PATH - 1);
+ }
+ RegCloseKey(hBase);
+ }
+ }
+
+ // Try to match extension against FoldersTree entries
+ if (ext[0] != L'\0')
+ {
+ HKEY hFolders = nullptr;
+ if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\DownloadManager\\FoldersTree", 0, KEY_READ, &hFolders) == ERROR_SUCCESS)
+ {
+ WCHAR subKeyName[MAX_PATH] = { L'\0' };
+ DWORD subKeyIdx = 0;
+ while (RegEnumKeyW(hFolders, subKeyIdx++, subKeyName, MAX_PATH) == ERROR_SUCCESS)
+ {
+ HKEY hSub = nullptr;
+ if (RegOpenKeyExW(hFolders, subKeyName, 0, KEY_READ, &hSub) == ERROR_SUCCESS)
+ {
+ WCHAR maskValue[512] = { L'\0' };
+ DWORD maskSize = sizeof(maskValue);
+ if (RegQueryValueExW(hSub, L"mask", nullptr, nullptr, reinterpret_cast(maskValue), &maskSize) == ERROR_SUCCESS)
+ {
+ // maskValue is space-delimited list of extensions without dots (e.g. "mp4 mkv avi")
+ WCHAR* ctx = nullptr;
+ WCHAR* tok = wcstok_s(maskValue, L" ", &ctx);
+ while (tok != nullptr)
+ {
+ WCHAR tokExt[64] = L".";
+ wcscat_s(tokExt, tok);
+ if (_wcsicmp(tokExt, ext) == 0)
+ {
+ // Compose: defaultPath\subKeyName\filename
+ swprintf_s(buffer, MAX_PATH_EX, L"%s\\%s\\%s", defaultPath, subKeyName, name);
+ RegCloseKey(hSub);
+ RegCloseKey(hFolders);
+ return;
+ }
+ tok = wcstok_s(nullptr, L" ", &ctx);
+ }
+ }
+ RegCloseKey(hSub);
+ }
+ }
+ RegCloseKey(hFolders);
+ }
+
+ // Extension not in FoldersTree — use the default download folder
+ if (defaultPath[0] != L'\0')
+ {
+ swprintf_s(buffer, MAX_PATH_EX, L"%s\\%s", defaultPath, name);
+ return;
+ }
+ }
+
+ // Fallback: search individual download entries in the registry for FR_FNCD match
+ HKEY hBase = nullptr;
+ if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\DownloadManager", 0, KEY_READ, &hBase) == ERROR_SUCCESS)
+ {
+ WCHAR subKeyName[MAX_PATH] = { L'\0' };
+ DWORD subKeyIdx = 0;
+ while (RegEnumKeyW(hBase, subKeyIdx++, subKeyName, MAX_PATH) == ERROR_SUCCESS)
+ {
+ HKEY hSub = nullptr;
+ if (RegOpenKeyExW(hBase, subKeyName, 0, KEY_READ, &hSub) == ERROR_SUCCESS)
+ {
+ WCHAR frFncd[MAX_PATH] = { L'\0' };
+ DWORD frSize = sizeof(frFncd);
+ if (RegQueryValueExW(hSub, L"FR_FNCD", nullptr, nullptr, reinterpret_cast(frFncd), &frSize) == ERROR_SUCCESS)
+ {
+ if (_wcsicmp(frFncd, name) == 0)
+ {
+ WCHAR localFileName[MAX_PATH_EX] = { L'\0' };
+ DWORD lfSize = sizeof(localFileName);
+ if (RegQueryValueExW(hSub, L"LocalFileName", nullptr, nullptr, reinterpret_cast(localFileName), &lfSize) == ERROR_SUCCESS)
+ {
+ wcscpy_s(buffer, MAX_PATH_EX, localFileName);
+ RegCloseKey(hSub);
+ RegCloseKey(hBase);
+ return;
+ }
+ }
+ }
+ RegCloseKey(hSub);
+ }
+ }
+ RegCloseKey(hBase);
+ }
+}
diff --git a/QuickLook.Native/QuickLook.Native32/IDMan.h b/QuickLook.Native/QuickLook.Native32/IDMan.h
new file mode 100644
index 0000000..529420b
--- /dev/null
+++ b/QuickLook.Native/QuickLook.Native32/IDMan.h
@@ -0,0 +1,30 @@
+// Copyright © 2017-2026 QL-Win Contributors
+//
+// This file is part of QuickLook program.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#pragma once
+
+#include "stdafx.h"
+
+class IDMan
+{
+public:
+ static void GetSelected(PWCHAR buffer);
+
+private:
+ static bool GetSelectedItemName(PWCHAR nameBuffer);
+ static void GetFilePath(PCWSTR name, PWCHAR buffer);
+};
diff --git a/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.vcxproj b/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.vcxproj
index b2484e9..96c595b 100644
--- a/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.vcxproj
+++ b/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.vcxproj
@@ -218,6 +218,7 @@
+
@@ -251,6 +252,7 @@
+
diff --git a/QuickLook.Native/QuickLook.Native32/Shell32.cpp b/QuickLook.Native/QuickLook.Native32/Shell32.cpp
index dfbebd3..88b1e81 100644
--- a/QuickLook.Native/QuickLook.Native32/Shell32.cpp
+++ b/QuickLook.Native/QuickLook.Native32/Shell32.cpp
@@ -23,6 +23,7 @@
#include "Everything.h"
#include "DOpus.h"
#include "MultiCommander.h"
+#include "IDMan.h"
using namespace std;
@@ -65,6 +66,13 @@ Shell32::FocusedWindowType Shell32::GetFocusedWindowType()
}
if (wcscmp(classBuffer, L"#32770") == 0)
{
+ WCHAR titleBuffer[512] = { L'\0' };
+ GetWindowText(hwndfg, titleBuffer, 512);
+ if (wcsncmp(titleBuffer, L"Internet Download Manager", 25) == 0)
+ {
+ return IDM;
+ }
+
if (FindWindowEx(hwndfg, nullptr, L"DUIViewWndClassName", nullptr) != nullptr)
{
if (!HelperMethods::IsExplorerSearchBoxFocused())
@@ -99,6 +107,9 @@ void Shell32::GetCurrentSelection(PWCHAR buffer)
case MULTICOMMANDER:
MultiCommander::GetSelected(buffer);
break;
+ case IDM:
+ IDMan::GetSelected(buffer);
+ break;
default:
break;
}
diff --git a/QuickLook.Native/QuickLook.Native32/Shell32.h b/QuickLook.Native/QuickLook.Native32/Shell32.h
index 82bf1d4..857bc83 100644
--- a/QuickLook.Native/QuickLook.Native32/Shell32.h
+++ b/QuickLook.Native/QuickLook.Native32/Shell32.h
@@ -31,6 +31,7 @@ public:
EVERYTHING,
DOPUS,
MULTICOMMANDER,
+ IDM,
};
static FocusedWindowType GetFocusedWindowType();
diff --git a/QuickLook.Native/QuickLook.Native64/QuickLook.Native64.vcxproj b/QuickLook.Native/QuickLook.Native64/QuickLook.Native64.vcxproj
index b39735d..4398e41 100644
--- a/QuickLook.Native/QuickLook.Native64/QuickLook.Native64.vcxproj
+++ b/QuickLook.Native/QuickLook.Native64/QuickLook.Native64.vcxproj
@@ -52,6 +52,7 @@
+
diff --git a/QuickLook.Native/QuickLook.NativeArm64/QuickLook.NativeArm64.vcxproj b/QuickLook.Native/QuickLook.NativeArm64/QuickLook.NativeArm64.vcxproj
index 9f864e8..5f47059 100644
--- a/QuickLook.Native/QuickLook.NativeArm64/QuickLook.NativeArm64.vcxproj
+++ b/QuickLook.Native/QuickLook.NativeArm64/QuickLook.NativeArm64.vcxproj
@@ -38,6 +38,7 @@
+
diff --git a/QuickLook/NativeMethods/QuickLook.cs b/QuickLook/NativeMethods/QuickLook.cs
index 7e5a22b..614bd16 100644
--- a/QuickLook/NativeMethods/QuickLook.cs
+++ b/QuickLook/NativeMethods/QuickLook.cs
@@ -151,6 +151,7 @@ internal static class QuickLook
Dialog,
Everything,
DOpus,
- MultiCommander
+ MultiCommander,
+ IDM,
}
}