1

We are starting to use Thinfinity UI to virtualize our application in a browser. When virtualised, the main window of our application is maximised to the bounds of the browser canvas. This means that, in effect, our desktop is reduced to the size of the browser canvas. It also means that when controls such as popup menus are positioned they often exceed the bounds of the browser canvas.

I believe we can overcome this issue if we can set the result of calls made to Vcl.Forms.TScreen.WorkAreaRect to the bounds of the browser canvas. Is this possible?

Mariana
  • 1
  • 2
  • 11
norgepaul
  • 6,013
  • 4
  • 43
  • 76
  • 1
    Look at the source code, work out what needs to be replaced, and write a detour. Detour the lowest level function the does what you need. – David Heffernan Sep 06 '14 at 08:59

1 Answers1

4

Based on How to change the implementation (detour) of an externally declared function from @GadDLord, you could hook SystemParametersInfoW which is used in TScreen.GetWorkAreaRect. I copied his part of code to prevent dead links.

type
  //strctures to hold the address and instructions to patch
  TJumpOfs = Integer;
  PPointer = ^Pointer;

  PXRedirCode = ^TXRedirCode;
  TXRedirCode = packed record
    Jump: Byte;
    Offset: TJumpOfs;
  end;

  PAbsoluteIndirectJmp = ^TAbsoluteIndirectJmp;
  TAbsoluteIndirectJmp = packed record
    OpCode: Word;
    Addr: PPointer;
  end;

var
 DataCompareBackup: TXRedirCode; //Store the original address of the function to patch

//get the address of a procedure or method of a function
function GetActualAddr(Proc: Pointer): Pointer;
begin
  if Proc <> nil then
  begin
    if (Win32Platform = VER_PLATFORM_WIN32_NT) and (PAbsoluteIndirectJmp(Proc).OpCode = $25FF) then
      Result := PAbsoluteIndirectJmp(Proc).Addr^
    else
      Result := Proc;
  end
  else
    Result := nil;
end;

//patch the original function or procedure
procedure HookProc(Proc, Dest: Pointer; var BackupCode: TXRedirCode);
var
  n: {$IFDEF VER230}NativeUInt{$ELSE}DWORD{$ENDIF};
  Code: TXRedirCode;
begin
  Proc := GetActualAddr(Proc);
  Assert(Proc <> nil);
  //store the address of the original procedure to patch
  if ReadProcessMemory(GetCurrentProcess, Proc, @BackupCode, SizeOf(BackupCode), n) then
  begin
    Code.Jump := $E9;
    Code.Offset := PAnsiChar(Dest) - PAnsiChar(Proc) - SizeOf(Code);
    //replace the target procedure address  with the new one.
    WriteProcessMemory(GetCurrentProcess, Proc, @Code, SizeOf(Code), n);
  end;
end;
//restore the original address of the hooked function or procedure
procedure UnhookProc(Proc: Pointer; var BackupCode: TXRedirCode);
var
  n: {$IFDEF VER230}NativeUInt{$ELSE}Cardinal{$ENDIF};
begin
  if (BackupCode.Jump <> 0) and (Proc <> nil) then
  begin
    Proc := GetActualAddr(Proc);
    Assert(Proc <> nil);
    WriteProcessMemory(GetCurrentProcess, Proc, @BackupCode, SizeOf(BackupCode), n);
    BackupCode.Jump := 0;
  end;
end;


function MySystemParametersInfo(uiAction, uiParam: UINT;
  pvParam: Pointer; fWinIni: UINT): BOOL; stdcall;
begin
  Result := SystemParametersInfoA(uiAction, uiParam,pvParam,fWinIni);
  if uiAction=SPI_GETWORKAREA then
      begin
        // Fake just for demo
        TRect(pvParam^).Right := 1234;
      end
end;


procedure TForm3.Button1Click(Sender: TObject);
begin
    Caption := IntToStr(Screen.WorkAreaRect.Right)
end;

initialization
 HookProc( @SystemParametersInfoW, @MySystemParametersInfo, DatacompareBackup);
finalization
 UnHookProc( @SystemParametersInfoW, DatacompareBackup);
Community
  • 1
  • 1
bummi
  • 27,123
  • 14
  • 62
  • 101