DELPHI实现VCL与FMX双框架兼容的外部应用启动代码问题
问题根因
报错的核心原因是VCL和FMX的窗体类对原生Windows句柄的封装逻辑不同:
- VCL框架的TForm类直接暴露
Handle属性,类型就是Win32 API要求的HWND,可以直接赋值使用 - FMX为了实现跨平台特性,默认隐藏了原生平台句柄,没有直接暴露对应
Handle属性,Windows平台下需要调用专属接口才能获取原生HWND
最优兼容方案
用Delphi内置的条件编译指令,根据当前工程的框架类型自动适配句柄获取逻辑,不需要修改业务代码就能同时兼容VCL和FMX两个框架。
步骤1:补充单元引用
在单元的uses部分增加条件编译配置:
uses {$IFDEF VCL} Vcl.Forms, Winapi.ShellAPI, Winapi.Windows; {$ENDIF} {$IFDEF FMX} FMX.Forms, FMX.Platform.Win, Winapi.ShellAPI, Winapi.Windows; {$ENDIF}
步骤2:修改句柄赋值逻辑
把原来的Wnd := OurClass.Handle;替换为双框架适配的条件编译代码:
{$IFDEF VCL} Wnd := OurClass.Handle; {$ENDIF} {$IFDEF FMX} Wnd := Fmx.Platform.Win.WindowHandleToPlatform(OurClass.Handle).Wnd; {$ENDIF}
完整兼容版代码
var ExitCode : DWORD; SEInfo : TShellExecuteInfo; begin FillChar(SEInfo, SizeOf(SEInfo), 0); SEInfo.cbSize := SizeOf(TShellExecuteInfo); WITH SEInfo DO begin fMask := SEE_MASK_NOCLOSEPROCESS; // 适配VCL/FMX双框架的父窗口句柄获取逻辑 {$IFDEF VCL} Wnd := OurClass.Handle; {$ENDIF} {$IFDEF FMX} Wnd := Fmx.Platform.Win.WindowHandleToPlatform(OurClass.Handle).Wnd; {$ENDIF} lpFile := PWidechar(EXENAMESTR); lpParameters := PWidechar(ParameterFile); nShow := SW_SHOWNORMAL; end; if ShellexecuteEx(@SEInfo) then begin repeat GetExitCodeProcess(SEInfo.hProcess, ExitCode); until (ExitCode <> STILL_ACTIVE) OR Application.Terminated; CloseHandle(SEInfo.hProcess); // 原代码漏了关闭进程句柄,补充后可避免资源泄漏 end; end;
补充说明
- 本方案仅适用于Windows平台,因为
TShellExecuteInfo是Win32专属API,如果你需要跨平台运行外部程序,需要单独针对Linux、macOS等平台实现对应逻辑 - 如果你不需要绑定父窗口,也可以直接给
Wnd赋值为0,不需要做框架适配,也可以正常运行
内容的提问来源于stack exchange,提问作者user9044066
相关产品推荐
相关产品推荐

