2010-12-09 26 views

回答

13

只是爲了補充Rob Kennedy的回答,您必須以這種方式使用SetThemeAppProperties

uses 
UxTheme; 

procedure DisableThemesApp; 
begin 
    SetThemeAppProperties(0); 
    SendMessage(Application.Handle,WM_THEMECHANGED,0,0); 
    SendMessage(Application.MainForm.Handle,CM_RECREATEWND,0,0); 
end; 

procedure EnableThemesApp; 
begin 
    SetThemeAppProperties(STAP_ALLOW_NONCLIENT or STAP_ALLOW_CONTROLS or STAP_ALLOW_WEBCONTENT); 
    SendMessage(Application.Handle,WM_THEMECHANGED,0,0); 
    SendMessage(Application.MainForm.Handle,CM_RECREATEWND,0,0); 
end; 

,並確定如果你的控件主題與否,你可以使用GetThemeAppProperties功能。

var 
    Flag : DWORD; 
begin 
    Flag:=GetThemeAppProperties; 
    if (Flag and STAP_ALLOW_CONTROLS)<>0 then //if the controls are themed 
    begin 

    end; 
end; 

UPDATE

由於對您所描述的問題,我檢查UxTheme單元的代碼,我看到的問題是關係到UseThemes功能。所以我寫了這個小補丁(使用功能補丁HookProcUnHookProcGetActualAddr由Andreas Hausladen開發),這在我的測試中工作正常。讓我知道你是否也適合你。

您必須在您的使用列表中包含PatchUxTheme。並呼叫功能 DisableThemesAppEnableThemesApp

unit PatchUxTheme; 

interface 


procedure EnableThemesApp; 
procedure DisableThemesApp; 


implementation 

uses 
Controls, 
Forms, 
Messages, 
UxTheme, 
Sysutils, 
Windows; 

type 
    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 
UseThemesBackup: TXRedirCode; 

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; 


procedure HookProc(Proc, Dest: Pointer; var BackupCode: TXRedirCode); 
var 
    n: DWORD; 
    Code: TXRedirCode; 
begin 
    Proc := GetActualAddr(Proc); 
    Assert(Proc <> nil); 
    if ReadProcessMemory(GetCurrentProcess, Proc, @BackupCode, SizeOf(BackupCode), n) then 
    begin 
    Code.Jump := $E9; 
    Code.Offset := PAnsiChar(Dest) - PAnsiChar(Proc) - SizeOf(Code); 
    WriteProcessMemory(GetCurrentProcess, Proc, @Code, SizeOf(Code), n); 
    end; 
end; 

procedure UnhookProc(Proc: Pointer; var BackupCode: TXRedirCode); 
var 
    n: Cardinal; 
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 UseThemesH:Boolean; 
Var 
Flag : DWORD; 
begin 
    Flag:=GetThemeAppProperties; 
    if ((@IsAppThemed<>nil) and (@IsThemeActive<>nil)) then 
    Result := IsAppThemed and IsThemeActive and ((Flag and STAP_ALLOW_CONTROLS)<>0) 
    else 
    Result := False; 
end; 

procedure HookUseThemes; 
begin 
    HookProc(@UxTheme.UseThemes, @UseThemesH, UseThemesBackup); 
end; 

procedure UnHookUseThemes; 
begin 
    UnhookProc(@UxTheme.UseThemes, UseThemesBackup); 
end; 


Procedure DisableThemesApp; 
begin 
    SetThemeAppProperties(0); 
    SendMessage(Application.Handle,WM_THEMECHANGED,0,0); 
    SendMessage(Application.MainForm.Handle,CM_RECREATEWND,0,0); 
end; 

Procedure EnableThemesApp; 
begin 
    SetThemeAppProperties(STAP_ALLOW_NONCLIENT or STAP_ALLOW_CONTROLS or STAP_ALLOW_WEBCONTENT); 
    SendMessage(Application.Handle,WM_THEMECHANGED,0,0); 
    SendMessage(Application.MainForm.Handle,CM_RECREATEWND,0,0); 
end; 

initialization 
HookUseThemes; 
finalization 
UnHookUseThemes; 
end. 
+0

@RRUZ。到達那裏但尚未完成...... CM_RECREATEWND絕對需要查看任何東西(儘管我會避免它,因爲它可能會給Combos,ListViews帶來不愉快的副作用...)。 使用** SpeedButton消失時,移除主題時仍存在問題,PageControls在更改標籤時不會重新繪製,而網格是顯示混亂**。其中一個原因可能是因爲** IsApp主題和IsThemeActive **仍然會返回True,這會在嘗試繪製時混淆VCL ... – 2010-12-09 19:15:14

4
+0

嗯。看起來它不適合我家裏的D2010。 `SetThemeAppProperties(0)`似乎沒有任何可見的效果。 `IsAppThemed和IsThemeActive`仍然返回`True`,有或沒有`WM_THEMECHANGED`或調用`ThemeServices.ApplyThemeChange`。我將在明天與Delphi XE一起嘗試更多的工作...... – 2010-12-09 08:25:22

1

爲我的項目之一,我使用的是這樣的:

Procedure RemoveTheme(Const Controls : Array Of HWnd; Const Redraw : Boolean = True); 
Var 
    I : Integer; 
Begin 
    If IsAppThemed And IsThemeActive Then Try 
    I := 0; 
    While (I < Length(Controls)) Do Begin 
     If (Controls[I] > 0) And IsWindow(Controls[I]) Then SetWindowTheme(Controls[I], '', ''); 
     If Redraw Then Begin 
     InvalidateRect(Controls[I], Nil, True); 
     UpdateWindow(Controls[I]); 
     End; 
     Inc(I); 
    End; 
    Except 
    End; 
End; 

使用像: RemoveTheme([Edit1.Handle,Edit2.Handle]);

+0

謝謝,但它不適用於我的情況。 (a)你需要遞減容器(面板,盒子,標籤/頁面控件...),(b)不是WinControls的控件(像SpeedButtons這樣的圖形控件)不被處理,(c) (d)由VCL繪製的控件像Grid一樣被部分改變(ScrollBar被Windows改變,單元沒有被VCL改變)。我寧願設置一個全局標誌,並告訴Windows /主題管理器/ VCL這個應用程序不是主題。如果有可能...... – 2010-12-09 19:34:16