我有一个用 Delphi 编写的遗留应用程序,需要构建一个机制
- 阅读和
- 写作
来自/到 TStringGrid 的数据。
我没有该应用程序的源代码,没有自动化接口(interface),供应商也不太可能提供该接口(interface)。
因此我创建了
- 一个 C++ DLL,用于注入(inject)
- 一个 Delphi DLL(由我编写)到
- 旧应用程序的地址空间。
DLL 2 可以访问旧应用程序内的 TStringGrid 实例,读取单元格值并将其写入调试日志。
阅读效果很好。但是,当我尝试使用类似
的调用将数据写入网格单元时realGrid.Cells[1,1] := 'Test';
发生访问冲突。
代码如下:
procedure DllMain(reason: integer) ;
type
PForm = ^TForm;
PClass = ^TClass;
PStringGrid = ^TStringGrid;
var
[...]
begin
if reason = DLL_PROCESS_ATTACH then
begin
handle := FindWindow('TForm1', 'FORMSSSSS');
formPtr := PForm(GetVCLObjectAddr(handle) + 4);
if (not Assigned(formPtr)) then
begin
OutputDebugString(PChar('Not assigned'));
Exit;
end;
form := formPtr^;
// Find the grid component and assign it to variable realGrid
[...]
// Iterate over all cells of the grid and write their values into the debug log
for I := 0 to realGrid.RowCount - 1 do
begin
for J := 0 to realGrid.ColCount - 1 do
begin
OutputDebugString(PChar('Grid[' + IntToStr(I) + '][' + IntToStr(J) + ']=' + realGrid.Cells[J,I]));
// This works fine
end;
end;
// Now we'll try to write data into the grid
realGrid.Cells[1,1] := 'Test'; // Crash - access violation
end;
end; (*DllMain*)
如何将数据写入 TStringGrid 而不会出现访问冲突问题?
最佳答案
这种方法根本行不通。目标可执行文件中有两个 VCL 实例。一份由目标应用程序拥有,一份由 DLL 拥有。这一个 VCL 实例太多了。如果使用完全相同版本的 Delphi 来构建目标应用程序和 DLL,您也许可以摆脱这种情况。
但是,您仍然有两个堆管理器在起作用。并且您的代码在不同的 VCL 实例之间传递堆分配的内存。您将在一个堆中分配并在另一堆中取消分配。这是行不通的,并且会导致访问冲突。
您正在将 DLL 堆中分配的字符串传递给使用目标应用程序堆的字符串网格对象。那是行不通的。
我认为,当 DLL 代码尝试释放由目标应用程序的堆管理器分配的 Cells[i,j]
的先前值时,就会发生访问冲突。
基本上你所尝试的方法是行不通的。您可以找到目标应用程序的 TStringGrid.SetCell
实现的地址,并伪造对其的调用。但您还需要找到目标应用程序的 GetMem
、FreeMem
等实现,并确保从 DLL 跨越到目标应用程序的所有动态内存都已分配并由目标应用程序的堆释放。你将有一份非常出色的工作来完成这项工作。当然,如果目标应用程序和 DLL 都使用共享内存管理器,那么您也许能够使这种方法发挥作用。
更简单的是伪造键盘输入。我个人会探讨使用 AutoHotKey 的可行性。
关于delphi - 从外部应用程序将数据写入 Delphi TStringGrid,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12454732/