android - FMX系统消息传递以发送指针(?)

标签 android c++ c++builder

我正在使用C++ Builder 10.2。
在Android中,我想将各种消息(包括主线程)发送到主GUI线程。在Windows中,我可以发布一条消息,并将LPARAM或WPARAM分配给结构或类的某些实例的地址。
我正在尝试使用System.Messaging.TMessageManager做同样的事情,类似于此处的示例:System.Messaging (C++)。但是我只能发送“简单”类型,例如UnicodeStringint。我什至没有想出如何发送一个指针,假设它甚至有可能。
我想发送一个这样的结构/类实例:

class TSendResult
{
public:
    String Message;
    unsigned int Value;
    int Errno;

    __fastcall TSendResult(void);
    __fastcall ~TSendResult();
};
如果可以做到,该怎么写?我设法得到一个版本进行编译,但是出现了链接器错误:

error: undefined reference to 'vtable for System::Messaging::TMessage__1<TSendResult>'


表单构造函数:
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    TMessageManager* MessageManager = TMessageManager::DefaultManager;
    TMetaClass* MessageClass = __classid(TMessage__1<TSendResult>);
    TMessageListenerMethod ShowReceivedMessagePointer = &(this->MMReceiveAndCallBack);
    MessageManager->SubscribeToMessage(MessageClass, ShowReceivedMessagePointer);
}
按钮点击处理程序:
void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
{
    ...

    TSendResult *SPtr = new TSendResult();
    SPtr->Message = "All good";
    SPtr->Value = 10;
    SPtr->Errno = 0;
    TMessageManager* MessageManager = TMessageManager::DefaultManager;
    TMessage__1<TSendResult>* Message = new TMessage__1<TSendResult>(*SPtr); // <-- this doesn't look right...
    MessageManager->SendMessage(Sender, Message, false);
}
捕获消息的功能:
void __fastcall TForm1::MMReceiveAndCallBack(System::TObject* const Sender,
        System::Messaging::TMessageBase* const M)
{
    TMessage__1<TSendResult>* Message = dynamic_cast<TMessage__1<TSendResult>*>(M);
    if (Message) {
        ShowMessage(Message->Value.Message);
    }
}

最佳答案

TMessage__1<T>是Delphi通用 TMessage<T> 类的C++类实现。不幸的是,在C++中使用Delphi泛型类时有一个已记录的限制,这就是为什么出现链接器错误的原因:
How to Handle Delphi Generics in C++

Delphi generics are exposed to C++ as templates. However, it is important to realize that the instantiations occur on the Delphi side, not in C++. Therefore, you can only use these template for types that were explicitly instantiated in Delphi code.

...

If C++ code attempts to use a Delphi generic for types that were not instantiated in Delphi, you'll get errors at link time.


这就是TMessage__1<UnicodeString>有效而TMessage__1<TSendResult>不起作用的原因,因为Delphi RTL中存在TMessage<UnicodeString>的实例化。您正在看的谁写了C++ example,可能都不知道此限制,而只是按原样翻译了Delphi example
话虽如此,您有两种选择:
  • 向您的C++项目中添加一个Delphi .pas单元,将TSendResult实现为Delphi record,并为其定义TMessage<TSendResult>的实例化。然后,您可以在C++代码中使用该单元(编译.hpp文件时,C++ Builder会为您生成一个C++ .pas文件),例如:

  • unit MyMessageTypes;
    
    interface
    
    uses
      System.Messaging;
    
    type
      TSendResult = record
        Message: String;
        Value: UInt32;
        Errno: Integer;
      end;
    
      TSendResultMsg = TMessage<TSendResult>;
    
    implementation
    
    initialization
      TSendResultMsg.Create.Free;
    finalization
    
    end.
    
    #include "MyMessageTypes.hpp"
    
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
        TMessageManager::DefaultManager->SubscribeToMessage(__classid(TSendResultMsg), &MMReceiveAndCallBack);
    }
    
    void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
    {
        ...
    
        TSendResult Res;
        Res.Message = _D("All good");
        Res.Value = 10;
        Res.Errno = 0;
    
        TSendResultMsg *Message = new TSendResultMsg(Res);
        TMessageManager::DefaultManager->SendMessage(this, Message, true);
    }
    
    void __fastcall TForm1::MMReceiveAndCallBack(System::TObject* const Sender,
        System::Messaging::TMessageBase* const M)
    {
        const TSendResultMsg* Message = static_cast<const TSendResultMsg*>(M);
        ShowMessage(Message->Value.Message);
    }
    
  • 而不是根本不使用TMessage__1,而是可以直接从 TSendResult 派生TMessageBase,例如:

  • class TSendResultMsg : public TMessageBase
    {
    public:
        String Message;
        unsigned int Value;
        int Errno;
    };
    
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
        TMessageManager::DefaultManager->SubscribeToMessage(__classid(TSendResultMsg), &MMReceiveAndCallBack);
    }
    
    void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
    {
        ...
    
        TSendResultMsg *Message = new TSendResultMsg;
        Message->Message = _D("All good");
        Message->Value = 10;
        Message->Errno = 0;
        TMessageManager::DefaultManager->SendMessage(this, Message, true);
    }
    
    void __fastcall TForm1::MMReceiveAndCallBack(System::TObject* const Sender,
        System::Messaging::TMessageBase* const M)
    {
        const TSendResultMsg* Message = static_cast<const TSendResultMsg*>(M);
        ShowMessage(Message->Message);
    }
    

    关于android - FMX系统消息传递以发送指针(?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64312162/

    相关文章:

    c++ - UnicodeString 兼容性问题

    C++Builder XE 原始 SSL 套接字

    android - 使用 Android Studio 使用 native 代码编译 apk 时,如何在链接处删除 libgnuSTL_static.a?

    c++ - 在 C++ 中按 "enter"并在整数数组中获取输入时如何中断循环

    Android:在谷歌地图中保存 map 状态

    C++:读取带分隔符的文件并存储在结构中

    c++ - *&连用是什么意思

    C++ 构建器 TstringGrid 从特定单元格获取字符串

    android - 这里 SDK v3.5.0_466 java.lang.ClassNotFoundException : Didn't find class "android.webkit.RenderProcessGoneDetail"

    android - RelativeLayout 不执行 "match_parent"和 alignBottom