I have an application in Delphi with a grid.
I need to create another application, which should
a) read data from the grid and
b) write data into the grid,
i. e. emulate the actions of a human user.
In order to read data from the table, I use following code:
Procedure TForm1.Button1Click(Sender: TObject);
type
PForm = ^TForm;
PClass = ^TClass;
var
formPtr : PForm;
I: Integer;
msg : string;
windowHandle : HWND;
begin
windowHandle := FindWindow('TForm1', 'FORMSSSSS');
formPtr := PForm(GetVCLObjectAddr(windowHandle) + 4);
if (not Assigned(formPtr)) then Exit;
for I := 0 to formPtr^.ControlCount - 1 do // Error
begin
msg := msg + formPtr^.Controls[i].Name;
if formPtr^.Controls[i].Name = 'StringGrid1' then
begin
msg := TStringGrid(formPtr^.Controls[i]).Cells[1, 1];
end;
end;
ShowMessage(msg);
end;
function GetVCLObjectAddr(AHandle: HWND): DWORD;
var
pid: DWORD;
begin
pid := 0;
GetWindowThreadProcessId(AHandle, pid);
if (pid =0) then
begin
Result := 0;
Exit;
end;
Result := GetPropW(AHandle, PWideChar(WideString(Format('Delphi%.8X', [PID]))))
end;
In the line with the “Error” comment, following problem occurs:
Project Project1.exe raised exception class EAccessViolation with message ‘Access
violation at address 0046C8C3 in module ‘Project1.exe’. Read of address 01262984′.
When I put a breakpoint on that line and inspect the value of the expression “formPtr^” in the “Watches” tab, I get “Inaccessible value” message.
How should the code be modified in order to be able to read data from the grid?
UPD:
If I change the code to the version given below, the memory problem disappears. But another problem arises – control count is equal to zero.
Procedure TForm1.Button1Click(Sender: TObject);
var
formPtr : TForm;
I: Integer;
msg : string;
windowHandle : HWND;
begin
windowHandle := FindWindow('TForm1', 'FORMSSSSS');
formPtr := TForm(GetVCLObjectAddr(windowHandle) + 4);
if (not Assigned(formPtr)) then Exit;
for I := 0 to formPtr.ControlCount - 1 do
begin
msg := msg + formPtr.Controls[i].Name;
if formPtr.Controls[i].Name = 'StringGrid1' then
begin
msg := TStringGrid(formPtr.Controls[i]).Cells[1, 1];
end;
end;
ShowMessage(msg);
end;
That approach cannot work. Your two processes have isolated address spaces. An address, and therefore an object, is only meaningful in the context of the process that owns that address or object. You can only call methods on objects that reside in your process.