我正在开发打算跨平台的应用程序。我以前使用Windows消息,但现在我正在删除它。我用回调替换了消息,但无论我是否可以使用不同的技术,我都不知道不使用Windows消息时的不同可能性。
我有主要的exe应用程序和一些DLL插件。我在dll中有一些对象和线程,我想通知主应用程序有关DLL对数据结构所做的一些更改。
正如我所说,我目前正在处理一些回调。为了提供与不同语言(C ++,VB,C#)的兼容性,我有非对象类型的回调。我不确定其他语言是否支持对象的回调。
所以我的问题是:
答案 0 :(得分:4)
您当然可以使用回调函数而不是消息。您不能使用回调方法,因为只有Delphi和C ++ Builder才能理解如何调用Delphi方法指针。但是,您可以将回调对象与任何支持COM的语言一起使用。下面是一个插件的示例,用于通知应用程序数据结构已更改:
定义界面。
type
IDataStructureChanged = interface
['{GUID}']
procedure Call; stdcall;
end;
您可以向方法添加一些参数,以便插件可以告诉数据结构如何更改,或者传递一些值来指示哪个插件正在发出通知。
< / LI>在应用程序中实现它。
type
TDataStructureChangedListener = class(TInterfacedObject, IDataStructureChanged)
private
FForm: TForm;
procedure Call; stdcall;
public
constructor Create(Form: TForm);
end;
当您实例化该类时,您可以向其传递对程序主表单的引用,或者当插件最终调用Call
方法时,程序需要能够执行的任何其他信息。实施Call
以使您的应用程序执行数据结构更改时需要执行的任何操作。
初始化时,传递对每个插件的引用。
ChangeListener := TDataStructureChangedListener.Create(Self);
for i := 0 to Pred(PlugIns.Count) do
PlugIns[i].Init(ChangeListener);
插件应该存储对侦听器对象的引用,当数据结构发生更改时,它可以调用Call
方法来通知您的应用程序。
我在这里描述的是通常所说的事件接收器。您的程序中可以有多个。如果要处理多个事件,则可以为每种事件设置单独的接口,或者可以将它们全部组合到单个接口中,并为每个事件使用不同的方法。您可以为每个插件使用不同的接收器对象,或者您可以为每个插件提供对同一接收器对象的引用,然后传递插件ID参数。
答案 1 :(得分:3)
我肯定会使用回调。主app可以给DLL一个回调函数,以便在需要时调用,然后回调函数本身可以在需要时向应用发送窗口消息。
答案 2 :(得分:3)
我同意雷米,(!)。简单的回调允许处理程序实现它选择的任何类型的进一步通信 - 它可以发布消息,它可以将参数推送到队列,无论它想要什么。如果你想成为跨平台的,你将不得不求助于传入和传出简单的类型。通常在设置回调时传入“用户上下文”指针。回调将此指针传递给处理程序。这允许调用者将上下文对象作为指针/ int传入并在处理程序中恢复它(通过将指针/ int转换回对象)。然后,处理程序可以调用上下文中的方法,无论它是Delphi,C ++等。
答案 3 :(得分: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.
编辑:你现在不能用腿射击自己。
我猜其他语言有不同的技术可以替代消息吗?
操作系统有一些消息替代方案。然而,真正便携的并不多。
您也可以使用: