Get handler of a specific monitor to place pop-up window in [duplicate] - c++

This question already has answers here:
How can I get monitors numbers from Screen Resolution dialog in win7 programmatically?
(3 answers)
Closed 5 years ago.
So I've been looking through the web for clues how to do this but I can't seem to get it right. I have a dual monitor setup by default and i want to "pick" 'Monitor 2', so i can put a window there in full-screen when a user presses a button in the program.
So far as I've understood i need the handler of the specified monitor as the first step, my approach is to call EnumDisplayMonitors according to msdn
"To retrieve information about all of the display monitors, use code like this":
int main()
{
EnumDisplayMonitors(NULL, NULL, MyInfoEnumProc, 0);
}
where MyInfoEnumProc is callback defined as follows:
std::vector<HMONITOR> handlerList;
static BOOL CALLBACK MyInfoEnumProc(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData)
{
MONITORINFOEX info_;
info_.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(hMon, &info_); // retrieve monitor info, put it in info_?
handlerList.push_back(hMon); // push handler to array
std::cout << info_.szDevice; // attempt to print data
std::cout << std::endl;
return true;
}
So this callback should go through all the monitors connected to the system but i don't quite understand how i obtain data like resolution, id and name? Like if i go into Monitor settings from Desktop, there is an ID assigned to each monitor, it would be useful to get these so I can place my window in monitor 2 instead of my primary monitor, monitor 1.
Also regarding the handler, I put this in an array but i really need the data so i know which monitor's handler that I have acquired I suppose? When i print the device name of the monitor std::cout << info_.szDevice; i just get the same number for both monitors.
I'm newbie at c++ so i have might have missed something obvious. Hope anyone can help.
Edit:
Thanks to Iinspectable, he mentioned that in the callback function, you can basically check the dwFlags attribute to find the primary monitor and then you know which one is the second screen:
static BOOL CALLBACK MyInfoEnumProc(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData)
{
MONITORINFOEX info_;
info_.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(hMon, &info_);
if (info_.dwFlags == 0) {
std::cout << std::endl;
std::cout << "Found the non-primary monitor" << std::endl;
handlerList.push_back(hMon);
}
return true;
}
Would be useful to have a general solution to this problem in case i wanna connect a third screen, dwFlags = 0 in 2 cases for an example with 3 monitors.

The MONITORINFOEX structure populated by the call to GetMonitorInfo has an rcMonitor field, storing the size of the display (in virtual coordinates).
The dwFlags field has the MONITORINFOF_PRIMARY set for the primary monitor. Since you only have 2 displays, you are looking for the monitor that doesn't have this flag set.

Related

How to use run-time dll injecting to write into a Running and Temp notepad/txt file

Basically I created a simple Dll injection code with a basic Dll that shows a message box and my question is how can I now use the Dll file to make it write text into the Notepad while its running and it hasn't been saved/is temporary?
Is there a way to find a path to the file?
(i don't think so because its still writing into the ram and is untitled so doesn't have a save on any drives)
Or is there a stream i can write into?
Like Timo said in the comment, you can get the handle to the Notepad's Window, and then use it to write text into it, and it even wouldn't require from you to inject your DLL into the Notepad Process.
In Windows, every window is receiving messages from the Operating System (or from other programs, like what you're going to try out), those messages tell the window what action was made, for instance - Pressing down a key, or pressing a mouse button. That way, the program controlling the Window will know what kind of action it's supposed to do.
You can use the Spy++ Tool (spyxx.exe, comes builtin in every Visual Studio) to track what Windows does when you press a key down the keyboard into the Notepad's Window.
You can read further about the topic of window messages here:
https://learn.microsoft.com/en-us/windows/win32/learnwin32/window-messages
And working with Spy++ here:
https://learn.microsoft.com/en-us/visualstudio/debugger/introducing-spy-increment?view=vs-2019
Opening Spy++, we can see all the Windows in the our session, and we look for the Notepad's:
how it looks
Small POC I made for searching the appropriate Window, according to what found by Spy++ (forgive me for the globals, and make sure you are aware of what I did here):
HWND notepad_window;
HWND notepad_edit;
BOOL CALLBACK GetEditWindow(HWND hWnd, LPARAM lParam)
{
wchar_t window_text[MAX_PATH] = { 0 };
if (0 != GetClassNameW(hWnd, window_text, MAX_PATH))
{
std::wstring text(window_text);
if (std::wstring::npos != text.find(L"Edit"))
{
std::wcout << "Found it" << text << std::endl;
notepad_edit = hWnd;
return false;
}
}
return true;
}
BOOL CALLBACK GetNotepadWindow(HWND hWnd, LPARAM lParam)
{
wchar_t window_text[MAX_PATH] = { 0 };
// Fun fact - The GetWindowTextW also posts a window message to the window, the WM_GETTEXT message
if (0 != GetWindowTextW(hWnd, window_text, MAX_PATH))
{
std::wstring text(window_text);
if (std::wstring::npos != text.find(L"Notepad"))
{
std::wcout << "Found it" << text << std::endl;
notepad_window = hWnd;
return false;
}
}
return true;
}
int wmain()
{
EnumWindows(GetNotepadWindow, 0);
EnumChildWindows(notepad_window, GetEditWindow, 0);
}
After you have the HWND, you can start dealing with the message posting. You can use Spy++ again to 'tap' on the Notepad's Edit Window, and see every Window Message sent when pressing down a key, you will see the WM_KEYDOWN, followed by a WM_KEYUP most likely.
Then, you can use the PostMessage WinAPI function to post your own WM_KEYDOWN/KEYUP messages to the Notepad Window, hence controlling the input it gets.

Count monitors from a service with C++

I'm trying to count the number of monitors (i.e. screens) attached to the console from a service application. I do the following:
int CountMonitors()
{
int nCnt = 0;
if(!EnumDisplayMonitors(NULL, NULL, _countMonitorEnumProc, (LPARAM)&nCnt))
{
//Error
nCnt = -1;
}
return nCnt;
}
BOOL _countMonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
int* pCnt = (int*)dwData;
(*pCnt)++;
return TRUE;
}
but the count is always 1 (when I'm testing it on a dual-monitor Windows 7.) I then do this (which is not exactly what I need due to its limitation):
int nCnt = GetSystemMetrics(SM_CMONITORS);
and the result is also 1.
So how do you count monitors from a service?
First, why is the console special to a service, vs number of displays attached on a remote session? Then, what about display mirroring / extended desktop / eyefinity?
Now, learn about Window Stations and Desktops. Then learn about shatter attacks.
Finally, if what you're really after is hardware enumeration, there are APIs for that. SetupDiGetClassDevs on the display monitor setup class will tell you how many physical screens the video card(s) expose.

Raw Input Device RAWMOUSE Usage

I'm using winapi's raw input devices for mouse input and it seems I'm not getting the correct values in my RAWMOUSE struct.
When I get the RAWMOUSE struct I get the values of lLastX and lLastY as I'd expect but for some reason the ulRawButtons is constantly 0. The msdn documentation says that ulRawButtons is "The raw state of the mouse buttons" so I take it this should change when I press a mouse button.
This is the code I create the raw input device with (I removed error checking for readability):
RAWINPUTDEVICE rid;
rid.usUsagePage = 0x01;
rid.usUsage = 0x02;
rid.dwFlags = RIDEV_INPUTSINK;
rid.hwndTarget = myWindowHandle;
RegisterRawInputDevices(&rid, 1, sizeof(rid));
After the WM_INPUT message I call:
void handleRawInput(HWND window, UINT, WPARAM wParam, LPARAM lParam)
{
RAWINPUT input;
UINT szData = sizeof(input), szHeader = sizeof(RAWINPUTHEADER);
HRAWINPUT handle = reinterpret_cast<HRAWINPUT>(lParam);
GetRawInputData(handle, RID_INPUT, &input, &szData, szHeader);
if (input.header.dwType == RIM_TYPEMOUSE)
{
// Here input.data.mouse.ulRawButtons is 0 at all times.
}
}
I'm using mingw32 (4.7) and I've defined WIN32_LEAN_AND_MEAN, WINVER=0x0501 and WIN32_WINNT=0x0501.
Any ideas why I'm not getting the correct values for ulRawButtons?
Windows populates the RAWMOUSE struct with what the mouse driver tells it via the MOUSE_INPUT_DATA struct.
You'll notice that the MSDN page for MOUSE_INPUT_DATA states the following:
RawButtons
Specifies the raw state of the mouse buttons. The Win32 subsystem does not use this member.
What the MSDN page doesn't say is that not only does Win32 not use RawButtons/ulRawButtons but the mouse drivers it ships do not populate them. So, unless you have a mouse driver from a 3rd party vendor, you are never going to get this field set.
I think what you are looking to use is: input.data.mouse.usButtonFlags for mouse clicks and input.data.mouse.usButtonData for scroll wheel delta.

Getting handle of child window in C++

I want to get handle of child window, but cannot.
I want to automatically insert text in an Edit control.
Here is what I have:
//global var
int id=0;
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
id = GetDlgCtrlID(hwnd);
HWND hwnd_Child;
hwnd_Child = GetDlgItem(hwnd, id);
SendMessage(hwnd_Child, WM_SETTEXT, NULL, (LPARAM)"mYtexttttt");
/* other code */
// id is always 0, why ?
// return FALSE; // stop enumerating
return TRUE; // continue enumeration
}
void MyFunction ()
{
HWND hwnd_Parent;
hwnd_Parent = FindWindow(NULL,"MyTitle"); if(! hwnd)return;
EnumChildWindows(hWnd ,(WNDENUMPROC)EnumWindowsProc, NULL);
}
In WinSpy++, the control IDs of all the components are 000000000. Is it possible that the control ID isn't defined?
How do I find the child handle of some specific (edit box) component if I have the handle of the main window, and the control ID is not defined?
Also, main window is a game application which runs with DirectX, I think.
I want to automatically insert text in a Edit control.
If WinSpy tells you that the control IDs are 0 then getting a 0 back from GetDlgCtrlID() is of course the expected outcome. You'll have to do something else, like counting down the number of EnumWindowsProc() calls and/or calling GetClassName() so you can see it is an edit control. Or GetWindowRect() to go by position.
In your callback method, please do the following:
// get the window text
GetWindowText(hWnd, (LPTSTR)windowText, MAX_PATH);
// get the window info
WINDOWINFO objWinInfo;
GetWindowInfo(hWnd, &objWinInfo)
The above should help you get the child windows.
Also you can do FindWindowEx to the get the child windows.
Control ids are one convenient way to identify child windows; but not the only way. So it is quite possible that control id will be set to arbitrary (or zero) values (in which case the parent window just refers to them directly by their handles.
From your point of view if no control ids exist you must reference them by the position in the tab sequence which should be constant and can be iterated through.

How to check if a window button is pressed C++

How can I test if a button is being pressed ?
I am using EnumChildWindows() to enumerate the child windows of a given window, and one of the child window is a button, I want to test if that specific button is being pressed.
My code until know is:
BOOL CALLBACK MyEnumProc(HWND hwnd, LPARAM lParam)
{
char buffer[256];
GetWindowText(hwnd, buffer, sizeof(buffer));
cout << buffer << endl;
return true;
}
int main()
{
HWND hwnd = FindWindow(0, "Window to find");
EnumChildWindows(hwnd, MyEnumProc, 0);
return 0;
}
You can send the BM_GETSTATE message to the button control, if it is pressed the result will be
BST_PUSHED.
You need to inject a DLL into the process space, hook the window message loop (like you used to hand code a subclassed window in native Win32 API C code, Window Proc) (google-able) and listen to the actual messages.
All of this is ancient stuff for me, and I'm afraid that recent Windows versions (hopefully) made this a little bit more difficult to do.
That said, if you can get the application trusted with the right level of permissions, you should still be able to do this