我在 Delphi 中使用 Visual Basic 6.0 OCX 时遇到宽度和高度问题。
当我将一些 OCX 控件拖放到 Delphi 12.1 中的窗体上时,OCX 的宽度和高度属性设置为 0(零),即使在对象检查器中也无法更改这些值。这些 OCX 控件在 Delphi 7 中完美工作。我还禁用了所有视觉清单,因此它在经典 Windows 模式下运行。
我试图理解为什么这些问题出现在较新版本的 Delphi 中。
这些 OCX 是由我以前工作的公司开发的,它们在 Delphi 7 中运行没有任何问题。
以下是 Olaf Monien 发布的问题报告内容 https://embt.atlassian.net/servicedesk/customer/portal/3/RSB-209
某些 ActiveX/OleControls 以零大小呈现。 IE。宽度/高度 无论您在设计或运行时做什么,都会回落到 (0,0) 这 似乎与以下事实有关:其中一些控件不 响应
,返回“E_Fail”。这不是“随机 error2,但根据 MS 文档,它是为组件设计的 要么没有 UI,要么在内部独立设置尺寸 他们的遏制控制。SetExtent()
中的相关代码过去几次没有改变 版本,所以它在伊卡利亚并不是什么新鲜事。还是值得入手的 已修复,因为 ActiveX 仍在旧项目中使用,已迁移到 12。VCL.OleCtrls.pas
该行为的原因显然是某些 ActiveX 控件 不会响应
所调用的SetExtent()
SetBounds()
。这不是一个“随机”错误,但可能是 设计 - 根据 MS 文档:VCL.OleCtrls.pas
如果一个对象的大小是固定的,也就是说,如果它不能由它的对象来设置 容器,IOleObject::SetExtent 应该返回 E_FAIL。这总是 具有链接对象的情况,其大小由其链接设置 来源,而不是容器。
在这些情况下,Delphi 只是将 ActiveX 的边界重置为零 - 这至少不方便。
中的代码也有一些奇怪的HighDPI 计算,但这些似乎并不影响这个bug。VCL.OleCtrls.pas
将导致 2645(对于 96dpi 屏幕),这至少看起来是 有疑问。我在 MS 文档中找不到有关这些单位的任何内容 不过,用在AWidth = 100
中。SetExtent()
MulDiv(AHeight, 2540, Screen.PixelsPerInch)); ``` Here is a proposal for a fixed `TOleControl.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);` ```delphi procedure TOleControl.SetBounds(ALeft, ATop, AWidth, AHeight: Integer); var LRect: TRect; Temp: TPoint; LResult: HResult; LIsVisible: boolean; begin if ((AWidth <> Width) and (Width >= 0)) or ((AHeight <> Height) and (Height >= 0)) then begin LResult := S_OK; LIsVisible := (FMiscStatus and OLEMISC_INVISIBLEATRUNTIME) = 0; //Only call SetExtent if control has visible UI at runtime if LIsVisible then begin Temp := Point(MulDiv(AWidth, 2540, Screen.PixelsPerInch), MulDiv(AHeight, 2540, Screen.PixelsPerInch)); {$IFDEF WIN64} LResult := FOleObject.SetExtent(DVASPECT_CONTENT, @Temp); {$ELSE} LResult := FOleObject.SetExtent(DVASPECT_CONTENT, Temp); {$ENDIF} end; // UI won't respond to SetExtend, use default dimensions for design time if ((LResult <> S_OK) or (not LIsVisible)) then begin if (Height > 0) and (Width > 0) then begin AWidth := Height; AHeight := Width; end else begin AWidth := 25; AHeight := 25; end; end; if FOleInplaceObject <> nil then begin LRect := Rect(Left, Top, Left+AWidth, Top+AHeight); FOleInplaceObject.SetObjectRects(LRect, LRect); end; end; inherited SetBounds(ALeft, ATop, AWidth, AHeight); end; ``` **Steps to reproduce** Install and Import an ActiveX control, such as SysTray_OCX.zip from here: [Sample Code : ActiveX Controls][2] Note: this control (like many others) depends on the VB5 Runtime. Note 2: MS does no longer offer an official link - due to it's age http://www.tools4vb.de/download/vb5run.exe Create a new VCL app, and drop a "cSysTray" component onto the main form. **Result:** component is on form, with dimension set to "zero". You can only find the component using the structure pane. **Expected:** Component should show up as 25x25 px component - like any non-visual component (TFDQuery etc…)