The MSDN says the following about the GetParent function:
To obtain the parent window and not
the owner, instead of using GetParent, use GetAncestor with the
GA_PARENT flag.
But when calling GetAncestor(hWnd, GA_PARENT); for a window that doesn't have a parent, it returns the desktop window, while GetParent returns NULL.
So what is the correct way of getting a parent (and not the owner), and getting NULL if there are none?
Of course I could check whether GetAncestor returns the desktop window, but that seems like a hack to me.
Here's what I came up with:
//
// Returns the real parent window
// Same as GetParent(), but doesn't return the owner
//
HWND GetRealParent(HWND hWnd)
{
HWND hParent;
hParent = GetAncestor(hWnd, GA_PARENT);
if(!hParent || hParent == GetDesktopWindow())
return NULL;
return hParent;
}
Updated in the year 2020 considering the latest Win32 documentation:
HWND GetRealParent(HWND hWnd)
{
HWND hWndOwner;
// To obtain a window's owner window, instead of using GetParent,
// use GetWindow with the GW_OWNER flag.
if (NULL != (hWndOwner = GetWindow(hWnd, GW_OWNER)))
return hWndOwner;
// Obtain the parent window and not the owner
return GetAncestor(hWnd, GA_PARENT);
}
A slightly better version that goes both "routes" and if it can't find a proper parent it will return the window itself(as to avoid null references).
Using GetParent instead of GetAncestor worked in my case and returned the window I was after.
public static IntPtr GetRealParent(IntPtr hWnd)
{
IntPtr hParent;
hParent = GetAncestor(hWnd, GetAncestorFlags.GetParent);
if (hParent.ToInt64() == 0 || hParent == GetDesktopWindow())
{
hParent = GetParent(hWnd);
if (hParent.ToInt64() == 0 || hParent == GetDesktopWindow())
{
hParent = hWnd;
}
}
return hParent;
}
Related
Window APIs are new for me. I am trying to find the number of windows that are open from windows desktop application. I wanted to open only one instance of an application.
I have my application abc.exe. If user tries to open the abc.exe application for the first time then the abc.exe application will open normally. But, if abc.exe application is already open and the usser tries to open it again then it should give an already open instance of Application.
I am able to get an already open instance with help from the below code in specific condition.
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
HWND *retHwnd = (HWND *)lParam;
if (*retHwnd) {
return FALSE;
}
DWORD procID = 0;
auto threadID = GetWindowThreadProcessId(hwnd, &procID);
auto handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, procID);
QString fileName;
if (handle) {
TCHAR filename[FILENAME_MAX];
auto len = GetModuleFileNameEx(handle, NULL, filename, FILENAME_MAX);
fileName = QFileInfo(QString::fromWCharArray(filename, len)).fileName();
if (GetLastApplicationName() == fileName) {
*retHwnd = hwnd;
}
CloseHandle(handle);
}
return TRUE;
}
void ShowExistingInstance() {
HWND hwnd = 0;
auto res = EnumWindows(&EnumWindowsProc, (LPARAM)&hwnd);
if (hwnd) {
ShowWindow(hwnd, SW_MINIMIZE);
ShowWindow(hwnd, SW_MINIMIZE);
ShowWindow(hwnd, SW_RESTORE);
}
}
However, I am not getting first instance of the application if two windows are open from the application.
Below I mention two situations. In the first situation the code works fine, and in the second situation the code the code does not work fine.
1) Get already open instance of application
Steps:
a. User clicks on abc.exe application icon.
b. Main window is open for example its name is mainWindow1.
c. Restore-down or Minimize mainWindow1
d. User clicks abc.exe again using the application icon
e. Here I am getting mainWindow1, and it is correct.
2) Does not get already open instance of application
Steps:
a. User clicks on abc.exe application icon.
b. Main window is open for example its name is mainWindow1.
c. User opens another window from the current application for example its name is mainWindow2. (mainWindow1 is not parent of mainWindow2).
d. Restore-down or Minimize mainWindow1
(here mainWindow2 is also minimized or Restore- down automatically w.r.t mainWindow1)
e. User clicks abc.exe again using the application icon.
f. Here I am getting mainWindow2 instead of mainWindow1.
I wanted some kind of guide line for windows API, which is help me to find the Hwnd of Mainwidnow1 in second situation.
I got my functionality with help of below code
BOOL isMainWindow(HWND handle) {
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
}
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
HWND *retHwnd = (HWND *)lParam;
if (*retHwnd) {
return FALSE;
}
DWORD procID = 0;
auto threadID = GetWindowThreadProcessId(hwnd, &procID);
if (!isMainWindow(hwnd)) {
return TRUE;
}
auto handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, procID);
QString fileName;
if (handle) {
TCHAR filename[FILENAME_MAX];
auto len = GetModuleFileNameEx(handle, NULL, filename, FILENAME_MAX);
fileName = QFileInfo(QString::fromWCharArray(filename, len)).fileName();
if (GetLastApplicationName() == fileName) {
*retHwnd = hwnd;
}
CloseHandle(handle);
}
return TRUE;
}
void ShowExistingInstance() {
HWND hwnd = 0;
auto res = EnumWindows(&EnumWindowsProc, (LPARAM)&hwnd);
if (hwnd) {
ShowWindow(hwnd, SW_MINIMIZE);
ShowWindow(hwnd, SW_MINIMIZE);
ShowWindow(hwnd, SW_RESTORE);
}
}
I want to obtain a monitor handle (HMONITOR) that can be used with the Windows multi-monitor APIs for a specific monitor attached to the system by index. For example, say I have three monitors attached to my system and forming part of my desktop; I want to get a handle to monitor 3.
I already know how to get the device name for a specific monitor by index by calling the EnumDisplayDevices function. For example:
HMONITOR MonitorFromIndex(int index /* (zero-indexed) */)
{
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
if (EnumDisplayDevices(NULL, index, &dd, 0) != FALSE)
{
// We found a match; make sure that it's part of the desktop.
if ((dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) == DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
{
// Yup. Now we've got the name of the device:
std::cout << dd.DeviceName << std::endl;
// But how do I obtain an HMONITOR for this device?
// ...
}
}
return NULL; // indicate failure
}
In the code above, we've found the name of the desired device (dd.DeviceName). I can use this name to create a DC for that monitor by calling CreateDC:
HDC hDC = CreateDC(dd.DeviceName, dd.DeviceName, NULL, NULL);
And I can obtain information about that monitor by calling EnumDisplaySettings:
DEVMODE dm;
dm.dmSize = sizeof(dm);
dm.dmDriverExtra = 0;
if (EnumDisplaySettings(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm) != FALSE)
{
std::cout << "The monitor supports " << dm.dmBitsPerPel << " bits per pixel." << std::endl;
}
Which is all great, but I want a handle to that monitor. How can I get it?
I tried to call EnumDisplayMonitors, passing a handle to the device context that I created using CreateDC, hoping to get a handle to the monitor passed to the callback function, but no such luck. The callback function was never called, and EnumDisplayMonitors returned FALSE (without setting an error code):
struct FoundMatch
{
BOOL found;
HMONITOR hMonitor;
};
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
{
FoundMatch* pfm = reinterpret_cast<FoundMatch*>(dwData);
pfm->found = TRUE;
pfm->hMonitor = hMonitor;
return FALSE; // stop enumerating
}
// elsewhere, after getting the device name and using it to create a DC
FoundMatch fm;
fm.found = FALSE;
fm.hMonitor = NULL;
BOOL result = EnumDisplayMonitors(hDC, NULL, MonitorEnumProc, reinterpret_cast<LPARAM>(&fm));
Sorry for such a late reply but maybe someone can find this useful.
The multi-monitor API is really minimalist to say the least. Once you've got your dd.DeviceName, it appears you have to go through EnumDisplayMonitors() enumeration until you find a match of dd.DeviceName against MONITORINFOEX.szDevice.
The MONITORINFOEX structure can be obtained by calling GetMonitorInfo().
Here is a non-compilable C++11 pseudo code:
struct DataBag
{
HMONITOR hmon;
TCHAR* devname;
} bag;
bag.hmon = NULL;
bag.devname = &dd.DeviceName;
BOOL bRes = EnumDisplayMonitors(
NULL, NULL,
[](HMONITOR hMonitor, HDC hDC, LPRECT rc, LPARAM data) -> BOOL {
auto& bag = *reinterpret_cast<DataBag*>(data);
MONITORINFOEX mi;
mi.cbSize = sizeof(mi);
if (/* match bag.devname against mi.szDevice */ && GetMonitorInfo(hMonitor, &mi))
{
bag.hmon = hMonitor;
return FALSE;
}
return TRUE;
},
reinterpret_cast<LPARAM>(&bag));
if (bRes && bag.hmon)
{
// Monitor found!
}
How to select all text in edit control by pressing Ctrl+A?
I can catch Ctrl+A for parent window in WndProc.
But I don't know how to catch ctrl+a which are applied for edit control.
Also I tried to use accelerators, but again it applies only for parent window.
Thanks.
EDIT: 1-st the simplest method
This method Based on #phord's answers in this question:
win32 select all on edit ctrl (textbox)
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
if (msg.message == WM_KEYDOWN && msg.wParam == 'A' && GetKeyState(VK_CONTROL) < 0)
{
HWND hFocused = GetFocus();
wchar_t className[6];
GetClassName(hFocused, className, 6);
if (hFocused && !wcsicmp(className, L"edit"))
SendMessage(hFocused, EM_SETSEL, 0, -1);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
EDIT: 2-nd method
Need to use CreateAcceleratorTable + TranslateAccelerator functions:
//global variables:
enum {ID_CTRL_A = 1};
HACCEL accel;
//main procedure
ACCEL ctrl_a;
ctrl_a.cmd = ID_CTRL_A; // Hotkey ID
ctrl_a.fVirt = FCONTROL | FVIRTKEY;
ctrl_a.key = 0x41; //'A' key
accel = CreateAcceleratorTable(&ctrl_a, 1); //we have only one hotkey
//How GetMessage loop looks
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
if (!TranslateAccelerator(hWnd, accel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
//in WndProc we must add next cases
case WM_COMMAND:
{
if (LOWORD(wParam) == ID_CTRL_A && HIWORD(wParam) == 1)
{
//on which control there was pressed Ctrl+A
//there is no way of getting HWND through wParam and lParam
//so we get HWND which currently has focus.
HWND hFocused = GetFocus();
wchar_t className[6];
GetClassName(hFocused, className, 6);
if (hFocudsed && !wcsicmp(className, L"edit"))
SendMessage(hFocused, EM_SETSEL, 0, -1);
}
}
break;
case WM_DESTROY:
{
DestroyAcceleratorTable(accel);
PostQuitMessage(0);
}
break;
As you can see this is pretty simple.
No need to handle WM_KEYDOWN! I know that most examples here (and CodeProject and many other places) all say there is, but it does not cure the beep that results whenever a WM_CHAR arises that is not handled.
Instead, try this:
LRESULT CALLBACK Edit_Prc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
if(msg==WM_CHAR&&wParam==1){SendMessage(hwnd,EM_SETSEL,0,-1); return 1;}
else return CallWindowProc((void*)WPA,hwnd,msg,wParam,lParam);
}
Remember to subclass the EDIT control to this Edit_Prc() using WPA=SetWindowLong(...) where WPA is the window procedure address for CallWindowProc(...)
First change the WindowProc for the edit control:
if (!(pEditProc = (WNDPROC)SetWindowLong(hEdit, GWL_WNDPROC, (LONG)&EditProc)))
{
assert(false);
return false;
}
Then in the new window proc, process the ctrl+a:
LRESULT CALLBACK EditProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
if (msg == WM_KEYDOWN) {
if (GetKeyState(VK_CONTROL) & 0x8000 && wParam == 'A') {
SendMessage(hwnd, EM_SETSEL, 0, -1);
}
}
return CallWindowProc(pEditProc, hwnd, msg, wParam, lParam);
}
Good News!
It seems Edit Controls (not multiline) now support Ctrl + A natively on Win10.
My current Windows SDK version is 10.0.17763.0.
Only tested on simple GUI APPs created with pure Windows API.
MFC APPs should have the same result.
The test binary platform is x86, and OS is Win10 x64.
Noob proof version?
I have written my own version using an accelerator table aswell.
This cleans out the WinMain a bit, and I tried to make everything as n00b proof as possible (since I am one).
Also the enum is ommited, since it is not needed.
As stated I am only a beginner in using the winapi, so please by all means
correct me if I am wrong.
In "Resource.h" I define two ID's
One for the accelerator table we will be using,
and one for the selectall command we will be using.
Inside Resource.h:
#define IDR_ACCEL1 101
#define ID_SELECT_ALL 9003
Then inside of the resource file (in vs2017 this is PROJECTNAME.rc)
we define the accelerator table.
PROJECTNAME.rc:
IDR_ACCEL1 ACCELERATORS
{
0x41, ID_SELECT_ALL, VIRTKEY, CONTROL // ctrl-A
}
Description
0x41 is virtkey 'a'.
ID_SELECT_ALL (will be the ID of the command, this should be the ID we defined in the Resource.h file.
The VIRTKEY keyword indicated that the 0x41 should be interpreted as a virtual key.
CONTROL is the modifier needed to combine the a with (ctrl+a).
Then inside the WinMain function load the accelerator:
HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCEL1));
if (hAccel == NULL)
{
MessageBox(NULL, _T("Failed to load accelerator table!"),_T("Error"), MB_OK | MB_ICONEXCLAMATION);
return 0;
}
Note: after trying to define hAccel we do a check to see if a valid handle has be assigned.
While this is not needed, I believe it's better convention.
After this we add the TranslateAccelerator function to the message loop, so the command can be processed in the window procedure:
BOOL bRet;
while (bRet = GetMessage(&Msg, NULL, 0, 0) > 0)
{
if (bRet == -1)
{
// Error handling can be done here.
}
else if (!TranslateAccelerator(hwnd, hAccel, &Msg))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
Then finally inside the Window procedure
We add the code as follows:
switch(msg)
{
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case ID_SELECT_ALL:
{
HWND hEdit;
hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT) // Define IDC_MAIN_EDIT with an integer value in "Resource.h".
}
break;
}
break;
}
}
Note: The message passed to WM_COMMAND is the ID we defined for the ctrl+a accel.
I hope this will help fellow n00bies.
I would like to write a program, which lets me change a values in text box of different program, or automatically copy a values from one program to another.
I found a way to get hWnd to most (no idea if all of them) of controls in targer program, and to point them with mouse cursor. I made a simple struct to do so, and an array of it
struct hWndpointer
{
HWND hWnd;
AnsiString text;
};
hWndpointer tbl[250];
The EnumWindowProc and EnumChildWindowProc loads handles and text of the window into the array and into the list control in my program, so i can click an item on the list (or select it with keyboard) and the cursor points the control (like button or textbox) like expected... Unfortunately there are some controls with no text (or rather GetWindowText returns no text) so there is no way to identify the control.
The question is:
Is there any way to get/read a NAME of the control?
Is there any way to get/read and set a specyfic value like 'enabled' or 'text' or 'value'?
Thanks in advance
PS: Sorry for my english ;)
You can use SendMessage and PostMessage to send WM_GETTEXT, WM_SETTEXT, WM_ENABLE to windows owned by other processes. (SendMessage for queries, PostMessage for write-only actions)
Often the child ID will be used to identify subwindows (especially in a dialog), but it's also possible for a program to rely purely on the dynamic HWND values, in which case you'll have to fall back to window positions to differentiate.
From the Win32 API's perspective, UI controls do not have Names, so you cannot ask the API to return the Name of a UI control in another process because such a value does not exist. Names are strictly a feature of the UI framework being used by the app (VCL in the case of C++Builder), and you cannot directly access frameworks across process boundaries. You would need cooperation from the control's owning app.
For instance, one way would be to have both apps call RegisterWindowMessage() to register a custom window message, then your app can post that message to the other app specifying the desired control's HWND and your own HWND as parameters. The other app can then SendMessage() the control's Name back to your app's HWND using the WM_COPYDATA message, which you can use to update your list accordingly.
In the VCL framework, you can convert an HWND to a TWinControl* pointer using the FindControl() function. It will return NULL if the HWND does not belong to the calling process, otherwise you can then copy the value from its Name property. For example:
const UINT WM_GETCONTROLNAME = RegisterWindowMessage("WM_GetControlName");
const UINT WM_GETCONTROLNAME_RESULT = RegisterWindowMessage("WM_GetControlName_Result");
#include <pshpack1.h>
struct sControlName
{
HWND hWnd;
int Length;
char Value[1];
};
#include <poppack.h>
void __fastcall TMyForm::WndProc(TMessage &Message)
{
if ((Message.Msg == WM_COPYDATA) && (WM_GETCONTROLNAME_RESULT != 0))
{
LPCOPYDATASTRUCT cds = (LPCOPYDATASTRUCT) Message.LParam;
if (cds->dwData == WM_GETCONTROLNAME_RESULT)
{
sControlName *pName = (sControlName*) cds->lpData;
AnsiString sName(pName->Value, pName->Length);
// locate pName->hWnd in your list and assign sName to it as needed...
return;
}
}
TForm::WndProc(Message);
}
void ___fastcall TMyForm::FillList()
{
...
if (WM_GETCONTROLNAME != 0)
{
HWND TheControlHWND = ...;
HWND OtherAppHWND = ...;
PostMessage(OtherAppHWND, WM_GETCONTROLNAME, (WPARAM)TheControlHWND, (LPARAM)this->Handle);
}
...
}
.
const UINT WM_GETCONTROLNAME = RegisterWindowMessage("WM_GetControlName");
const UINT WM_GETCONTROLNAME_RESULT = RegisterWindowMessage("WM_GetControlName_Result");
#include <pshpack1.h>
struct sControlName
{
HWND hWnd;
int Length;
char Value[1];
};
#include <poppack.h>
void __fastcall TMyForm::WndProc(TMessage &Message)
{
if ((Message.Msg == WM_GETCONTROLNAME) && (WM_GETCONTROLNAME != 0) && (WM_GETCONTROLNAME_RESULT != 0))
{
HWND hWnd = (HWND) Message.WParam;
TWinControl *Ctrl = FindControl(hWnd);
if (Ctrl)
{
AnsiString sName = Ctrl->Name;
std::vector<unsigned char> buffer((sizeof(sControlName) - 1) + sName.Length());
sControlName *pName = (sControlName*) &buffer[0];
pName->hWnd = hWnd;
pName->Length = sName.Length();
strncpy(pName->Value, sName.c_str(), pName->Length);
COPYDATASTRUCT cds = {0};
cds.dwData = WM_GETCONTROLNAME_RESULT;
cds.cdData = buffer.size();
cds.lpData = pName;
SendMessage((HWND)Message.LParam, WM_COPYDATA, (WPARAM)this->Handle, (LPARAM)&cds);
}
return;
}
TForm::WndProc(Message);
}
I have been trying various code snippets here and there, but still not successful.I am simply trying to find one of the open windows (it is the Browser window) using FindWindow(NULL,WINDOWTITLE), with a specific Title string. Once I get the handle of the window, I need the coordinates using GetWindowRect.
This code gets me the coordinates, but seems like it's in an infinite loop, there are about a 100 lines of output with the coordindates, should be just 1. I don't see any while construct (originally a Java programmer)... wonder why it's repeating...
struct WindowInfo
{
HWND m_hWnd;
string m_title;
WindowInfo(HWND hwnd, string title) : m_hWnd(hwnd), m_title(title) {}
};
BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam)
{
vector<WindowInfo*> & windows = *(vector<WindowInfo*>*)lParam;
char title[256];
HANDLE wndHandle;
LPCWSTR WINDOWTITLE = L"eBargain 2 Share - Windpos Internet Explorer";
RECT rRect;
LPRECT lpRect;
RECT rc;
hwnd = FindWindow(NULL,WINDOWTITLE);
GetWindowRect(hwnd,&rc);
printf("Position: %d x %d\tSize: %d x %d\n",rc.left,rc.top,rc.right- rc.left,rc.bottom-rc.top);
/* Enumerating through all the windows tells me that I am on the right track... (Should I just try to find the TITLE STRING by comparing every title from the following enumeration ?
*/
GetWindowTextA(hwnd, title, 256);
windows.push_back(new WindowInfo(hwnd,title));
// printf("%s\n", title);
return TRUE;
}
int main()
{
vector<WindowInfo*> windows;
BOOL ret = EnumWindows(EnumWindowsProc, (LPARAM) &windows);
if ( ret )
{
//windows have windowinfo of all enumerated windows
}
}
Your EnumWindowsProc seems to be a bit confused - are you enumerating or using FindWindow?
If you enumerate, simply get the window title and compare to the string you search for:
BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam)
{
char title[256];
if (GetWindowTextA(hwnd, title, 256)) {
if (strcmp(title, "eBargain 2 Share - Windpos Internet Explorer") == 0) {
/* GetWindowRect ... */
}
}
return TRUE;
}
Or, if you're using FindWindow, no need to enumerate:
int main() {
HWND hwnd = FindWindowA(0, "eBargain 2 Share - Windpos Internet Explorer");
if (hwnd) {
/* GetWindowRect ... */
}
}