1

重複の可能性:
実行時にアプリケーションをテーマとテーマなしの間で切り替える方法は?

ランタイムテーマオプションが有効に設定されていないGUIアプリを作成し、アプリの初期化中に埋め込みマニフェストを手動で有効にするオプションが必要です。

質問:

VCLは、拡張ポイントがそれを実装することを許可しますか?

説明させてください:

  • カスタムマニフェストは、文字列定数としてバイナリに埋め込まれます。
  • ランタイムテーマは、コマンドラインパラメータスイッチを使用して有効になります。例:MyApp.exe -themeOn

ハンドルを見つけるためにForms.TApplicationを詳しく調べましたが、進むべき方向を示す興味深いものは何も見つかりませんでした。

4

1 に答える 1

5

私はこれを逆にします。プロジェクト設定でランタイムテーマを有効にすることで、標準のcomctlv6マニフェストを含めます。次にSetThemeAppProperties、起動時に.dprファイルから呼び出して、必要に応じてランタイムテーマを無効にします。

procedure DisableRuntimeThemes;
begin
  InitThemeLibrary;
  if Assigned(SetThemeAppProperties) then
    SetThemeAppProperties(STAP_ALLOW_NONCLIENT);
end;

begin
  if not FindCmdLineSwitch('themeOn') then
    DisableRuntimeThemes;
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TMainForm, MainForm);
  Application.Run;
end.

UxThemeそれが.dpruses句に含まれていることを確認する必要があります。または、その関数を専用のユニットに移動することをお勧めします。

マニフェストを通常どおりに含めてから、ランタイムテーマを無効にする方が簡単です。ランタイムテーマを有効にする別の方法には、このアプローチよりもかなり複雑なアクティベーションコンテキストが含まれます。


アクティベーションコンテキストを使用するよりも簡単だと言ったので、それに何が関係しているかを確認することにしました。そして、これが私が思いついたものです:

unit ActivateRuntimeThemes;

interface

implementation

uses
  Windows, SysUtils;

type
  TActivationContext = class
  private
    FActCtxHandle: THandle;
    FCreateActCtx: function(var pActCtx: TActCtx): THandle; stdcall;
    FActivateActCtx: function(hActCtx: THandle; var lpCookie: LongWord): BOOL; stdcall;
    FDeactivateActCtx: function(dwFlags: DWORD; ulCookie: LongWord): BOOL; stdcall;
    FReleaseActCtx: procedure(hActCtx: THandle); stdcall;
    FCookie: LongWord;
    FSucceeded: Boolean;
  public
    constructor Create;
    destructor Destroy; override;
  end;

constructor TActivationContext.Create;
var
  ActCtx: TActCtx;
  hKernel32: HMODULE;
begin
  inherited;
  hKernel32 := GetModuleHandle(kernel32);
  FCreateActCtx := GetProcAddress(hKernel32, 'CreateActCtxW');
  if Assigned(FCreateActCtx) then
  begin
    FReleaseActCtx := GetProcAddress(hKernel32, 'ReleaseActCtx');
    FActivateActCtx := GetProcAddress(hKernel32, 'ActivateActCtx');
    FDeactivateActCtx := GetProcAddress(hKernel32, 'DeactivateActCtx');
    ZeroMemory(@ActCtx, SizeOf(ActCtx));
    ActCtx.cbSize := SizeOf(ActCtx);
    ActCtx.lpSource := 'C:\desktop\comctlv6.manifest.txt';
    FActCtxHandle := FCreateActCtx(ActCtx);
    FSucceeded := (FActCtxHandle<>INVALID_HANDLE_VALUE) and FActivateActCtx(FActCtxHandle, FCookie);
  end
  else
    FActCtxHandle := INVALID_HANDLE_VALUE;
end;

destructor TActivationContext.Destroy;
begin
  if FSucceeded then
    FDeactivateActCtx(0, FCookie);
  if FActCtxHandle<>INVALID_HANDLE_VALUE then
    FReleaseActCtx(FActCtxHandle);
  inherited;
end;

var
  ActivationContext: TActivationContext;

procedure FinaliseActivationContext;
begin
  ActivationContext.Free;
end;

initialization
  if FindCmdLineSwitch('themeOn') then
    ActivationContext := TActivationContext.Create;

finalization
  ActivationContext.Free;

end.

このユニットは、できるだけ早く.dprファイルに含める必要があります。メモリマネージャの後、ただしRTL/VCLユニットの前。プロジェクト設定でランタイムテーマを[なし]に設定します。マニフェストファイルをリソースとして含めたいと思うかもしれませんが、ここでは便宜上ファイルとして作成しました。

于 2012-04-09T14:44:38.013 に答える