2011-02-27 15 views
6

Çağlar için, Delphi, Uygulama zamanlamaları sekmesini etkinleştirmek için çalışma zamanı temalarını etkinleştirmiştir. Ancak, bu sadece yürütülebilirler için çalışır. DLL'lerin, ana uygulamalarından tema (ve diğer) ayarlarının üstleneceği varsayılır.Windows Temasını Office Com eklentisine uygula

Maalesef, Microsoft Office orada iyi çalışmıyor. Onların 'temalı' görünümü, Windows'un kendi Ortak Kontrolleri ile değil, özel kontroller kullanılarak elde edilir.

MSDN makalesinde 830033 - How to apply Windows XP themes to Office COM add-ins Microsoft bu İzolasyon Aware hale bir DLL ana süreçten ayarlar göz ardı edilir, öyle ki bir bildirim nasıl uygulanacağını açıklar.

Temelde, aşağıya iki aşamada gelir:

  1. (normal olarak kullanacağınızdan 1 aksine) 2 olan bir int-kaynak kimliği kullanarak, süreç içinde varsayılan tezahür kaynak ekleyin.
  2. ISOLATION_AWARE_ENABLED tanımını derleyin. ** Delphi'de mevcut değildir. **

Bence brcc32, tamsayılar veya tamsayı dizeleri olarak brcc32 kaynak kimliklerini alıp almadığından emin değilim. Asıl sorun (2) ile yatmaktadır. Varsayılan olarak, bu tanım birkaç DLL işlev bağını değiştirir.

Bu problemi Delphi'de kim çözdü? Bu rotayı daha fazla araştırmalı mıyım, aktivasyon bağlamlarını manuel olarak oluşturmaya çalışmalı mıyım yoksa bu problem için başka zarif çözümler var mı?

+0

Hiçbir zarif çözüm bilmiyorum. WinSDK başlıklarındaki hızlı bakış, ActivateActCtx ve DeactivateActCtx öğelerinin önemli olduğunu gösteriyor - CommCtrl API işlevlerini yüklerken, LoadLibrary ve GetProcAddress çağrılarını tamamlıyor. WinSDK üstbilgileri tüm AFAICS kodlarını içerir, ancak çakışmaları önlemek için yeniden adlandırıldıkları için bazı deobfuscation (örn., IsolationAwarePrivatezltRgCebPnQQeRff, CommctrlIsolationAwarePrivatetRgCebPnQQeRff_pbZPgYQP_QYY, vb.) –

+0

@ Hamry: Keşif için teşekkürler!Delphi RTL/VCL'nin aktivasyon bağlamları ile _anything_ yapmadığını ve tamamen oluşturulan bildirime bağlı olduğunu muhakeme ediyorum? –

+0

Herhangi bir bilgim yok, sadece ipuçlarına yardımcı olmak için SDK başlıklarına baktım. –

cevap

8

Bunu COM eklentim için yaptım. Aktivasyon bağlamları kullandım. Eklenti arabiriminin yüzey alanı çok küçük olduğu için COM eklentisi için oldukça kolaydır. Kodu gönderebilirdim ama yarınlara kadar onunla bir makinede olmayacağım. Bu yardımcı olur umarım!

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; 

Bunu kullanmak istiyor

, sadece şöyle kod yazmak:

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


GÜNCELLEME Söz verdiğimiz gibi

, burada kullandığım kodu

GUI'nin çalışması için her giriş noktasının olması gerekir. Bu kodda d. Benim COM eklentisi DLL ben DLLMain sırasında kod çalıştıran önlemek için özel tedbirler almış ve böylece InitialiseActivationContext ve FinaliseActivationContext geçirici birim başlangıç ​​/ bitiş bölümlerde olmayan

Not. Ancak, bu kodun orada yerleştirilmesinin güvenli olmayacağına dair bir neden göremiyorum.

+0

Teşekkürler David, aktivasyon ortamlarını doğrulamak için uygun bir çözümdür. Daha fazla bakacaktır. Toplam yüzey alanıyla ilgili söylediklerinizle biraz şaşırdım, bu da ilgili iş miktarını etkiliyor mu? Gibi: daha fazla kontrol, daha fazla aktivasyon bağlamında ateş açılması gerekiyor? –

+0

Size DLL girdiğinizde ve ayrıldığınızda devre dışı bırakmanız gerekir. Ancak COM eklentisi ile çok az giriş noktanız var. Örnek kod göndermememi isterseniz bana bildirin, ancak 24 saat boyunca bunu yapamadım. –

+0

Ah bana aptal, orada söylediklerini tamamen yanlış okudum. Zihnimde hala tema üzerine asılıyım = interface UI, işler oradan yokuş aşağı gitti. Bunu temizlediğin için teşekkürler! :) –