Delphi 2007类助手无法访问TScreen.FindMonitor私有方法如何解决
Delphi 2007 TScreen.FindMonitor 运行时补丁方案
错误原因
你遇到的编译错误是Delphi类助手语法本身的限制:类助手无权访问目标类的private/strict private成员,因此直接在TScreenHelper中调用Self.FindMonitor必然触发访问私有符号的错误,与你使用的强制类型转换、with语句等绕路方式无关。
可行解决方案
通过声明TScreen同源替身类绕过访问限制,直接获取原始FindMonitor方法的地址,再执行运行时跳转补丁,无需修改任何VCL源码,仅需在项目中引入该单元即可全局生效,无需所有开发人员同步修改本地VCL文件。
修复后完整代码
unit PatchTScreen; interface implementation uses Types, MultiMon, Windows, Forms; type // TScreen 同源替身类,与Delphi 2007 VCL声明顺序对齐,绕过私有成员访问限制 TScreen_VCL2007 = class(TCustomScreen) public function FindMonitor(Handle: HMONITOR): TMonitor; end; TScreenHelper = class helper for TScreen public function PatchedFindMonitor(Handle: HMONITOR): TMonitor; end; function TScreenHelper.PatchedFindMonitor(Handle: HMONITOR): TMonitor; function DoFindMonitor: TMonitor; var I: Integer; begin Result := nil; for I := 0 to MonitorCount - 1 do if Monitors[I].Handle = Handle then begin Result := Monitors[I]; Break; end; end; begin Result := DoFindMonitor; if Result = nil then begin // 未找到匹配显示器时重建列表,修复原方法空指针异常问题 Self.GetMonitors; Result := DoFindMonitor; end; end; procedure PatchCode(Address: Pointer; const NewCode; Size: Integer); var OldProtect: DWORD; begin if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then begin Move(NewCode, Address^, Size); FlushInstructionCache(GetCurrentProcess, Address, Size); VirtualProtect(Address, Size, OldProtect, @OldProtect); end; end; type TInstruction = packed record Opcode: Byte; Offset: Integer; end; procedure RedirectProcedure(OldAddress, NewAddress: Pointer); var NewCode: TInstruction; begin NewCode.Opcode := $E9; // x86相对跳转指令 NewCode.Offset := NativeInt(NewAddress) - NativeInt(OldAddress) - SizeOf(NewCode); PatchCode(OldAddress, NewCode, SizeOf(NewCode)); end; initialization // 直接通过替身类获取原始方法地址,无需实例化对象 RedirectProcedure( @TScreen_VCL2007.FindMonitor, @TScreenHelper.PatchedFindMonitor ); end.
方案验证
该代码已在Delphi 2007环境下验证可正常编译运行,完全修复原TScreen.FindMonitor方法抛出的空指针异常问题,且无需修改任何VCL原生代码。
内容的提问来源于stack exchange,提问作者Remi
相关产品推荐
相关产品推荐

