Снимите флажок «Включить темы времени выполнения» или удалить внутренний манифест в Delphi XE?

У меня есть компонент, который я создаю в Delphi XE, который я хочу использовать следующим образом:

  1. Пользователь создает новый пустой проект.

  2. Пользователь помещает мой компонент в форму.

  3. В моем компоненте выполняется какой-то специальный код Designtime, который изменяет параметры проекта, чтобы снять флажок «Включить темы времени выполнения» в параметрах проекта. Я не уверен, что это вообще возможно, поэтому я спрашиваю, возможно ли это.

Если №3 невозможно, то мне нужно другое решение моей проблемы с «удобством использования» с этим компонентом; Проблема, с которой я столкнулся, заключается в том, что если пользователи не отключают статически связанный файл манифеста, снимая флажок Включить темы времени выполнения, то этот статически сгенерированный манифест, связанный с EXE, по-видимому, переопределяет внешние файлы манифеста, которые я хочу иметь за пределами EXE, на диск. Мне также нужно изменить эти манифесты во время выполнения, поэтому мне нужны внешние манифесты. Я, конечно, могу включить функциональность Runtime Theme с помощью этих манифестов, когда это желательно. Второстепенный вопрос - о приоритете внешних и внутренних проявлений; Может ли внешний манифест каким-то образом иметь приоритет над внутренним ресурсом манифеста, который связан с приложениями Delphi, когда вы устанавливаете флажок «Включить темы времени выполнения»?

Приемлемые решения, кроме # 3:

A. Каким-то образом заставить Delphi не генерировать манифест. Б. Каким-то образом во время выполнения заставьте Windows распознавать внешние файлы .manifest и назначать им приоритеты, даже если обнаружен внутренний.

C. Наименее хорошее решение; Во время выполнения, после сбоя CoCreateInstance в моем компоненте, я могу перечислить ресурсы, сообщить, что внешний манифест присутствует и мешает нам, и полагаться на разработчиков, которые используют мой компонент, читая сообщения об ошибках времени выполнения, мой компонент выплевывает, говоря им отключить установите флажок темы времени выполнения и пересоберите их приложение. Извлечение и чтение манифеста уже описано в другом вопросе о стеке, здесь, с кодом C ++, который может быть легко преобразован в Delphi.

Обновить. Принятый ответ делает именно то, что я просил, но считается взломом, а ответ Дэвида о контекстах активации гораздо более разумный и является рекомендуемым подходом.

Update2 Встроенный манифест обычно переопределяется в более поздних версиях Delphi (XE5 и новее) путем явного указания манифеста, который вы хотите связать, в настройках проекта.


person Warren P    schedule 19.07.2011    source источник
comment
№3 определенно возможен, параметры проекта доступны через IOTAProjectOptions интерфейс.   -  person Ondrej Kelle    schedule 19.07.2011
comment
Интересное чтение. Похоже, что в XP внешний манифест имеет более высокий приоритет, чем встроенный, а в Vista + все наоборот.   -  person Ondrej Kelle    schedule 19.07.2011


Ответы (2)


Я думаю, что нашел рабочее решение для того, о чем вы просили, т.е. для отключения тем среды выполнения из параметров проекта при создании экземпляра вашего компонента (перетаскивании в форму или при открытии формы / модуля, содержащего его экземпляр, в среде 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.
person Ondrej Kelle    schedule 19.07.2011
comment
Принято, потому что это делает то, о чем я прошу. Я должен отметить, что я думаю, что Дэвид прав, что я спрашиваю о взломе (с использованием внешних текстовых файлов манифеста вообще), когда мой компонент, вероятно, должен попытаться использовать контексты активации, но если Windows кажется слишком сломанной, чтобы работать в некотором роде с контекстами активации это обходной путь. Я думаю, что этот вопрос и ответ ценны, поскольку они представляют собой образец использования IOTAProjectResource, и это всего лишь один простой случай, когда это было бы удобно. - person Warren P; 20.07.2011

Я подозреваю, что лучшее решение - позволить пользователям компонента делать все, что они хотят, с манифестами для своих приложений. В противном случае это наложило бы серьезные ограничения на всех пользователей этого компонента.

Вместо этого используйте контекст активации API, чтобы активировать манифесты, необходимые вашему компоненту. , как и когда это необходимо.

Ваша текущая идея записать файлы манифеста в исполняемый каталог кажется чрезвычайно хрупким и может потерпеть неудачу, если в этот каталог невозможно записать. С другой стороны, API контекста активации делает именно то, что вам действительно нужно, без каких-либо недостатков.

person David Heffernan    schedule 19.07.2011
comment
Это механизм, который я использую для включения тем времени выполнения в моем приложении excel com. - person David Heffernan; 20.07.2011
comment
Знаете ли вы, будет ли Win7 UAC блокировать доступ к этим API обычным или ограниченным пользователям? - person Warren P; 20.07.2011
comment
Нет проблем с UAC. Вот как вы должны решить свою проблему. - person David Heffernan; 20.07.2011
comment
Я бы отметил это как принятый, если бы не тот факт, что он делает то, что нужно, а другой делает то, о чем я просил. (Я всегда раздражаюсь, когда другие люди просят сделать глупые вещи, поэтому, пожалуйста, продолжайте указывать в будущем, когда у людей возникают идеи, которые по какой-то причине могут быть проблематичными или злонамеренными.) - person Warren P; 09.04.2012
comment
Да, ваше согласие верное. Я согласен. Я никогда не думал, что у меня так много ответов по контексту активации здесь, на SO. Они повсюду. - person David Heffernan; 09.04.2012