EnableVisualStyles.bas
#5
I think there is a common misconception here about activation contexts and visual styles.

The activation context does not need to remain active for the entire lifetime of the application in order for visual styles to keep working.

What actually matters is that the activation context is active when Windows loads and initializes the version 6 Common Controls (ComCtl32.dll). Once the themed controls have been created, deactivating the activation context does not suddenly "turn off" visual styles for controls that already exist.

In other words, the activation context is used to tell the Side-by-Side loader which version of the Common Controls library should be used. It is not a permanent switch that must stay enabled as long as the application is running.

For that reason, my implementation in FreeBasic simply:

- Creates the activation context.
- Activates it.
- Lets Windows load the themed Common Controls v6.
- Immediately deactivates and releases the activation context.

After that, the controls continue to use visual styles normally.

Keeping the activation context active for the entire process is only necessary if you intend to create additional objects later that must also be created under that same activation context. For the simple goal of enabling themed Common Controls, activating it temporarily is sufficient.

This is why the following FreeBasic code activates the context and immediately deactivates/releases it:

ActivateActCtx(hActCtx, @activationCookie)
 
DeactivateActCtx(0, activationCookie)
ReleaseActCtx(hActCtx)

and the application still gets visual styles correctly.

Conceptually, it is very similar to having an external manifest: the manifest influences how the process is initialized and which assemblies are selected, but Windows does not continuously consult it afterwards to decide whether already-created controls should remain themed.

The important point is that visual styles are a property of the Common Controls v6 implementation that gets loaded, not of the current activation state of the activation context stack after the controls have already been created.

This is the function that I use in FreeBasic:

Code:
' ========================================================================================
' * Enables visual styles without using a manifest in the application.
' ========================================================================================
PUBLIC FUNCTION EnableVisualStyles () AS BOOLEAN

  ' // Fill the ACTCTXW structure
  DIM actCtx AS ACTCTXW
  actCtx.cbSize = SIZEOF(ACTCTXW)
  actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID OR ACTCTX_FLAG_SET_PROCESS_DEFAULT OR ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID

  ' // Get system directory
  DIM systemDir AS WSTRING * MAX_PATH
  DIM cch AS UINT = GetSystemDirectoryW(@systemDir, MAX_PATH)
  IF cch >= MAX_PATH THEN RETURN FALSE  ' Ensure buffer is not exceeded
  systemDir[cch] = ASC("\")  ' Append backslash
  actCtx.lpAssemblyDirectory = @systemDir
  DIM wszSource AS WSTRING * MAX_PATH = systemDir & "shell32.dll"
  actCtx.lpSource = CAST(WSTRING PTR, @wszSource)  ' Use shell32.dll's manifest
  actCtx.lpResourceName = CAST(WSTRING PTR, 124)  ' Resource ID for the manifest (IDR_MANIFEST = 1, RT_MANIFEST = 24)

  ' // Create the activation context
  DIM hActCtx AS HANDLE = CreateActCtxW(@actCtx)
  IF hActCtx = INVALID_HANDLE_VALUE THEN RETURN FALSE
  ' // Activate the context
  DIM activationCookie AS ULONG_PTR
  ActivateActCtx(hActCtx, @activationCookie)

  ' // Deactivate and release the context
  DeactivateActCtx(0, activationCookie)
  ReleaseActCtx(hActCtx)
  RETURN TRUE

END FUNCTION
' ========================================================================================
Reply


Messages In This Thread
RE: EnableVisualStyles.bas - by José Roca - 5 hours ago

Forum Jump:


Users browsing this thread: 1 Guest(s)