Sandboxie/SandboxiePlus/SandMan/SbieFindWnd.cpp

234 lines
7.6 KiB
C++

//////////////////////////////////////////////////////////////////////////////////////////
// WinSpy based window finder
//
#include <windows.h>
#include "Helpers/FindTool.h"
typedef enum DEVICE_SCALE_FACTOR {
DEVICE_SCALE_FACTOR_INVALID = 0,
SCALE_100_PERCENT = 100,
SCALE_120_PERCENT = 120,
SCALE_125_PERCENT = 125,
SCALE_140_PERCENT = 140,
SCALE_150_PERCENT = 150,
SCALE_160_PERCENT = 160,
SCALE_175_PERCENT = 175,
SCALE_180_PERCENT = 180,
SCALE_200_PERCENT = 200,
SCALE_225_PERCENT = 225,
SCALE_250_PERCENT = 250,
SCALE_300_PERCENT = 300,
SCALE_350_PERCENT = 350,
SCALE_400_PERCENT = 400,
SCALE_450_PERCENT = 450,
SCALE_500_PERCENT = 500
} DEVICE_SCALE_FACTOR;
typedef HRESULT (CALLBACK *P_GetScaleFactorForMonitor)(HMONITOR, DEVICE_SCALE_FACTOR*);
UINT GetMonitorScaling(HWND hwnd)
{
static HINSTANCE shcore = LoadLibrary(L"Shcore.dll");
if (shcore != nullptr)
{
if (auto getScaleFactorForMonitor =
P_GetScaleFactorForMonitor(GetProcAddress(shcore, "GetScaleFactorForMonitor")))
{
HMONITOR monitor =
MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
DEVICE_SCALE_FACTOR Scale;
getScaleFactorForMonitor(monitor, &Scale);
return Scale;
}
}
return 100;
}
#define IDD_FINDER_TOOL 111
#define ID_FINDER_TARGET 112
#define ID_FINDER_EXPLAIN 113
#define ID_FINDER_RESULT 114
struct SFinderWndData {
int Scale;
HFONT hFont;
};
#define DS(x) ((x) * WndData.Scale / 100)
UINT CALLBACK FindProc(HWND hwndTool, UINT uCode, HWND hwnd)
{
ULONG pid;
if (uCode == WFN_END)
GetWindowThreadProcessId(hwnd, &pid);
else
pid = 0;
hwndTool = GetParent(hwndTool);
SFinderWndData &WndData = *(SFinderWndData*)GetWindowLongPtr(hwndTool, 0);
if (pid && pid != GetCurrentProcessId())
{
RECT rc;
GetWindowRect(hwndTool, &rc);
if (rc.bottom - rc.top <= DS(150))
SetWindowPos(hwndTool, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top + DS(70), SWP_SHOWWINDOW | SWP_NOMOVE);
CBoxedProcessPtr pProcess = theAPI->GetProcessById(pid);
if (!pProcess.isNull())
{
std::wstring result = CSandMan::tr("The selected window is running as part of program %1 in sandbox %2").arg(pProcess->GetProcessName()).arg(pProcess->GetBoxName()).toStdWString();
SetWindowText(GetDlgItem(hwndTool, ID_FINDER_RESULT), result.c_str());
//::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_YES_BOXED), SW_SHOW);
}
else
{
std::wstring result = CSandMan::tr("The selected window is not running as part of any sandboxed program.").toStdWString();
SetWindowText(GetDlgItem(hwndTool, ID_FINDER_RESULT), result.c_str());
//::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_NOT_BOXED), SW_SHOW);
}
::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_RESULT), SW_SHOW);
}
else
{
RECT rc;
GetWindowRect(hwndTool, &rc);
if (rc.bottom - rc.top > DS(150))
SetWindowPos(hwndTool, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top - DS(70), SWP_SHOWWINDOW | SWP_NOMOVE);
//::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_YES_BOXED), SW_HIDE);
//::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_NOT_BOXED), SW_HIDE);
::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_RESULT), SW_HIDE);
}
return 0;
}
// hwnd: All window processes are passed the handle of the window
// that they belong to in hwnd.
// msg: Current message (e.g., WM_*) from the OS.
// wParam: First message parameter, note that these are more or less
// integers, but they are really just "data chunks" that
// you are expected to memcpy as raw data to float, etc.
// lParam: Second message parameter, same deal as above.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
CREATESTRUCT* createStruct = (CREATESTRUCT*)lParam;
SFinderWndData &WndData = *(SFinderWndData*)createStruct->lpCreateParams;
SetWindowLongPtr(hwnd, 0, (LONG_PTR)&WndData);
std::wstring info = CSandMan::tr("Drag the Finder Tool over a window to select it, then release the mouse to check if the window is sandboxed.").toStdWString();
CreateWindow(L"Static", L"", SS_BITMAP | SS_NOTIFY | WS_VISIBLE | WS_CHILD, DS(10), DS(10), DS(32), DS(32), hwnd, (HMENU)ID_FINDER_TARGET, NULL, NULL);
CreateWindow(L"Static", info.c_str(), WS_VISIBLE | WS_CHILD, DS(60), DS(10), DS(180), DS(85), hwnd, (HMENU)ID_FINDER_EXPLAIN, NULL, NULL);
CreateWindow(L"Static", L"", WS_CHILD, DS(60), DS(100), DS(180), DS(50), hwnd, (HMENU)ID_FINDER_RESULT, NULL, NULL);
WndData.hFont = CreateFont(DS(13), 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Tahoma"));
if (WndData.hFont) {
SendMessage(GetDlgItem(hwnd, ID_FINDER_EXPLAIN), WM_SETFONT, (WPARAM)WndData.hFont, TRUE);
SendMessage(GetDlgItem(hwnd, ID_FINDER_RESULT), WM_SETFONT, (WPARAM)WndData.hFont, TRUE);
}
MakeFinderTool(GetDlgItem(hwnd, ID_FINDER_TARGET), FindProc);
break;
}
case WM_CLOSE:
SFinderWndData &WndData = *(SFinderWndData*)GetWindowLongPtr(hwnd, 0);
if (WndData.hFont) DeleteObject(WndData.hFont);
//DestroyWindow(hwnd);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
DWORD WINAPI FinderThreadFunc(LPVOID lpParam)
{
MSG msg;
WNDCLASS mainWindowClass = { 0 };
HINSTANCE hInstance = NULL;
// You can set the main window name to anything, but
// typically you should prefix custom window classes
// with something that makes it unique.
mainWindowClass.lpszClassName = TEXT("SBp.WndFinder");
mainWindowClass.hInstance = hInstance;
mainWindowClass.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
mainWindowClass.lpfnWndProc = WndProc;
mainWindowClass.hCursor = LoadCursor(0, IDC_ARROW);
mainWindowClass.cbWndExtra = sizeof(void*); // SFinderWndData
RegisterClass(&mainWindowClass);
// Notes:
// - The classname identifies the TYPE of the window. Not a C type.
// This is a (TCHAR*) ID that Windows uses internally.
// - The window name is really just the window text, this is
// commonly used for captions, including the title
// bar of the window itself.
// - parentHandle is considered the "owner" of this
// window. MessageBoxes can use HWND_MESSAGE to
// free them of any window.
// - menuHandle: hMenu specifies the child-window identifier,
// an integer value used by a dialog box
// control to notify its parent about events.
// The application determines the child-window
// identifier; it must be unique for all
// child windows with the same parent window.
SFinderWndData WndData;
WndData.Scale = GetMonitorScaling(MainWndHandle);
HWND hwnd = CreateWindow(mainWindowClass.lpszClassName, CSandMan::tr("Sandboxie-Plus - Window Finder").toStdWString().c_str()
, WS_SYSMENU | WS_CAPTION | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, DS(275), DS(135), NULL, 0, hInstance, &WndData);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
void CSandMan::OnWndFinder()
{
m_pWndFinder->setEnabled(false);
HANDLE hThread = CreateThread(NULL, 0, FinderThreadFunc, NULL, 0, NULL);
QWinEventNotifier* finishedNotifier = new QWinEventNotifier(hThread);
finishedNotifier->setEnabled(true);
connect(finishedNotifier, &QWinEventNotifier::activated, this, [finishedNotifier, this, hThread]() {
CloseHandle(hThread);
m_pWndFinder->setEnabled(true);
finishedNotifier->setEnabled(false);
finishedNotifier->deleteLater();
});
}