2012-03-12 64 views
4

我正在開發打算跨平臺的應用程序。我曾經使用Windows消息,但現在我放棄了。我用回調替換了消息,但是不管我能否使用不同的技術,我都沒有意識到不使用Windows消息時的不同可能性。通知有關從dll到主應用程序的事件

那麼我有主要的exe應用程序和一些dll插件。我在DLL中有一些對象和線程,我想通知主應用程序有關DLL對數據結構進行的一些更改。

正如我所說我目前正在使用一些回調。爲了提供與不同語言(C++,VB,C#)的兼容性,我有非對象類型的回調。我不確定其他語言是否支持回調對象。

所以我的問題是:

  • 有什麼選擇(跨平臺)到窗口消息?回調可以取代消息嗎?
  • 其他語言是否支持回調對象?
  • 我猜其他語言有不同的技術作爲消息的替代?

回答

2

所以我的問題是: 什麼是windows消息的替代(跨平臺)?回調可以取代消息嗎?

是的,你可以用回調替換消息。

其他語言是否支持回調對象?

您不應該使用對象方法作爲回調。在可移植的代碼通常的做法是使用手柄(通知調用約定):

DLL來源:

type 
    THandle = LongWord; 
    {$IF SizeOf(THandle) < SizeOf(Pointer))} 
    {$MESSAGE Error 'Invallid handle type'} 
    {$ENDIF} 

    TCallback = procedure(const aHandle: THandle); cdecl; 

    var 
     gCallback: record 
     Routine: TCallback; 
     Obj: TObject; 
     Info: string 
    end; 

    function Object2Handle(const aObj: TObject): THandle; 
    begin 
    Result:= THandle(Pointer(aObj)) 
    end; 

    function Handle2Object(const aHandle: THandle; out aObj: TObject): Boolean; 
    begin 
    if gCallback.Obj <> nil then 
     if aHandle = Object2Handle(gCallback.Obj) then 
     begin 
     aObj:= gCallback.Obj; 
     Result:= true; 
     Exit // WARRNING: program flow disorder 
     end; 

    aObj:= nil; 
    Result:= false 
    end; 

procedure DoCallback(); 
begin 
    if Assigned(gCallback.Routine) then 
    gCallback.Routine(Object2Handle(gCallback.Obj)) 
end; 

procedure SetupCallback(const aCallback: TCallback); cdecl; 
begin 
    gCallback.Routine:= aCallback; 
end; 

procedure DoSomething(const aHandle: THandle; out aInfo: string); cdecl; 
var 
    O: TObject; 
begin 
    if Handle2Object(aHandle, O) then 
    aInfo:= Format('%s class object %s', [O.ClassName(), gCallback.Info]) 
end; 

procedure Test(); 
begin 
    gCallback.Obj:= TStream.Create(); 
    try 
    gCallback.Info:= 'created'; 
    DoCallback(); 
    finally 
    FreeAndNil(gCallback.Obj) 
    end; 
    gCallback.Obj:= TMemoryStream.Create(); 
    try 
    gCallback.Info:= 'will be freed'; 
    DoCallback(); 
    finally 
    FreeAndNil(gCallback.Obj) 
    end 
end; 

exports 
    SetupCallback, 
    DoSomething, 
    Test; 

可執行來源:

procedure Cb(const aHandle: THandle); cdecl; 
const 
    STUPID: THandle = 1; 
    EQUALLY_STUPID = $DEAD; 
var 
    S: string; 
begin 
    DoSomething(STUPID, S); 
    DoSomething(aHandle, S); 
    DoSomething(EQUALLY_STUPID, S) 
end; 

begin 
    SetupCallback(@Cb); 
    Test() 
end. 

編輯:不能搬起石頭砸自己的腳,你現在。

我猜其他語言有不同的技術作爲消息的替代?

操作系統有幾個消息選擇。然而,並不是真正的便攜式。

您還可以使用:

  • 插座,
  • (IMO太在這種情況下大嗎?)準備好的消息系統(我最喜歡的0MQ
+0

如果DLL知道EXE要存儲在句柄參數中的東西的類型,那麼DLL甚至會使用*該類型的句柄參數,那麼你已經錯過了句柄點。提供句柄的模塊應允許存儲*任何*數據類型,而不用擔心句柄的使用者以任何方式使用句柄,除非將句柄傳回給句柄提供者。在你的例子中,EXE必須存儲一個有效的TObject引用。如果沒有,那麼DoSomething會崩潰。也可以直接傳遞TObject而不是THandle charade。 – 2012-03-12 22:15:26

+0

並傳遞TObject參考「提供與不同語言的兼容性」和可移植性?!?我只是展示了最簡單的句柄實現,僅此而已。 – g2mk 2012-03-12 23:26:14

+0

那麼我的問題很簡單。我不需要傳遞我只需要通知主應用程序一些更改的對象,因此我可以刷新GUI。我正在尋找跨平臺的解決方案,可以與其他語言一起使用。我想我會用回調來完成它。我只需要一些批准和不同方面來解決我的問題。謝謝。 – Nix 2012-03-13 11:27:33

3

我肯定會使用回調。主應用程序可以給DLL回調函數以在需要時調用,然後回調函數本身可以發送窗口消息給應用程序(如果需要的話)。

4

你當然可以使用回調函數而不是消息。您不能使用回調方法,因爲只有Delphi和C++ Builder瞭解如何調用Delphi方法指針。但是,您可以使用支持COM的任何語言使用回調對象。下面是插件通知應用程序數據結構已更改的示例:

  1. 定義接口。

    type 
        IDataStructureChanged = interface 
        ['{GUID}'] 
        procedure Call; stdcall; 
        end; 
    

    你可以添加一些參數的方法,以便插件可以告訴數據結構如何改變,或通過一些值,指示該插件正在通知。

  2. 在應用程序中實現它。

    type 
        TDataStructureChangedListener = class(TInterfacedObject, IDataStructureChanged) 
        private 
        FForm: TForm; 
        procedure Call; stdcall; 
        public 
        constructor Create(Form: TForm); 
        end; 
    

    當你實例化類,你可以將它傳遞給你的程序的主要形式,或任何其他信息,你的程序將需要能夠採取行動時,插件最終調用Call方法的引用。實施Call可以讓您的應用程序在數據結構發生變化時執行任何需要的操作。

  3. 當初始化它們時,傳遞每個插件的引用。

    ​​

    插件應該存儲到收聽對象的引用,並且當數據結構的變化,它可以調用Call方法來通知應用程序。

什麼我這裏描述的是什麼通常被稱爲事件接收。你的程序中可以有多個。如果有多個事件需要處理,您可以爲每種事件分別設置一個接口,或者將它們全部組合到一個接口中,並針對每個事件採用不同的方法。每個插件可以有不同的接收器對象,也可以爲每個插件分配一個對同一個接收器對象的引用,然後傳遞一個插件ID參數。

3

我同意雷米(!)。一個簡單的回調允許處理程序實現它選擇的任何進一步的通信 - 它可能會發布消息,它可能會將參數推送到隊列中,無論它想要什麼。如果你想要跨平臺,你將不得不求助於傳入和傳出簡單的類型。當設置回調時,通常會傳入「用戶上下文」指針。回調將該指針傳遞給處理程序。這允許調用者作爲指針/ int傳入上下文對象,並在處理程序中恢復它(通過將指針/ int轉換回對象)。然後處理程序可以在上下文中調用方法,不管它是Delphi還是C++等。

相關問題