Reputation: 11
I'm new to programming. I'm using Delphi 10.4 Community Edition. I'm trying to run the BassPlayer demo project, but I get an error when trying to compile and run it. It happens in a file named wa_ipc.pas
on line 1691. I have no idea how to fix this error.
function SendMessageRetStr(wnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): String;
var
dwProcessId: DWORD;
phandle: THandle;
P: Pointer;
C: Cardinal;
PB: Pointer;
B: Byte;
begin
Result := '';
GetWindowThreadProcessID(wnd, pointer(dwProcessId));
phandle := OpenProcess(PROCESS_VM_READ, False, dwProcessId);
if phandle = 0 then exit;
P := Pointer(SendMessage(wnd, uMsg, wParam, lParam));
PB := nil;
B := 0;
repeat
if not ReadProcessMemory(phandle,P,@PB,1,C) then break; (*<-- Error message here*)
B := Byte(PB);
if B <> 0 then begin
Result := Result + Chr(B);
end;
P := Pointer(DWord(P)+1);
until (B=0);
CloseHandle(phandle);
end;
The error I get is:
[dcc32 Error] wa_ipc.pas(1691): E2033 Types of actual and formal var parameters must be identical
Within the Winapi.Windows.pas
unit, the ReadProcessMemory()
function is declared as:
function ReadProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: SIZE_T; var lpNumberOfBytesRead: SIZE_T): BOOL; stdcall;
Upvotes: 0
Views: 326
Reputation: 595981
I see a number of problems with this code.
Your use of pointer(dwProcessId)
in the 2nd parameter of GetWindowThreadProcessId()
is wrong. It will not work as expected at runtime. You are passing an invalid memory address for the API to write to, leading to undefined behavior. You need to use @dwProcessId
instead.
Your use of @PB
in the 3rd parameter of ReadProcessMemory()
is wrong. You are reading 1 byte from the remote process into a Pointer
variable, and then you are truncating that Pointer
into a Byte
. Although this will behave as expected at runtime, it is logically wrong, you really should use @B
instead and get rid of PB
altogether.
Your use of C
in the 5th parameter of ReadProcessMemory()
is wrong. This is the cause of your compiler error. In the Win32 API, that parameter expects a pointer to a SIZE_T
(which is a pointer-sized unsigned integer), not the value of a Cardinal
(which is a fixed-sized 32bit unsigned integer). In Delphi's Winapi.Windows
unit, that parameter is declared as a var
reference to a SIZE_T
variable, not a var
reference to a Cardinal
variable, hence why you are getting the compiler error. You must declare your variable the exact same data type that the var
reference is expecting.
The remote data in question is clearly an 8bit null-terminated ANSI string, but you are appending the 8bit characters as-is to a 16bit UnicodeString
. Unless the characters in question are purely ASCII, the result will not be what you are expecting.
You are casting your P
pointer to a Dword
when incrementing its value. Dword
is a 32bit integer, so that cast will only work correctly if your app is compiled as a 32bit executable, which uses 32bit memory addresses at runtime. But in a 64bit executable, you risk truncating the memory address that the pointer is pointing at. You would need to use DWORD_PTR
(or equivalent) instead.
Now, with all of that said, try something more like this instead:
function SendMessageRetStr(wnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): String;
var
dwProcessId: DWORD;
hProcess: THandle;
PCh: LRESULT;
bytesRead: SIZE_T;
Ch: AnsiChar;
S: AnsiString;
begin
Result := '';
GetWindowThreadProcessID(wnd, @dwProcessId);
hProcess := OpenProcess(PROCESS_VM_READ, False, dwProcessId);
if hProcess = 0 then Exit;
try
PCh := SendMessage(wnd, uMsg, wParam, lParam);
repeat
if not ReadProcessMemory(hProcess, Pointer(PCh), @Ch, 1, bytesRead{or: PSize_t(nil)^}) then break;
if Ch = #0 then break;
S := S + Ch;
Inc(PCh);
until False;
finally
CloseHandle(hProcess);
end;
Result := string(S);
end;
Upvotes: 1