将 Windows 主题应用于 Office Com 加载项 [英] Apply Windows Theme to Office Com add-in

查看:18
本文介绍了将 Windows 主题应用于 Office Com 加载项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

多年来,Delphi 一直支持应用程序设置"选项卡上的启用运行时主题 开关.但是,这只适用于可执行文件.假定 DLL 会从其父应用程序中接管主题(和其他)设置.

For ages, Delphi has supported the Enable runtime themes switch on the Application Settings tab. However, this only works for executables. DLLs are assumed to take over the theming (and other) setings from their parent application.

不幸的是,Microsoft Office 在那里表现不佳.它们的主题"外观是使用自定义控件实现的,而不是通过 Windows 自己的通用控件实现的.

Unfortunately, Microsoft Office doesn't play nice there. Their 'themed' look is achieved using custom controls, not through Windows' own Common Controls.

在 MSDN 文章 830033 - 如何将 Windows XP 主题应用于 Office COM 加载项 Microsoft 解释了如何将清单应用于 DLL,使其隔离感知,从而忽略来自父进程的设置.

In the MSDN article 830033 - How to apply Windows XP themes to Office COM add-ins Microsoft explains how to apply a manifest to a DLL, making it Isolation Aware such that settings from the parent process are ignored.

基本上分为两个步骤:

  1. 在您的流程中包含默认清单资源,使用 int-resource id 2(而不是您通常使用的 1).
  2. 使用 ISOLATION_AWARE_ENABLED 定义进行编译.**这在 Delphi 中不可用.**

我想我已经确定了 (1),尽管我从来不确定 brcc32 是将资源 ID 作为整数还是作为文字字符串来选择.真正的问题在于(2).据说,这个定义改变了几个 DLL 函数绑定.

I think I've got (1) nailed down, although I'm never quite sure whether brcc32 picks up resource IDs as integers or as literal strings. The real problem lies with (2). Supposedly, this define changes several DLL function bindings.

有没有人在Delphi中解决过这个问题?我应该进一步调查这条路线,我应该尝试手动创建激活上下文,还是有其他优雅的解决方案来解决这个问题?

Has anyone solved this problem in Delphi? Should I further investigate this route, should I try and manually creating activation contexts, or are there other elegant solutions to this problem?

推荐答案

我已经为我的 COM 加载项完成了这项工作.我使用了激活上下文.COM 加载项非常容易,因为加载项界面的表面积非常小.我可以发布代码,但直到明天我才能在机器上使用它.希望这会有所帮助!

I've done this for my COM add-in. I used activation contexts. It's pretty easy for a COM add-in because the surface area of the add-in interface is so small. I could post code but I won't be at a machine with it on until tomorrow. Hope this helps!

更新

正如承诺的那样,这是我使用的代码:

As promised, here is the code that I use:

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;

当你想使用它时,你只需像这样编写代码:

When you want to use this, you simply write code like so:

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

您需要将执行 GUI 工作的每个入口点包装在此类代码中.

You need each entry point that does GUI work to be wrapped in such code.

请注意,在我的 COM 加载项 DLL 中,我采取了特殊措施来避免在 DLLMain 期间运行代码,因此我调用了 InitialiseActivationContextFinaliseActivationContext 不在单元初始化/结束部分.但是,我认为没有理由将此代码放在那里不安全.

Note that in my COM add-in DLL I have taken special measures to avoid running code during DLLMain, and so my calls to InitialiseActivationContext and FinaliseActivationContext are not in unit initialization/finalization sections. However, I see no reason why this code would not be safe to place there.

这篇关于将 Windows 主题应用于 Office Com 加载项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆