6

長い間、Delphi は[アプリケーション設定] タブの [ランタイム テーマを有効にする] スイッチをサポートしてきました。ただし、これは実行可能ファイルに対してのみ機能します。DLL は、親アプリケーションからテーマ (およびその他の) 設定を引き継ぐものと見なされます。

残念ながら、Microsoft Office はそこでうまく機能しません。それらの「テーマに沿った」外観は、Windows 独自のコモン コントロールではなく、カスタム コントロールを使用して実現されます。

MSDN の記事830033 - Windows XP テーマを Office COM アドイン に適用する方法 Microsoft はマニフェストを DLL に適用し、親プロセスからの設定が無視されるようにIsolation Awareにする方法を説明しています。

基本的には、次の 2 つのステップに分かれます。

  1. 2 の int-resource id を使用して、デフォルトのマニフェスト リソースをプロセスに含めます (通常は 1 を使用します)。
  2. ISOLATION_AWARE_ENABLED 定義でコンパイルします。**これは Delphi では使用できません。**

brcc32 がリソース ID を整数として取得するのか、リテラル文字列として取得するのかはよくわかりませんが、(1) は突き止められたと思います。本当の問題は (2) にあります。おそらく、この定義はいくつかの DLL 関数バインディングを変更します。

Delphiでこの問題を解決した人はいますか? このルートをさらに調査する必要がありますか、アクティベーション コンテキストを手動で作成する必要がありますか、またはこの問題に対する他のエレガントな解決策はありますか?

4

1 に答える 1

9

COMアドインでこれを行いました。アクティベーションコンテキストを使用しました。アドイン インターフェイスの表面積が非常に小さいため、COM アドインの場合は非常に簡単です。コードを投稿することはできますが、明日までそれがオンになっているマシンにいることはできません。お役に立てれば!


アップデート

約束どおり、私が使用するコードは次のとおりです。

type
  (* TActivationContext is a loose wrapper around the Windows Activation Context API and can be used
     to ensure that comctl32 v6 and visual styles are available for UI elements created from a DLL .*)
  TActivationContext = class
  private
    FCookie: LongWord;
    FSucceeded: Boolean;
  public
    constructor Create;
    destructor Destroy; override;
  end;

var
  ActCtxHandle: THandle=INVALID_HANDLE_VALUE;
  CreateActCtx: function(var pActCtx: TActCtx): THandle; stdcall;
  ActivateActCtx: function(hActCtx: THandle; var lpCookie: LongWord): BOOL; stdcall;
  DeactivateActCtx: function(dwFlags: DWORD; ulCookie: LongWord): BOOL; stdcall;
  ReleaseActCtx: procedure(hActCtx: THandle); stdcall;

constructor TActivationContext.Create;
begin
  inherited;
  FSucceeded := (ActCtxHandle<>INVALID_HANDLE_VALUE) and ActivateActCtx(ActCtxHandle, FCookie);
end;

destructor TActivationContext.Destroy;
begin
  if FSucceeded then begin
    DeactivateActCtx(0, FCookie);
  end;
  inherited;
end;

procedure InitialiseActivationContext;
var
  ActCtx: TActCtx;
  hKernel32: HMODULE;
begin
  if IsLibrary then begin
    hKernel32 := GetModuleHandle(kernel32);
    CreateActCtx := GetProcAddress(hKernel32, 'CreateActCtxW');
    if Assigned(CreateActCtx) then begin
      ReleaseActCtx := GetProcAddress(hKernel32, 'ReleaseActCtx');
      ActivateActCtx := GetProcAddress(hKernel32, 'ActivateActCtx');
      DeactivateActCtx := GetProcAddress(hKernel32, 'DeactivateActCtx');
      ZeroMemory(@ActCtx, SizeOf(ActCtx));
      ActCtx.cbSize := SizeOf(ActCtx);
      ActCtx.dwFlags := ACTCTX_FLAG_RESOURCE_NAME_VALID or ACTCTX_FLAG_HMODULE_VALID;
      ActCtx.lpResourceName := MakeIntResource(2);//ID of manifest resource in isolation aware DLL
      ActCtx.hModule := HInstance;
      ActCtxHandle := CreateActCtx(ActCtx);
    end;
  end;
end;

procedure FinaliseActivationContext;
begin
  if ActCtxHandle<>INVALID_HANDLE_VALUE then begin
    ReleaseActCtx(ActCtxHandle);
  end;
end;

initialization
  InitialiseActivationContext;

finalization
  FinaliseActivationContext;

これを使用する場合は、次のようにコードを記述します。

var
  ActivationContext: TActivationContext;
....
ActivationContext := TActivationContext.Create;
try
  //GUI code in here will support XP themes
finally
  ActivationContext.Free;
end;

GUI 作業を行う各エントリ ポイントをそのようなコードでラップする必要があります。

私の COM アドイン DLL では、 中DLLMainにコードが実行されるのを避けるために特別な手段を講じInitialiseActivationContextていることに注意してくださいFinaliseActivationContext。ただし、このコードを安全に配置できない理由はわかりません。

于 2011-02-27T12:32:54.017 に答える