多年来,Delphi一直支持“应用程序设置”选项卡上的“启用运行时主题”开关.但是,这仅适用于可执行文件.假设DLL从其父应用程序接管主题(和其他)设置.
不幸的是,Microsoft Office在那里玩得不好.他们的“主题”外观是使用自定义控件实现的,而不是通过Windows自己的通用控件实现的.
在MSDN文章830033 – How to apply Windows XP themes to Office COM add-ins
中,Microsoft解释了如何将清单应用于DLL,使其成为隔离感知,以便忽略来自父进程的设置.
基本上,它归结为两个步骤:
>使用int-resource id为2(而不是通常使用的1),在流程中包含默认清单资源.
>使用ISOLATION_AWARE_ENABLED定义进行编译. ** Delphi中没有.**
我认为我已经(1)确定了,虽然我不确定brcc32是否将资源ID作为整数或文字字符串.真正的问题在于(2).据推测,这个定义改变了几个DLL函数绑定.
有没有人在Delphi中解决这个问题?我是否应该进一步研究这条路线,我应该尝试手动创建激活上下文,还是有其他优雅的解决方案来解决这个问题?
解决方法
我已经为我的COM加载项做了这个.我使用了激活上下文. COM加载项非常简单,因为加载项界面的表面区域非常小.我可以发布代码,但直到明天我都不会在机器上.希望这可以帮助!
UPDATE
正如所承诺的,这是我使用的代码:
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的调用不在单元初始化/完成部分中.但是,我认为没有理由将这些代码放在那里是不安全的.