TomJones965
TomJones965

Reputation: 11

Delphi 10.4 compiler error: "Types of actual and formal var parameters must be identical"

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

Answers (1)

Remy Lebeau
Remy Lebeau

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

Related Questions