I use C++ Builder and I pass messages to window which are handled in WndProc
to update user interface. Something like:
struct TWmGuiUpdatedStruct
{
int id1;
int id2;
};
TWmGuiUpdatedStruct gui { 1, 2 };
TMessage msg;
msg.Message = WM_MY_GUI_UPDATED;
msg.WParam = WM_MY_GUI_UPDATED_MESSAGE_LIST;
msg.LParam = reinterpret_cast<NativeInt>(&guiparam);
// send to all forms in a loop
for (int i = 0; i < Screen->FormCount; i++) Screen->Forms[i]->Perform(msg.Message, msg.WParam, msg.LParam);
// in WndProc
if (fMessage.Msg == WM_MY_GUI_UPDATED && msg.WParam == WM_MY_GUI_UPDATED_MESSAGE_LIST)
{
TWmGuiUpdatedStruct* gui = reinterpret_cast<TWmGuiUpdatedStruct*>(fMessage.LParam);
// use gui->id1 and guid->id2 here...
fMessage.Result = 0;
return;
}
TForm::WndProc(fMessage);
I find it over-complicated to initialize all in so many lines.
I need something simpler, like:
TMessage msg { WM_MY_GUI_UPDATED, {WM_MY_GUI_UPDATED_MESSAGE_LIST, reinterpret_cast<NativeInt>(&guiparam), 0} };
But it doesn't compile - it wants System::Word
instead.
Is there a simpler way to initialize this to pass such GUI update messages?
If you look at the declaration of TMessage
, it is a struct
containing a union
holding 2 struct
s.
struct DECLSPEC_DRECORD TMessage
{
public:
unsigned Msg;
public:
union
{
struct
{
System::Word WParamLo;
System::Word WParamHi;
System::Word LParamLo;
System::Word LParamHi;
System::Word ResultLo;
System::Word ResultHi;
};
struct
{
NativeUInt WParam;
NativeInt LParam;
NativeInt Result;
};
};
};
Per cppreference, Struct and union initialization explains that when dealing with a "nested initialization", you can only initialize the first member of a union
, but you are trying to initialize the second member.
Since C++Builder does not support designated initializers at this time, you will have to do something like this instead:
WPARAM wParam = WM_MY_GUI_UPDATED_MESSAGE_LIST;
LPARAM lParam = reinterpret_cast<NativeInt>(&guiparam);
TMessage msg { WM_MY_GUI_UPDATED, { { LOWORD(wParam), HIWORD(wParam), LOWORD(lParam), HIWORD(lParam), 0, 0 } } };
With that said, I would suggest simply getting rid of the TMessage
altogether, you don't actually need it:
Screen->Forms[i]->Perform(WM_MY_GUI_UPDATED, WM_MY_GUI_UPDATED_MESSAGE_LIST, reinterpret_cast<LPARAM>(&guiparam));
Otherwise, if you must use TMessage
, then I would suggest creating a wrapper function to create a new TMessage
, eg:
TMessage MakeTMessage(unsigned Msg, WPARAM wParam, LPARAM lParam)
{
TMessage msg;
msg.Msg = Msg;
msg.WParam = wParam;
msg.LParam = lParam;
msg.Result = 0;
return msg;
}
And then call a control's WindowProc()
instead of Perform()
, eg:
TMessage msg = MakeTMessage(WM_MY_GUI_UPDATED, WM_MY_GUI_UPDATED_MESSAGE_LIST, reinterpret_cast<LPARAM>(&guiparam));
...
Screen->Forms[i]->WindowProc(msg);