Changing visual style of controls based on windows

2019-08-27 01:41发布

问题:

I'm looking to have vista/win7 use Aero-style windows while XP users use normal window style (how does one get windows XP stlye and not win95 styles btw?)

The idea is something like this:

OSVERSIONINFOEX osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
GetVersionEx((OSVERSIONINFO*)&osvi);
if (osvi.dwMajorVersion > 5) {
               #pragma comment(linker,"/manifestdependency:\"type='win32' "\
               "name='Microsoft.Windows.Common-Controls' "\
               "version='6.0.0.0' "\
               "processorArchitecture='x86' "\
               "publicKeyToken='6595b64144ccf1df' "\
               "language='*' "\
               "\"")
}

Now, the #pragma gets executed no matter if the if-statement is true or false, which I guess is just the way #pragma works. Surely there is some other way to get this to working (something like #ifndef #define ... #endif I guess)

Cheers

回答1:

You are mixing compile-time evaluation of pragma with run-time execution of code. Obviously this won't work.

It's possible to keep a manifest for the application in "PutYourProgramNameHere.exe.manifest" file. So if you need different manifests for XP and Vista/Win7, then you can install different manifest files when you install the application on the target computer. I.e. your installer checks OS version and installs matching manifest.



回答2:

You can use the Activation Context API functions to do this. The requirements are:

  • Use LoadLibrary & GetProcAddress to actually load the API functions in question as they don't exist prior to NT 5.1
  • Either embed a manifest containing the comctl 6 dependency as a resource with a resource id > 16, or have it as a file on disk.

This sample code assumes that the manifest is embedded as a RT_MANIFEST resource, with an id of 17. TestOSVersion() is your function to decide wether or not you want a skinned window.

ACTCTX actx = {0};
actx.cbSize = sizeof(ACTCTX);
actx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
actx.lpResourceName = MAKEINTRESOURCE(17);
actx.hModule = GetModuleHandle(NULL); // assumes the manifest is exe embedded.

HANDLE hactx = INVALID_HANDLE_VALUE;

if(TestOsVersion())
  hactx = CreateActCtx(&actx);
ULONG_PTR actxCookie = NULL;
if (hactx != INVALID_HANDLE_VALUE)
  ActivateActCtx(hactx,&actxCookie);

// Now, with the activation context active, create the dialog box
// or window or whatever.
HWND hwndDialog = CreateDialogBoxParam(...);

// and pop the context. It doesn't matter if the dialog still exists, the
// ctl6 dll is now   loaded and serving requests.
if (hactx != INVALID_HANDLE_VALUE)
  DeactivateActCtx(0,actxCookie);

Obviously, in order for this to work, the v6 common control cannot be in the processes default manifest.