1638 lines
47 KiB
C
1638 lines
47 KiB
C
/*
|
|
* Copyright 2004-2020 Sandboxie Holdings, LLC
|
|
* Copyright 2020 David Xanatos, xanasoft.com
|
|
*
|
|
* 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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
//---------------------------------------------------------------------------
|
|
// GUI Services
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "dll.h"
|
|
|
|
#include "gui_p.h"
|
|
#include "core/svc/GuiWire.h"
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Functions
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
static HWND Gui_GetWindow(HWND hWnd, UINT uCmd);
|
|
|
|
static HWND Gui_GetParent(HWND hWnd);
|
|
|
|
static HWND Gui_SetParent(HWND hWndChild, HWND hWndNewParent);
|
|
|
|
static BOOL Gui_SwapMouseButton(BOOL fSwap);
|
|
|
|
static BOOL Gui_SetDoubleClickTime(UINT uInterval);
|
|
|
|
static BOOL Gui_ClipCursor(const RECT *lpRect);
|
|
|
|
static BOOLEAN Gui_GrantHandle(ULONG_PTR handle);
|
|
|
|
static HCURSOR Gui_SetCursor(HCURSOR hCursor);
|
|
|
|
static BOOL Gui_GetIconInfo(HICON hIcon, PICONINFO piconinfo);
|
|
|
|
static BOOL Gui_SetCursorPos(int x, int y);
|
|
|
|
static BOOL Gui_SetForegroundWindow(HWND hWnd);
|
|
|
|
static HMONITOR Gui_MonitorFromWindow(HWND hWnd, DWORD dwFlags);
|
|
|
|
static BOOL Gui_BlockInput(BOOL fBlockIt);
|
|
|
|
static UINT Gui_SendInput(ULONG nInputs, LPINPUT pInputs, ULONG cbInput);
|
|
|
|
static HDESK Gui_OpenInputDesktop(
|
|
DWORD dwFlags, BOOL fInherit, ACCESS_MASK dwDesiredAccess);
|
|
|
|
static BOOL Gui_GetUserObjectInformationW(
|
|
HANDLE hObj, int nIndex,
|
|
void *pvInfo, DWORD nLength, DWORD *lpnLengthNeeded);
|
|
|
|
static BOOL Gui_OpenClipboard(HWND hwnd);
|
|
|
|
static BOOL Gui_CloseClipboard(void);
|
|
|
|
static HANDLE Gui_SetClipboardData(UINT uFormat, HANDLE hMem);
|
|
|
|
static HANDLE Gui_GetClipboardData(UINT uFormat);
|
|
|
|
static void Gui_GetClipboardData_BMP(void *buf, ULONG fmt);
|
|
|
|
static void Gui_GetClipboardData_MF(void *buf, ULONG sz, ULONG fmt);
|
|
|
|
static void Gui_GetClipboardData_EnhMF(void *buf, ULONG sz, ULONG fmt);
|
|
|
|
static BOOL Gui_EmptyClipboard();
|
|
|
|
static LONG Gui_ChangeDisplaySettingsExA(
|
|
void *lpszDeviceName, void *lpDevMode, HWND hwnd,
|
|
DWORD dwflags, void *lParam);
|
|
|
|
static LONG Gui_ChangeDisplaySettingsExW(
|
|
void *lpszDeviceName, void *lpDevMode, HWND hwnd,
|
|
DWORD dwflags, void *lParam);
|
|
|
|
|
|
static LONG Gui_GetRawInputDeviceInfoA(
|
|
_In_opt_ HANDLE hDevice, _In_ UINT uiCommand,
|
|
_Inout_ LPVOID pData, _Inout_ PUINT pcbSize);
|
|
|
|
static LONG Gui_GetRawInputDeviceInfoW(
|
|
_In_opt_ HANDLE hDevice, _In_ UINT uiCommand,
|
|
_Inout_ LPVOID pData, _Inout_ PUINT pcbSize);
|
|
|
|
static HDC Gui_GetDC(HWND hWnd);
|
|
|
|
static HDC Gui_GetWindowDC(HWND hWnd);
|
|
|
|
static HDC Gui_GetDCEx(HWND hWnd, HRGN hrgnClip, DWORD flags);
|
|
|
|
static BOOL Gui_PrintWindow(HWND hwnd, HDC hdcBlt, UINT nFlags);
|
|
|
|
static int Gui_ReleaseDC(HWND hWnd, HDC hDc);
|
|
|
|
static BOOL Gui_ShutdownBlockReasonCreate(HWND hWnd, LPCWSTR pwszReason);
|
|
|
|
static EXECUTION_STATE Gui_SetThreadExecutionState(EXECUTION_STATE esFlags);
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
typedef BOOL (*P_GetUserObjectInformationW)(
|
|
HANDLE hObj, int nIndex,
|
|
void *pvInfo, DWORD nLength, DWORD *lpnLengthNeeded);
|
|
|
|
typedef HMETAFILE (*P_SetMetaFileBitsEx)(
|
|
UINT nSize, const BYTE *lpData);
|
|
|
|
typedef HENHMETAFILE (*P_SetEnhMetaFileBits)(
|
|
UINT nSize, const BYTE *lpData);
|
|
|
|
typedef int (*P_SetDIBits)
|
|
(HDC hdc, HBITMAP hbm, UINT start, UINT cLines, CONST VOID *lpBits, CONST BITMAPINFO * lpbmi, UINT ColorUse);
|
|
|
|
typedef HDC (*P_GetDC)(
|
|
HWND hWnd);
|
|
|
|
typedef int (*P_ReleaseDC)(
|
|
HWND hWnd,
|
|
HDC hDC);
|
|
|
|
static P_GetUserObjectInformationW __sys_GetUserObjectInformationW = NULL;
|
|
|
|
#ifndef _DPI_AWARENESS_CONTEXTS_
|
|
struct DPI_AWARENESS_CONTEXT__ { int unused; };
|
|
typedef DPI_AWARENESS_CONTEXT__ *DPI_AWARENESS_CONTEXT;
|
|
#endif
|
|
|
|
typedef DPI_AWARENESS_CONTEXT (WINAPI *P_GetThreadDpiAwarenessContext)(
|
|
VOID);
|
|
|
|
static P_GetThreadDpiAwarenessContext __sys_GetThreadDpiAwarenessContext = NULL;
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Variables
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
static BOOLEAN Gui_ClipCursorActive = FALSE;
|
|
|
|
static HWND Gui_OpenClipboard_hwnd = NULL;
|
|
static ULONG Gui_OpenClipboard_tid = 0;
|
|
static ULONG Gui_OpenClipboard_seq = -1;
|
|
|
|
static HANDLE Gui_DummyInputDesktopHandle = NULL;
|
|
|
|
static BOOLEAN Gui_BlockInterferenceControl = FALSE;
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_InitMisc
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOLEAN Gui_InitMisc(HMODULE module)
|
|
{
|
|
if (! Gui_OpenAllWinClasses) {
|
|
|
|
Gui_BlockInterferenceControl = SbieApi_QueryConfBool(NULL, L"BlockInterferenceControl", FALSE);
|
|
|
|
SBIEDLL_HOOK_GUI(SetParent);
|
|
if (Gui_UseProxyService) {
|
|
SBIEDLL_HOOK_GUI(GetWindow);
|
|
SBIEDLL_HOOK_GUI(GetParent);
|
|
|
|
SBIEDLL_HOOK_GUI(MonitorFromWindow);
|
|
|
|
SBIEDLL_HOOK_GUI(SetCursor);
|
|
SBIEDLL_HOOK_GUI(GetIconInfo);
|
|
|
|
}
|
|
SBIEDLL_HOOK_GUI(SetCursorPos);
|
|
SBIEDLL_HOOK_GUI(SetForegroundWindow);
|
|
SBIEDLL_HOOK_GUI(ClipCursor);
|
|
SBIEDLL_HOOK_GUI(SwapMouseButton);
|
|
SBIEDLL_HOOK_GUI(SetDoubleClickTime);
|
|
|
|
if (Gui_UseBlockCapture) {
|
|
SBIEDLL_HOOK_GUI(GetWindowDC);
|
|
SBIEDLL_HOOK_GUI(GetDC);
|
|
SBIEDLL_HOOK_GUI(GetDCEx);
|
|
SBIEDLL_HOOK_GUI(PrintWindow);
|
|
SBIEDLL_HOOK_GUI(ReleaseDC);
|
|
}
|
|
|
|
if (Dll_OsBuild >= 6000) {
|
|
|
|
//
|
|
// hook BlockInput and SendInput on Windows Vista because UIPI
|
|
// is disabled if UAC is disabled. if UAC is enabled, kernel
|
|
// side UIPI will also protect these two APIs. see also Gui_Init
|
|
// in core/drv/gui.c and PostThreadMessage in core/dll/guimsg.c
|
|
//
|
|
|
|
SBIEDLL_HOOK_GUI(BlockInput);
|
|
SBIEDLL_HOOK_GUI(SendInput);
|
|
}
|
|
}
|
|
|
|
if (!Gui_UseProxyService)
|
|
return TRUE;
|
|
|
|
SBIEDLL_HOOK_GUI(OpenClipboard);
|
|
SBIEDLL_HOOK_GUI(CloseClipboard);
|
|
SBIEDLL_HOOK_GUI(SetClipboardData);
|
|
SBIEDLL_HOOK_GUI(GetClipboardData);
|
|
SBIEDLL_HOOK_GUI(EmptyClipboard);
|
|
|
|
//
|
|
// Chinese instant messenger QQ.exe (aka TM.exe) uses OpenInputDesktop,
|
|
// GetThreadDesktop and GetUserObjectInformation to determine if the
|
|
// desktop is locked, and if OpenInputDesktop fails, it assumes lock.
|
|
// Fortunately it is enough to hook just OpenInputDesktop to fix this
|
|
//
|
|
// Google Chrome also uses OpenInputDesktop and GetUserObjectInformation
|
|
// to check if the desktop is locked, and other programs might as well
|
|
//
|
|
|
|
if (!Dll_CompartmentMode) {
|
|
|
|
typedef HDESK (*P_OpenInputDesktop)(
|
|
DWORD dwFlags, BOOL fInherit, ACCESS_MASK dwDesiredAccess);
|
|
|
|
P_OpenInputDesktop __sys_OpenInputDesktop = (P_OpenInputDesktop)
|
|
Ldr_GetProcAddrNew(DllName_user32, L"OpenInputDesktop","OpenInputDesktop");
|
|
|
|
__sys_GetUserObjectInformationW = (P_GetUserObjectInformationW)
|
|
Ldr_GetProcAddrNew(DllName_user32, L"GetUserObjectInformationW","GetUserObjectInformationW");
|
|
|
|
if (__sys_OpenInputDesktop) {
|
|
SBIEDLL_HOOK_GUI(OpenInputDesktop);
|
|
}
|
|
|
|
if (__sys_GetUserObjectInformationW) {
|
|
SBIEDLL_HOOK_GUI(GetUserObjectInformationW);
|
|
}
|
|
}
|
|
|
|
//
|
|
// ChangeDisplaySettingsEx on Windows 8
|
|
//
|
|
|
|
if (Dll_OsBuild >= 8400) {
|
|
P_ChangeDisplaySettingsEx __sys_ChangeDisplaySettingsExA =
|
|
Ldr_GetProcAddrNew(DllName_user32, L"ChangeDisplaySettingsExA","ChangeDisplaySettingsExA");
|
|
P_ChangeDisplaySettingsEx __sys_ChangeDisplaySettingsExW =
|
|
Ldr_GetProcAddrNew(DllName_user32, L"ChangeDisplaySettingsExW","ChangeDisplaySettingsExW");
|
|
SBIEDLL_HOOK_GUI(ChangeDisplaySettingsExA);
|
|
SBIEDLL_HOOK_GUI(ChangeDisplaySettingsExW);
|
|
}
|
|
|
|
SBIEDLL_HOOK_GUI(GetRawInputDeviceInfoA);
|
|
SBIEDLL_HOOK_GUI(GetRawInputDeviceInfoW);
|
|
|
|
__sys_GetThreadDpiAwarenessContext = (P_GetThreadDpiAwarenessContext)
|
|
Ldr_GetProcAddrNew(DllName_user32, L"GetThreadDpiAwarenessContext","GetThreadDpiAwarenessContext");
|
|
|
|
|
|
if (SbieApi_QueryConfBool(NULL, L"BlockInterferePower", FALSE)) {
|
|
|
|
SBIEDLL_HOOK_GUI(ShutdownBlockReasonCreate);
|
|
|
|
module = Dll_Kernel32;
|
|
|
|
SBIEDLL_HOOK(Gui_, SetThreadExecutionState);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetWindow
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX HWND Gui_GetWindow(HWND hWnd, UINT uCmd)
|
|
{
|
|
if (uCmd < 0x10)
|
|
return Gui_GetWindowFromProxy(uCmd, hWnd);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetParent
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX HWND Gui_GetParent(HWND hWnd)
|
|
{
|
|
if (__sys_IsWindow(hWnd) || (! hWnd))
|
|
return __sys_GetParent(hWnd);
|
|
else
|
|
return Gui_GetWindowFromProxy('prnt', hWnd);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_SetParent
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX HWND Gui_SetParent(HWND hWndChild, HWND hWndNewParent)
|
|
{
|
|
//
|
|
// fail the request (with a warning) if either the child or the
|
|
// parent windows are not accessible to this process. but note that
|
|
// we make a special exception of converting the desktop hwnd to NULL
|
|
//
|
|
|
|
if (! Gui_IsWindowAccessible(hWndChild)) {
|
|
SetLastError(ERROR_INVALID_WINDOW_HANDLE);
|
|
return NULL;
|
|
}
|
|
|
|
if (hWndNewParent && (! Gui_IsWindowAccessible(hWndNewParent))) {
|
|
if (hWndNewParent == __sys_GetDesktopWindow())
|
|
hWndNewParent = NULL;
|
|
else {
|
|
//SbieApi_Log(2205, L"SetParent");
|
|
SetLastError(ERROR_INVALID_WINDOW_HANDLE);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return __sys_SetParent(hWndChild, hWndNewParent);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_ClipCursor
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_ClipCursor(const RECT *lpRect)
|
|
{
|
|
if (Gui_BlockInterferenceControl && lpRect) {
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!Gui_UseProxyService)
|
|
return __sys_ClipCursor(lpRect);
|
|
|
|
GUI_CLIP_CURSOR_REQ req;
|
|
void *rpl;
|
|
|
|
req.msgid = GUI_CLIP_CURSOR;
|
|
if (lpRect) {
|
|
req.have_rect = TRUE;
|
|
memcpy(&req.rect, lpRect, sizeof(req.rect));
|
|
Gui_ClipCursorActive = TRUE;
|
|
} else {
|
|
req.have_rect = FALSE;
|
|
memzero(&req.rect, sizeof(req.rect));
|
|
Gui_ClipCursorActive = FALSE;
|
|
}
|
|
req.dpi_awareness_ctx = __sys_GetThreadDpiAwarenessContext ? (LONG64)(LONG_PTR)__sys_GetThreadDpiAwarenessContext() : 0;
|
|
|
|
rpl = Gui_CallProxy(&req, sizeof(req), sizeof(ULONG));
|
|
if (rpl) {
|
|
Dll_Free(rpl);
|
|
return TRUE;
|
|
} else {
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_ResetClipCursor
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX void Gui_ResetClipCursor(void)
|
|
{
|
|
//
|
|
// programs that set a clip cursor (e.g. full screen games) tend to
|
|
// remove the clip on alt-tab switch, but do not remove the clip when
|
|
// terminating. and the clip remains in effect probably because the
|
|
// sandboxed process does not have WINSTA_WRITEATTRIBUTES access.
|
|
// to work around this, we have DllMain call this function on exit.
|
|
//
|
|
|
|
if (Gui_ClipCursorActive)
|
|
Gui_ClipCursor(NULL);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_SwapMouseButton
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_SwapMouseButton(BOOL fSwap)
|
|
{
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_SetDoubleClickTime
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_SetDoubleClickTime(UINT uInterval)
|
|
{
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GrantHandle
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOLEAN Gui_GrantHandle(ULONG_PTR handle)
|
|
{
|
|
GUI_GRANT_HANDLE_REQ req;
|
|
void *rpl;
|
|
|
|
if (! handle)
|
|
return FALSE;
|
|
|
|
req.msgid = GUI_GRANT_HANDLE;
|
|
req.handle_type = 1; // bitmap/cursor/icon
|
|
req.handle_value = (ULONG)handle;
|
|
|
|
rpl = Gui_CallProxy(&req, sizeof(req), sizeof(ULONG));
|
|
if (rpl) {
|
|
Dll_Free(rpl);
|
|
return TRUE;
|
|
|
|
} else {
|
|
SetLastError(ERROR_INVALID_CURSOR_HANDLE);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_SetCursor
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX HCURSOR Gui_SetCursor(HCURSOR hCursor)
|
|
{
|
|
HCURSOR hCursorRet = __sys_SetCursor(hCursor);
|
|
if ((! hCursorRet) && (GetLastError() == ERROR_INVALID_CURSOR_HANDLE)) {
|
|
|
|
//
|
|
// the cursor handle is probably not yet accessible to our
|
|
// job object so ask SbieSvc GUI Proxy server to grant us access
|
|
//
|
|
|
|
if (Gui_GrantHandle((ULONG_PTR)hCursor)) {
|
|
|
|
hCursorRet = __sys_SetCursor(hCursor);
|
|
}
|
|
}
|
|
|
|
return hCursorRet;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetIconInfo
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_GetIconInfo(HICON hIcon, PICONINFO piconinfo)
|
|
{
|
|
BOOL ok = __sys_GetIconInfo(hIcon, piconinfo);
|
|
if ((! ok) && (GetLastError() == ERROR_INVALID_CURSOR_HANDLE)) {
|
|
|
|
//
|
|
// the icon handle is probably not yet accessible to our
|
|
// job object so ask SbieSvc GUI Proxy server to grant us access
|
|
//
|
|
|
|
if (Gui_GrantHandle((ULONG_PTR)hIcon)) {
|
|
|
|
ok = __sys_GetIconInfo(hIcon, piconinfo);
|
|
}
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_SetCursorPos
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_SetCursorPos(int x, int y)
|
|
{
|
|
if (Gui_BlockInterferenceControl)
|
|
return FALSE;
|
|
|
|
if (!Gui_UseProxyService)
|
|
return __sys_SetCursorPos(x, y);
|
|
|
|
GUI_SET_CURSOR_POS_REQ req;
|
|
GUI_SET_CURSOR_POS_RPL *rpl;
|
|
ULONG error;
|
|
BOOL retval;
|
|
|
|
req.msgid = GUI_SET_CURSOR_POS;
|
|
req.error = GetLastError();
|
|
req.x = x;
|
|
req.y = y;
|
|
req.dpi_awareness_ctx = __sys_GetThreadDpiAwarenessContext ? (LONG64)(LONG_PTR)__sys_GetThreadDpiAwarenessContext() : 0;
|
|
rpl = Gui_CallProxyEx(&req, sizeof(req), sizeof(ULONG), TRUE);
|
|
if (rpl) {
|
|
retval = rpl->retval;
|
|
error = rpl->error;
|
|
Dll_Free(rpl);
|
|
} else {
|
|
error = ERROR_ACCESS_DENIED;
|
|
retval = FALSE;
|
|
}
|
|
SetLastError(error);
|
|
return retval;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_SetForegroundWindow
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_SetForegroundWindow(HWND hWnd)
|
|
{
|
|
GUI_SET_FOREGROUND_WINDOW_REQ req;
|
|
void *rpl;
|
|
|
|
if (Gui_BlockInterferenceControl) {
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!Gui_UseProxyService || __sys_IsWindow(hWnd) || (! hWnd)) {
|
|
// window is in the same sandbox (or is NULL), no need for GUI Proxy
|
|
return __sys_SetForegroundWindow(hWnd);
|
|
}
|
|
|
|
if (__sys_SetForegroundWindow(hWnd))
|
|
return TRUE;
|
|
|
|
Gui_AllowSetForegroundWindow();
|
|
|
|
req.msgid = GUI_SET_FOREGROUND_WINDOW;
|
|
req.hwnd = (ULONG)(ULONG_PTR)hWnd;
|
|
rpl = Gui_CallProxyEx(&req, sizeof(req), sizeof(ULONG), TRUE);
|
|
if (rpl) {
|
|
Dll_Free(rpl);
|
|
return TRUE;
|
|
} else {
|
|
SetLastError(ERROR_INVALID_WINDOW_HANDLE);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_MonitorFromWindow
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX HMONITOR Gui_MonitorFromWindow(HWND hWnd, DWORD dwFlags)
|
|
{
|
|
ULONG err = GetLastError();
|
|
HMONITOR result = __sys_MonitorFromWindow(hWnd, dwFlags);
|
|
if (! result) {
|
|
|
|
GUI_MONITOR_FROM_WINDOW_REQ req;
|
|
GUI_MONITOR_FROM_WINDOW_RPL *rpl;
|
|
|
|
req.msgid = GUI_MONITOR_FROM_WINDOW;
|
|
req.error = err;
|
|
req.hwnd = (ULONG)(ULONG_PTR)hWnd;
|
|
req.flags = dwFlags;
|
|
|
|
rpl = Gui_CallProxy(&req, sizeof(req), sizeof(*rpl));
|
|
if (! rpl)
|
|
return FALSE;
|
|
|
|
err = rpl->error;
|
|
result = (HMONITOR)(LONG_PTR)(LONG)rpl->retval;
|
|
Dll_Free(rpl);
|
|
|
|
SetLastError(err);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_BlockInput
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_BlockInput(BOOL fBlockIt)
|
|
{
|
|
if (fBlockIt)
|
|
return 0;
|
|
else
|
|
return __sys_BlockInput(fBlockIt);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_SendInput
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX UINT Gui_SendInput(ULONG nInputs, LPINPUT pInputs, ULONG cbInput)
|
|
{
|
|
//
|
|
// we are going to pass the input to the system one INPUT structure
|
|
// at a time, so we can check for change in the foreground window
|
|
//
|
|
|
|
ULONG retval = 0;
|
|
while (nInputs && nInputs < 16) {
|
|
|
|
//
|
|
// if the foreground window is not sandboxed, stop
|
|
//
|
|
|
|
HWND hwnd = __sys_GetForegroundWindow();
|
|
if (! hwnd)
|
|
break;
|
|
if (! Gui_IsSameBox(hwnd, NULL, NULL))
|
|
break;
|
|
|
|
//
|
|
// otherwise pass one INPUT structure to the system, then advance
|
|
// to the next INPUT structure. note that we must get a return
|
|
// of exactly 1
|
|
//
|
|
|
|
if (__sys_SendInput(1, pInputs, cbInput) != 1)
|
|
break;
|
|
|
|
++retval;
|
|
--nInputs;
|
|
pInputs = (LPINPUT)((UCHAR *)pInputs + cbInput);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_OpenInputDesktop
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX HDESK Gui_OpenInputDesktop(
|
|
DWORD dwFlags, BOOL fInherit, ACCESS_MASK dwDesiredAccess)
|
|
{
|
|
if (! Gui_DummyInputDesktopHandle)
|
|
Gui_DummyInputDesktopHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
return Gui_DummyInputDesktopHandle;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetUserObjectInformationW
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_GetUserObjectInformationW(
|
|
HANDLE hObj, int nIndex,
|
|
void *pvInfo, DWORD nLength, DWORD *lpnLengthNeeded)
|
|
{
|
|
if (Gui_DummyInputDesktopHandle && hObj == Gui_DummyInputDesktopHandle && nIndex == UOI_NAME) {
|
|
|
|
ULONG Default_len = (7 + 1) * sizeof(WCHAR);
|
|
if (lpnLengthNeeded)
|
|
*lpnLengthNeeded = Default_len;
|
|
if (pvInfo && nLength >= Default_len) {
|
|
memcpy(pvInfo, L"Default", Default_len);
|
|
return TRUE;
|
|
}
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
return __sys_GetUserObjectInformationW(
|
|
hObj, nIndex, pvInfo, nLength, lpnLengthNeeded);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Clipboard support functions
|
|
//
|
|
// The sandboxed process is running in a restricting job, so it can't
|
|
// get clipboard data that was copied by a process outside the sandbox.
|
|
//
|
|
// a second problem on UIPI systems is that an integrity level is given
|
|
// to each clipboard data item, so a process outside the sandbox copies
|
|
// data to the clipboard with integrity level zero. this prevents a
|
|
// process outside the sandbox from pasting (perhaps a bug in win32k).
|
|
//
|
|
// to work around both issues we use the SbieSvc GUI Proxy.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_OpenClipboard
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_OpenClipboard(HWND hwnd)
|
|
{
|
|
BOOL ok = __sys_OpenClipboard(hwnd);
|
|
if (ok) {
|
|
Gui_OpenClipboard_hwnd = hwnd;
|
|
Gui_OpenClipboard_tid = GetCurrentThreadId();
|
|
Gui_OpenClipboard_seq = __sys_GetClipboardSequenceNumber();
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_CloseClipboard
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_CloseClipboard(void)
|
|
{
|
|
//
|
|
// this request is used on Windows Vista and later where we need to
|
|
// adjust the internal integrity level numbers stored in the clipboard.
|
|
// see CloseClipboardSlave in core/svc/GuiServer.cpp,
|
|
// and also see core/drv/gui.c
|
|
//
|
|
// there is a potential problem if there is a clipboard viewer program
|
|
// (registered via SetClipboardViewer or AddClipboardFormatListener),
|
|
// in which case we have a race condition: do we get to fix the
|
|
// clipboard before the viewer gets the clipboard notification?
|
|
// SbieSvc is an "above normal" priority process, so we rely on that.
|
|
//
|
|
|
|
BOOL ok = __sys_CloseClipboard();
|
|
ULONG err = GetLastError();
|
|
|
|
if (ok && Dll_OsBuild >= 6000) {
|
|
|
|
ULONG new_seq = __sys_GetClipboardSequenceNumber();
|
|
if (new_seq != Gui_OpenClipboard_seq) {
|
|
|
|
ULONG req = GUI_CLOSE_CLIPBOARD;
|
|
|
|
// While calling the Service we want to suppress
|
|
// any informational msg boxes that the application
|
|
// my through up. This is because we're bringing
|
|
// forward the rendering of "Delay rendered"
|
|
// clipboard types (e.g. the Enhanced Metafile type
|
|
// from Office applications).
|
|
// This causes some issues because sometimes
|
|
// the application (e.g. Excel) will pop up message
|
|
// box where it normally wouldn't do so. There
|
|
// is also no option to turn off that informational
|
|
// message.
|
|
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
|
|
ULONG * rpl = NULL;
|
|
|
|
if (TlsData)
|
|
TlsData->gui_should_suppress_msgbox = TRUE;
|
|
|
|
rpl = Gui_CallProxyEx(
|
|
&req, sizeof(ULONG), sizeof(ULONG), TRUE);
|
|
if (TlsData)
|
|
TlsData->gui_should_suppress_msgbox = FALSE;
|
|
|
|
if (rpl)
|
|
Dll_Free(rpl);
|
|
|
|
Gui_OpenClipboard_seq = new_seq;
|
|
}
|
|
}
|
|
|
|
if (ok) {
|
|
Gui_OpenClipboard_hwnd = NULL;
|
|
Gui_OpenClipboard_tid = 0;
|
|
}
|
|
|
|
SetLastError(err);
|
|
return ok;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_SetClipboardData
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX HANDLE Gui_SetClipboardData(UINT uFormat, HANDLE hMem)
|
|
{
|
|
if (!SbieApi_QueryConfBool(NULL, L"OpenClipboard", TRUE))
|
|
return NULL;
|
|
|
|
return __sys_SetClipboardData(uFormat, hMem);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_EmptyClipboard
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_EmptyClipboard()
|
|
{
|
|
if (!SbieApi_QueryConfBool(NULL, L"OpenClipboard", TRUE))
|
|
return FALSE;
|
|
|
|
return __sys_EmptyClipboard();
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetClipboardData
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX HANDLE Gui_GetClipboardData(UINT uFormat)
|
|
{
|
|
static HANDLE *_hGlobalClipData = NULL;
|
|
HANDLE hGlobalRet;
|
|
HWND OpenClipboardHwnd;
|
|
GUI_GET_CLIPBOARD_DATA_REQ req;
|
|
GUI_GET_CLIPBOARD_DATA_RPL *rpl;
|
|
ULONG error;
|
|
ULONG retry;
|
|
|
|
//
|
|
// first we try the system GetClipboardData. this always fails with
|
|
// ERROR_ACCESS_DENIED if the process is running in a job that has a
|
|
// UIRestriction which prevents clipboard access. it fails with
|
|
// ERROR_INVALID_HANDLE if the job has UIRestriction which prevents
|
|
// access to handles outside the job, and the clipboard data belongs
|
|
// to a process outside the job
|
|
//
|
|
// in either case, we go to SbieSvc GUI Proxy Server to ask for the
|
|
// clipboard data
|
|
//
|
|
|
|
if (!SbieApi_QueryConfBool(NULL, L"OpenClipboard", TRUE))
|
|
return NULL;
|
|
|
|
hGlobalRet = __sys_GetClipboardData(uFormat);
|
|
if (hGlobalRet)
|
|
return hGlobalRet;
|
|
error = GetLastError();
|
|
if (error != ERROR_ACCESS_DENIED && error != ERROR_INVALID_HANDLE)
|
|
return hGlobalRet;
|
|
|
|
//
|
|
// we have to close the clipboard before another process can access it
|
|
// (the other process being the SbieSvc GuiProxy process)
|
|
//
|
|
// if we can't close the clipboard (which means the thread has not
|
|
// actually opened the clipboard), then abort
|
|
//
|
|
|
|
OpenClipboardHwnd = __sys_GetOpenClipboardWindow();
|
|
|
|
if (OpenClipboardHwnd != Gui_OpenClipboard_hwnd ||
|
|
GetCurrentThreadId() != Gui_OpenClipboard_tid) {
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return NULL;
|
|
}
|
|
|
|
if (! __sys_CloseClipboard()) {
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// ask SbieSvc to call GetClipboardData for us
|
|
//
|
|
|
|
req.msgid = GUI_GET_CLIPBOARD_DATA;
|
|
req.format = uFormat;
|
|
rpl = Gui_CallProxyEx(&req, sizeof(req), sizeof(*rpl), TRUE);
|
|
if (! rpl)
|
|
error = GetLastError();
|
|
else {
|
|
|
|
if (! rpl->result)
|
|
error = rpl->error;
|
|
else {
|
|
|
|
//
|
|
// if the request was successful, we were given a handle to a
|
|
// section which contains the data from the clipboard, but we
|
|
// have to convert this into an HGLOBAL
|
|
//
|
|
|
|
void *src = MapViewOfFileEx(
|
|
(HANDLE)(ULONG_PTR)rpl->section_handle,
|
|
FILE_MAP_READ, 0, 0, 0, NULL);
|
|
if (! src)
|
|
error = GetLastError();
|
|
else {
|
|
|
|
HGLOBAL hGlobal =
|
|
GlobalAlloc(GMEM_FIXED, (ULONG_PTR)rpl->section_length);
|
|
if (hGlobal) {
|
|
|
|
void *dst = GlobalLock(hGlobal);
|
|
if (! dst)
|
|
error = GetLastError();
|
|
else {
|
|
|
|
memcpy(dst, src, (ULONG_PTR)rpl->section_length);
|
|
|
|
if (uFormat == CF_BITMAP)// || uFormat == CF_DIB)
|
|
Gui_GetClipboardData_BMP(dst, uFormat);
|
|
|
|
if (uFormat == CF_ENHMETAFILE) {
|
|
Gui_GetClipboardData_EnhMF(
|
|
dst, (ULONG)(ULONG_PTR)rpl->section_length,
|
|
uFormat);
|
|
}
|
|
|
|
if (uFormat == CF_METAFILEPICT) {
|
|
Gui_GetClipboardData_MF(
|
|
dst, (ULONG)(ULONG_PTR)rpl->section_length,
|
|
uFormat);
|
|
}
|
|
|
|
GlobalUnlock(hGlobal);
|
|
|
|
hGlobalRet = hGlobal;
|
|
error = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
UnmapViewOfFile(src);
|
|
}
|
|
|
|
CloseHandle((HANDLE)(ULONG_PTR)rpl->section_handle);
|
|
}
|
|
|
|
Dll_Free(rpl);
|
|
}
|
|
|
|
//
|
|
// applications aren't supposed to free clipboard HGLOBALs, so we have
|
|
// to free the HGLOBAL we returned last time, and keep the HGLOBAL that
|
|
// we return now, to free it on the next call to this function
|
|
//
|
|
|
|
if (hGlobalRet) {
|
|
|
|
if (_hGlobalClipData)
|
|
{
|
|
// reuse the previous returned data if it is the same
|
|
BOOL bReuse = FALSE;
|
|
SIZE_T nSizeOld = GlobalSize(_hGlobalClipData);
|
|
SIZE_T nSizeNew = GlobalSize(hGlobalRet);
|
|
|
|
if (nSizeOld && nSizeOld == nSizeNew)
|
|
{
|
|
if (memcmp(hGlobalRet, _hGlobalClipData, nSizeOld) == 0)
|
|
{
|
|
bReuse = TRUE;
|
|
}
|
|
}
|
|
|
|
if (bReuse)
|
|
{
|
|
GlobalFree(hGlobalRet);
|
|
hGlobalRet = _hGlobalClipData;
|
|
}
|
|
else
|
|
{
|
|
GlobalFree(_hGlobalClipData);
|
|
}
|
|
}
|
|
_hGlobalClipData = hGlobalRet;
|
|
|
|
//
|
|
// if this is a bitmap paste, Gui_GetClipboardData_BMP should have
|
|
// stored the HBITMAP handle at the top of the global data buffer
|
|
//
|
|
|
|
if (uFormat == CF_BITMAP) { // || uFormat == CF_DIB) {
|
|
|
|
void *dst = GlobalLock(_hGlobalClipData);
|
|
hGlobalRet = *(HANDLE *)dst;
|
|
GlobalUnlock(_hGlobalClipData);
|
|
}
|
|
else if (uFormat == CF_ENHMETAFILE)
|
|
{
|
|
void *dst = GlobalLock(_hGlobalClipData);
|
|
hGlobalRet = *(HANDLE *)dst;
|
|
GlobalUnlock(_hGlobalClipData);
|
|
}
|
|
}
|
|
|
|
//
|
|
// grab ownership of the clipboard again before returning
|
|
//
|
|
|
|
for (retry = 0; retry < 5000; ++retry) {
|
|
BOOL ok = Gui_OpenClipboard(OpenClipboardHwnd);
|
|
if (ok)
|
|
break;
|
|
Sleep(1);
|
|
}
|
|
|
|
SetLastError(error);
|
|
|
|
return hGlobalRet;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetClipboardData_BMP
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX void Gui_GetClipboardData_BMP(void *buf, ULONG fmt)
|
|
{
|
|
//
|
|
// GetClipboardData(CF_BITMAP) returns an HBITMAP that is valid in the
|
|
// context of SbieSvc. GuiServer::GetClipboardBitmapSlave already sent
|
|
// us the bitmap data in the reply buffer, we just need to turn it into
|
|
// a local HBITMAP handle
|
|
//
|
|
|
|
P_CreateCompatibleBitmap CreateCompatibleBitmap = NULL;
|
|
P_SetDIBits SetDIBits = NULL;
|
|
P_GetDC GetDC = NULL;
|
|
P_ReleaseDC ReleaseDC = NULL;
|
|
|
|
HBITMAP hBitmap = NULL;
|
|
|
|
if (fmt != CF_BITMAP)
|
|
SbieApi_Log(2205, L"Clipboard Bitmap (fmt %04X)", fmt);
|
|
|
|
else {
|
|
BITMAPINFO *pBitmapInfo = (BITMAPINFO *)buf;
|
|
|
|
CreateCompatibleBitmap = Ldr_GetProcAddrNew(DllName_gdi32, L"CreateCompatibleBitmap", "CreateCompatibleBitmap");
|
|
SetDIBits = Ldr_GetProcAddrNew(DllName_gdi32, L"SetDIBits", "SetDIBits");
|
|
GetDC = Ldr_GetProcAddrNew(DllName_user32, L"GetDC", "GetDC");
|
|
ReleaseDC = Ldr_GetProcAddrNew(DllName_user32, L"ReleaseDC", "ReleaseDC");
|
|
|
|
if (CreateCompatibleBitmap && GetDC && SetDIBits && ReleaseDC)
|
|
{
|
|
HDC hdc = GetDC(NULL);
|
|
|
|
if(hdc)
|
|
{
|
|
hBitmap = CreateCompatibleBitmap(hdc, pBitmapInfo->bmiHeader.biWidth, pBitmapInfo->bmiHeader.biHeight);
|
|
|
|
if (hBitmap)
|
|
{
|
|
SetDIBits(hdc, hBitmap, 0, pBitmapInfo->bmiHeader.biHeight, (UCHAR *)buf + 128, pBitmapInfo, DIB_RGB_COLORS);
|
|
}
|
|
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
*(HANDLE *)buf = hBitmap;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetClipboardData_EnhMF
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX void Gui_GetClipboardData_EnhMF(void *buf, ULONG sz, ULONG fmt)
|
|
{
|
|
//
|
|
// GetClipboardData(CF_ENHMETAFILE) returns an HENHMETAFILE object.
|
|
//
|
|
P_SetEnhMetaFileBits SetEnhMetaFileBits;
|
|
HENHMETAFILE hEnhMetaFile;
|
|
|
|
if (fmt != CF_ENHMETAFILE) {
|
|
SbieApi_Log(2205, L"Clipboard Enhanced MetaFile (fmt %04X sz %d)", fmt, sz);
|
|
return;
|
|
}
|
|
|
|
SetEnhMetaFileBits = Ldr_GetProcAddrNew(DllName_gdi32, L"SetEnhMetaFileBits","SetEnhMetaFileBits");
|
|
if (! SetEnhMetaFileBits)
|
|
return;
|
|
|
|
hEnhMetaFile = SetEnhMetaFileBits(sz, buf);
|
|
*(HANDLE*)buf = hEnhMetaFile;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetClipboardData_MF
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX void Gui_GetClipboardData_MF(void *buf, ULONG sz, ULONG fmt)
|
|
{
|
|
GUI_GET_CLIPBOARD_DATA_REQ req;
|
|
GUI_GET_CLIPBOARD_DATA_RPL *rpl;
|
|
P_SetMetaFileBitsEx SetMetaFileBitsEx;
|
|
|
|
//
|
|
// GetClipboardData(CF_METAFILEPICT) returns a structure which contains
|
|
// an HMETAFILE handle that is valid in the context of SbieSvc, so we
|
|
// make a secondary call to SbieSvc to get the data bytes so that we can
|
|
// create a local HMETAFILE handle
|
|
//
|
|
|
|
if (!SbieApi_QueryConfBool(NULL, L"OpenClipboard", TRUE))
|
|
return;
|
|
|
|
if ((fmt != CF_METAFILEPICT) || (sz != sizeof(METAFILEPICT))) {
|
|
SbieApi_Log(2205, L"Clipboard MetaFile (fmt %04X sz %d)", fmt, sz);
|
|
return;
|
|
}
|
|
|
|
SetMetaFileBitsEx = Ldr_GetProcAddrNew(DllName_gdi32, L"SetMetaFileBitsEx","SetMetaFileBitsEx");
|
|
if (! SetMetaFileBitsEx)
|
|
return;
|
|
|
|
req.msgid = GUI_GET_CLIPBOARD_METAFILE;
|
|
req.format = fmt;
|
|
rpl = Gui_CallProxyEx(&req, sizeof(req), sizeof(*rpl), TRUE);
|
|
if (! rpl)
|
|
return;
|
|
|
|
if (rpl->result) {
|
|
|
|
//
|
|
// if the request was successful, we were given a handle to a
|
|
// section which contains the data from the clipboard, but we
|
|
// have to convert this into an HGLOBAL
|
|
//
|
|
|
|
void *src = MapViewOfFileEx(
|
|
(HANDLE)(ULONG_PTR)rpl->section_handle,
|
|
FILE_MAP_READ, 0, 0, 0, NULL);
|
|
if (src) {
|
|
|
|
HGLOBAL hGlobal =
|
|
GlobalAlloc(GMEM_FIXED, (ULONG_PTR)rpl->section_length);
|
|
if (hGlobal) {
|
|
|
|
void *dst = GlobalLock(hGlobal);
|
|
if (dst) {
|
|
|
|
HMETAFILE hmf = SetMetaFileBitsEx(
|
|
(ULONG)(ULONG_PTR)rpl->section_length, src);
|
|
|
|
if (hmf) {
|
|
|
|
((METAFILEPICT *)buf)->hMF = hmf;
|
|
}
|
|
|
|
GlobalUnlock(hGlobal);
|
|
}
|
|
}
|
|
|
|
UnmapViewOfFile(src);
|
|
}
|
|
|
|
CloseHandle((HANDLE)(ULONG_PTR)rpl->section_handle);
|
|
}
|
|
|
|
Dll_Free(rpl);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_ChangeDisplaySettingsEx_impl
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX LONG Gui_ChangeDisplaySettingsEx_impl(
|
|
void* lpszDeviceName, void* lpDevMode, HWND hwnd,
|
|
DWORD dwflags, void* lParam, BOOLEAN bUnicode)
|
|
{
|
|
GUI_CHANGE_DISPLAY_SETTINGS_REQ req;
|
|
GUI_CHANGE_DISPLAY_SETTINGS_RPL* rpl;
|
|
|
|
if ((dwflags & ~(CDS_UNKNOWNFLAG | CDS_RESET | CDS_FULLSCREEN | CDS_TEST)) || lParam || hwnd) {
|
|
SbieApi_Log(2205, L"ChangeDisplaySettingsEx %08X", dwflags);
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return DISP_CHANGE_FAILED;
|
|
}
|
|
|
|
req.msgid = GUI_CHANGE_DISPLAY_SETTINGS;
|
|
req.flags = dwflags;
|
|
req.unicode = bUnicode;
|
|
|
|
if (lpszDeviceName) {
|
|
if (bUnicode) {
|
|
WCHAR* name = (WCHAR*)req.devname;
|
|
ULONG len = wcslen(lpszDeviceName);
|
|
if (len > 62)
|
|
len = 62;
|
|
wmemcpy(name, lpszDeviceName, len);
|
|
name[len] = L'\0';
|
|
}
|
|
else {
|
|
UCHAR* name = (UCHAR*)req.devname;
|
|
ULONG len = strlen(lpszDeviceName);
|
|
if (len > 62)
|
|
len = 62;
|
|
memcpy(name, lpszDeviceName, len);
|
|
name[len] = L'\0';
|
|
}
|
|
req.have_devname = TRUE;
|
|
}
|
|
else {
|
|
memzero(req.devname, sizeof(req.devname));
|
|
req.have_devname = FALSE;
|
|
}
|
|
|
|
if (lpDevMode) {
|
|
memcpy(&req.devmode, lpDevMode, bUnicode ? sizeof(DEVMODEW) : sizeof(DEVMODEA));
|
|
req.have_devmode = TRUE;
|
|
}
|
|
else
|
|
req.have_devmode = FALSE;
|
|
|
|
rpl = Gui_CallProxy(&req, sizeof(req), sizeof(*rpl));
|
|
if (!rpl)
|
|
return DISP_CHANGE_FAILED;
|
|
else {
|
|
ULONG error = rpl->error;
|
|
ULONG retval = rpl->retval;
|
|
Dll_Free(rpl);
|
|
SetLastError(error);
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_ChangeDisplaySettingsExA
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX LONG Gui_ChangeDisplaySettingsExA(
|
|
void *lpszDeviceName, void *lpDevMode, HWND hwnd,
|
|
DWORD dwflags, void *lParam)
|
|
{
|
|
return Gui_ChangeDisplaySettingsEx_impl(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam, FALSE);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_ChangeDisplaySettingsExW
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX LONG Gui_ChangeDisplaySettingsExW(
|
|
void *lpszDeviceName, void *lpDevMode, HWND hwnd,
|
|
DWORD dwflags, void *lParam)
|
|
{
|
|
return Gui_ChangeDisplaySettingsEx_impl(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam, TRUE);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetRawInputDeviceInfo_impl
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX LONG Gui_GetRawInputDeviceInfo_impl(
|
|
_In_opt_ HANDLE hDevice, _In_ UINT uiCommand,
|
|
_Inout_ LPVOID pData, _Inout_ PUINT pcbSize, BOOLEAN bUnicode)
|
|
{
|
|
GUI_GET_RAW_INPUT_DEVICE_INFO_REQ* req;
|
|
GUI_GET_RAW_INPUT_DEVICE_INFO_RPL* rpl;
|
|
|
|
// Note: pcbSize seems to be in tchars not in bytes!
|
|
ULONG lenData = 0;
|
|
if (pData && pcbSize)
|
|
lenData = (*pcbSize) * (bUnicode ? sizeof(WCHAR) : 1);
|
|
|
|
ULONG reqSize = sizeof(GUI_GET_RAW_INPUT_DEVICE_INFO_REQ) + lenData + 10;
|
|
req = Dll_Alloc(reqSize);
|
|
|
|
LPVOID reqData = (BYTE*)req + sizeof(GUI_GET_RAW_INPUT_DEVICE_INFO_REQ);
|
|
|
|
req->msgid = GUI_GET_RAW_INPUT_DEVICE_INFO;
|
|
req->hDevice = (ULONG64)hDevice;
|
|
req->uiCommand = uiCommand;
|
|
req->unicode = bUnicode;
|
|
if (lenData) {
|
|
memcpy(reqData, pData, lenData);
|
|
req->hasData = TRUE;
|
|
} else
|
|
req->hasData = FALSE;
|
|
req->cbSize = pcbSize ? *pcbSize : -1;
|
|
|
|
rpl = Gui_CallProxy(req, reqSize, sizeof(*rpl));
|
|
|
|
Dll_Free(req);
|
|
|
|
if (!rpl)
|
|
return -1;
|
|
else {
|
|
ULONG error = rpl->error;
|
|
ULONG retval = rpl->retval;
|
|
|
|
if (pcbSize)
|
|
*pcbSize = rpl->cbSize;
|
|
if (lenData) {
|
|
LPVOID rplData = (BYTE*)rpl + sizeof(GUI_GET_RAW_INPUT_DEVICE_INFO_RPL);
|
|
memcpy(pData, rplData, lenData);
|
|
}
|
|
|
|
Dll_Free(rpl);
|
|
SetLastError(error);
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetRawInputDeviceInfoA
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX LONG Gui_GetRawInputDeviceInfoA(
|
|
_In_opt_ HANDLE hDevice, _In_ UINT uiCommand,
|
|
_Inout_ LPVOID pData, _Inout_ PUINT pcbSize)
|
|
{
|
|
return Gui_GetRawInputDeviceInfo_impl(hDevice, uiCommand, pData, pcbSize, FALSE);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetRawInputDeviceInfoW
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX LONG Gui_GetRawInputDeviceInfoW(
|
|
_In_opt_ HANDLE hDevice, _In_ UINT uiCommand,
|
|
_Inout_ LPVOID pData, _Inout_ PUINT pcbSize)
|
|
{
|
|
return Gui_GetRawInputDeviceInfo_impl(hDevice, uiCommand, pData, pcbSize, TRUE);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// IMM32 - ImmAssociateContext and ImmAssociateContextEx
|
|
//
|
|
// kernel side handlers for ImmAssociateContext and ImmAssociateContextEx
|
|
// check that the specified HWND and HIMC objects are on the same desktop.
|
|
// but the default HIMC is created during WIN32K thread creation, at which
|
|
// time the thread is connected to a dummy desktop (see more about this in
|
|
// Gui_ConnectToWindowStationAndDesktop).
|
|
//
|
|
// when a thread calls these functions it is already connected to the real
|
|
// desktop, so we can easily work around this problem by creating a new
|
|
// HIMC object in the real desktop and passing it instead.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
static ULONG_PTR Gui_ImmAssociateContext(ULONG_PTR hwnd, ULONG_PTR imc);
|
|
|
|
static BOOL Gui_ImmAssociateContextEx(
|
|
ULONG_PTR hwnd, ULONG_PTR imc, ULONG flags);
|
|
|
|
typedef ULONG_PTR (*P_ImmAssociateContext)(ULONG_PTR hwnd, ULONG_PTR imc);
|
|
|
|
typedef BOOL (*P_ImmAssociateContextEx)(
|
|
ULONG_PTR hwnd, ULONG_PTR imc, ULONG flags);
|
|
|
|
typedef ULONG_PTR (*P_ImmCreateContext)(void);
|
|
|
|
static P_ImmAssociateContext __sys_ImmAssociateContext = NULL;
|
|
static P_ImmAssociateContextEx __sys_ImmAssociateContextEx = NULL;
|
|
static P_ImmCreateContext __sys_ImmCreateContext = NULL;
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_Init_IMM32
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOLEAN Gui_Init_IMM32(HMODULE module)
|
|
{
|
|
// NoSbieDesk BEGIN
|
|
if (Dll_CompartmentMode || SbieApi_QueryConfBool(NULL, L"NoSandboxieDesktop", FALSE))
|
|
return TRUE;
|
|
// NoSbieDesk END
|
|
|
|
__sys_ImmAssociateContext = (P_ImmAssociateContext)
|
|
GetProcAddress(module, "ImmAssociateContext");
|
|
|
|
__sys_ImmAssociateContextEx = (P_ImmAssociateContextEx)
|
|
GetProcAddress(module, "ImmAssociateContextEx");
|
|
|
|
__sys_ImmCreateContext = (P_ImmCreateContext)
|
|
GetProcAddress(module, "ImmCreateContext");
|
|
|
|
if (__sys_ImmCreateContext) {
|
|
|
|
if (__sys_ImmAssociateContext) {
|
|
SBIEDLL_HOOK_GUI(ImmAssociateContext);
|
|
}
|
|
|
|
if (__sys_ImmAssociateContextEx) {
|
|
SBIEDLL_HOOK_GUI(ImmAssociateContextEx);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_ImmAssociateContext
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX ULONG_PTR Gui_ImmAssociateContext(ULONG_PTR hwnd, ULONG_PTR imc)
|
|
{
|
|
ULONG LastError;
|
|
THREAD_DATA *TlsData = Dll_GetTlsData(&LastError);
|
|
|
|
imc = __sys_ImmAssociateContext(hwnd, imc);
|
|
if ((! imc) && (GetLastError() == ERROR_ACCESS_DENIED)) {
|
|
|
|
imc = TlsData->gui_himc;
|
|
if (! imc) {
|
|
imc = __sys_ImmCreateContext();
|
|
if (! imc) {
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return FALSE;
|
|
}
|
|
TlsData->gui_himc = imc;
|
|
}
|
|
|
|
imc = __sys_ImmAssociateContext(hwnd, imc);
|
|
}
|
|
|
|
return imc;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_ImmAssociateContextEx
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_ImmAssociateContextEx(
|
|
ULONG_PTR hwnd, ULONG_PTR imc, ULONG flags)
|
|
{
|
|
ULONG LastError;
|
|
THREAD_DATA *TlsData = Dll_GetTlsData(&LastError);
|
|
|
|
BOOL ok = __sys_ImmAssociateContextEx(hwnd, imc, flags);
|
|
if ((! ok) && (GetLastError() == ERROR_ACCESS_DENIED)) {
|
|
|
|
imc = TlsData->gui_himc;
|
|
if (! imc) {
|
|
imc = __sys_ImmCreateContext();
|
|
if (! imc) {
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return FALSE;
|
|
}
|
|
TlsData->gui_himc = imc;
|
|
}
|
|
|
|
ok = __sys_ImmAssociateContextEx(hwnd, imc, 0);
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetDC
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX HDC Gui_GetDC(HWND hWnd)
|
|
{
|
|
HDC ret = __sys_GetDC(hWnd);
|
|
|
|
ULONG_PTR pid = 0, tid = 0;
|
|
if (Gui_UseBlockCapture && (hWnd == NULL || hWnd == __sys_GetDesktopWindow() || !Gui_IsSameBox(hWnd, &pid, &tid))) {
|
|
|
|
return Gdi_GetDummyDC(ret, hWnd);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetWindowDC
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX HDC Gui_GetWindowDC(HWND hWnd)
|
|
{
|
|
HDC ret = __sys_GetWindowDC(hWnd);
|
|
|
|
ULONG_PTR pid = 0, tid = 0;
|
|
if (Gui_UseBlockCapture && (hWnd == NULL || hWnd == __sys_GetDesktopWindow() || !Gui_IsSameBox(hWnd, &pid, &tid))) {
|
|
|
|
return Gdi_GetDummyDC(ret, hWnd);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_GetDCEx
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX HDC Gui_GetDCEx(HWND hWnd, HRGN hrgnClip, DWORD flags)
|
|
{
|
|
HDC ret = __sys_GetDCEx(hWnd, hrgnClip, flags);
|
|
|
|
ULONG_PTR pid = 0, tid = 0;
|
|
if (Gui_UseBlockCapture && (hWnd == NULL || hWnd == __sys_GetDesktopWindow() || !Gui_IsSameBox(hWnd, &pid, &tid))) {
|
|
|
|
return Gdi_GetDummyDC(ret, hWnd);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_PrintWindow
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_PrintWindow(HWND hwnd, HDC hdcBlt, UINT nFlags)
|
|
{
|
|
if (Gui_UseBlockCapture) {
|
|
|
|
if (hwnd == NULL || hwnd == __sys_GetDesktopWindow()) {
|
|
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return 0;
|
|
}
|
|
|
|
ULONG_PTR pid = 0, tid = 0;
|
|
if (!Gui_IsSameBox(hwnd, &pid, &tid)) {
|
|
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return 0;
|
|
}
|
|
}
|
|
return __sys_PrintWindow(hwnd, hdcBlt, nFlags);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_ReleaseDC
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX int Gui_ReleaseDC(HWND hWnd, HDC hdc)
|
|
{
|
|
hdc = Gdi_OnFreeDC(hdc);
|
|
if (!hdc)
|
|
return 1;
|
|
return __sys_ReleaseDC(hWnd, hdc);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_ShutdownBlockReasonCreate
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOL Gui_ShutdownBlockReasonCreate(HWND hWnd, LPCWSTR pwszReason)
|
|
{
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return 0;
|
|
//return __sys_ShutdownBlockReasonCreate(hWnd, pwszReason);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Gui_SetThreadExecutionState
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX EXECUTION_STATE Gui_SetThreadExecutionState(EXECUTION_STATE esFlags)
|
|
{
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return 0;
|
|
//return __sys_SetThreadExecutionState(esFlags);
|
|
}
|