2014-09-06 48 views
0

我們開始使用Thinfinity UI在瀏覽器中虛擬我們的應用程序。虛擬化時,我們應用程序的主窗口最大化爲瀏覽器畫布的邊界。這意味着,實際上,我們的桌面縮小到瀏覽器畫布的大小。這也意味着,當諸如彈出菜單的控件被定位時,它們經常超出瀏覽器畫布的邊界。是否可以更改Vcl.Forms.TScreen.WorkAreaRect返回的值?

我相信我們可以解決這個問題,如果我們可以將對Vcl.Forms.TScreen.WorkAreaRect的調用結果設置爲瀏覽器畫布的邊界。這可能嗎?

+1

看看源代碼,找出需要替換的東西,並編寫一個繞道。繞過最低級別的功能,做你所需要的。 – 2014-09-06 08:59:34

回答

3

基於來自@GadDLord的How to change the implementation (detour) of an externally declared function,您可以掛鉤在TScreen.GetWorkAreaRect中使用的SystemParametersInfoW。 我複製了他的部分代碼以防止死鏈接。

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); 
相關問題