使用指针共享组件的Delphi MDI应用程序 [英] Delphi MDI application with components shared using pointers

查看:71
本文介绍了使用指针共享组件的Delphi MDI应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆