diff --git a/QuickLook.Native/QuickLook.Native32/DialogHook.cpp b/QuickLook.Native/QuickLook.Native32/DialogHook.cpp new file mode 100644 index 0000000..6e875dc --- /dev/null +++ b/QuickLook.Native/QuickLook.Native32/DialogHook.cpp @@ -0,0 +1,131 @@ +#include "stdafx.h" +#include "DialogHook.h" +#include "WoW64HookHelper.h" +#include "HelperMethods.h" + + +#pragma comment(linker, "/SECTION:.shared,RWS") +#pragma data_seg(".shared") + +static HHOOK ghHook = nullptr; // Hook handle +static UINT WM_HOOK_NOTIFY = 0; +static WCHAR filePathBuffer[MAX_PATH] = {'\0'}; + +#pragma data_seg() + +#define SHARED_MEM_NAME L"QUICKLOOK_WOW64HOOKHELPER_MEM" + +void DialogHook::GetSelectedFromCommonDialog(PWCHAR buffer) +{ + auto hwndfg = GetForegroundWindow(); + DWORD pid = 0; + auto tid = GetWindowThreadProcessId(hwndfg, &pid); + + auto hProc = OpenProcess(PROCESS_QUERY_INFORMATION, false, pid); + if (hProc == nullptr) + return; + + if (WM_HOOK_NOTIFY == 0) + WM_HOOK_NOTIFY = RegisterWindowMessage(L"WM_QUICKLOOK_HOOK_NOTIFY_MSG"); + + BOOL isTargetWoW64 = false; + if (GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process") && !IsWow64Process(hProc, &isTargetWoW64)) + return; + + BOOL isSelfWoW64 = false; + if (GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process") && !IsWow64Process(GetCurrentProcess(), &isSelfWoW64)) + return; + + if (isTargetWoW64 && !isSelfWoW64) + { + // if self is 64bit and target is 32bit, do this + GetSelectedFromWoW64HookHelper(buffer); + } + else + { + if (ghHook != nullptr) + UnhookWindowsHookEx(ghHook); + ghHook = SetWindowsHookEx(WH_CALLWNDPROC, static_cast(MsgHookProc), ModuleFromAddress(MsgHookProc), tid); + if (ghHook == nullptr) + return; + + SendMessage(hwndfg, WM_HOOK_NOTIFY, 0, 0); + wcscpy_s(buffer, wcslen(buffer) - 1, filePathBuffer); + } +} + +void DialogHook::getSelectedInternal(CComPtr psb, PWCHAR buffer) +{ + CComPtr psv; + if (FAILED(psb->QueryActiveShellView(&psv))) + return; + + CComPtr dao; + if (FAILED(psv->GetItemObject(SVGIO_SELECTION, IID_IDataObject, reinterpret_cast(&dao)))) + return; + + return HelperMethods::ObtainFirstItem(dao, buffer); +} + +void DialogHook::GetSelectedFromWoW64HookHelper(PWCHAR buffer) +{ + if (!WoW64HookHelper::CheckStatus()) + if (!WoW64HookHelper::Launch()) + return; + + auto hHelperWnd = FindWindowEx(HWND_MESSAGE, nullptr, WoW64HookHelper::GetMsgWindowClassName(), nullptr); + if (hHelperWnd == nullptr) + return; + + auto hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, MAX_PATH * sizeof WCHAR, SHARED_MEM_NAME); + if (hMapFile == nullptr) + return; + + auto sharedBuffer = static_cast(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, MAX_PATH * sizeof WCHAR)); + if (sharedBuffer == nullptr) + { + CloseHandle(hMapFile); + return; + } + + SendMessage(hHelperWnd, WM_HOOK_NOTIFY, 0, 0); + + // the sharedBuffer should now ready + wcscpy_s(buffer, MAX_PATH, sharedBuffer); + + UnmapViewOfFile(sharedBuffer); + CloseHandle(hMapFile); +} + +HMODULE DialogHook::ModuleFromAddress(PVOID pv) +{ + MEMORY_BASIC_INFORMATION mbi; + return VirtualQuery(pv, &mbi, sizeof mbi) != 0 ? static_cast(mbi.AllocationBase) : nullptr; +} + +LRESULT DialogHook::MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (nCode < 0) + goto CONTINUE; + + auto pMSG = reinterpret_cast(lParam); + + // only response to WM_HOOK_NOTIFY + if (pMSG->message != WM_HOOK_NOTIFY) + goto CONTINUE; + + UnhookWindowsHookEx(ghHook); + ghHook = nullptr; + + // get current selected item + auto psb = reinterpret_cast(SendMessage(GetForegroundWindow(), WM_USER + 7, 0, 0)); + if (psb == nullptr) + goto CONTINUE; + + getSelectedInternal(psb, filePathBuffer); + + return 0; + +CONTINUE: + return CallNextHookEx(ghHook, nCode, wParam, lParam); +} diff --git a/QuickLook.Native/QuickLook.Native32/DialogHook.h b/QuickLook.Native/QuickLook.Native32/DialogHook.h new file mode 100644 index 0000000..898dfe0 --- /dev/null +++ b/QuickLook.Native/QuickLook.Native32/DialogHook.h @@ -0,0 +1,12 @@ +#pragma once +class DialogHook +{ +public: + static void GetSelectedFromCommonDialog(PWCHAR buffer); + +private: + static void getSelectedInternal(CComPtr psb, PWCHAR buffer); + static void GetSelectedFromWoW64HookHelper(PWCHAR buffer); + static HMODULE ModuleFromAddress(PVOID pv); + static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam); +}; diff --git a/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.cpp b/QuickLook.Native/QuickLook.Native32/DllExport.cpp similarity index 74% rename from QuickLook.Native/QuickLook.Native32/QuickLook.Native32.cpp rename to QuickLook.Native/QuickLook.Native32/DllExport.cpp index 12bf894..a2e9216 100644 --- a/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.cpp +++ b/QuickLook.Native/QuickLook.Native32/DllExport.cpp @@ -1,9 +1,15 @@ #include "stdafx.h" #include "Shell32.h" +#include "WoW64HookHelper.h" #define EXPORT extern "C" __declspec(dllexport) +EXPORT void LaunchWoW64HookHelper() +{ + WoW64HookHelper::Launch(); +} + EXPORT Shell32::FocusedWindowType GetFocusedWindowType() { return Shell32::GetFocusedWindowType(); diff --git a/QuickLook.Native/QuickLook.Native32/HelperMethods.cpp b/QuickLook.Native/QuickLook.Native32/HelperMethods.cpp new file mode 100644 index 0000000..9ef1ada --- /dev/null +++ b/QuickLook.Native/QuickLook.Native32/HelperMethods.cpp @@ -0,0 +1,56 @@ +#include "stdafx.h" +#include "HelperMethods.h" + +void HelperMethods::GetSelectedInternal(CComQIPtr pwba, PWCHAR buffer) +{ + CComQIPtr psp; + if (FAILED(pwba->QueryInterface(IID_IServiceProvider, reinterpret_cast(&psp)))) + return; + + CComPtr psb; + if (FAILED(psp->QueryService(SID_STopLevelBrowser, IID_IShellBrowser, reinterpret_cast(&psb)))) + return; + + CComPtr psv; + if (FAILED(psb->QueryActiveShellView(&psv))) + return; + + CComPtr dao; + if (FAILED(psv->GetItemObject(SVGIO_SELECTION, IID_IDataObject, reinterpret_cast(&dao)))) + return; + + return ObtainFirstItem(dao, buffer); +} + +void HelperMethods::ObtainFirstItem(CComPtr dao, PWCHAR buffer) +{ + FORMATETC formatetc; + STGMEDIUM medium; + + formatetc.cfFormat = CF_HDROP; + formatetc.ptd = nullptr; + formatetc.dwAspect = DVASPECT_CONTENT; + formatetc.lindex = -1; + formatetc.tymed = TYMED_HGLOBAL; + + medium.tymed = TYMED_HGLOBAL; + + if (FAILED(dao->GetData(&formatetc, &medium))) + return; + + int n = DragQueryFile(HDROP(medium.hGlobal), 0xFFFFFFFF, nullptr, 0); + + if (n < 1) + return; + + DragQueryFile(HDROP(medium.hGlobal), 0, buffer, MAX_PATH - 1); +} + +bool HelperMethods::IsCursorActivated(HWND hwnd) +{ + auto tId = GetWindowThreadProcessId(hwnd, nullptr); + + GUITHREADINFO gui = {sizeof gui}; + GetGUIThreadInfo(tId, &gui); + return gui.flags || gui.hwndCaret; +} diff --git a/QuickLook.Native/QuickLook.Native32/HelperMethods.h b/QuickLook.Native/QuickLook.Native32/HelperMethods.h new file mode 100644 index 0000000..3552afd --- /dev/null +++ b/QuickLook.Native/QuickLook.Native32/HelperMethods.h @@ -0,0 +1,8 @@ +#pragma once +class HelperMethods +{ +public: + static void GetSelectedInternal(CComQIPtr pWebBrowserApp, PWCHAR buffer); + static void ObtainFirstItem(CComPtr dao, PWCHAR buffer); + static bool IsCursorActivated(HWND hwndfg); +}; diff --git a/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.vcxproj b/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.vcxproj index 5052e6e..4a3571a 100644 --- a/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.vcxproj +++ b/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.vcxproj @@ -82,11 +82,15 @@ + + + + false @@ -95,12 +99,14 @@ - + + Create Create + diff --git a/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.vcxproj.filters b/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.vcxproj.filters index e376cd7..bcee8ac 100644 --- a/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.vcxproj.filters +++ b/QuickLook.Native/QuickLook.Native32/QuickLook.Native32.vcxproj.filters @@ -24,6 +24,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + @@ -35,7 +44,16 @@ Source Files - + + Source Files + + + Source Files + + + Source Files + + Source Files diff --git a/QuickLook.Native/QuickLook.Native32/Shell32.cpp b/QuickLook.Native/QuickLook.Native32/Shell32.cpp index 7a7f2bd..c09f3a4 100644 --- a/QuickLook.Native/QuickLook.Native32/Shell32.cpp +++ b/QuickLook.Native/QuickLook.Native32/Shell32.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "Shell32.h" +#include "HelperMethods.h" +#include "DialogHook.h" using namespace std; @@ -10,10 +12,10 @@ Shell32::FocusedWindowType Shell32::GetFocusedWindowType() auto hwndfg = GetForegroundWindow(); - if (isCursorActivated(hwndfg)) + if (HelperMethods::IsCursorActivated(hwndfg)) return INVALID; - auto classBuffer = new WCHAR[MAX_PATH]; + WCHAR classBuffer[MAX_PATH] = {'\0'}; if (SUCCEEDED(GetClassName(hwndfg, classBuffer, MAX_PATH))) { if (wcscmp(classBuffer, L"WorkerW") == 0 || wcscmp(classBuffer, L"Progman") == 0) @@ -35,7 +37,6 @@ Shell32::FocusedWindowType Shell32::GetFocusedWindowType() } } } - delete[] classBuffer; return type; } @@ -51,7 +52,7 @@ void Shell32::GetCurrentSelection(PWCHAR buffer) getSelectedFromExplorer(buffer); break; case DIALOG: - getSelectedFromCommonDialog(buffer); + DialogHook::GetSelectedFromCommonDialog(buffer); break; default: break; @@ -90,10 +91,10 @@ void Shell32::getSelectedFromExplorer(PWCHAR buffer) if (FAILED(pwba->get_HWND(reinterpret_cast(&hwndwba)))) continue; - if (hwndwba != hwndfg || isCursorActivated(hwndwba)) + if (hwndwba != hwndfg || HelperMethods::IsCursorActivated(hwndwba)) continue; - getSelectedInternal(pwba, buffer); + HelperMethods::GetSelectedInternal(pwba, buffer); } } @@ -112,138 +113,8 @@ void Shell32::getSelectedFromDesktop(PWCHAR buffer) if (FAILED(psw->FindWindowSW(&pvarLoc, &pvarLoc, SWC_DESKTOP, &phwnd, SWFO_NEEDDISPATCH, reinterpret_cast(&pwba)))) return; - if (isCursorActivated(reinterpret_cast(LongToHandle(phwnd)))) + if (HelperMethods::IsCursorActivated(reinterpret_cast(LongToHandle(phwnd)))) return; - getSelectedInternal(pwba, buffer); + HelperMethods::GetSelectedInternal(pwba, buffer); } - -void Shell32::getSelectedInternal(CComQIPtr pwba, PWCHAR buffer) -{ - CComQIPtr psp; - if (FAILED(pwba->QueryInterface(IID_IServiceProvider, reinterpret_cast(&psp)))) - return; - - CComPtr psb; - if (FAILED(psp->QueryService(SID_STopLevelBrowser, IID_IShellBrowser, reinterpret_cast(&psb)))) - return; - - CComPtr psv; - if (FAILED(psb->QueryActiveShellView(&psv))) - return; - - CComPtr dao; - if (FAILED(psv->GetItemObject(SVGIO_SELECTION, IID_IDataObject, reinterpret_cast(&dao)))) - return; - - return obtainFirstItem(dao, buffer); -} - -void Shell32::obtainFirstItem(CComPtr dao, PWCHAR buffer) -{ - FORMATETC formatetc; - STGMEDIUM medium; - - formatetc.cfFormat = CF_HDROP; - formatetc.ptd = nullptr; - formatetc.dwAspect = DVASPECT_CONTENT; - formatetc.lindex = -1; - formatetc.tymed = TYMED_HGLOBAL; - - medium.tymed = TYMED_HGLOBAL; - - if (FAILED(dao->GetData(&formatetc, &medium))) - return; - - int n = DragQueryFile(HDROP(medium.hGlobal), 0xFFFFFFFF, nullptr, 0); - - if (n < 1) - return; - - DragQueryFile(HDROP(medium.hGlobal), 0, buffer, MAX_PATH - 1); -} - -bool Shell32::isCursorActivated(HWND hwnd) -{ - auto tId = GetWindowThreadProcessId(hwnd, nullptr); - - GUITHREADINFO gui = {sizeof gui}; - GetGUIThreadInfo(tId, &gui); - return gui.flags || gui.hwndCaret; -} - -#pragma region DialogHook - -#pragma comment(linker, "/SECTION:.shared,RWS") -#pragma data_seg(".shared") -HWND ghMsgWindow = nullptr; // Window handle -HHOOK ghHook = nullptr; // Hook handle -UINT WM_HOOK_NOTIFY = 0; -WCHAR filePathBuffer[MAX_PATH] = {'\0'}; -#pragma data_seg() - -void Shell32::getSelectedFromCommonDialog(PWCHAR buffer) -{ - auto hwndfg = GetForegroundWindow(); - auto tid = GetWindowThreadProcessId(hwndfg, nullptr); - - if (WM_HOOK_NOTIFY == 0) - WM_HOOK_NOTIFY = RegisterWindowMessage(L"WM_QUICKLOOK_HOOK_NOTIFY_MSG"); - - if (ghHook != nullptr) - UnhookWindowsHookEx(ghHook); - ghHook = SetWindowsHookEx(WH_CALLWNDPROC, static_cast(MsgHookProc), ModuleFromAddress(MsgHookProc), tid); - if (ghHook == nullptr) - return; - - SendMessage(hwndfg, WM_HOOK_NOTIFY, 0, 0); - wcscpy_s(buffer, wcslen(buffer) - 1, filePathBuffer); -} - -HMODULE Shell32::ModuleFromAddress(PVOID pv) -{ - MEMORY_BASIC_INFORMATION mbi; - return VirtualQuery(pv, &mbi, sizeof mbi) != 0 ? static_cast(mbi.AllocationBase) : nullptr; -} - -LRESULT Shell32::MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam) -{ - if (nCode < 0) - goto CONTINUE; - - auto pMSG = reinterpret_cast(lParam); - - // only response to WM_HOOK_NOTIFY - if (pMSG->message != WM_HOOK_NOTIFY) - goto CONTINUE; - - UnhookWindowsHookEx(ghHook); - ghHook = nullptr; - - // get current selected item - auto psb = reinterpret_cast(SendMessage(GetForegroundWindow(), WM_USER + 7, 0, 0)); - if (psb == nullptr) - goto CONTINUE; - - getSelectedInternal2(psb, filePathBuffer); - - return 0; - -CONTINUE: - return CallNextHookEx(ghHook, nCode, wParam, lParam); -} - -void Shell32::getSelectedInternal2(CComPtr psb, PWCHAR buffer) -{ - CComPtr psv; - if (FAILED(psb->QueryActiveShellView(&psv))) - return; - - CComPtr dao; - if (FAILED(psv->GetItemObject(SVGIO_SELECTION, IID_IDataObject, reinterpret_cast(&dao)))) - return; - - return obtainFirstItem(dao, buffer); -} - -#pragma endregion DialogHook diff --git a/QuickLook.Native/QuickLook.Native32/Shell32.h b/QuickLook.Native/QuickLook.Native32/Shell32.h index 96310e9..496498f 100644 --- a/QuickLook.Native/QuickLook.Native32/Shell32.h +++ b/QuickLook.Native/QuickLook.Native32/Shell32.h @@ -15,20 +15,8 @@ public: static FocusedWindowType GetFocusedWindowType(); static void GetCurrentSelection(PWCHAR buffer); - static LRESULT __stdcall WindowProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); private: static void getSelectedFromDesktop(PWCHAR buffer); static void getSelectedFromExplorer(PWCHAR buffer); - - static void getSelectedInternal(CComQIPtr pWebBrowserApp, PWCHAR buffer); - static void obtainFirstItem(CComPtr dao, PWCHAR buffer); - static bool isCursorActivated(HWND hwndfg); - -#pragma region DialogHook - static void getSelectedFromCommonDialog(PWCHAR buffer); - static HMODULE ModuleFromAddress(PVOID pv); - static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam); - static void getSelectedInternal2(CComPtr psb, PWCHAR buffer); -#pragma endregion DialogHook }; diff --git a/QuickLook.Native/QuickLook.Native32/WoW64HookHelper.cpp b/QuickLook.Native/QuickLook.Native32/WoW64HookHelper.cpp new file mode 100644 index 0000000..b630888 --- /dev/null +++ b/QuickLook.Native/QuickLook.Native32/WoW64HookHelper.cpp @@ -0,0 +1,54 @@ +#include "stdafx.h" +#include "WoW64HookHelper.h" + +#define HELPER_FILE L"\\QuickLook.WoW64HookHelper.exe" +#define RUN_ARG L"033A853A-E4B2-4552-9A91-E88789761C48" + +HANDLE hHelper = nullptr; +HANDLE hJob = nullptr; + +bool WoW64HookHelper::CheckStatus() +{ + DWORD running = -1; + GetExitCodeProcess(hHelper, &running); + return running == STILL_ACTIVE; +} + +bool WoW64HookHelper::Launch() +{ + if (CheckStatus()) + return true; + + createJob(); + + WCHAR fullPath[MAX_PATH] = {'\0'}; + GetModuleFileName(nullptr, fullPath, MAX_PATH - 1); + auto p = wcsrchr(fullPath, L'\\'); + memcpy(p, HELPER_FILE, wcslen(HELPER_FILE) * sizeof WCHAR); + + STARTUPINFO si = {'\0'}; + PROCESS_INFORMATION pi = {nullptr}; + si.cb = sizeof si; + + CreateProcess(fullPath, RUN_ARG, nullptr, nullptr, false, 0, nullptr, nullptr, &si, &pi); + hHelper = pi.hProcess; + + AssignProcessToJobObject(hJob, hHelper); + + return CheckStatus(); +} + +void WoW64HookHelper::createJob() +{ + if (hJob != nullptr) + return; + + hJob = CreateJobObject(nullptr, nullptr); + + JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation = {'\0'}; + BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + JOBOBJECT_EXTENDED_LIMIT_INFORMATION lpJobObjectInfo = {'\0'}; + lpJobObjectInfo.BasicLimitInformation = BasicLimitInformation; + + SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &lpJobObjectInfo, sizeof JOBOBJECT_EXTENDED_LIMIT_INFORMATION); +} diff --git a/QuickLook.Native/QuickLook.Native32/WoW64HookHelper.h b/QuickLook.Native/QuickLook.Native32/WoW64HookHelper.h new file mode 100644 index 0000000..5a41ceb --- /dev/null +++ b/QuickLook.Native/QuickLook.Native32/WoW64HookHelper.h @@ -0,0 +1,18 @@ +#pragma once + +#include "stdafx.h" + +class WoW64HookHelper +{ +public: + static PWCHAR GetMsgWindowClassName() + { + return L"QUICKLOOK_WOW64HOOKHELPER_MSG_CLASS"; + } + + static bool CheckStatus(); + static bool Launch(); + +private: + static void createJob(); +}; diff --git a/QuickLook.Native/QuickLook.Native64/QuickLook.Native64.vcxproj b/QuickLook.Native/QuickLook.Native64/QuickLook.Native64.vcxproj index 5d21ee2..439e1c8 100644 --- a/QuickLook.Native/QuickLook.Native64/QuickLook.Native64.vcxproj +++ b/QuickLook.Native/QuickLook.Native64/QuickLook.Native64.vcxproj @@ -10,6 +10,25 @@ x64 + + + + + false + false + + + + + + + + + Create + Create + + + 15.0 {794E4DCF-F715-4836-9D30-ABD296586D23} @@ -72,17 +91,6 @@ true - - - - - - - - - - - diff --git a/QuickLook.Native/QuickLook.Native64/QuickLook.Native64.vcxproj.filters b/QuickLook.Native/QuickLook.Native64/QuickLook.Native64.vcxproj.filters index 2717474..a7a53cb 100644 --- a/QuickLook.Native/QuickLook.Native64/QuickLook.Native64.vcxproj.filters +++ b/QuickLook.Native/QuickLook.Native64/QuickLook.Native64.vcxproj.filters @@ -1,14 +1,12 @@  - + + + - - - - - + \ No newline at end of file diff --git a/QuickLook.Native/QuickLook.WoW64HookHelper/QuickLook.WoW64HookHelper.cpp b/QuickLook.Native/QuickLook.WoW64HookHelper/QuickLook.WoW64HookHelper.cpp new file mode 100644 index 0000000..588868f --- /dev/null +++ b/QuickLook.Native/QuickLook.WoW64HookHelper/QuickLook.WoW64HookHelper.cpp @@ -0,0 +1,88 @@ +// QuickLook.WoW64HookHelper.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" + +#include "QuickLook.WoW64HookHelper.h" +#include +#include + +typedef void (__cdecl *PGCS)(PWCHAR); + +#define RUN_ARG L"033A853A-E4B2-4552-9A91-E88789761C48" + +#define SHARED_MEM_NAME L"QUICKLOOK_WOW64HOOKHELPER_MEM" +#define MSG_WINDOW_CLASS L"QUICKLOOK_WOW64HOOKHELPER_MSG_CLASS" + +HMODULE pDll = nullptr; +PGCS pGCS = nullptr; +HWND hMsgWindow = nullptr; +UINT WM_HOOK_NOTIFY = 0; + +int APIENTRY wWinMain(_In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPWSTR lpCmdLine, + _In_ int nCmdShow) +{ + // do not run when double-clicking + if (wcsstr(GetCommandLine(), RUN_ARG) == nullptr) + { + MessageBox(nullptr, L"This executable is not designed to launch directly.", L"QuickLook.WoW64HookHelper", 0); + return 0; + } + + pDll = LoadLibrary(L"QuickLook.Native32.dll"); + pGCS = reinterpret_cast(GetProcAddress(pDll, "GetCurrentSelection")); + + WM_HOOK_NOTIFY = RegisterWindowMessage(L"WM_QUICKLOOK_HOOK_NOTIFY_MSG"); + + WNDCLASS wc = {}; + wc.lpfnWndProc = WndProc; + wc.lpszClassName = MSG_WINDOW_CLASS; + if (!RegisterClass(&wc)) + return 0; + + hMsgWindow = CreateWindow(MSG_WINDOW_CLASS, nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr); + if (hMsgWindow == nullptr) + return 0; + + MSG msg; + while (GetMessage(&msg, nullptr, 0, 0) > 0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return msg.wParam; +} + +LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_HOOK_NOTIFY) + { + GetCurrentSelection(); + return 0; + } + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +void GetCurrentSelection() +{ + WCHAR dllBuffer[MAX_PATH] = {'\0'}; + pGCS(dllBuffer); + + auto hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, SHARED_MEM_NAME); + if (hMapFile == nullptr) + return; + + auto buffer = static_cast(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, MAX_PATH * sizeof WCHAR)); + if (buffer == nullptr) + { + CloseHandle(hMapFile); + return; + } + + wcscpy_s(buffer, MAX_PATH, dllBuffer); + + UnmapViewOfFile(buffer); + CloseHandle(hMapFile); +} diff --git a/QuickLook.Native/QuickLook.WoW64HookHelper/QuickLook.WoW64HookHelper.h b/QuickLook.Native/QuickLook.WoW64HookHelper/QuickLook.WoW64HookHelper.h new file mode 100644 index 0000000..71ea333 --- /dev/null +++ b/QuickLook.Native/QuickLook.WoW64HookHelper/QuickLook.WoW64HookHelper.h @@ -0,0 +1,6 @@ +#pragma once + +#include "stdafx.h" + +LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +void GetCurrentSelection(); diff --git a/QuickLook.Native/QuickLook.WoW64HookHelper/QuickLook.WoW64HookHelper.vcxproj b/QuickLook.Native/QuickLook.WoW64HookHelper/QuickLook.WoW64HookHelper.vcxproj new file mode 100644 index 0000000..43505b0 --- /dev/null +++ b/QuickLook.Native/QuickLook.WoW64HookHelper/QuickLook.WoW64HookHelper.vcxproj @@ -0,0 +1,98 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + 15.0 + {2C58F9B2-D8FA-4586-942B-5170CECE5963} + Win32Proj + QuickLookWoW64HookHelper + 10.0.15063.0 + QuickLook.WoW64HookHelper + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + true + $(SolutionDir)Build\$(Configuration)\ + + + false + $(SolutionDir)Build\$(Configuration)\ + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + + + Windows + true + true + + + + + + + + + + + Create + Create + + + + + + \ No newline at end of file diff --git a/QuickLook.Native/QuickLook.WoW64HookHelper/QuickLook.WoW64HookHelper.vcxproj.filters b/QuickLook.Native/QuickLook.WoW64HookHelper/QuickLook.WoW64HookHelper.vcxproj.filters new file mode 100644 index 0000000..2bbf8d7 --- /dev/null +++ b/QuickLook.Native/QuickLook.WoW64HookHelper/QuickLook.WoW64HookHelper.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/QuickLook.Native/QuickLook.WoW64HookHelper/stdafx.cpp b/QuickLook.Native/QuickLook.WoW64HookHelper/stdafx.cpp new file mode 100644 index 0000000..2082734 --- /dev/null +++ b/QuickLook.Native/QuickLook.WoW64HookHelper/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// QuickLook.Native.WoW64HookHelper.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/QuickLook.Native/QuickLook.WoW64HookHelper/stdafx.h b/QuickLook.Native/QuickLook.WoW64HookHelper/stdafx.h new file mode 100644 index 0000000..bb80440 --- /dev/null +++ b/QuickLook.Native/QuickLook.WoW64HookHelper/stdafx.h @@ -0,0 +1,21 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + +// C RunTime Header Files +#include +#include +#include +#include + + +// TODO: reference additional headers your program requires here diff --git a/QuickLook.Native/QuickLook.WoW64HookHelper/targetver.h b/QuickLook.Native/QuickLook.WoW64HookHelper/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/QuickLook.Native/QuickLook.WoW64HookHelper/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/QuickLook.sln b/QuickLook.sln index 44e8638..a2feb93 100644 --- a/QuickLook.sln +++ b/QuickLook.sln @@ -40,6 +40,7 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "QuickLook.Installer", "Quic {1B746D92-49A5-4A37-9D75-DCC490393290} = {1B746D92-49A5-4A37-9D75-DCC490393290} {A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D} = {A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D} {AB1270AF-7EB4-4B4F-9E09-6404F1A28EA0} = {AB1270AF-7EB4-4B4F-9E09-6404F1A28EA0} + {2C58F9B2-D8FA-4586-942B-5170CECE5963} = {2C58F9B2-D8FA-4586-942B-5170CECE5963} {DE2E3BC5-6AB2-4420-A160-48C7A7506C1C} = {DE2E3BC5-6AB2-4420-A160-48C7A7506C1C} {794E4DCF-F715-4836-9D30-ABD296586D23} = {794E4DCF-F715-4836-9D30-ABD296586D23} {8B4A9CE5-67B5-4A94-81CB-3771F688FDEB} = {8B4A9CE5-67B5-4A94-81CB-3771F688FDEB} @@ -50,9 +51,17 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.IPreviewHandlers", "QuickLook.Plugin\QuickLook.Plugin.IPreviewHandlers\QuickLook.Plugin.IPreviewHandlers.csproj", "{E37675EA-D957-4495-8655-2609BF86756C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickLook.Native64", "QuickLook.Native\QuickLook.Native64\QuickLook.Native64.vcxproj", "{794E4DCF-F715-4836-9D30-ABD296586D23}" + ProjectSection(ProjectDependencies) = postProject + {2C58F9B2-D8FA-4586-942B-5170CECE5963} = {2C58F9B2-D8FA-4586-942B-5170CECE5963} + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "QuickLook.Native", "QuickLook.Native", "{D18A23FF-76BD-43BD-AC32-786D166EBAC9}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickLook.WoW64HookHelper", "QuickLook.Native\QuickLook.WoW64HookHelper\QuickLook.WoW64HookHelper.vcxproj", "{2C58F9B2-D8FA-4586-942B-5170CECE5963}" + ProjectSection(ProjectDependencies) = postProject + {D31EE321-C2B0-4984-B749-736F7DE509F1} = {D31EE321-C2B0-4984-B749-736F7DE509F1} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -153,6 +162,12 @@ Global {794E4DCF-F715-4836-9D30-ABD296586D23}.Release|Any CPU.ActiveCfg = Release|x64 {794E4DCF-F715-4836-9D30-ABD296586D23}.Release|Any CPU.Build.0 = Release|x64 {794E4DCF-F715-4836-9D30-ABD296586D23}.Release|x86.ActiveCfg = Release|x64 + {2C58F9B2-D8FA-4586-942B-5170CECE5963}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {2C58F9B2-D8FA-4586-942B-5170CECE5963}.Debug|Any CPU.Build.0 = Debug|Win32 + {2C58F9B2-D8FA-4586-942B-5170CECE5963}.Debug|x86.ActiveCfg = Debug|Win32 + {2C58F9B2-D8FA-4586-942B-5170CECE5963}.Release|Any CPU.ActiveCfg = Release|Win32 + {2C58F9B2-D8FA-4586-942B-5170CECE5963}.Release|Any CPU.Build.0 = Release|Win32 + {2C58F9B2-D8FA-4586-942B-5170CECE5963}.Release|x86.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -168,5 +183,6 @@ Global {AB1270AF-7EB4-4B4F-9E09-6404F1A28EA0} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93} {E37675EA-D957-4495-8655-2609BF86756C} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93} {794E4DCF-F715-4836-9D30-ABD296586D23} = {D18A23FF-76BD-43BD-AC32-786D166EBAC9} + {2C58F9B2-D8FA-4586-942B-5170CECE5963} = {D18A23FF-76BD-43BD-AC32-786D166EBAC9} EndGlobalSection EndGlobal diff --git a/QuickLook/App.xaml.cs b/QuickLook/App.xaml.cs index 85efc4c..f8aad95 100644 --- a/QuickLook/App.xaml.cs +++ b/QuickLook/App.xaml.cs @@ -52,7 +52,7 @@ namespace QuickLook RunListener(e); - // second instance: run and preview this file + // first instance: run and preview this file if (e.Args.Any() && (Directory.Exists(e.Args.First()) || File.Exists(e.Args.First()))) RemoteCallShowPreview(e); } @@ -68,6 +68,9 @@ namespace QuickLook if (!e.Args.Contains("/autorun")) TrayIconManager.GetInstance().ShowNotification("", "QuickLook is running in the background."); + if (Is64Bit) + NativeMethods.QuickLook.LaunchWoW64HookHelper(); + PluginManager.GetInstance(); BackgroundListener.GetInstance(); PipeServerManager.GetInstance().MessageReceived += diff --git a/QuickLook/NativeMethods/QuickLook.cs b/QuickLook/NativeMethods/QuickLook.cs index 9a36bd8..8b5cf5b 100644 --- a/QuickLook/NativeMethods/QuickLook.cs +++ b/QuickLook/NativeMethods/QuickLook.cs @@ -1,6 +1,7 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; +using System.Windows; namespace QuickLook.NativeMethods { @@ -16,6 +17,10 @@ namespace QuickLook.NativeMethods CallingConvention = CallingConvention.Cdecl)] private static extern void GetCurrentSelectionNative_32([MarshalAs(UnmanagedType.LPWStr)] StringBuilder sb); + [DllImport("QuickLook.Native64.dll", EntryPoint = "LaunchWoW64HookHelper", + CallingConvention = CallingConvention.Cdecl)] + private static extern void LaunchWoW64HookHelper_64(); + [DllImport("QuickLook.Native64.dll", EntryPoint = "GetFocusedWindowType", CallingConvention = CallingConvention.Cdecl)] private static extern FocusedWindowType GetFocusedWindowTypeNative_64(); @@ -24,6 +29,12 @@ namespace QuickLook.NativeMethods CallingConvention = CallingConvention.Cdecl)] private static extern void GetCurrentSelectionNative_64([MarshalAs(UnmanagedType.LPWStr)] StringBuilder sb); + internal static void LaunchWoW64HookHelper() + { + if (App.Is64Bit) + LaunchWoW64HookHelper_64(); + } + internal static FocusedWindowType GetFocusedWindowType() { return App.Is64Bit ? GetFocusedWindowTypeNative_64() : GetFocusedWindowTypeNative_32();