SkinFramework Articles and Tutorials

Microsoft Detours base API hook core for SkinFramework

Author: Alexander Stoyan
Platform: Visual C++ MFC

The Problem

In its core SkinFramework intecepts Win32 API calls from the host application and performs either custom drawing logic or adjusts size parameters and return values so that the result of the subsequent call of an original Win32 function results in visual changes in UI required by the selected skin.

This approach relies on the fact that all necessary API calls without exceptions are intercepted and handled by SkinFramework. Any missing API call may result in undefined behavior, broken user interface or absence of skinning coverage.

The way the legacy SkinFramework API hooking was initially implemented unforunately allowed some necessary API calls to be missed. It's been a long time issue with SkinFramework and reported by many users in many different use cases.

The Solution

Starting from version 19.2 both ToolkitPro and SuitePro have a new API hook core that uses Microsoft Detours library for intercepting Win32 API calls. The difference between old and new hooking approaches is in the location of the hooking code. While the legacy hooking core intercept functions at the point of invocation, the Detours hooks intercept the point of implementation.

The difference is easier to understand visually:

  • The legacy approach of intercepting API calls:
  • The new approach of intercepting API calls:

Obviously intercepting API calls at the point of implementation using one hook is not only less error prone but also ensures hook avilalability for all API calls regardless their origin.

ToolkitPro implications

As mentioned above, the new Microsoft Detours API hooking core is enabled by default in ToolkitPro 19.2, it does not require any changes in the existing code that depends on SkinFramework. Should any issues arise with the new core it is possible to enable legacy core by recompiling ToolkitPro with XTP_SKINFRAMEWORK_USE_LEGACY_API_HOOK macro enabled in project options and defining XTP_SKINFRAMEWORK_USE_LEGACY_API_HOOK either in the client application project properties or any place in StdAfx.h prior to XTToolkitPro.h inclusion.

SuitePro implications

SuitePro also has the new Microsoft Detours API hooking core enabled by default and it does not require any changes in the dependent code. In case of compability issues the legacy hooking core can be activated by setting SkinFrameworkGlobalSettings.UseLegacyCore to True prior to any SkinFramework call and even before any user interface is visible.

Limitations

The only drawback when using the new Microsoft Detours API hooking core is that it makes it impossible to exclude selected modules from hooking because it sets one hook for each API function at the point of implementation and there is no efficient and reliable way to determine the origin module of the call.

In some cases it may be necessary as some modules can generate too many calls and thus slow down application performance or, due to its complexity or specific, deadlocks or unexpected behavior may occur. But this was also causing different kinds of issues when used as it allowed to have application state that is partially handled by SkinFramework and partially handled by operating system. Mixing those states could result in the same problems as not excluding the trouble modules.

So, the new core does not implement module exclusion, but for backward compatibility ExcludeModule method is still exposed and it can be called, but calling it will have no effect.

If you do need to use module exclusion you will need to fallback to the legacy core as described above.