1

Possible Duplicate:
How to switch an Application between Themed and not Themed at run-time?

I create a GUI App with runtime themes option set to not enabled and need the option to manually enable an embedded Manifest during App initialization.

Question:

Does the VCL allow an extension point to implement that?

Let me explain:

  • The custom Manifest is embedded in the binary as a string constant.
  • Runtime themes is enabled using command line parameter switch, e.g.: MyApp.exe -themeOn

I have delved into Forms.TApplication in hope to find a handle but found nothing of interest pointing to a direction to go.

Community
  • 1
  • 1
menjaraz
  • 7,551
  • 4
  • 41
  • 81
  • 2
    Try this question [How to switch an Application between Themed and not Themed at run-time?](http://stackoverflow.com/questions/4393723/how-to-switch-an-application-between-themed-and-not-themed-at-run-time) – RRUZ Apr 09 '12 at 14:51
  • 1
    @RRUZ: Thank you pointing to it. – menjaraz Apr 09 '12 at 15:06
  • The only reason it wouldn't be an exact duplicate is because this question stipulates that you want to do something silly (not include a manifest). Ergo, it's a dupe. – Warren P Apr 09 '12 at 18:21
  • Hey, I'm sorry if I've offended anybody. I'm an enthusiast too, and sometimes I have been known to swat a fly with a hammer too. Sorry if I've offended. – Warren P Apr 10 '12 at 13:44

1 Answers1

5

I would do this the other way around. I would include the standard comctl v6 manifest by enabling runtime themes in the project settings. Then I would call SetThemeAppProperties at startup, from the .dpr file, to disable runtime themes if necessary.

procedure DisableRuntimeThemes;
begin
  InitThemeLibrary;
  if Assigned(SetThemeAppProperties) then
    SetThemeAppProperties(STAP_ALLOW_NONCLIENT);
end;

begin
  if not FindCmdLineSwitch('themeOn') then
    DisableRuntimeThemes;
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TMainForm, MainForm);
  Application.Run;
end.

You'll need to make sure that UxTheme is in the .dpr uses clause, or even better move that function to its own dedicated unit.

It's easier to include the manifest as normal and then disable runtime themes. The alternative of enabling runtime themes involves activation contexts which is rather more involved than this approach.


Having said it was easier than using the activation context, I decided to see what was involved in that. And here's what I came up with:

unit ActivateRuntimeThemes;

interface

implementation

uses
  Windows, SysUtils;

type
  TActivationContext = class
  private
    FActCtxHandle: THandle;
    FCreateActCtx: function(var pActCtx: TActCtx): THandle; stdcall;
    FActivateActCtx: function(hActCtx: THandle; var lpCookie: LongWord): BOOL; stdcall;
    FDeactivateActCtx: function(dwFlags: DWORD; ulCookie: LongWord): BOOL; stdcall;
    FReleaseActCtx: procedure(hActCtx: THandle); stdcall;
    FCookie: LongWord;
    FSucceeded: Boolean;
  public
    constructor Create;
    destructor Destroy; override;
  end;

constructor TActivationContext.Create;
var
  ActCtx: TActCtx;
  hKernel32: HMODULE;
begin
  inherited;
  hKernel32 := GetModuleHandle(kernel32);
  FCreateActCtx := GetProcAddress(hKernel32, 'CreateActCtxW');
  if Assigned(FCreateActCtx) then
  begin
    FReleaseActCtx := GetProcAddress(hKernel32, 'ReleaseActCtx');
    FActivateActCtx := GetProcAddress(hKernel32, 'ActivateActCtx');
    FDeactivateActCtx := GetProcAddress(hKernel32, 'DeactivateActCtx');
    ZeroMemory(@ActCtx, SizeOf(ActCtx));
    ActCtx.cbSize := SizeOf(ActCtx);
    ActCtx.lpSource := 'C:\desktop\comctlv6.manifest.txt';
    FActCtxHandle := FCreateActCtx(ActCtx);
    FSucceeded := (FActCtxHandle<>INVALID_HANDLE_VALUE) and FActivateActCtx(FActCtxHandle, FCookie);
  end
  else
    FActCtxHandle := INVALID_HANDLE_VALUE;
end;

destructor TActivationContext.Destroy;
begin
  if FSucceeded then
    FDeactivateActCtx(0, FCookie);
  if FActCtxHandle<>INVALID_HANDLE_VALUE then
    FReleaseActCtx(FActCtxHandle);
  inherited;
end;

var
  ActivationContext: TActivationContext;

procedure FinaliseActivationContext;
begin
  ActivationContext.Free;
end;

initialization
  if FindCmdLineSwitch('themeOn') then
    ActivationContext := TActivationContext.Create;

finalization
  ActivationContext.Free;

end.

You should include this unit as early as possible in your .dpr file. After any memory managers, but before any RTL/VCL units. Set runtime themes to None in the project settings. You'd probably want to include the manifest file as a resource, but I've done it as a file here for my convenience.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I guess this is not possible to do [`at runtime`](http://stackoverflow.com/q/7526665/960757) ? – TLama Apr 09 '12 at 14:49
  • 1
    @TLama Sure you can use activation contexts, but it's just harder than the approach outlined above. I always like the easy option! – David Heffernan Apr 09 '12 at 14:50
  • 1
    @RRUZ's link in that question takes you to a question with lots of SetThemeAppProperties answers. – David Heffernan Apr 09 '12 at 14:54
  • @David Heffernan: +1. Your option defaulting a Manifest is Ok. I didn't include it on my requirements but the other alternative gives room for extension: Suppose I have to choose between few manisfests. I must investigate but likely, another post if need be. Thank you. – menjaraz Apr 09 '12 at 15:19
  • 1
    @menjaraz I've given you the alternative activation context version too! – David Heffernan Apr 09 '12 at 15:40
  • @David Heffernan: Fine! your posts in the comment thread [here](http://stackoverflow.com/a/7526737/744588) are valuable and put me on the right track for the next things I have to do (activation context/all manifests in one pure resource dll). I've found a relevant sample written in Digital Mars D (application.d of the D Form Library by Christopher E. Miller/ namely Application.EnableVisualStyles()) – menjaraz Apr 09 '12 at 15:41
  • @David Heffernan: Sorry, I missed the last paragraph. – menjaraz Apr 09 '12 at 15:53
  • @David Heffernan: Skimmed over the D code. But, my godness, too involved approach and beyond my capacity for the time being. Thank you again. – menjaraz Apr 09 '12 at 16:01
  • Still a good answer. Upvoted even though this is a dupe. I think the OP's request is wrong headed, but this answer is still very helpful, and shows lots of effort! Good one david. – Warren P Apr 09 '12 at 18:21
  • Thanks Warren. I always enjoy an opportunity to roll out my activation context code! ;-) – David Heffernan Apr 09 '12 at 18:23