Adding a Win32 menu bar to pre-existing GUI - c++

Menus are pretty popular in many applications:
Example
I've read a lot of threads and have learned out how to add a menu bar to your gui:
//Pseudocode
//..RegisterClassEx
HMENU Menu = CreateMenu();
HMENU Tools = CreateMenu();
AppendMenu(Menu, MF_POPUP, (UINT_PTR)Tools, L"Tools");
AppendMenu(Tools, MF_STRING, 1, L"Test");
SetMenu(hwnd_to_gui, Menu);
//...
//..GetMessage
//..TranslateMessage
//..DispatchMessage
First you RegisterClassEx on your WNDCLASSEX struct that has a property called "lpfnWndProc" which directs to the function to be called when DispatchMessage is called. Then you actually create the menu bar. Finally, you set up a loop that calls GetMessage, and if a message is received, it will translate and dispatch it, effectively calling the lpfnWndProc function.
I was wondering if you could do this with an already existing gui. For example, the console application. I know I can easily set up the menu bar, but handling the input seems to be hard for me.
Console Application w/ Menu Bar Added
I have a loop that calls GetMessage, however it seems to be picking up no input.
More information:
I am overwriting the current WNDCLASSEX (RegisterClassEx) with a copy of the old one (achieved from GetClassInfoEx) with the only modification that is the "lpfnWndProc" function (to handle input differently).
The rewrite seems to be successful, I am just not picking up any input from the GetMessage function (I am clicking buttons, etc.)
Any help on how I would go about doing this?

Related

Make focused modeless dialog topmost

So I have my main dialog that calls modeless dialogs through this function (this is the legacy code on the project):
void MyClass::ShowDialog(CDialog* dialog)
{
if (!IsWindow(dialog->m_hWnd))
{
return;
}
int nCmdshow1 = dialog->IsWindowVisible() ? SW_HIDE : SW_SHOW;
dialog->ShowWindow( nCmdshow1 );
}
Problem: all sub dialogs stay on top of my main dialog.
Desired behavior: whichever's focused (they are all modeless), be it the main dialog, or sub dialogs, I want it to be the topmost dialog. Thank you!
Note: I already tried on my main dialog's OnInitDialog() these but didn't work:
1. SetWindowPos(&this->wndTop,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
2.SetWindowPos(&this->wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
EDIT
Also, sub dialogs are created this way:
m_subDlg1->Create( SubDlg1::IDD, this );
As long as there is an owner relation between two windows. the owner of a window can never be on top of the owned window.
Windows in an owner, parent, child relation always behave the same. The owned/child window is always on top of the parent/owner.
If you want to break this, you have to break the owner/child relation. Let all dialog windows have no owner... than they may float freely.
But: I will expect the you program doesn't behave better. Even worse. User might search windows that are deep below covered under other windows. And they will never get in front, when your program gets active.
See the description about parent/child/owned windows here. Also this article might be helpful.
Edit: The problem is that internally the MFC sets the main window as an owner if no parent is given. Only the call to BOOL Wnd::CreateDlgIndirect(LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd, HINSTANCE hInst) allows to leave pParentWnd NULL.
So you may create the window as normal, but use SetParent(NULL) after it was created. Again the MFC ASSERTs this. SO you may use the API function and the handle of your dialog.

How can I register another win32 message handler

I want to change the message handler for an old legacy app we use but don't have the source for any more. In a dll that we do have the source for I'm wanting to intercept the window messages and then pass them onto the app. Is this possible? I tried something along the lines of:
WNDPROC lpfnWndProc = NULL;
void GetHandler()
{
HINSTANCE hInstance = GetModuleHandle(NULL);
HWND hWnd = GetActiveWindow();
WCHAR lpClassName[1024];
GetClassName(hWnd,lpClassName,1024);
WNDCLASSEX wc;
GetClassInfoEx(hInstance, lpClassName, &wc);
lpfnWndProc = wc.lpfnWndProc;
wc.lpfnWndProc = NewMessageProc;
RegisterClassEx(&wc);
}
However GetActiveWindow fails and just returns NULL. Is there a simpler way to do this. Infact I'd be happy if I could just simply add another message handler.
It is not clear whether you want to subclass specific controls, or all windows of a particular window class.
If you want to subclass specific controls, the section Subclassing Controls in the MSDN describes how to do this, both for ComCtl32.dll version 6 and above, and the legacy procedure of directly replacing a control's window procedure.
If you want to subclass all controls of a particular window class you would have to change the entries stored in the registered window class, using SetClassLongPtr. Note that this will only affect windows subsequently created with that window class. This is a bit of a Catch 22, as you need to have a window handle when calling SetClassLongPtr, limiting the applicability of subclassing a window class.
As for the code you posted, there are a number of issues:
Your call to GetModuleHandle retrieves the wrong HINSTANCE, namely that of the calling application. Since you need the module handle of the module that registers the window class you have to pass the name of the .dll that implements the controls.
Calling GetActiveWindow may or may not return a value, depending on whether or not the calling thread actually does have an active window. In your case it apparently doesn't, so you need another means of retrieving a window handle, such as FindWindowEx.
Your final call to RegisterClassEx doesn't do what you think: It will simply fail, since you cannot re-register a window class with the same name of an existing window class. You need to call SetClassLongPtr instead, as illustrated above.
I'd actually use SetWindowSubclass after getting the HWND of the window you want to modify the behaviour of. SetWindowLong was deprecated as a way to change the WndProc of a window back around the time that CommCtrl.dll version 6 came out. MSDN can tell you all about that particular part of history and its motivation - just look up SetWindowSubclass.
As it stands, assuming the calling thread has an active window, your code will simply create a new window-class with the same attributes as your target window, albeit with a different WndProc - it wont set the wndproc of an existing window.. - (hence my mention of SetWindowLong and SetWindowSubclass)
EDIT: Or at leaast, it would of not for the oversight I made on that point. As pointed-out in a comment below, this call to RegisterClass will actually fail - you can't register the same className more than once.
You should also probably look at the FindWindow function - just give it a NULL lpWindowName, and the (known) class-name of the target window. In the event that the desired window is not the one that's returned, you could use EnumWindows. Simply call GetClassName in the callback function you supply to EnumWindows, subclassing any/all windows whose class-name matches the class-name of the target window.
Once this window has been subclassed, you can consume its messages as you wish, passing them onto the original window-proc as needed.

Parent-Less Button

Can I create a button without a parent in WINAPI?
I tried doing:
CreateWindowEx(0, "Button", "BTN", WS_POPUP | BS_PUSHBUTTON, 0, 0, 15, 15, nullptr, nullptr, nullptr, nullptr);
then setting the parent to a specified window later on and also showing the button using ShowWindow. This indeed created a fine looking button.
However, the button has no ID and cannot be Identified in WM_COMMAND because the ID is 0.. If two buttons were parentless, there'd be no way to tell them apart. Now if I give it an ID through the HMENU parameter:
CreateWindowEx(0, "Button", "BTN", WS_POPUP | BS_PUSHBUTTON, 0, 0, 15, 15, nullptr, 15, nullptr, nullptr);
GetLastError() prints "Invalid Menu Handle" and the button will not be created.
If I give it no parent and WS_CHILD, it will say cannot create a top level child window which is understandable.
So what I did was I set the Parent to GetDesktopWindow() and give the button an ID. That works but the button isn't parentless..
So is there a way to give a button an ID (So as to identify it in WM_COMMAND) and at the same time, have its parent NULL so that I can set the parent later? How does Windows Forms do it? The buttons can be parentless until you do Form.add(ButtonName);
Can the same effect be achieved in WINAPI?
This is appears on its face to be a very silly sort of question.
Button controls are by definition child controls, so the call to the CreateWindowEx function you use to create the button should also be specifying the WS_CHILD style.
Of course, as you mention, you cannot create a child control with no parent; you'll get an error. There is no such thing as a top-level child window.
So then, the answer to the initial question
Can I create a button without a parent in WINAPI?
is clearly no. Buttons are child controls, and all child controls must have a parent.
Just because Windows let you get away with specifying the WS_POPUP flag when you create a button control doesn't mean that it's a valid combination.
I strongly recommend re-reading the documentation for the CreateWindowEx function. In particular, note that the hMenu parameter is overloaded with respect to its meaning. If you are creating an overlapped or pop-up window (WS_OVERLAPPED or WS_POPUP), it specifies a handle to a menu. If you're creating a child window (WS_CHILD), it specifies the identifier of the child window. The fact that the same parameter is used for both things, depending on the style of the window, should tell you something.
How does Windows Forms do it? The buttons can be parentless until you do Form.add(ButtonName);
They most certainly cannot. The button controls are not created until you add them to a form or other parent control. The System.Windows.Forms.Button class constructor does not create a Win32 window. It just holds a collection of necessary styles used to create the underlying Win32 window when appropriate.
You could, of course, do the same thing by writing a C++ Button class. A simple implementation would just have member variables corresponding to the parameters of CreateWindowEx and a Create member function that would actually call CreateWindowEx to create the Win32 window once all of the members had been set. The Create method could throw an exception if one of the necessary members had not yet been set to a valid value.
I solved it. I had to pass HWND_MESSAGE as the Parent Parameter. When you call SetParent, that parameter gets changed to the Parent's handle and all is well.
No, this really is not a "solution" to the problem. As kero points out, you've simply set the button control's parent to the message-only window. Again, this might appear to work, but it's a rather strange thing to do and I hardly recommend it as a solution.
If you really want to hack it, I recommend creating your own hidden top-level window to use as a parent for your "unparented" child controls. Then you could use the same trick of calling SetParent to reparent them.
I solved it. I had to pass HWND_MESSAGE as the Parent Parameter. When
you call SetParent, that parameter gets changed to the Parent's handle
and all is well.
No, you didn't get "Parent-Less Button": the parent window of your message-only button is the "main" message-only window (class "Message").

Listbox in main window

I'm creating a Win32 GUI application using Code::Blocks and MinGW. I am using this tutorial as a guide. Everything worked well until I decided I needed a listbox to display files in the current directory. I don't want the list box in a window by itself, I want it inside the main window. The tutorial I was following wasn't very helpful on this part, so I still don't know how to create a listbox. Using the resource editor somehow, I think. Could someone please help me?
I assume you have a window procedure somewhere (let's call it WndProc) for your main window (let's call it hWndMain).
Add a WM_CREATE handler in WndProc if it's not already there.
In the WM_CREATE handler, add a call to CreateWindowEx to create the listbox as a child window of hWndMain:
const HWND hWndList = CreateWindowEx(...);
The picky parameters of CreateWindowEx that are essential here are the class name "LISTBOX", that the style parameter must include the WS_CHILD flag (plus the other essential listbox flags, of course) and that the parent parameter must be hWndMain.
For the other parameters, use your brain and read the docs.

Do you have to register a Dialog Box?

So, I am a total beginner in any kind of Windows related programming. I have been playing around with the Windows API and came across a couple of examples on how to initialize create windows and such.
One example creates a regular window (I abbreviated some of the code):
int WINAPI WinMain( [...] )
{
[...]
// Windows Class setup
wndClass.cbSize = sizeof( wndClass );
wndClass.style = CS_HREDRAW | CS_VREDRAW;
[...]
// Register class
RegisterClassEx( &wndClass );
// Create window
hWnd = CreateWindow( szAppName, "Win32 App",
WS_OVERLAPPEDWINDOW,
0, 0, 512, 384,
NULL, NULL, hInstance, NULL );
[...]
}
The second example creates a dialog box (no abbreviations except the WinMain arguments):
int WINAPI WinMain( [...] )
{
// Create dialog box
DialogBox(hInstance,
MAKEINTRESOURCE(IDD_MAIN_DLG),
NULL,
(DLGPROC)DialogProc);
}
The second example does not contain any call to the register function. It just creates the DialogBox with its DialogProc process attached.
This works fine, but I am wondering if there is a benefit of registering the window class and then creating the dialog box (if this is at all possible).
You do not have to register a dialog box.
Dialog boxes are predefined so (as you noted) there is no reference to a window class when you create a dialog. If you want more control of a dialog (like you get when you create your own window class) you would subclass the dialog which is a method by which you replace the dialogs window procedure with your own. When your procedure is called you modify the behavior of the dialog window; you then might or might not call the original window procedure depending upon what you're trying to do.
It's been a while since I've done this, but IIRC, the first case is for creating a dialog dynamically, from an in-memory template. The second example is for the far more common case of creating a dialog using a resource. The dynamic dialog stuff in Win32 was fairly complex, but it allowed you to create a true data-driven interface, and avoid issues with bundling resources with DLLs.
As for why use Win32 - if you need a windows app and you don't want to depend on MFC or the .NET runtime, then that's what you use.