WM_DEVICECHANGE received but not DBT_DEVICEARRIVAL in my Qt app - c++

I am following an example to detect USB flash drive plugin and plugout detection in Windows 7. I do receive the notification WM_DEVICECHANGE but not DBT_DEVICEARRIVAL which is when USB device is plugged in. My code is below:
/*******************************************
* WINDOWS EVENTS
********************************************/
/*We use the first WM_PAINT event to get the handle of main window
and pass it to RegisterDeviceNotification function.
It not possible to do this in the contructor because the
main window does not exist yet.
WM_DEVICECHANGE event notify us that a device is attached or detached */
bool USBexample::nativeEvent(const QByteArray & eventType, void * message, long * result)
{
MSG * msg = static_cast< MSG * > (message);
int msgType = msg->message;
if(msgType == WM_PAINT)
{
if(!msgp) //Only the first WM_PAINT
{
GUID InterfaceClassGuid = HID_CLASSGUID;
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = InterfaceClassGuid;
HWND hw = (HWND) this->effectiveWinId(); //Main window handle
hDevNotify = RegisterDeviceNotification(hw,&NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
msgp = true;
}
}
if(msgType == WM_DEVICECHANGE)
{
qDebug() << "WM_DEVICECHANGE recieved";
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
switch(msg->wParam)
{
case DBT_DEVICEARRIVAL: // never comes here!
if (lpdb -> dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
qDebug() << "DBT_DEVICEARRIVAL case";
PDEV_BROADCAST_DEVICEINTERFACE lpdbv = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb;
int i = 0;
QString s;
//to find a better way for this...
while(lpdbv->dbcc_name[i] != 0)
{
s.append(lpdbv->dbcc_name[i]);
i++;
}
s = s.toUpper();
if(s.contains(MY_DEVICE_VIDPID))
emit USB_Arrived();
}
break;
case DBT_DEVICEREMOVECOMPLETE:
if (lpdb -> dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
qDebug() << "DBT_DEVICEREMOVECOMPLETE case";
PDEV_BROADCAST_DEVICEINTERFACE lpdbv = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb;
int i = 0;
QString s;
//to find a better way for this...
while(lpdbv->dbcc_name[i] != 0)
{
s.append(lpdbv->dbcc_name[i]);
i++;
}
s = s.toUpper();
if(s.contains(MY_DEVICE_VIDPID))
emit USB_Removed();
}
break;
case DBT_DEVICEREMOVEPENDING :
{
qDebug() << "DBT_DEVICEREMOVEPENDING case";
}
break;
default:
{
qDebug() << "Went to Default case";
}
}
}
return false;
}

I figure this out and here is the solution if anyone else runs into similar issue.
The problem was InterfaceClassGuid in the line below.
GUID InterfaceClassGuid = HID_CLASSGUID;
HID_CLASSGUID was set to the following in my code:
#define HID_CLASSGUID {0x4d1e55b2, 0xf16f, 0x11cf,{ 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30}}
This was wrong, I picked this up from example and never realized I would need to change it. There are different values to register for different kind of notifications and the help system was not that helpful in this case but here is the list of valid GUID values.
I changed it to the following and now I get the desired notifications.
#define HID_CLASSGUID {0x745a17a0,0x74d3, 0x11d0, 0xb6fe, 0x00a0c90f57da}

Another possible cause of this problem could be the incorrect handle of the window being passed to the RegisterDeviceNotification(...) call.
Wrong code:
QMainWindow w;
...
HANDLE windowId = w.window()->winId();
RegisterDeviceNotification(&windowId,&NotificationFilter,DEVICE_NOTIFY_WINDOW_HANDLE);
I was passing the wrong value for winId's address and I kept getting 7 for wparam although the device insertion and removal was getting detected.
After I changed it to use the correct address of the window handle, I passed this to the RegisterDeviceNotification call and it worked.
Correct code:
QMainWindow w;
...
HANDLE *windowId = (HANDLE *)w.window()->winId();
RegisterDeviceNotification(windowId,&NotificationFilter,DEVICE_NOTIFY_WINDOW_HANDLE);

Related

SendInput to Ctrl+C text Doesn't Work When Launched from Hotkey

Currently using this code to Copy selected text in currently open Window in Windows 10. This code is working fine if I run it on its own by when my target program (Notepad) has focus. The selected text in notepad is copied into data variable OK.
wchar_t title[MAX_PATH];
HWND target_window = GetForegroundWindow();
GetWindowText(target_window, title, MAX_PATH);
std::wcout << "Target window is '" << title << "'" << std::endl;
// Send Control + C
int key_count = 4;
INPUT* input = new INPUT[key_count];
for (int i = 0; i < key_count; i++)
{
input[i].ki.dwFlags = 0;
input[i].type = INPUT_KEYBOARD;
}
input[0].ki.wVk = VK_CONTROL;
input[0].ki.wScan = MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC);
input[1].ki.wVk = 0x43; // Virtual key code for 'c'
input[1].ki.wScan = MapVirtualKey(0x43, MAPVK_VK_TO_VSC);
input[2].ki.dwFlags = KEYEVENTF_KEYUP;
input[2].ki.wVk = input[0].ki.wVk;
input[2].ki.wScan = input[0].ki.wScan;
input[3].ki.dwFlags = KEYEVENTF_KEYUP;
input[3].ki.wVk = input[1].ki.wVk;
input[3].ki.wScan = input[1].ki.wScan;
if (!SendInput(key_count, (LPINPUT)input, sizeof(INPUT)))
{
// TODO: error handling
}
else
{
// not ideal but not sure of another way to wait for SendInput to complete
Sleep(100);
if (OpenClipboard(NULL))
{
HGLOBAL hglb = GetClipboardData(CF_UNICODETEXT);
LPWSTR lpwstr = (LPWSTR)(GlobalLock(hglb));
std::wstring data(lpwstr);
GlobalUnlock(hglb);
CloseClipboard();
// do something with selected text in data
}
else
{
// TODO: error handling
}
}
However, if I launch the exact same code via Hotkey, it doesn't work:
if (RegisterHotKey(
NULL,
1,
MOD_CONTROL | MOD_ALT | MOD_NOREPEAT,
VK_OEM_2)) // back slash question mark key
{
std::cout << "Hotkey 'Ctrl+Alt+/' registered, using MOD_NOREPEAT flag\n";
}
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0) != 0)
{
if (msg.message == WM_HOTKEY)
{
std::cout << "WM_HOTKEY received\n";
// Call function to COPY TEXT here
if (RegisterHotKey(
NULL,
1,
MOD_CONTROL | MOD_ALT | MOD_NOREPEAT,
VK_OEM_2)) // back slash question mark key
{
std::cout << "Hotkey 'Ctrl+Alt+/' registered, using MOD_NOREPEAT flag\n";
}
}
}
Now, in both cases, GetWindowText() is showing the title of the program I want to copy text from.
In addition, I wrote a simple test utility to check Ctrl+C is being passed to Window, which it is. It seems like Ctrl+C is being passed, but the copy is not occurring.
Is it possible that Alt is still down because of the hotkey and you are actually sending Ctrl+Alt+C? SendInput inserts the input directly into the global input queue.
You could try setting a timer in response to the hotkey and call GetAsyncKeyState in the timer handler until all modifier keys are up before generating input.
A better alternative would be to use UI Automation instead of a hack like this.

Get Raw Mouse Movement in Qt

After working on this and QAbstractNativeEventFilter class I finally got native events from HID (both mouse and keyboard).
I've read many similar questions but none solved my problem. I try to get mouse movement based on dpi. I work on Qt 5.5 cause my whole project built there.
I can't separate mouse movement events from other HID events (mouse and keyboard) even with RIM_TYPEMOUSE flag.
Here is some code from my implementation:
bool MouseRawMovement::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
if(eventType == "windows_generic_MSG")
{
MSG *msg = reinterpret_cast<MSG*>(message);
qDebug()<<msg->message; // It prints numbers such as 6,26,28,141 on each event
if(msg->message == WM_INPUT) //it never gets in
{
UINT dwSize = 40;
static BYTE lpb[40];
GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT,
lpb, &dwSize, sizeof(RAWINPUTHEADER));
RAWINPUT* raw = (RAWINPUT*)lpb;
if (raw->header.dwType == RIM_TYPEMOUSE)
{
int xPosRelative = raw->data.mouse.lLastX;
int yPosRelative = raw->data.mouse.lLastY;
qDebug()<<xPosRelative<<yPosRelative ;
}
}
}
return false;
}
Also here is my constructor
MouseRawMovement::MouseRawMovement()
{
Rid[0].usUsagePage = 0x01;
Rid[0].usUsage = 0x02;
Rid[0].dwFlags = RIDEV_INPUTSINK;
Rid[0].hwndTarget = 0;
if(!RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])))
qDebug()<<QString::number(GetLastError()); //I see error msg 6 - Ref. ERROR_INVALID_HANDLE
}
Output shows me zeros (0) all time.
Whats going on with hWnd. I tried to give this:
HWND hWnd =::GetConsoleWindow();
but I had the same result.
In main.cpp I install native Filter
MainWindow w;
a.installNativeEventFilter(&w.mm);
I try for days and I could not find the solution. Is there anyone...(???)
#nnatarr your help was substantial! Thank you!!!
I finally find the solution.
I had to call RegisterRawInputDevices in main.cpp and change lot of things.
Here is main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <windows.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
a.installNativeEventFilter(&w.mm);
w.show();
UINT nDevices;
PRAWINPUTDEVICELIST pRawInputDeviceList;
if (!GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)))
{
qDebug() << "ERROR -- GetRawInputDeviceList ...";
return 1;
}
if (!(pRawInputDeviceList = (PRAWINPUTDEVICELIST)malloc(sizeof(RAWINPUTDEVICELIST) * nDevices)))
{
qDebug() << "Initialization failed...";
return 1;
}
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
Rid[0].dwFlags = RIDEV_INPUTSINK;
Rid[0].hwndTarget = (HWND)w.effectiveWinId();
if(!RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])))
qDebug()<<"Huston Problem.";
qDebug()<<QString::number(GetLastError());
return a.exec();
}
And here is a part from Mouse Handlig Class
bool MouseRawMovement::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
if(eventType == "windows_generic_MSG")
{
MSG *msg = reinterpret_cast<MSG*>(message);
if(msg->message == WM_INPUT)
{
UINT dwSize = 40;
static BYTE lpb[40];
if(!GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT,lpb, &dwSize, sizeof(RAWINPUTHEADER)))
qDebug()<<"Error GetRawInputData";
else
{
RAWINPUT* raw = (RAWINPUT*)lpb;
if (raw->header.dwType == RIM_TYPEMOUSE)
{
int xPosRelative = raw->data.mouse.lLastX;
int yPosRelative = raw->data.mouse.lLastY;
//qDebug()<<xPosRelative<<yPosRelative;
}
}
}
}
return false;
}
As the GetRawInputData MSDN page states, first parameter of this function is
hRawInput [in] Type: HRAWINPUTA handle to the RAWINPUT structure. This comes from the lParam in WM_INPUT.
So, you need to check first if message you are processing is a WM_INPUT message (msg->message == WM_INPUT) and only then try to extract raw input data.
Next, the lParam of WM_INPUT message is
lParam
A handle to the RAWINPUT structure that contains the raw input from the device.
as it says on WM_INPUT MSDN page. You need to use this handle in GetRawInputData function. Right now, you are using incorrect data handle so GetRawInputData do not return any valid information to you (it just doesn't know where to take data to process).
You should read article MSDN: Using Raw Input. There you can find sample code for the keybaord and mouse raw input processing.
Useful links:
MSDN: GetRawInputData
MSDN: WM_INPUT
MSDN: RegisterRawInputDevices – you should associate your application with raw input to receive WM_INPUT messages
MSDN: Using Raw Input – sample code for registering for raw input and for raw input processing.
One more thing. You can use equality operator to compare QByteArray instance to a string, in your case it will be like this: if (eventType == "windows_generic_MSG") {...}. This is because QByteArray has the overloaded equality operator:
bool QByteArray::operator==(const QString & str) const
You can read about it at this page: QByteArray::operator==.
UPDATE
MSDN: RAWINPUTDEVICE page notes that
RIDEV_INPUTSINK 0x00000100 If set, this enables the caller to receive
the input even when the caller is not in the foreground. Note that
hwndTarget must be specified.
You have the INVALID_HANDLE_ERROR error because you need to specify hWnd of your window.
What is MainWindow class? Do you inherit from QMainWindow or QWidget? Every widget in Qt have the winId property (WId QWidget::winId() const) which is the very hWnd you are looking for. So you need to take winId() of your window, cast it to HWND and write into the Rid structure like this:
Rid[0].hwndTarget = (HWND)w->winId();
If it won't help, then you need to provide a Minimal, Complete, and Verifiable example for further investigation.

C++ Win32 Listen for global keybinds

I am trying to implement global hotkeys on Windows in my C++/Qt application. I used RegisterHotKey, which surprisingly worked and I can see that pressing the combination triggers my event, but since I did not know any other way, I just used a loop, which now blocks my windows and stops it from ever showing up.
You can find my code below. How do I listen for this combination? There certainly has to be another way.
void set_win32_keys(MainWindow *mwin) {
HWND main_hwnd = (HWND)mwin->winId();
RegisterHotKey(main_hwnd, 2, MOD_CONTROL | MOD_SHIFT, 0x32 /*2 key*/);
MSG *msg;
msg = new MSG();
BOOL b_ret;
while ((b_ret = GetMessage(msg, main_hwnd, 0, 0)) != 0) {
if (b_ret == -1) {
qDebug() << "Error";
} else {
if (msg->message == WM_HOTKEY) {
mwin->new_screenshot();
qDebug() << msg;
}
}
}
}
Shameless plug: I have written a library for Qt that provides global hotkeys in a cross-platform manner - and allows the usage of for example QKeySequence to create the hotkey. It allows you to use a QKeySequenceEdit to let the user enter his own shortcut:
https://github.com/Skycoder42/QHotkey
Example:
//MainWindow constructor:
QHotkey *hotkey = new QHotkey(Qt::Key_2, Qt::ControlModifier | Qt::ShiftModifier, true, this);
connect(hotkey, &QHotkey::activated, this, &MainWindow::new_screenshot);
And that's it! Hope it helps
How can I listen to the system hot key bound to the app main window?
Many system events can be caught at main window native event handler. And the original author post actually binds to main window. The below should process the requested message:
class MainWindow : public QMainWindow
{
// ... snip ...
bool nativeEvent(const QByteArray& eventType, void* message, long* result) override;
// ... snip ...
};
bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
MSG* pMsg = reinterpret_cast<MSG*>(message);
if (pMsg->message == WM_HOTKEY)
{
// process pMsg->wParam / lParam etc.
// the intended action
this->new_screenshot();
}
// call the parent, could be QWidget::nativeEvent
return QMainWidow::nativeEvent(eventType, message, result);
}
Because of assumption that mwin has QMainWindow*:
HWND main_hwnd = (HWND)mwin->winId();
RegisterHotKey(main_hwnd, 2, MOD_CONTROL | MOD_SHIFT, 0x32 /*2 key*/);

RawInput loads 100% of my first CPU core and doesn't update properly

When I register RawInput, I check all the returns of the functions, everything is fine.However, when I update it it clogs up the performance on my 1st CPU core and it doesn't work properly(when I check if the 'M' button is pressed and have it create a message box when it is, it doesn't just trigger when I press 'M', but it triggers whenever I press anything or move the mouse.Also the message box doesn't come out, there's only a beep.)
Here's the code I use to initialize it:
const ushort usageTable[] =
{
InputDeviceUsage::UsageMouse,
InputDeviceUsage::UsageKeyboard,
InputDeviceUsage::UsageGamepad,
};
const ulong flagsTable[] =
{
mouseFlags,
keyboardFlags,
hidFlags
};
const List<SystemDevices>& systemDevices = EnumerateSystemDevices();
List<String> deviceNames;
List<InputDeviceInfo> deviceInfo;
for(uint i = 0; i < systemDevices.Size(); i++)
{
deviceNames.Add(GetDeviceName(systemDevices[i].hDevice));
deviceInfo.Add(GetDeviceInfo(systemDevices[i].hDevice));
InputDevice device =
{
InputDeviceUsagePage::UsagePageHID,
usageTable[deviceInfo[i].dwType],
flagsTable[deviceInfo[i].dwType],
window
};
RegisteredDevices.Add(device);
Devices[systemDevices[i].hDevice] = CreateDevice(deviceInfo[i].dwType);
Where List is the equivalent of std::vector<> and these are the typedefs and defines involved:
enum InputDeviceUsagePage
{
UsagePageHID = 0x01
};
enum InputDeviceUsage
{
UsageMouse = 0x02,
UsageKeyboard = 0x06,
UsageGamepad = 0x04
};
enum InputDeviceType
{
TypeMouse = RIM_TYPEMOUSE,
TypeKeyboard = RIM_TYPEKEYBOARD,
TypeHID = RIM_TYPEHID
};
enum InputDeviceChangeBehavior
{
Arrival = GIDC_ARRIVAL,
Removal = GIDC_REMOVAL
};
enum InputDeviceDataRequest
{
PreparseData = RIDI_PREPARSEDDATA,
Name = RIDI_DEVICENAME,
Info = RIDI_DEVICEINFO
};
And this is the Update function:
try
{
InputData data;
RawDevice::UpdateUnbuffered(reinterpret_cast<HRAWINPUT>(lparam), &data);
DevicePtr it = Devices[data.header.hDevice];
if(it == nullptr)
{
DevicePtr newDevice = CreateDevice(data.header.dwType);
Devices.Add(data.header.hDevice, newDevice);
if(data.header.hDevice != null)
{
it = newDevice;
}
}
DevicePtr device = it;
device->Read(data);
switch(data.header.dwType)
{
case InputDeviceType::TypeMouse:
{
const RawMouse& mouse = static_cast<RawMouse&>(*device);
//TODO: add event handling here
break;
}
case InputDeviceType::TypeKeyboard:
{
const RawKeyboard& keyboard = static_cast<RawKeyboard&>(*device);
//TODO: add event handling here
break;
}
case InputDeviceType::TypeHID:
{
const RawHID& hid = static_cast<RawHID&>(*device);
//TODO: add event handling here
break;
}
default:
{
}
}
return(exit_success);
}
catch(...)
{
return(DefWindowProc(window, message, wparam, lparam));
}
So for instance in the places that have //TODO: add event handling here I put:
case InputDeviceType::TypeKeyboard:
{
const RawKeyboard& keyboard = static_cast<RawKeyboard&>(*device);
if(keyboard.KeyDown('M'))
{
MessageBox(window, L"Pressed key is 'M'", L"Input event", MB_OK);
}
break;
}
I get a beep every time I press any key or any button on the mouse, not just M and also the message box doesn't show, the window just beeps.And the CPU core gets loaded to the maximum.This is the KeyDown() function:
const bool RawKeyboard::KeyDown(ushort key) const
{
if(_data.VKey == key && !(_data.Flags & KeyActions::KeyDown))
{
return(true);
}
{
return(false);
}
}
DevicePtr is basically a RawDevice* which contains a name and DeviceInfo and from RawDevice inherits RawMouse, RawKeyboard and RawHID, which in them have RAWMOUSE, RAWKEYBOARD, RAWHID members named _data.
EDIT: Just to add the place where Update is called:
case WM_INPUT:
{
return(_input.Update(_mainWindow.GetHandle(), message, wparam, lparam));
}
break;
EDIT2: Forgot to add the ReadUnbuffered method:
void RawDevice::UpdateUnbuffered(const HRAWINPUT rawInput, RAWINPUT* data)
{
wint64 size(sizeof(RAWINPUT));
boolresult = GetRawInputData(rawInput, RID_INPUT, data, &size, sizeof(RAWINPUTHEADER));
if(result == false)
{
throw RawInputException(GetLastError(), L"GetRawInputData()");
}
}
your message loop needs to process all messages in the queue before updating you application.
sounds like you are poping the first message switching to your app. filling the msg queue, getting one message, filling the queue some more... you get the point

C++/Win32 enumerate windows belonging to my process & close them

I have a Windows app that houses a web browser (Internet explorer) embedded in it. The app can be closed from another process by means of IPC. It works just fine except the situation when the embedded web browser may be displaying a pop-up dialog window (say, during saving of contents). In that case my app crashes when it tries to close from an outside request via IPC. (Internally it simply posts the WM_CLOSE message to itself.)
In light of that I thought to come up with a way to enumerate all windows that belong to my process and close them first before closing my process itself. The question is, how do you enumerate all windows belonging to my process for the purpose of closing them?
OK, I guess I got it myself. Here's if someone is interested:
#define SIZEOF(f) (sizeof(f) / sizeof(f[0]))
typedef struct _ENUM_POPUPS_INFO{
DWORD dwProcID;
HWND hThisWnd;
int nNextHWNDIndex;
HWND hFoundHWNDs[256];
}ENUM_POPUPS_INFO;
void CloseAllOpenPopups(HWND hWnd, int dwmsWait)
{
//'hWnd' = our main window handle (we won't close it)
//'dwmsWait' = maximum wait time in milliseconds, or -1 to wait for as long as needed
ENUM_POPUPS_INFO epi = {0};
BOOL bR;
int i, iIteration;
HWND hWndRoot, hWndActivePopup;
DWORD dwmsTickBegin = GetTickCount();
for(iIteration = 0;; iIteration = 1)
{
//Get our process ID
memset(&epi, 0, sizeof(epi));
epi.hThisWnd = hWnd;
epi.dwProcID = GetCurrentProcessId();
bR = EnumWindows(EnumPopupWindowsProc, (LPARAM)&epi);
//Did we get any
if(epi.nNextHWNDIndex == 0)
break;
//Wait on a second and later iteration
if(iIteration > 0)
{
if(dwmsWait != -1)
{
DWORD dwmsTick = GetTickCount();
int nmsDiff = abs((long)(dwmsTick - dwmsTickBegin));
if(nmsDiff >= dwmsWait)
{
//Timed out
break;
}
//Wait
Sleep(min(100, dwmsWait - nmsDiff));
}
else
{
//Wait
Sleep(100);
}
}
//Go through all windows found
for(i = 0; i < epi.nNextHWNDIndex; i++)
{
//Get root owner
hWndRoot = GetAncestor(epi.hFoundHWNDs[i], GA_ROOTOWNER);
if(!hWndRoot)
continue;
//Get it's active popup
hWndActivePopup = GetLastActivePopup(hWndRoot);
if(!hWndActivePopup)
continue;
//Close it
PostMessage(hWndActivePopup, WM_CLOSE, 0, 0);
}
}
}
BOOL CALLBACK EnumPopupWindowsProc(HWND hWnd, LPARAM lParam)
{
ENUM_POPUPS_INFO* pEPI = (ENUM_POPUPS_INFO*)lParam;
//Get process ID of the window
DWORD dwProcID = 0;
GetWindowThreadProcessId(hWnd, &dwProcID);
//We need this window only if it's our process
if(dwProcID == pEPI->dwProcID &&
pEPI->hThisWnd != hWnd &&
((GetWindowLongPtr(hWnd, GWL_STYLE) & (WS_VISIBLE | WS_POPUP | WS_CAPTION)) == (WS_VISIBLE | WS_POPUP | WS_CAPTION)))
{
if(pEPI->nNextHWNDIndex >= SIZEOF(pEPI->hFoundHWNDs))
{
//Stop, we're full
return FALSE;
}
//Add it
pEPI->hFoundHWNDs[pEPI->nNextHWNDIndex] = hWnd;
pEPI->nNextHWNDIndex++;
}
return TRUE;
}
When you want your process to exit, just call ExitProcess. It doesn't matter what windows might be open at the time, they all go away.