在运行时创建ActiveX组件会导致访问冲突。

4

我有一个硬件设备需要在Delphi中使用ActiveX组件进行处理。如果我在设计时将该组件拖放到表单上,一切正常。然而,如果我在运行时使用Creat(Self)动态创建它,执行方法会导致mfc100.dll中的访问冲突。这段代码非常简单:

uses
  Windows, Messages, ...
  OleCtrls, MG17MotorLib_TLB; // <-- The latter is the hardware driver

type
  TForm1 = class(TForm)
    motorX: TMG17Motor;
    ...
  end;

...

procedure TForm1.FormCreate(Sender: TObject);
begin
  motorX := TMG17Motor.Create(Self);
  motorX.HWSerialNum := 94835472;
  motorX.StartCtrl; // <--- This causes AV in mfc100.dll
end;

我在动态创建ActiveX对象时犯了错误,还是TMG17Motor类看起来更像是一个bug?也许,如果我避免使用Create(Self)在设计时将控件放在表单上,就可以以与应用程序相同的方式创建TMG17Motor类的对象。

P.S. 我想能够动态创建控件的原因是我希望将硬件处理代码移动到工作线程中。


控件可能/很可能有一些依赖关系(例如,它期望设置父属性或类似的内容)。如果您拥有目标控件的源代码或符号,那么在调试器中查看触发AV的具体原因应该很简单。 - EricLaw
@Warren P:是的,我已经向Thorlabs报告了这个问题。但还没有收到回复。 - Ilya
其次,也许这个ActiveX控件在创建和调用StartCtrl之间需要一些时间(甚至几毫秒)。尝试使用TTimer将它们解耦,或者作为一个快速的hack-test,添加sleep(100)和Application.ProcessMessages()。 - Warren P
2
在设计时和运行时实例化任何控件之间最显著的区别之一是,运行时创建将绕过流式传输系统,这意味着不会调用Loaded方法。如果你有源代码,请检查你的ActiveX组件是否已重写了Loaded方法。如果已经重写,那么在创建组件并设置其他属性之前调用该方法可能会有所帮助。 - Marjan Venema
嗯...我不确定我是否理解正确。我有MG17MotorLib_TLB的源代码,其中定义了TMG17Motor类。Loaded方法在那里没有被覆盖。此外,motorX.Loaded未定义,因此该方法在某种程度上不存在。 - Ilya
显示剩余3条评论
1个回答

6

我很乐意帮助您翻译关于IT技术的内容。以下是所需翻译的内容:

我花了精力下载了该软件并查看问题所在。看起来TMG17Motor是一个可视化控件。因此,你的问题源于你的组件没有父窗口。

修复非常容易:

procedure TForm1.FormCreate(Sender: TObject);
begin
  motorX := TMG17Motor.Create(Self);
  motorX.Parent := Self; // <--- you need this!
  // set other properties...
  motorX.HWSerialNum := 94835472;
  motorX.Align := alclient;
  motorX.StartCtrl;
end;

样例截图: enter image description here 您在问题中提到想将代码移动到工作线程,但这是一个视觉控件,所以不可能实现。请尝试联系Thorlabs,看看他们是否有其他方法来实现您想要的功能...
编辑: 正如David在评论中建议的那样,您可以尝试使用非VCL窗口和工作线程。 由于这是一个ActiveX对象,请确保在工作线程的Execute方法中调用CoInitialize(nil)/CoUninitialize。

+1 做得好。可以移动到工作线程中了。将其父窗口设置为非 VCL 窗口。 - David Heffernan
@whosrdaddy:非常感谢!这是一个出乎意料的解决方案,因为上面一行代码也会发送父级对象。 - Ilya
@David Heffernan:感谢您提供有关非VCL窗口的提示!我确信一定有解决方法! - Ilya
好的,我已经使用Remy Lebeau的答案在工作线程中创建了一个WinAPI不可见窗口,并在该窗口内创建了ActiveX控件。我的工作线程在没有任何明显原因的情况下终止,直到我看到了关于CoInitialize(nil)/CoUninitialize的最后一条评论。现在一切都运行得非常完美!谢谢! - Ilya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接