Good afternoon, i have a section of code i am using to monitor screen saver activity in Windows XP onwards, this currently works correctly on all Windows OS's except for Windows 7, i am aware that certain screen saver parameters to the SystemParametersInfo function are not available in Windows 7 but thought that SPI_GETSCREENSAVERRUNNING was available, the code is as follows:
BOOL bScrnSvrRunning = FALSE;
BOOL bResult = SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &boolScreenSaverRunning, 0);
The function always returns true for bResult but bScrnSvrRunning is always false,
does anyone have any idea what might cause this?
If you really want to monitor the screen saver activity you can consider to use System Event Notification Service (SENS). The System Event Notification Service monitors and dispatches there, so it can notify your application about the starting (see ISensLogon::StartScreenSaver) and stopping (see ISensLogon::StopScreenSaver) of the screen saver many events. An example how to use SENS you can find here (see also here and here).
You are using the wrong parameter "slot". Look closely at the declaration of SystemParametersInfo:
BOOL WINAPI SystemParametersInfo(
__in UINT uiAction,
__in UINT uiParam,
__inout PVOID pvParam,
__in UINT fWinIni
);
And let me quote the info for SPI_GETSCREENSAVERRUNNING:
Determines whether a screen saver is currently running on the window station of the calling process. The pvParam parameter must point to a BOOL variable that receives TRUE if a screen saver is currently running, or FALSE otherwise.
pvParam is the one that recieves the info, so you must supply your bool in the pvParam parameter:
BOOL bScrnSvrRunning = FALSE;
BOOL bResult = SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &boolScreenSaverRunning, 0);
Related
I have a two-monitor setup running on Windows 10 and my secondary monitor is a touch-screen. I can detect both monitors with EnumDisplayMonitors and discover that there is a digitizer present with GetSystemMetrics(SM_DIGITIZER). I'd like my app window to open on the touch monitor, but I can't find any function that tells me which monitor the digitizer "belongs" to.
In the absence of a solution, I suppose I could have a start-up sequence during which the user is asked to tap the touch screen, then my code could move the window to the corresponding monitor. I'd just like it to be slicker than that.
Any ideas?
GetPointerDevices function give you that information. POINTER_DEVICE_INFO contains monitor handle and device pointer type in the same structure:
typedef struct tagPOINTER_DEVICE_INFO {
DWORD displayOrientation;
HANDLE device;
POINTER_DEVICE_TYPE pointerDeviceType; // can be POINTER_DEVICE_TYPE_TOUCH see below
HMONITOR monitor; // Monitor handle
ULONG startingCursorId;
USHORT maxActiveContacts;
WCHAR productString[POINTER_DEVICE_PRODUCT_STRING_MAX];
} POINTER_DEVICE_INFO;
typedef enum tagPOINTER_DEVICE_TYPE {
POINTER_DEVICE_TYPE_INTEGRATED_PEN,
POINTER_DEVICE_TYPE_EXTERNAL_PEN,
POINTER_DEVICE_TYPE_TOUCH,
POINTER_DEVICE_TYPE_TOUCH_PAD,
POINTER_DEVICE_TYPE_MAX
} POINTER_DEVICE_TYPE;
GetDesktopWindow() returns only the primary desktop. I've also tried EnumDisplayMonitors(), but that doesn't return the desktop handle.
You can do this using the functions that are available, as follows:
Method 1 (less accurate for windows overlapping a monitor boundary)
Enumerate all windows (EnumWindows())
Use MonitorFromWindow() to ignore the ones that aren't on the monitor are on a monitor other than the one you care about.
Method 2 (more accurate)
Get the bounds of the monitor you care about (GetMonitorInfo() function)
Enumerate all windows (EnumWindows())
Check each window's outline rectangle (GetWindowRect() for XP, otherwise DwmGetWindowAttribute(DWMWA_EXTENDED_FRAME_BOUNDS)) to see if it intersects (IntersectRect()) with the monitor rectangle.
You can use EnumWindows function and then check that window belongs to the specific monitor:
BOOL CALLBACK EnumWindowsProc(_In_ HWND hwnd, _In_ LPARAM lParam) noexcept
{
auto const h_monitor{::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL)};
if(h_monitor == g_h_target_minitor)
{
// Do something...
}
return TRUE;
}
I'm trying to access text of Google Chrome's webpage to read it and offer some actions (for example, remind). Everything works good, but I need to enable accessibility inspection programmatically. I use this code:
wchar_t className[100];
GetClassName(hwnd, className, 100) == 0 || wcscmp(className, L"Chrome_WidgetWin_1");
CComPtr<IAccessible> pAccMain;
HRESULT hr = ::AccessibleObjectFromWindow(hWndChrome, 1, IID_IAccessible, (void**)(&pAccMain));
CComPtr<IAccessible> pAccMain2;
::AccessibleObjectFromWindow(hWndChrome, OBJID_CLIENT, IID_IAccessible, (void**)(&pAccMain2));
And nothing happens until I run browser with --force-renderer-accessibility parameter or manually change accessibility settings located in chrome://accessibility.
What am i doing wrong?
Found this info: "Chrome calls NotifyWinEvent with EVENT_SYSTEM_ALERT and the custom object id of 1. If it subsequently receives a WM_GETOBJECT call for that custom object id, it assumes that assistive technology is running". Does anybody know how to implement this?
Use SetWinEventHook, e.g.
HWINEVENTHOOK hook = SetWinEventHook(EVENT_SYSTEM_ALERT, EVENT_SYSTEM_ALERT,NULL, WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT)
Then in your WinEventProc, you'll be given a hWnd, idObject, and idChild when Chrome sends the EVENT_SYSTEM_ALERT.
If idObject == 1 then call AccessibleObjectFromEvent(), passing it those hWnd, idObject, and idChild arguments.
AccessibleObjectFromEvent will then send the WM_GETOBJECT. From the docs::
Applications never send this message directly. Microsoft Active Accessibility sends this message in response to calls to AccessibleObjectFromPoint, AccessibleObjectFromEvent, or AccessibleObjectFromWindow.
By using AccEvent I can see that Google Chrome only appears to send the EVENT_SYSTEM_ALERT when it starts, e.g. opening a new tab doesn't trigger it, so you'd need to have done the SetWinEventHook() before Chrome is launched.
I'm a little bit confused about how to notify my c++ application with event that the user has plugged in a device (USB, HID etc.). Application type is not defined. I'm trying to play around with console/message-only/service example apps, but there is no result. I'm using VS2015 and Windows 10.
I've found out that there are multiple ways to deal with it:
Using WMI like here. But I can not actually understand where is WMI here.
Using RegisterDeviceNotification and WM_DEVICECHANGE. As far as I can understand, there is no way to do that for the console applications, only for once with the GUI (real window) or for the message-only window. I've tried the last one with the example from this answer but my app doesn't receive any notifications when I plug in my USB flash drive. I've found this answer (from the same question as the answer mentioned above) and tried to use ChangeWindowMessageFilterEx() function with GetProcAddress from user32.dll to load it without connection dll to my app in such way:
BOOL InitInstance(HWND hWnd)
{
HMODULE hDll = GetModuleHandle(TEXT("user32.dll"));
if (hDll)
{
typedef BOOL(WINAPI *MESSAGEFILTERFUNCEX)(HWND hWnd, UINT message, DWORD action, VOID* pChangeFilterStruct);
const DWORD MSGFLT_ALLOW = 1;
MESSAGEFILTERFUNCEX ChangeWindowMessageFilterEx= (MESSAGEFILTERFUNCEX)::GetProcAddress(hDll, "ChangeWindowMessageFilterEx");
if (ChangeWindowMessageFilterEx) return func(hWnd, WM_COPYDATA, MSGFLT_ALLOW, NULL);
}
return FALSE; }
And the usage of this function is:
hWnd = CreateWindowEx(0, CLS_NAME, "DevNotifWnd", WS_ICONIC,
0, 0, CW_USEDEFAULT, 0, HWND_MESSAGE,
NULL, GetModuleHandle(0), (void*)&guid);
InitInstance(hWnd);
But there is no effect.
Using while(true){...} loop and call appropriate Win API functions like in this answer. But this way seems not be a perfect solution for my problem.
My questions are:
Could anybody explain me what is the best way? And if it is the second one with RegisterDeviceNotification, why it's not working in case of message-only window app?
Do other ways exist? And if not, what can I do, for example, to notify application when some certain software was installed?
Any comments are appreciated.
So I've finally found sort of answers to the questions.
The issue was with the GUID I've provided for the NotificationFilter. So I've set it to receive notifications from all devices with this code:
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
// No need to set up dbcc_classguid as it is ignored when
// DEVICE_NOTIFY_ALL_INTERFACE_CLASSES is setted (see line down below)
HDEVNOTIFY dev_notify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
As far as for other types of notifications in windows that the app could sign up for, I found only one partially deprecated list of all Win32 API functions, where I found some new Notifications with Ctrl+F search :)
Hope this could save somebody's time.
The following sample has reliably returned the name of the process that is associated with the active window, but does not work with the newer modern/universal apps because it returns the name of a helper process WWAHost.exe on Windows 8 and ApplicationFrameHost.exe on Windows 10 rather than the name of the app.
HWND active_window = GetForegroundWindow();
GetWindowThreadProcessId(active_window, &active_process_id);
HANDLE active_process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, active_process_id);
GetProcessImageFileName(active_process, image_name, 512);
With Windows 10 the ApplicationFrameHost.exe is the process that creates the window handles and is what gets returned by GetWindowThreadProcessId(), is there another Win32 API that can be used to get the active process of universal app that is active?
Also tried using GetApplicationUserModelId() and GetPackageFullName() with no success as they return APPMODEL_ERROR_NO_APPLICATION and APPMODEL_ERROR_NO_PACKAGE respectively because the active_process handle is just the helper process and not the process of the active application.
Any other APIs to use to get the process name of a Modern/Universal application given the hwnd of the window, or otherwise figure out the process name of the universal app is active.
Thanks in advance!
Be sure to use the Spy++ utility when you want to reverse-engineer something like this. Included with Visual Studio, you need the 64-bit version in Common7\Tools\spyxx_amd64.exe. Use Search > Find Window and drag the bullseye to a UWP app, like Weather.
You'll see the window you'll find with GetForegroundWindow(), it has at least 3 child windows:
ApplicationFrameTitleBarWindow
ApplicationFrameInputSinkWindow
Windows.Core.UI.CoreWindow, that's the host window for the UWP app and the one you are interested in. Right-click it and select Properties, Process tab, click the Process ID. That takes you to the real owner process you want to know.
So you just need to make an extra step from the code you already have, you just have to enumerate the child windows and look for one with a different owner process. Some C code, trying to make it as universal as possible without making too many assumptions and not enough error checking:
#include <stdio.h>
#include <Windows.h>
typedef struct {
DWORD ownerpid;
DWORD childpid;
} windowinfo;
BOOL CALLBACK EnumChildWindowsCallback(HWND hWnd, LPARAM lp) {
windowinfo* info = (windowinfo*)lp;
DWORD pid = 0;
GetWindowThreadProcessId(hWnd, &pid);
if (pid != info->ownerpid) info->childpid = pid;
return TRUE;
}
int main()
{
Sleep(2000);
HWND active_window = GetForegroundWindow();
windowinfo info = { 0 };
GetWindowThreadProcessId(active_window, &info.ownerpid);
info.childpid = info.ownerpid;
EnumChildWindows(active_window, EnumChildWindowsCallback, (LPARAM)&info);
HANDLE active_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, info.childpid);
WCHAR image_name[MAX_PATH] = { 0 };
DWORD bufsize = MAX_PATH;
QueryFullProcessImageName(active_process, 0, image_name, &bufsize);
wprintf(L"%s\n", image_name);
CloseHandle(active_process);
return 0;
}
Output on the Weather program:
C:\Program Files\WindowsApps\Microsoft.BingWeather_4.5.168.0_x86__8wekyb3d8bbwe\
Microsoft.Msn.Weather.exe
Here is a small console app application that continuously (so you can test it easily selecting different windows on your desktop) display information about the current foreground window process and store process, if any.
Apps can have a window hierarchy that can span multiple processes. What I do here is search the first sub window that has the 'Windows.UI.Core.CoreWindow' class name.
This app uses the UIAutomation API (and also smart pointers, smart BSTRs and smart VARIANTs provided by the #import directive). I suppose you can do the same with standard Windows SDK, but I find the UIAutomation used this way quite elegant.
#include "stdafx.h"
#import "UIAutomationCore.dll"
using namespace UIAutomationClient;
int main()
{
// initialize COM, needed for UIA
CoInitialize(NULL);
// initialize main UIA class
IUIAutomationPtr pUIA(__uuidof(CUIAutomation));
do
{
// get the Automation element for the foreground window
IUIAutomationElementPtr foregroundWindow = pUIA->ElementFromHandle(GetForegroundWindow());
wprintf(L"pid:%i\n", foregroundWindow->CurrentProcessId);
// prepare a [class name = 'Windows.UI.Core.CoreWindow'] condition
_variant_t prop = L"Windows.UI.Core.CoreWindow";
IUIAutomationConditionPtr condition = pUIA->CreatePropertyCondition(UIA_ClassNamePropertyId, prop);
// get the first element (window hopefully) that satisfies this condition
IUIAutomationElementPtr coreWindow = foregroundWindow->FindFirst(TreeScope::TreeScope_Children, condition);
if (coreWindow)
{
// get the process id property for that window
wprintf(L"store pid:%i\n", coreWindow->CurrentProcessId);
}
Sleep(1000);
} while (TRUE);
cleanup:
CoUninitialize();
return 0;
}
Does taking snapshot of running processes and pulling the name out of it by comparing process id not work?
Full reference here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686837(v=vs.85).aspx
But you fix the snapshot with CreateToolhelp32Snapshot().
Or from WTSEnumerateProcesses() and surrounding API?
Pretty sure it worked in Win 8. Is it broken in 10?
Starting from Win10 Anniversary Update ApplicationFrameHost child window return anything but UWP application. It worked only in Tablet mode after relogon.