VCL 应用程序何时获取其 Application->MainForm->Handle?

When does a VCL application get its Application->MainForm->Handle?

我的应用程序使用 Message.hpp 中的 SendStructMessage() 函数通过传入消息填充某些面板。

SendStructMessage() 需要一个有效的 windows 句柄才能发送到。

我把SendStrucMessage()封装在一个函数里,像这样:

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;
}

尝试从 MainForm 的 OnShowOnCreate 事件调用它不起作用,因为在这两种情况下 Application->MainForm->Handle 仍然是 NULL。

我的问题是,在 VCL 应用程序的启动阶段,在哪里可以确定确实创建了 Application->MainForm->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";
        }
    }
}

有没有更好的方法?

TWinControl::Handle 属性 getter 在读取 属性 时创建一个新的 HWND,如果 HWND 没有尚未创建。如果在创建 HWND 时发生错误,将抛出异常。

所以,你的!Handle条件总是为假,因为Handle属性永远不会 return NULL(不过 WindowHandle 属性 可以)。

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;
}

如果你想检查 Handle 是否已经创建而不实际创建它,请使用表单的 HandleAllocated() 方法:

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;
}

否则,根本不要使用SendMessage()/SendStructMessage()。您可以改为调用表单的 Perform() 方法,该方法会将消息直接传递给表单分配的 WindowProc,根本不需要任何 HWND

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;
}

或者,考虑从 sendAppMessage() 中删除 MainForm 依赖项。您可以改为发送到 Application->Handle,然后让 MainForm 使用 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;
}