My application populates some panels by means of incoming messages, using the SendStructMessage()
function in Message.hpp
.
SendStructMessage()
need a valid windows handle to send to.
I have encapsulated the SendStrucMessage()
in a function, like this:
bool sendAppMessage(ApplicationMessageEnum msgID, void* s)
{
if(!Application || !Application->MainForm || !Application->MainForm->Handle)
{
Log(lError) << "Failed to get a valid handle when trying to send application message";
return false;
}
HWND h = Application->MainForm->Handle;
AppMessageStruct data;
data.mMessageEnum = msgID;
data.mData = s;
LRESULT res = SendStructMessage(h, UWM_MESSAGE, 0, &data);
if(res)
{
Log(lError) << "Sending message: "<<msgID<<" was unsuccesful";
return false;
}
return true;
}
Trying to call this from either the MainForm's OnShow
or OnCreate
event doesn't work, as in either case the Application->MainForm->Handle
is still NULL.
My question is, in a VCL application's startup phase, where can one be sure that the Application->MainForm->Handle
is actually created?
Currently I kick off a Timer checking for a valid handle:
void __fastcall TMain::WaitForHandleTimerTimer(TObject *Sender)
{
if(Application->MainForm->Handle)
{
WaitForHandleTimer->Enabled = false;
//Send a message to main ui to update sequence shortcuts
if(sendAppMessage(abSequencerUpdate) != true)
{
Log(lDebug)<<"Sending sequencer update to UI was unsuccesful";
}
}
}
Is there a better way?
The TWinControl::Handle
property getter creates a new HWND
at the time the property is read, if an HWND
hasn't already been created yet. If an error occurs while creating the HWND
, an exception will be thrown.
So, your !Handle
condition will always be false, because the Handle
property can never return NULL (the WindowHandle
property can, though).
bool sendAppMessage(ApplicationMessageEnum msgID, void* s)
{
if (!((Application) && (Application->MainForm)))
{
Log(lError) << "Failed to get a valid handle when trying to send application message";
return false;
}
AppMessageStruct data;
data.mMessageEnum = msgID;
data.mData = s;
LRESULT res = SendStructMessage(Application->MainForm->Handle, UWM_MESSAGE, 0, &data);
if (res)
{
Log(lError) << "Sending message: " << msgID << " was unsuccesful";
return false;
}
return true;
}
If you want to check if the Handle
has been created without actually creating it, use the Form's HandleAllocated()
method:
bool sendAppMessage(ApplicationMessageEnum msgID, void* s)
{
if (!((Application) && (Application->MainForm) && (Application->MainForm->HandleAllocated())))
{
Log(lError) << "Failed to get a valid handle when trying to send application message";
return false;
}
AppMessageStruct data;
data.mMessageEnum = msgID;
data.mData = s;
LRESULT res = SendStructMessage(Application->MainForm->Handle, UWM_MESSAGE, 0, &data);
if (res)
{
Log(lError) << "Sending message: " << msgID << " was unsuccesful";
return false;
}
return true;
}
Otherwise, don't use SendMessage()
/SendStructMessage()
at all. You can call the Form's Perform()
method instead, which will deliver the message directly to the Form's assigned WindowProc
without requiring any HWND
at all:
bool sendAppMessage(ApplicationMessageEnum msgID, void* s)
{
if (!((Application) && (Application->MainForm))
{
Log(lError) << "Failed to get a valid handle when trying to send application message";
return false;
}
AppMessageStruct data;
data.mMessageEnum = msgID;
data.mData = s;
LRESULT res = Application->MainForm->Perform(UWM_MESSAGE, 0, (LPARAM)&data);
if (res)
{
Log(lError) << "Sending message: " << msgID << " was unsuccesful";
return false;
}
return true;
}
Alternatively, consider removing the MainForm
dependency from sendAppMessage()
. You can send to Application->Handle
instead, and then have the MainForm
register a callback method using Application->HookMainWindow()
.
bool sendAppMessage(ApplicationMessageEnum msgID, void* s)
{
if (!((Application) && (Application->Handle))
{
Log(lError) << "Failed to get a valid handle when trying to send application message";
return false;
}
AppMessageStruct data;
data.mMessageEnum = msgID;
data.mData = s;
LRESULT res = SendStructMessage(Application->Handle, UWM_MESSAGE, 0, &data);
if (res)
{
Log(lError) << "Sending message: " << msgID << " was unsuccesful";
return false;
}
return true;
}
__fastcall TMainForm::TMainForm(TComponent *Owner)
: TForm(Owner)
{
Application->HookMainWindow(&AppMessage);
}
__fastcall TMainForm::~TMainForm()
{
Application->UnhookMainWindow(&AppMessage);
}
bool __fastcall TMainForm::AppMessage(TMessage &Message)
{
if (Message.Msg == UWM_MESSAGE)
{
WindowProc(Message);
return true;
}
return false;
}