使用指针共享组件的Delphi MDI应用程序 [英] Delphi MDI application with components shared using pointers
问题描述
我正在开发一个MDI应用程序(Delphi 7),它将以插件的形式作为MDI子级加载.bpl软件包.只能打开一个插件实例,但是显然可以同时打开多个插件.
I am developing an MDI application (Delphi 7) that will load .bpl packages in the form of plugins as the MDI children. Only one instance of a plugin can be opened, but obviously multiple plugins can be opened simultaneously.
我有一个类,它是一个通用类,用于共享" MDI父级上可用的某些组件.我可以通过在构造通用类时为每个相关组件存储一个指针来实现这一点.
I have a class which is a common class that is used to 'share' certain components available on the MDI parent. I achieve this by having the common class store a pointer to each relevant component when it is constructed.
例如:
...
TCommonClass = class(TObject)
public
MainMenu: ^TMainMenu;
MyClass: ^TMyClass;
...
constructor TCommonClass.Create;
var
CtrlItm: array[0..999] of TComponent;
...
for i := 0 to (Application.MainForm.ComponentCount - 1) do
begin
CtrlItm[i] := Application.MainForm.Components[i];
if CtrlItm[i].ClassName = ‘TMainMenu’ then MainMenu := @CtrlItm[i];
if CtrlItm[i].ClassName = ‘TMyClass’ then MyClass := @CtrlItm[i];
end;
每当我引用一个对象时,我都会简单地执行以下操作:
Whenever I refer to an object I simply do as follows:
...
var
tmp: String;
begin
MainMenu^.items[0].Caption := 'Something'; //just to demonstrate
MyClass.DoSomething;
end;
每个插件都将拥有自己的该通用类实例,其思想是对组件之一的任何更新都将真正更新MDI父组件上的组件. 在我编写的最后一个插件(相当大且包含许多TMS组件)开始给我带来我似乎无法追踪的错误之前,这种方法一直对我有效.
Every plugin will have its own instance of this common class with the idea that any update to one of its components will truly update the component on the MDI parent. This approach has been working well for me until the last plugin I wrote (which is rather large and contains many TMS Components) has started giving me errors which I cannot seem to trace.
我想知道的是,这种方法在内存(指针)使用方面是否合理?通过加载和卸载程序包,是否有可能内存映射中的更改破坏了指针?我应该这样做吗?
What I would like to know is if this approach is sound in terms of memory (pointers) usage? By loading and unloading packages is there a possibility that changes in the memory mapping is corrupting the pointers? Should I be doing this differently?
推荐答案
您不需要当前正在使用的额外级别的指针间接.您可以将其缩小,例如:
You don't need the extra level of pointer indirection that you are currently using. You can slim that down, eg:
TCommonClass = class(TObject)
public
MainMenu: TMainMenu;
MyClass: TMyClass;
...
end;
constructor TCommonClass.Create;
var
Ctrl: TComponent;
...
begin
...
for i := 0 to (Application.MainForm.ComponentCount - 1) do
begin
CtrlItm := Application.MainForm.Components[i];
if CtrlItm.ClassName = 'TMainMenu' then MainMenu := TMainMenu(CtrlItm);
else if CtrlItm.ClassName = 'TMyClass' then MyClass := TMyClass(CtrlItm);
...
end;
...
end;
.
var
tmp: String;
begin
MainMenu.Items[0].Caption := 'Something'; //just to demonstrate
MyClass.DoSomething;
end;
现在,我要建议一种替代方法.让MainForm本身提供指向每个插件的指针,而不是让插件为它们轮询MainForm. MainForm知道所有指针,因此让它在自己的本地记录中收集指针,并将指向该记录的指针传递给它加载的每个插件.如果任何指针发生更改,所有活动的插件将自动具有最新的指针,而无需为此做任何额外的事情.在每个插件中,只需在访问每个指针之前检查每个指针是否为nil即可.例如:
Now, with that said, I would suggest an alternative approach. Have the MainForm itself provide the pointers to each plugin, rather than having the plugins poll the MainForm for them. The MainForm knows all of the pointers, so have it collect the pointers in its own local record and pass a pointer to that record to every plugin that it loads. If any of the pointers change, all active plugins will automatically have the up-to-date pointer without having to do anything extra for that. Inside each plugin, simply check each pointer for nil before accessing it. For example:
MainForm:
type
PSharedPointers = ^TSharedPointers;
TSharedPointers = record
MainMenu: TMainMenu;
MyClass: TMyClass;
...
end;
var
SharedPointers: TSharedPointers;
procedure TMainForm.FormCreate(Sender: TObject);
begin
SharedPointers.MainMenu := MainMenu1;
...
end;
procedure TMainForm.LoadAPlugin;
type
InitProc = procedure(Pointers: PSharedPointers);
var
PluginInst: HInstance;
Init: InitProc;
begin
PluginInst := LoadPackage('plugin.bpl');
@Init := GetProcAddress(PluginInst, 'InitPlugin');
Init(@SharedPointers);
end;
插件:
type
PSharedPointers = ^TSharedPointers;
TSharedPointers = record
MainMenu: TMainMenu;
MyClass: TMyClass;
...
end;
var
SharedPointers: PSharedPointers = nil;
procedure InitPlugin(Pointers: PSharedPointers);
begin
SharedPointers := Pointers;
end;
...
var
tmp: String;
begin
if SharedPointers.MainMenu <> nil then
SharedPointers.MainMenu.Items[0].Caption := 'Something'; //just to demonstrate
if SharedPointers.MyClass <> nil then
SharedPointers.MyClass.DoSomething;
end;
exports
InitPlugin;
这篇关于使用指针共享组件的Delphi MDI应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!