Detect external devices insertion on Windows - c++

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.

Related

c++ enable accessibility inspection in Google Chrome

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.

Name of process for active window in Windows 8/10

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.

Monitoring Screensaver activity fails on Windows 7

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);

How to get names of the icons on desktop

guys.
I want to obtain names of icons on desktop in c++. And I know how to get their handle:
HWND hwnd = FindWindow("Progman","Program Manager");
HWND hwndSHELLDLL_DefView = ::FindWindowEx( hwnd, NULL, "SHELLDLL_DefView", NULL );
HWND hwndSysListView32 = ::FindWindowEx( hwndSHELLDLL_DefView, NULL, "SysListView32", "FolderView" );
What's next?
First, you need to get the location of the desktop folder using SHGetFolderLocation.. Next, you enumerate the contents of this folder using IShellFolder::EnumObjects
From here, the sky is the limit. Tons of information on interacting with the windows shell here.
Have fun!
Update:
A quick google search turns up this sample which seems to do exactly what you want.

ActiveX HWND, DirectX WindowLess mode

I would like to render video in ActiveX control (not in pop-up DirectShow window). I have:
IID_IVMRWindowlessControl
IID_IVMRFilterConfig9
CLSID_VideoMixingRenderer9
I would like to set WindowLess mode, but I don't know how to get HWND of..., exactly, of what? IEFrame, HTML element?
hr = pWc->SetVideoClippingWindow(???);
Anyone with some hint?
Regards.
First of all, add this to the constructor of your ActiveX control:
// this seemingly innocent line is _extremely_ important.
// This causes the window for the control to be created
// otherwise, you won't get an hWnd to render to!
m_bWindowOnly = true;
Your ActiveX control will have a member variable called m_hWnd that you'll be able to use as a render target. without the m_bWindowOnly variable set true, the ActiveX control won't create its own window.
Finally, pick your renderer (VMR9 for example)
CRect rcClient;
CComPtr<IBaseFilter> spRenderer;
CComPtr<IVMRWindowlessControl9> spWindowless;
// Get the client window size
::GetClientRect(m_hWnd, rcClient);
// Get the renderer filter
spRenderer.Attach( m_pGraph->GetVideoRenderer() );
if( ! spRenderer )
return E_POINTER;
spWindowless = spRenderer;
if( spWindowless )
{
spWindowless->SetVideoClippingWindow( m_hWnd );
spWindowless->SetVideoPosition(NULL, rcClient);
spWindowless.Release();
}
spRenderer.Detach();
Please note that my graph object is a custom object and that GetVideoRenderer() is one of my own functions - it returns an IBaseFilter*.
It took me ages to find this one out. ATL is poorly documented, which is a shame, because it's an excellent technology. Anyways, hope this helps!
freefallr's info is extremely helpful, but I don't think it answers your question completely. The trick with windowless activex controls is that you don't get a window. When you draw you'll just basically get a device context and you have to respond to call from the browser and only draw when it tells you to.
The interfaces required are here: http://msdn.microsoft.com/en-us/library/ms682300%28v=VS.85%29.aspx
more info here: http://msdn.microsoft.com/en-us/library/aa751970%28VS.85%29.aspx#OC96_and_Windowless_
We've been meaning to add support for this in FireBreath (http://firebreath.org) for awhile; we have support for it in all npapi browsers, but looks like we don't (yet) support IE. If you find more details, post a summary here =]