Application with multiple windows as instances of a class, C++ - c++

I wrote an application. There is a class named APP, with handle to the window, and message loop inside it, and all this stuff.
It is intended to "run" some objects of this class, each with its own window based on a set of variables necessary for a standard window.
Message loop is allowed for public use, it is ran by RunMessageLoop method.
int nCmdShow - of course, it is used to tell how to display a window.
Now, when i create some objects like this:
vector <APP *> App;
for (int i=0; i<3; i++)
{
App.push_back(&APP(nCmdShow))
App[i]->RunMessageLoop();
}
program waits for each message loop to end before it starts another.
I figured out to make it this way:
vector <APP *> App;
for (int i=0; i<3; i++)
{
App.push_back(&APP(nCmdShow))
}
for (int i=0; i<3; i++)
{
App[i]->RunMessageLoop();
}
When i know how many windows I want at startup to be run, it seems to be ok.
But I don't know how to create new windows dynamically, with complete independence of other windows. It should invoke message loops and immediately return to WinMain() without ending message loops.
I thought about multi-threaded app, each thread per one instance of an APP class. But don't know how to build multithreaded app, though.
Any ideas for a possible solution?

I see what you are trying to do now, I have achieved this in my application framework called Lucid (it is still a work in progress). For the sake of the answer, your window class will be called Window instead of APP.
This is done by passing a global procedure to every window you create. All windows share this same procedure. Every time any window gets a message, that message is sent to the global procedure, the global procedure checks if the HWND belongs to a Window that you created, and if it does, sends the message to that Windows' procedure. Here's an overview of how this works.
class Window
{
public:
// The contents of this function can vary from window to window
// provided that you make a subclass and override this method.
virtual LRESULT procedure(HWND wnd, UINT msg, WPARAM wp, LPARAM lp);
// When you create a Window object, add a pointer to it in this map.
// Eg. if (this->hwnd != NULL) createdWindows[this->hwnd] = this;
static map<HWND, Window*> createdWindows;
// When you create a window, make this its procedure.
static LRESULT CALLBACK routeMessage(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
if (createdWindows.find(wnd) != createdWindows.end()) {
// Message belongs to one of our 'Window' objects.
// Pass the message to that window and return the result.
return createdWindows[wnd]->procedure(wnd, msg, wp, lp);
} else {
// It seems you made 'routeMessage' the procedure
// of a window that doesn't belong in the map. Go ahead
// and process the message in the default manner.
return DefWindowProc(wnd, msg, wp, lp);
}
}
};
Now you will only need a single message loop and a single thread. I have a test project using Lucid that creates 2 windows with different procedures on a single thread with a single message loop:
#include "Lucid.h"
using namespace Lucid;
void sayBye(MessageEventArgs& e)
{
MessageBox(NULL, "Goodbye!", "Form 2", MB_OK);
e.handled = true;
}
void Program::onStart()
{
Form* myForm1 = new Form("Hello World!");
myForm1->show();
Form* myForm2 = new Form("Hello World!");
myForm2->addMessageHandler(WM_CLOSE, sayBye);
myForm2->show();
// This Program::onStart() function is called
// immediately before the single message loop is entered.
}

Create the threads with _beginthreadex equal to the number of window you need to run. Then, run message loop in the thread procedure and wait until all thread has been terminated with WaitForMultipleObjects.

Related

Safe place for an ATL object to release itself

Is there a strategy for safely allowing an ATL object to release itself in response to a Windows message or sink event?
In other words, let's say you have an ATL class that's subclassing some windows (using a message map) and/or sinking events from COM objects (using a sink map). And you'd like the class to release itself given a particular message or event. For example, you might want to release when a particular subclassed window receives WM_CLOSE, or you're sinking DWebBrowserEvents2 and want to release upon DISPID_ONQUIT.
I think the problem is that if you release in the middle of your message or event handler, the ATL framework might still have some processing to do afterward (even if you, say, do something like bHandled = TRUE). And if your object has been released/deleted at that point, then bad things will ensue.
Does anyone know of an approach to solve this? Thanks for any input.
you can do next implementation
class MySubClass : public CWindowImplBaseT<>
{
ULONG dwRefCount = 1;
BEGIN_MSG_MAP(MySubClass)
MESSAGE_HANDLER(WM_CHAR, OnChar)
END_MSG_MAP()
LRESULT OnChar(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
bHandled = FALSE;
// for instance unsublass when ESC pressed
// but possible do this on any event
if (uMsg == WM_CHAR && wParam == VK_ESCAPE)
{
UnsubclassWindow(FALSE);
}
return 0;
}
virtual void OnFinalMessage(_In_ HWND hWnd)
{
__super::OnFinalMessage(hWnd);
Release();
}
~MySubClass()
{
DbgPrint("%s<%p>\n", __FUNCTION__, this);
}
public:
BOOL SubclassWindow(_In_ HWND hWnd)
{
if (__super::SubclassWindow(hWnd))
{
AddRef();
return TRUE;
}
return FALSE;
}
HWND UnsubclassWindow(_In_ BOOL bForce /*= FALSE*/)
{
if (HWND hwnd = __super::UnsubclassWindow(bForce))
{
// mark window as destroyed
m_dwState |= WINSTATE_DESTROYED;
m_hWnd = hwnd;
return hwnd;
}
return 0;
}
void AddRef()
{
dwRefCount++;
}
void Release()
{
if (!--dwRefCount)
{
delete this;
}
}
};
void DoSubclass(HWND hwnd)
{
if (MySubClass* pObj = new MySubClass)
{
pObj->SubclassWindow(hwnd);
pObj->Release();
}
}
so key points - have reference count on object ( ULONG dwRefCount - here i assume that object will be accessed only from single UI thread, otherwise need use atomic/interlocked operations). delete object inside Release() when dwRefCount became 0. when we subclass window - add additional reference, and in UnsubclassWindow - set WINSTATE_DESTROYED bit in state ( m_dwState |= WINSTATE_DESTROYED ) - as result OnFinalMessage will be called after last message and here we already call Release. or if we not direct unsubclass until window will be destroyed - atl implementation anyway finally call OnFinalMessage where we release self.
According to the documentation for CWindowImpl::OnFinalMessage:
The default implementation of OnFinalMessage does nothing, but you can override this function to handle cleanup before destroying a window. If you want to automatically delete your object upon the window destruction, you can call delete this; in this function.
So that looks like the place to do it.

Port Win32/WinAPI application to wxWidgets

I'm currently using Windows 10, MSVC v142 (with VS2019) and wxWidgets 3.1.3. I have an old Windows C++ application that uses WinAPI for its GUI features, i.e Windows message loop, using "CreateWindow", and having to "manually" create all window procedures and event handling.
I want to improve this application by gradually replacing the UI using wxWidgets so I don't have to start over from scratch. I would implement new, independent UI features in wxWidgets (e.g specific dialogs), and then work my way back and replace all the old UI code with a wxWidgets implementation, without having to break the app along the way.
Below is a skeleton of how my app is currently set up:
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// Handling window messages, e.g menus, buttons, etc.
}
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char* lpCmdLine, int nCmdShow)
{
// Initialize resources, register main window class using MainWndProc, etc.
// ...
HWND mainwnd = CreateWindow(/* CreateWindow args... */);
do
{
MSG msg = {};
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Per-frame application logic
// ...
} while (msg.message != WM_QUIT);
// Clean up resources
// ...
return 0;
}
How would I need to modify this so that all the WinAPI objects continue to function, but I can now also create windows using wxWidgets? I previously tried replacing the message loop above by initializing wxWidgets through a custom class derived from wxApp, but my application kept crashing during the cleanup code (which it sometimes wouldn't even reach).
EDIT: I managed to make it work, updated skeleton can be found below.
// Main WinAPI window procedure
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// Code to handle other messages
// ...
case WM_CLOSE:
// Closing this window should shut down the app
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
class MyApp : public wxApp
{
public:
virtual bool OnInit() override
{
if(!Old_Init())
{
// Perform cleanup in case something goes wrong
Old_Exit();
return false;
}
// Wrap the WinAPI window in a dummy wxWindow
m_dummyMainWindow = new wxWindow();
m_dummyMainWindow->SetHWND(m_mainWnd);
return true;
}
int OnExit() override
{
// Unset the dummy window HWND and delete it (is this necessary?)
m_dummyMainWindow->SetHWND(NULL);
delete m_dummyMainWindow;
// Clean up everything else
return Old_Exit();
}
private:
bool Old_Init()
{
// Perform the old initialization
// ...
m_mainWnd = CreateWindow(/* CreateWindow args... */);
if(m_mainWnd)
{
return true;
}
else
{
return false;
}
}
int Old_Exit()
{
// Perform the old cleanup (previously done after exiting the Windows message loop)
// ...
return 0;
}
HWND m_mainWnd;
wxWindow* m_dummyMainWindow;
};
wxIMPLEMENT_APP_NO_MAIN(MyApp);
// App entrypoint
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char* lpCmdLine, int nCmdShow)
{
if (wxEntry())
{
// Exit if something goes wrong (this might not be the correct way to do it?)
wxExit();
}
return 0;
}
This does seem to function, all the old UI elements are working as before, but I am not 100% sure this is a stable solution. My debugger is warning me about memory leaks, which appear to increase in number when I activate UI elements (e.g open and close dialogs). I suspect WinAPI resources might not be cleaned up correctly. Am I missing anything?
EDIT2: I did some more debugging, and the code in my original app (i.e without wxWidgets) causes those "memory leaks" as well, and I can't replicate it in a minimal working example, so I suspect the issue is not related to wxWidgets at all. I am therefore confident that the approach described above should solve my problem, but I would not mind a second opinion.
I recommend looking at the MFC sample to see a working example of something close to what you want to do. MFC is, of course, not quite the same as Win32 API, but it should still be a good starting point.
Notably it shows how to pass the messages to wx event loop when you're running your own one (this part is in wxMFCApp class in include/wx/msw/mfc.h). Of course, if you can switch to running wx event loop, it would be even simpler.
You may also find it helpful to know that you can wrapp HWNDs you create into wxWindows using AssociateHandle() and handle their messages by overriding MSWHandleMessage() or even just using wxNativeWindow directly.
Good luck!

How to check if CWnd message map contains message id without handling message?

ParentWnd contains mfc control called modeOfOperation (drop down list). When modeOfOperation is Normal everything is normal. We added new modeOfOperation=Extreme. When modeOfOperation is Extreme I want to disable 90% of existing ParentWnd controls because they don't work in Extreme mode. I have existing codebase with hundreds of UI controls. I want to find one place in code to disable 90% of them without hurting rest of functionality.
I know that 90% of UI controls that I need to disable are in several child windows. One of them is m_childWindow1. I need to tell if given message is is handled by m_childWindow1,...,m_childWindowN.
So ParentWnd routes messages to childWindow. I want to override childWindow handler in case when given message is handled by childWindow. So I need function like bool CWnd::isMessageIdInMessageMap(int id).
BOOL ParentWnd::OnCmdMsg( UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo )
{
if ( nCode == CN_UPDATE_COMMAND_UI )
{
CWnd *contents = m_childWindow1->getContents();
if( contents )
{
if( contents->OnCmdMsg( nID, nCode, pExtra, pHandlerInfo ) )
{
//I want to enter additional code here
//But I don't want to call contents->OnCmdMsg
return true;
}
}
}
}
...
}
Simply use the existing functions (OnCmdMsg).
Create your own CCmdUI object (overwrite the Enable... functions if required) pass is as pExtra argument to OnCmdMsg and you know after the call if the was a handler or not.
There are no side effects...

Add visible window titles to combobox MFC

I want to add visible window titles to a combobox. Here is my source:
BOOL CALLBACK EnumWindowsProc(HWND hWnd, long lParam)
{
TCHAR buff[255];
CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_PROCESS);
if (IsWindowVisible(hWnd))
{
GetWindowText(hWnd, buff, 254);
pComboBox->AddString(buff);
}
return TRUE;
}
void CFindProcess::OnDropdownComboProcess()
{
EnumWindows(EnumWindowsProc, 0);
}
but I get error:
error C2660: 'GetDlgItem' : function does not take 1 arguments 60
How I can correctly add titles to combo?
MFC objects are thread-sensitive, GetDlgItem works well in the thread that created the object, probably the main UI thread. Function EnumWindows probably creates a worker thread to access the callback function, and that is why GetDlgItem failed to get a valid handle of the combobox.
To access the combobox properly in another thread, you have to use the static function: CWnd::FromHandle with the raw handle of the combobox object as follows:
BOOL CALLBACK EnumWindowsProc(HWND hWnd, long lParam)
{
if (IsWindowVisible(hWnd))
{ TCHAR szBuffer[255];
INT nLength = GetWindowText(hWnd, szBuffer, 254);
if (nLength>0)
{ // only add windows that has a caption
CComboBox *pComboBox = (CComboBox*)CWnd::FromHandle((HWND)lParam);
pComboBox->AddString(szBuffer);
}
}
return TRUE;
}
// call EnumWindows --------------------
CComboBox *pComboBox = (CComboBox *)GetDlgItem(IDC_COMBO1);
// passing the raw handle of the combobox as parameter
EnumWindows(EnumWindowsProc, (LPARAM)pComboBox->m_hWnd);
Firstly, your GetDlgItem has two parameters, and the first is a handle to the dialog box that contains the control.
So it expects a HWND parameter of the dialog that contains this control, I would presume that will be the HWND you pass as a parameter to your function.
CComboBox* pComboBox = (CComboBox*)GetDlgItem(hWnd,IDC_COMBO_PROCESS);
^^^^ added parameter
If you look at EnumWindows in MSDN, you'll see you have to pass a callback and it has a HWND parameter, if you look at what this parameter is for it says:
A handle to a top-level window.
This is exactly what you have to pass to GetDlgItem.
Also, you should check the return value of GetWindowText as this returns the number of characters written to the buff you passed it.
int ret = GetWindowText(hWnd, buff, 254);
if (ret > 0) pComboBox->AddString(buff); // only add non-empty strings.
In addition to what user #mfc has provided, I would not do UI update from a different thread. I believe EnumWindows does not create thread for enumeration. It would call the callbacks within the call-stack of current thread.
This, in turn, means that UI may freeze for a while. Thus, it is recommended to create a thread for enumeration. More over, I would not directly update UI from different thread. May be a vector of string, or a PostMessage (on each iteration) I would have used.
It is true that EnumWindows may perform quite fast. But when you move to enumerate other (kernel) objects like file, printers, users etc - the UI is definitely going to freeze. So, better practice writing multithreaded code. Initially writing MT-code would be a pain, but later you'd love it, appreciate it, and cannot live without it.

Get main frame window

I want to get main frame window.
How to get main frame window in WTL-MDI?
class CChildFrame : public CMDIChildWindowImpl<CChildFrame>
{
...
LRESULT OnEdit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& bHandled)
{
...
mainfrm->FlashWindow(TRUE);
return 1;
}
}
The WTL base classes CMDIChildWindowImpl, CFrameWindowImplBase don't hold a pointer to main frame. It does not mean that you cannot do it yourself, you derive from these classes so you can pass the pointer explicitly as a part of initialization, and use it from there. After all you always have parent HWND in the child window class, so you can send an application defined message to exchange with certain information with the parent window.