WinAPI FindWindow - winapi

I am building a win32 application in visual studio 2012. I have 4 disabled buttons created with the following code:
HWND hWndButton=CreateWindowEx(NULL,
L"BUTTON",
L"APP1",
WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON|WS_DISABLED|BS_ICON,
40,
40,
180,
140,
hWnd,
(HMENU)IDC_BUTTON1,
GetModuleHandle(NULL),
NULL);
What I want to do is to enable the buttons as the application runs. I tried to use findwindow to find and enable the first button but it doesn't find it. My code is:
HWND hwB1 = FindWindow(L"BUTTON",L"APP1");
if (hwB1 !=0) MessageBox(NULL,L"FOUND",L"Button Found",MB_OK);
EnableWindow(hwB1,true);
Am I doing something wrong?
Thank you in advance.

FindWindow() finds top-level windows, not child windows.
If you really do want to look up a child window by name, you can use the FindWindowEx() function, but using the ID is usually more efficient.
The function that does this is GetDlgItem(). This looks up child windows by their ID, which you provide when you create them.
HWND hwB1 = GetDlgItem(hWnd, IDC_BUTTON1);
hWnd is the parent window, and IDC_BUTTON1 is the ID.
Another alternative is to simply store the window handle that's returned when you create the child window - hWndButton in your code example - and then you don't need to look it up at all.

Use FindWindowEx(),
HWND hwB1=FindWindowEx(hWnd/*Parent window*/,
hWndButton/*Child window*/,
"BUTTON"/*Class of the child window*/,
"APP1"/*Title of the child window*/);
This is a better method when the control ID is unknown.

Related

Finding handle for a button in the window of another program

I need some help. I wrote my questions at the end and will first explain what exactly my code is supposed to do:
I am making a program that will communicate with other programs. What I need my software to do is be able to click on a button on another program, and I believe the appropriate code to do this would be:
SendMessage(hWnd, Msg, wParam, lParam);
with
Msg = B_Click
wParam = 0;
lParam = 0;
however I am not sure how to get the hWnd which is the handle of a specific button on a specific window of another program that is running at the same time. I have read somewhere that I could possibly do the following:
HWND buttonHandle = FindWindowEx(hwndParent, hwndChildAfter, lpszClass, lpszWindow);
where:
HWND hwndParent = A handle to the parent window whose child windows are to be searched
HWND hwndChildAfter = if its null child windows are of the parent window are looked through
LPCTSTR lpszClass = (NOT SURE WHAT THIS IS)
LPCTSTR lpszWindow = (NOT SURE WHAT THIS IS)
I have a few issues with the FindWindowEX() function however.
Question 1: The window I am looking at has various buttons, so how would the function know which one of the 3 i am looking at?
Question 2: What are the lpszClass and lpszWindow variables and how might I get them?
Question 3: Is this even the right approach? If it's not, please point me to the right direction!
You don't need the handle of the button, you need the handle of its parent window. The button sends BN_CLICKED to its parent window. Look up the button's ID with spy++. Then use EnumChildWindows of the parent to look at all the child windows. For each child use GetWindowLong with GWL_ID to check its ID.

Get ListBox handle from Window handle

I am incredibly confused by the whole "window" verses "listbox" thing in the WIN32 API. I am simply trying to create a window as a "listbox" and add elements to it. My end goal will be a listbox similar to the on here: http://msdn.microsoft.com/en-us/library/windows/desktop/hh298365%28v=vs.85%29.aspx
I start by create a window with a listbox like so:
hDlg = CreateWindowExA(
WS_EX_CLIENTEDGE,
"ListBox",
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
But from what I understand, hDlg now points to the entire window and not the listbox.
Ideally I want to be able to add items to the listbox similar to this:
int pos = (int)SendMessage(hwndList, LB_ADDSTRING, 0,
(LPARAM) "Test Item1");
However I cannot get the handle of the list in the same way as the tutorial because they use this line:
HWND hwndList = GetDlgItem(hDlg, IDC_LISTBOX_EXAMPLE);
but IDC_LISTBOX_EXAMPLE throws a compilation error because it isn't included anywhere. And for the life of me, I cannot google a correct result for the second parameter int nIDDlgItem.
Can someone please explain to me how I can find the value GetDlgItem() or otherwise find a handle to my listbox from CreateWindowExA()?
The problem is that you're using the predefined ListBox window class to create a top-level window.
hDlg = CreateWindowExA(WS_EX_CLIENTEDGE, "ListBox", ...
This is creating a listbox control. The second parameter to CreateWindowEx specifies the window class - this tells the system what type of window you want to create. Since you're passing "ListBox" for that value, it will be creating an instance of the ListBox class.
The trouble is that you're creating that window to be a top-level window. WS_OVERLAPPEDWINDOW is a window style used for top-level windows (i.e. the one titled "List Box Example" in the above screenshot). Child windows, such as the listbox control, need to have the WS_CHILD style set.
What you really need to do is use RegisterClass to register your own window class for the top-level window. You would use this class name when calling CreateWindowEx to create the main window, and then create the various controls as children of that window.

Child Window Z-Order

I see in MSDN, it says:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx
If the created window is a child window, its default position is at the bottom of the Z-order. If the created window is a top-level window, its default position is at the top of the Z-order (but beneath all topmost windows unless the created window is itself topmost).
However, another documentation says:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms632599(v=vs.85).aspx
When an application creates a window, the system puts it at the top of the z-order for windows of the same type
I tested it like this:
btn1 = ::CreateWindow(L"button", L"OK", WS_TABSTOP|BS_DEFPUSHBUTTON|WS_VISIBLE|WS_CHILD
, 10, 10, 50, 30, hWnd, (HMENU)51, hInst, NULL);
btn2 = ::CreateWindow(L"button", L"Cancel", WS_TABSTOP|WS_CHILD|BS_PUSHBUTTON|WS_VISIBLE
, 20, 20, 70, 30, hWnd, (HMENU)52, hInst, NULL);
I created two buttons in a window and they overlapped, I can see that the button created later is covering the first button created.
Is the first statement in MSDN contradictory to my testing?
The documentation is accurate. You are being tripped up by another problem, you allow the child windows to draw themselves across other child windows. So now the painting order matters.
You fix that by adding the WS_CLIPSIBLINGS style flag to your CreateWindowEx call. You'll now see that the OK button is on top. Fix:
btn1 = ::CreateWindow(L"button", L"OK",
WS_TABSTOP|BS_DEFPUSHBUTTON|WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS,
10, 10, 50, 30, hWnd, (HMENU)51, hInst, NULL);
// etc, use it as well on other child windows
You should not rely to much on the how the child windows are displayed and which one is drawn last. If I run your sample code I get an OK button which is overlapped by the Cancel button. If I move the mouse over the buttons then the OK button comes into foreground and draws over the Cancel button.
I once had similar trouble with overlapping child controls. Then I found out that Microsoft says Overlapping Controls Are Not Supported by Windows.
BTW, if you really want to see the Z-order, then use GetTopWindow and GetNextWindow. Or the simpler way: run Microsoft Spy++.

How to discover the method that is called by a Windows Context Menu item?

When you click the right mouse button on your clean desktop it opens a context menu.
Each item there is a call to a method.
To programmatically call those methods, first I need to know which one I want.
IIRC there is a tool that helps with that, but I can't remember its name.
You cannot call such a method in another process. You could try to inject the WM_COMMAND message that a context menu usually generates with SendMessage. Use Spy++ to find out what that message might be, if it exists.
Use Spy++ to find the handle and use SendMessage / PostMessage. It will be something similar to:
hwnd = FindWindow(...)
hmenu = GetMenu(hwnd)
hsubmenu = GetSubMenu(hmenu, 0)
menuid = GetMenuItem(hsubmenu, 1)
SendMessage(hwnd, WM_COMMAND, menuid, 0)

Using CreateWindow and adding buttons and such to it? How?

I have realised after so long of coding DirectX/OpenGL applications I don't have the faintest of ideas how to create windows with basic form objects like text boxes, labels, command buttons etc.
I can create a window using the CreateWindow function just fine, how can I add buttons, command prompts and other form objects to it?
Look at Create Window Help. Once you create your main window you can create child windows by providing the parent HWND to the function. For standard controls you use one of the class names defined at the button, like EDIT for an edit box and BUTTON for a button.
As an example: CreateWindow(L"BUTTON", L"Button", BS_TEXT | WS_CHILD | WS_VISIBLE, 40, 40, 100, 40, hMainWnd, (HMENU)ID_MYBUTTON, hInstance, NULL);
Or you could just create a dialog box instead and edit it with Visual Studio's resource editor (if you have full VS that is).

Resources