- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在 RAD Studio 2007 中开发一个项目,使用 C++ 中的 VCL 类。
TDBLookupControl 是 VCL 的一部分,并且有一些不良行为,这是由于使用内部变量 SearchTickCount
var
SearchTickCount: Integer = 0; //file scope in DBCtrls.pas
procedure TDBLookupControl.ProcessSearchKey(Key: Char);
var
TickCount: Integer;
S: string;
begin
//some code removed for brevity
TickCount := GetTickCount;
if TickCount - SearchTickCount > 2000 then SearchText := '';
SearchTickCount := TickCount;
//some code removed for brevity
end;
但是,SearchTickCount
从未在 VCL 中打包,如下例所示。
extern PACKAGE int SearchTickCount;
我想在我的 C++ 代码中将 SearchTickCount
设置为零(按需)。在我的代码中外部它使 c++ 编译。但是,链接器(显然)找不到该变量。
namespace Dbctrls
{
extern int SearchTickCount;
}
// later on, inside a function
Dbctrls::SearchTickCount = 0;
有什么方法/解决方法可以链接到这个变量吗?
编辑:不幸的是,我们还使用了一些从 TDBLookupControl 派生的自定义控件,因此我试图避免创建更多自定义控件。
最佳答案
SearchTickCount
是在单元的实现部分中声明的全局(单元级别)变量,不应该在该单元之外访问它。如果您使用 Delphi,而不是 C++ Builder,您也会遇到同样的问题。
TDBLookupControl
,重写 ProcessSearchKey()
并确保它使用您自己的 SearchTickCount
(易于访问)。令人高兴的是 ProcessSearchKey()
是虚拟的,理论上这应该可行,但实际上代码依赖于 FListField
,这是一个私有(private)字段,所以我们将回到第 1 步。 TDBLookupControl
复制到您自己的 TMyDBLookupControl
并确保您可以访问 SearchTickCount
。这绝对有效。当然,黑客更有趣。 CPU 可以毫无问题地找到 SearchTickCount
,因为该地址被编码到构成 ProcessSearchKey
代码的 ASM 指令中。 CPU能读的,我们也能读。
评估 ProcessSearchKey
方法的代码,它仅使用一个全局变量 (SearchTickCount
),并在两个地方使用它。本次测试中的第一个:
if TickCount - SearchTickCount > 2000 then
然后在这个指令中:
SearchTickCount := TickCount;
如果您查看该例程的反汇编列表,很容易发现全局变量访问,因为它在方括号中给出了变量的地址,没有其他限定符。为了使 if
正常工作,编译器会执行以下操作:
SUB EAX, [$000000]
对于赋值,编译器会执行如下操作:
MOV [$000000], EAX // or ESI on Delphi 7 with debug enabled
如果您查看汇编指令的左侧,您可以轻松地看到实际的操作码(以十六进制表示法)。例如 SUB EAX,[$000000] 看起来像这样:
2B0500000000
我的黑客解决方案利用了这一点。我获取实际过程的地址 (TDBLookupControl.ProcessSearchKey
),扫描代码查找操作码 (2B 05
) 并获取地址。就是这样,并且有效。
当然,这有潜在的问题。这取决于使用这些确切的寄存器编译的代码(在我的示例中为EAX
)。编译器可以自由选择不同的寄存器。我使用Delphi7和Delphi 2010进行了测试,代码编译为调试,编译为不调试。在所有 4 种情况下,编译器都选择使用 EAX
作为 SUB
指令,并且在 3/4 种情况下选择使用 ESI
作为MOV
指令。因此,我的代码只查找 SUB
指令。
另一方面,如果代码运行一次,则代码每次都运行。代码一旦发布就不会改变,所以如果你可以在开发机器上正确测试,你就不会在客户端机器上遇到讨厌的反病毒软件。但使用风险自负,这毕竟是一种黑客行为!
代码如下:
unit Unit2;
interface
uses DbCtrls;
function GetSearchTickCountPointer: PInteger;
implementation
type
THackDbLookupControl = class(TDBLookupControl); // Hack to get address of protected member
TInstructionHack = packed record
OpCodePrefix: Word;
OpCodeAddress: PInteger;
end;
PInstructionHack = ^TInstructionHack;
function GetSearchTickCountPointer: PInteger;
var P: PInstructionHack;
N: Integer;
begin
P := @THackDbLookupControl.ProcessSearchKey;
N := 0; // Sentinel counter, so we don't look for the opcode for ever
while N < 2000 do
begin
if P.OpCodePrefix = $052B then // Looking for SUB EAX, [SearchTickCount]
begin
Result := P.OpCodeAddress;
Exit;
end;
Inc(N);
P := PInstructionHack(Cardinal(P)+1); // Move pointer 1 byte
end;
Result := nil;
end;
end.
您可以像这样使用 hacky 版本:
var P: PInteger;
begin
P := GetSearchTickCountPointer;
if Assigned(P) then
P^ := 1; // change SearchTickCount value!
end;
关于Delphi:有什么方法可以链接到 BPL 中尚未打包的变量吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6504089/
我正在使用 C++ Builder 10 Seattle,我正在尝试安装一个组件包,该组件包注册了在不同 bpl 中实现的组件。 从技术上讲,我已经这样做了: 我创建了两个包。一个仅定义为运行时 (c
我想知道是否有人知道一种优雅的方法来确定给定(编译)的 DLL、EXE 或 BPL 需要哪些 BPL。 我不确定这是否可能比简单地扫描二进制文件中对 .bpl 文件名的文本引用(这可能容易出现误报 )
我的一般问题是如何解决“由于依赖项不会消失,无论我清理和重新编译多少次,我的 BPL 都不会加载”。 更新 您可能认为您有一个干净的重新编译系统,但由于 Windows 的逆向奇迹及其文件系统虚拟化错
Delphi 中设计时包的可怕错误之一是以下错误,这意味着注册安装新组件到您的 Palette 上的包: Component TSomething can't be registered by pac
我有一个 BPL 项目(带有一些基本内容)和一个 EXE 项目,该项目的搜索路径中包含其他项目输出(BPL 和 DCP)的位置。当使用“Build With Runtime Packages”构建 E
我在 Internet 上发现的每个 BPL 相关问题都涉及一些 BPL,这些 BPL 已经随 Delphi 一起提供,或者至少在全局范围内安装到 Delphi 文件夹中。 我想制作我自己的应用程序来
我正在学习 TMS 的一个组件。我收到“...rtl100.bpl 未找到...”。如果我使用包含“rtl”的“使用运行时包构建”,可能会发生此错误。 rtl100.bpl 在哪里(我使用的是 D20
情况如下。我通常使用 RAD Studio 2010 进行 Delphi 开发。我有一些组件想以二进制形式重新分发(*.bpl,没有源代码)。但我希望人们能够使用它们,尽管有 Delphi 版本。但是
有一个从 BPL 导出的函数,简化如下 function DoA(amount: currency; var Info: string): Currency; stdcall; begin re
看起来很简单,但下面的代码不起作用。 BPL: procedure DoSomething(); begin LogEvent('Did'); end; exports DoSomething
我使用ADO Component制作了一个应用程序,并使用它连接到Oracle,当我在另一台计算机上运行它时,我没有任何问题。 但是,当我使用ODAC组件和TOraSession并通过Direct C
是否可以在程序启动时检查客户端计算机上安装了哪个版本的 BPL(即 Rtl70.BPL、Indy70.bpl 等)? 我有一些程序崩溃,因为那里计算机上的 BPL 与构建机器上的不同。 如果我必须在每
我使用 Delphi XE,我有以下设置: Mydll.dll和Package1.bpl(运行时包)都包含Unit3.pas unit Unit3; interface implementation
我正在尝试将 Orpheus 4.08 的最新版本添加到 Delphi XE2 和 Delphi XE3 中。除了通常的警告之外,包编译时没有错误,并且编译器发出成功信号。但是,我找不到 *.bpl
我正在 RAD Studio 2007 中开发一个项目,使用 C++ 中的 VCL 类。 TDBLookupControl 是 VCL 的一部分,并且有一些不良行为,这是由于使用内部变量 Search
试图了解为什么我们会收到“未找到入口点”的消息,而我知道它应该在那里。除了 map 之外,是否有一个工具可以“探索”.bpl 或 .dll 并显示入口点? 最佳答案 Delphi 附带 a comma
我正在一名delphi IDE专家中工作,现在为了避免依赖性问题,我正在考虑将这位专家重建为dll专家,正如其中一个answers中所建议的那样。 ,现在我的专家(编译为 bpl)访问 Screen
如果我在 EXE 中有一个资源并且我想提取它,这非常简单。像这样的东西: stream := TResourceStream.Create(HInstance, ResourceName, RT_RC
从 BPL 中,是否可以获得自己的文件名?例如C:\foo\bar.bpl (动态加载和delphi7,如果重要的话) 最佳答案 调用GetModuleFileName 。对于模块句柄,请使用 Sys
我想创建 *.bpl 文件,但我没有这样做。 具体来说,我正在尝试制作 JEDI 插件,但我也尝试过一个空的纯 Delphi 包。 如果我在 Delphi XE3 中创建一个新包,我会得到一个空单元
我是一名优秀的程序员,十分优秀!