I have a dialog class made from dialog template in memory which runs it's own nested message loop (in addition to main app msg loop).
To create a dialog I use CreateDialogIndirectParamW which returns handle to the dialog window,
Since the dialog is completely customized, all the message processing and creation is done manually.
I omitted Dialog procedure, but basically it calls the below relevant message handlers, once the the dialog is closing down.
Note that, we can't use EndDialog function to destroy the dialog and end message loop because for CreateDialogIndirectParamW we must use DestroyWindow explicitly.
I'm looking for efficient way to end the dialog loop.
I tried to implement this loop but problem is that this approach will either consume too much CPU resources since the for loop in the sample code will just run silly until there is a message, or if for is omited then PeekMessage will stop the loop immediately, which is not what I wan't.
Relevant class declaration:
class Dialog :
public ContainerWindow,
public MessageWindow,
public SuperClassWindow
{
// ...
public:
/** Process messages for dialog window */
[[nodiscard]] int RunMessageLoop() override;
protected:
/** Handler for WM_NCDESTROY */
std::uint32_t OnNcDestroy(const UINT& uMsg, const WPARAM& wParam, const LPARAM& lParam) override;
/** Handler for WM_DESTROY */
inline void OnDestroy() const noexcept override;
/** Handler for WM_CLOSE */
inline virtual bool OnClose() noexcept;
// ...
protected:
HWND mhWnd; /** Window handle of derived component */
}
Simplified class definition:
std::uint32_t Dialog::OnNcDestroy(
[[maybe_unused]] const UINT& uMsg,
[[maybe_unused]] const WPARAM& wParam,
[[maybe_unused]] const LPARAM& lParam)
{
// ...
delete this; // note we can't set this pointer to nullptr!
// ...
return count;
}
void Dialog::OnDestroy() const noexcept
{
PostQuitMessage(0);
}
bool Dialog::OnClose() noexcept
{
return DestroyWindow(mhWnd);
}
And here is the message loop for a dialog:
I need to add some checking code into the loop to check if dialog is valid object, that is stop the loop somehow if the Dialog object has been deleted
Once the OnNcDestroy handler is called, IsDialogMessageW bellow will fail, see comment.
Looks like GetMessageW will continue running after WM_NCDESTROY is dispatched, the loop is still waiting for WM_QUIT sent by OnDestroy handler so the msg loop will continue running once the Dialog object is deleted, and that will make IsDialogMessageW(mhWnd, &msg) bellow fail. since mhWnd does not exist any more.
int Dialog::RunMessageLoop()
{
EnableWindow(mhWndParent, FALSE);
MSG msg{ };
BOOL result = FALSE;
while ((result = GetMessageW(&msg, nullptr, 0, 0)) != FALSE)
{
if (result == -1)
{
ShowError(ERR_BOILER); // error checking function.
break;
}
// once OnNcDestroy is called "mhWnd" is invalid memory
// and this will off course cause access violation!
if (!IsDialogMessageW(mhWnd, &msg))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
EnableWindow(mhWndParent, TRUE);
return static_cast<int>(msg.wParam);
}
note that we can't if (this) because this is not nullptr and can't be set to nullptr in OnNcDestroy handler.
OK, after some time experimenting I come out with the following change to the code which makes everything works as it should! (see comments for more info)
btw. I will leave this question open, hopefully there is more efficient way for this, currently IsWindow is called for every message which is maybe a performance issue.
int Dialog::RunMessageLoop()
{
EnableWindow(mhWndParent, FALSE);
MSG msg{ };
BOOL result = FALSE;
// first we save the handle to the window
HWND hwnd = mhWnd;
if (!IsWindow(hwnd)) // make sure the handle is valid dialog window
std::abort();
while ((result = GetMessageW(&msg, nullptr, 0, 0)) != FALSE)
{
if (result == -1)
{
ShowError(ERR_BOILER);
break;
}
// if object is deleted the handle is no longer valid!
// because prior to OnNcDestroy handler DestroyWindow has been called
if (!IsWindow(hwnd))
goto invalid;
if (!IsDialogMessageW(mhWnd, &msg))
{
invalid: // non dialog message processing
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
// NOTE that we removed EnableWindow(mHwndParent) here!
return static_cast<int>(msg.wParam);
}
This on it's own will work but one additional step is to enable owner window (main window) before the dialog is destroyed, so update the handler:
bool Dialog::OnClose() noexcept
{
// otherwise first window in Z order (such as Desktop) will get focus!
EnableWindow(mhWndParent, TRUE);
return DestroyWindow(mhWnd);
}
Related
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.
So I'm delving into the world of MFC and in particular, customised use of CWinThread to implement worker threads. I have successfully implemented worker threads other ways, so the main motivation for using CWinThread for a worker thread is to make use of the message map.
For future use I am deriving CWinThread into what will eventually become some form of super class.. See the following declaration..
class WinThreadBase : public CWinThread
{
DECLARE_DYNCREATE(WinThreadBase)
protected:
WinThreadBase(); // protected constructor used by dynamic creation
DECLARE_MESSAGE_MAP()
public:
BOOL isdone_;
};
This is extended and implement by the following
The declaration
class WinThreadImplementation :public WinThreadBase {
DECLARE_DYNCREATE(WinThreadImplementation)
protected:
WinThreadImplementation(); //Declare protected because of dynamic creation
public:
//The following CWinThread methods have to be overriden to complete specfic work.
virtual BOOL InitInstance();
virtual int Run();
private:
CDialog* owner_;
BOOL isinit_;
public:
virtual ~WinThreadImplementation();
void SetOwner( CDialog* pOwner ) { owner_ = pOwner; }
BOOL Isinit() const { return isinit_; }
DECLARE_MESSAGE_MAP()
//Message handler declaration
void OnMyThreadMessage( WPARAM wParam, LPARAM lParam );
void OnQuit( WPARAM wParam, LPARAM lParam );
};
The implemetation
IMPLEMENT_DYNCREATE( WinThreadImplementation, WinThreadBase)
WinThreadImplementation::WinThreadImplementation() {
owner_ = FALSE;
isinit_ = FALSE;
}
WinThreadImplementation::~WinThreadImplementation() {
//........Do some stuff here... //
}
BOOL WinThreadImplementation::InitInstance() {
//Do some initialisation here..
return TRUE; //returning true allows thread start successfully
}
int WinThreadImplementation::Run() {
isinit_ = TRUE;
while( !isdone_ ) {
//Do some work...
//TRACE( "Hello from pat's derived CWinThread" );
Sleep( 1000 ); //Give other threads a chance to run..
}
owner_->PostMessage( WM_QUIT, 0, 0 ); // Tell our parent thread that this thread has finished work
return 0;
}
BEGIN_MESSAGE_MAP(WinThreadImplementation,CWinThread)
//Map messages to handler method here...
//CWinThread messages must be handles like this....
ON_THREAD_MESSAGE(WM_MYTHREADMESSAGE,OnMyThreadMessage)
END_MESSAGE_MAP()
//Put message handlers here...`
void WinThreadImplementation::OnMyThreadMessage( WPARAM wParam, LPARAM lParam ) {
TRACE( "Hello from my message handler\n\r" );
}
Now for actually posting the message
mywinthreadimpl_ = (WinThreadImplementation*)
AfxBeginThread( RUNTIME_CLASS( WinThreadImplementation ), THREAD_PRIORITY_NORMAL,
0, CREATE_SUSPENDED );
mywinthreadimpl_->SetOwner( this );
mywinthreadimpl_->ResumeThread();
while( !mywinthreadimpl_->Isinit() ); //Make sure that the thread has initialised before attempting to post a message
if( PostThreadMessage( mywinthreadimpl_->m_nThreadID, WM_MYTHREADMESSAGE, NULL, NULL ) ) {
TRACE( "message was sent correctly\n" );
}
So the result of this is that it compiles, my CWinThread derivation is working and enters the overriden run function. But I cannot for the life of me receive the message posted by PostThreadMessage.
I have read the following
http://support.microsoft.com/kb/142415?wa=wsignin1.0
and concluded that this does not apply to me since I am using VS 2010.
Can anyone suggest what I may have missed, that would be preventing my CWinThread implementation from receiving the messages?
Thanks
Without using AfxPumpMessage or calling the base class implementation of CWinThread (__super::Run), you will never receive a message!
Don't use isdone_. Instead use PostQuitMessage to terminate thecurrent workerthread too. Just use the base implementation of Run to run the thread and pump the messages.
You can also use OnIdle or other function of CWinThread, to do some work...
Just calling Sleep blocks your thread but the thread isnever interrupted by a windows message
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.
I'm writing a WTL Aero wizard and I'd like to gray out the window's Close button (its first step will require no user interaction and can not be canceled, so disabling the button is perfectly appropriate).
Putting the following code:
CMenuHandle pMenu = GetSystemMenu(FALSE);
pMenu.EnableMenuItem(SC_CLOSE, FALSE);
in OnInitDialog does not work, as the procedure is called before the window itself is displayed on the screen (the ATLASSERT(::IsMenu(m_hMenu)); assertion in EnableMenuItem is tripped at runtime).
Is there an elegant way to disable the Close button? (I'm a WTL beginner, and I'd like the solution to be as clean as possible).
This is a minimal version of the wizard's page code:
#include "stdafx.h"
class MainPage : public CAeroWizardPageImpl<MainPage> {
public:
BEGIN_MSG_MAP(MainPage)
MESSAGE_HANDLER_EX(WM_INITDIALOG, OnInitDialog)
CHAIN_MSG_MAP(__super)
END_MSG_MAP()
enum {
IDD = IDR_MAINFRAME
};
MainPage() : CAeroWizardPageImpl<MainPage>(IDR_MAINFRAME) {
/* Set the wizard's title */
m_headerTitle.LoadString(IDS_INSTALLHEADER);
SetHeaderTitle(m_headerTitle);
}
private:
CString m_headerTitle;
LRESULT OnInitDialog(UINT message, WPARAM wParam, LPARAM lParam) {
UNREFERENCED_PARAMETER(message);
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
/* Disable the wizard buttons and center the window */
ShowWizardButtons(0, 0);
EnableWizardButtons(PSWIZB_BACK, 0);
CenterWindow();
return TRUE;
}
};
The close [X] button is a part of Common Controls wizard property sheet class. You are not supposed to alter its presentation and behavior. What you can do is to handle PSN_QUERYCANCEL notification and prevent wizard from closing. With WTL it is easy, however you need to know that that there are two versions of notifications handlers available.
If _WTL_NEW_PAGE_NOTIFY_HANDLERS is defined, typically in stdafx.h, then you do it like this:
class MainPage :
public CAeroWizardPageImpl<MainPage>
{
// ...
INT OnQueryCancel()
{
return 1; // Zero to Allow Wizard Close
}
};
Otherwise, older syntax is in use:
class MainPage :
public CAeroWizardPageImpl<MainPage>
{
// ...
BOOL OnQueryCancel()
{
return FALSE; // Allow Wizard Close?
}
};
Along with preventing cancellation/close you are free to indicate this by showing a message box suggesting use to wait until the pending operation is completed, or otherwise display a notification (e.g. flash a static control etc.)
I have asked two questions earlier about this and for each post there was some solutions i tried them, but the problem still exist.
My first question was : why a windowless Activex does not return the Handle. the suggestion was "change the creation setting an make windowless activate off, i have tried it but still m_hWnd property has returned zero as GetSafeHwnd() method has did.
the second one was the same question this one focused on COleControl class and it's ancestor CWnd. the solution was as this "Create invisible window somewhere in your control initialization code. Handle the messages sent to this window, and call controls methods directly". so i did that but the created class still returns zero handle.
here is my new invisible class source:
// moWind.cpp : implementation file
//
#include "stdafx.h"
#include "PINActive.h"
#include "moWind.h"
#include "include\xfspin.h"
#include <math.h>
// moWind
IMPLEMENT_DYNAMIC(moWind, CWnd)
moWind::moWind(){}
moWind::~moWind(){}
//=============================================================
LRESULT moWind::OnExecuteEvent (WPARAM wParam, LPARAM lParam)
{
WFSRESULT *pResult = (WFSRESULT *)lParam;
CString EK=_T("");
CString str;
int reskey=0;
if (pResult->u.dwEventID=WFS_EXEE_PIN_KEY)
{
LPWFSPINKEY pressedkey;
pressedkey=(LPWFSPINKEY)pResult->lpBuffer;
reskey = log10((double)pressedkey->ulDigit) / log10((double)2);
EK.Format("%d",reskey);
xfsOnKeyEvent->OnKeyRecieved(reskey);
}
else
{
str.Format("ExecuteEvent: ID = %d\r\n", pResult->u.dwEventID);
}
MessageBox("a Execute message Recieved");
return 0;
}
BEGIN_MESSAGE_MAP(moWind, CWnd)
ON_MESSAGE(WFS_EXECUTE_EVENT,OnExecuteEvent)
END_MESSAGE_MAP()
and this is .h file of the class:
// moWind.h
class IXFSEvents
{
protected:
IXFSEvents(){};
virtual ~IXFSEvents(){};
public:
virtual void OnKeyRecieved(int key)=0;
};
class moWind : public CWnd
{
DECLARE_DYNAMIC(moWind)
public:
moWind();
virtual ~moWind();
void Register(IXFSEvents* obj)
{
xfsOnKeyEvent= obj;
}
protected:
IXFSEvents* xfsOnKeyEvent;
LRESULT OnExecuteEvent (WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
};
and at the end here this the way I've used this class in my Activex:
in the myActivex.h file:
include "moWind.h"
class CmyActivexCtrl : public COleControl, public IXFSEvents
{
...
Class definition
...
protected:
moWind tmpWind;
.
.
};
finally in the creation method of myActivex i have initialized the component callback method an wanted to get it's Handle as this:
CmyActivexCtrl::CmyActivexCtrl()
{
InitializeIIDs(&IID_DmyActivex, &IID_DmyActivexEvents);
tmpWind.Register(this);
myOtherComponent.WindowsHandle=tmpWind.GetSafeHwnd(); //here my Cwnd derived class returns zero
//my other component gets the handle and call an API with it to register
//the given handle and force the API to send the messages to that handle.
}
As you mentioned you need a window handle to be able to receive user messages through it, you always have an option of creating a helper window, such as message only window, see Using CreateWindowEx to Make a Message-Only Window.
For your windowless control it is okay to not have any window handle at all, so you cannot really rely on handle availability unless you own a window yourself.