9

次の方法で使用したい Delphi XE で作成しているコンポーネントがあります。

  1. ユーザーが新しい空のプロジェクトを作成します。

  2. ユーザーがコンポーネントをフォームにドロップします。

  3. 私のコンポーネントのいくつかの特別なデザインタイム コードが実行されます。これにより、プロジェクト オプションが変更され、プロジェクト オプションの [ランタイム テーマを有効にする] チェックボックスがオフになります。これが可能かどうかさえわからないので、可能かどうか尋ねています。

#3 が不可能な場合は、このコンポーネントの「使いやすさ」の問題に対する別の解決策が必要です。私が抱えている問題は、ユーザーが [ランタイム テーマを有効にする] のチェックを外して静的にリンクされたマニフェスト ファイルを無効にしない場合、EXE にリンクされている静的に生成されたマニフェストが、EXE の外部に必要な外部マニフェスト ファイルを上書きするように見えることです。ディスク。また、実行時にこれらのマニフェストを変更する必要があるため、外部マニフェストが必要になります。もちろん、必要に応じて、これらのマニフェストを使用してランタイム テーマ機能を有効にすることもできます。2 つ目の質問は、外部マニフェストと内部マニフェストの優先度に関するものです。「ランタイム テーマを有効にする」をオンにすると、Delphi アプリにリンクされている内部マニフェスト リソースよりも、外部マニフェストが何らかの形で優先されることがありますか?

#3 以外の許容される解決策:

A. Delphi がマニフェストを生成しないようにします。B. 内部の .manifest ファイルが見つかった場合でも、何らかの方法で実行時に Windows に外部の .manifest ファイルを認識させ、優先順位を付ける。

C. 最も良くないソリューション。実行時に、コンポーネントの CoCreateInstance が失敗した後、リソースを列挙し、外部マニフェストが存在し、混乱していることを報告し、コンポーネントを使用する開発者に、コンポーネントが吐き出すランタイム エラー メッセージを読み取って、無効にするように指示することができます。ランタイムテーマのチェックボックスをオンにして、アプリを再構築します。マニフェストの抽出と読み取りは、Delphi に簡単に変換できる C++ コードを使用して、別の stackoverflow question hereで既に説明されています。

更新受け入れられた回答は私が尋ねたこととまったく同じですが、ハックと見なされ、アクティベーションコンテキストに関するデビッドの回答ははるかに正気であり、推奨されるアプローチです。

Update2組み込みのマニフェストは、プロジェクト設定を介して、リンクするマニフェストを明示的に指定することにより、通常、Delphi の新しいバージョン(XE5 以降)でオーバーライドされます。

4

2 に答える 2

11

私はあなたが求めたもの、つまり、実用的な解決策を見つけたと思います。コンポーネントのインスタンスが作成されたとき (フォームにドロップされたとき、またはそのインスタンスを含むフォーム/モジュールが IDE で開かれたとき) に、プロジェクト オプションからランタイム テーマを無効にします。これは、ユーザーがランタイム テーマを後で手動で再度有効にすることを妨げるものではありませんが、それでも役立つ場合があります。

ところで、IOTAProjectOptionsこの場合は役に立たないようです。が必要なようIOTAProjectResourceです。

TestComponentU.pas(ランタイム パッケージの一部):

unit TestComponentU;

interface

uses
  Windows, Classes;

type
  ITestComponentDesign = interface
    function DisableRuntimeThemes: Boolean;
  end;

  TTestComponent = class(TComponent)
  public
    constructor Create(AOwner: TComponent); override;
  end;

var
  TestComponentDesign: ITestComponentDesign = nil;

implementation

uses
  Dialogs;

constructor TTestComponent.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  if (csDesigning in ComponentState) and Assigned(TestComponentDesign) and
    TestComponentDesign.DisableRuntimeThemes then
    ShowMessage('Project runtime themes disabled');
end;

end.

TestComponentRegU.pas(IDE にインストールされたデザイン パッケージの一部):

unit TestComponentRegU;

interface

procedure Register;

implementation

uses
  Windows, Classes, SysUtils, TestComponentU, ToolsAPI;

type
  TTestComponentDesign = class(TInterfacedObject, ITestComponentDesign)
  public
    function DisableRuntimeThemes: Boolean;
  end;

procedure Register;
begin
  RegisterComponents('Test', [TTestComponent]);
end;

function GetProjectResource(const Project: IOTAProject): IOTAProjectResource;
var
  I: Integer;
begin
  Result := nil;
  if not Assigned(Project) then
    Exit;

  for I := 0 to Project.ModuleFileCount - 1 do
    if Supports(Project.ModuleFileEditors[I], IOTAProjectResource, Result) then
      Break;
end;

function GetProjectResourceHandle(const ProjectResource: IOTAProjectResource; ResType, ResName: PChar): TOTAHandle;
var
  I: Integer;
  ResEntry: IOTAResourceEntry;
begin
  Result := nil;
  if not Assigned(ProjectResource) then
    Exit;

  for I := 0 to ProjectResource.GetEntryCount - 1 do
  begin
    ResEntry := ProjectResource.GetEntry(I);
    if Assigned(ResEntry) and (ResEntry.GetResourceType = ResType) and (ResEntry.GetResourceName = ResName) then
    begin
      Result := ResEntry.GetEntryHandle;
      Break;
    end;
  end;
end;

function DisableProjectRuntimeThemes(const Project: IOTAProject): Boolean;
var
  ProjectResource: IOTAProjectResource;
  ResHandle: TOTAHandle;
begin
  Result := False;
  ProjectResource := GetProjectResource(Project);
  if not Assigned(ProjectResource) then
    Exit;

  ResHandle := GetProjectResourceHandle(ProjectResource, RT_MANIFEST, CREATEPROCESS_MANIFEST_RESOURCE_ID);
  if Assigned(ResHandle) then
  begin
    ProjectResource.DeleteEntry(ResHandle);
    Result := True;
  end;
end;

function TTestComponentDesign.DisableRuntimeThemes: Boolean;
var
  Project: IOTAProject;
begin
  Project := GetActiveProject;
  Result := Assigned(Project) and DisableProjectRuntimeThemes(Project);
end;

initialization
  TestComponentDesign := TTestComponentDesign.Create;

finalization
  TestComponentDesign := nil;

end.
于 2011-07-19T17:38:56.270 に答える
6

最良の解決策は、コンポーネントのユーザーがアプリケーションのマニフェストでやりたいことを何でもできるようにすることだと思います。そうしないと、このコンポーネントのユーザーに深刻な制約が課せられます。

代わりに、アクティブ化コンテキストAPI を使用して、コンポーネントが必要とするマニフェストを必要なときにアクティブ化します。

マニフェスト ファイルを実行可能ディレクトリに書き込むという現在のアイデアは、非常に脆く、そのディレクトリに書き込めないときはいつでも失敗する可能性があります。一方、アクティベーション コンテキスト API は、欠点がなく、本当に必要なことを正確に実行します。

于 2011-07-19T19:51:16.383 に答える