I suspect that you are building with ISOLATION_AWARE_ENABLED defined to 1.
ISOLATION_AWARE_ENABLED enables wrapper functions in winbase.inl (and other
files, such an Winuser.inl) for the activation context functions. These
wrappers essentially use the function address returned by calling
GetProcAddress on Kernel32 to call the specified function. This would allow
you to call CreateActCtx, etc. and still run on pre-Windows XP systems.
For example, the function that wraps CreateActCtxW (from Winbase.inl):
ISOLATION_AWARE_INLINE HANDLE WINAPI IsolationAwareCreateActCtxW(PCACTCTXW
pActCtx)
{
HANDLE result = INVALID_HANDLE_VALUE;
typedef HANDLE (WINAPI* PFN)(PCACTCTXW pActCtx);
static PFN s_pfn;
if (s_pfn == NULL)
{
s_pfn =
(PFN)WinbaseIsolationAwarePrivatetRgCebPnQQeRff_xReaRYQP_QYY("CreateActCtxW "
);
if (s_pfn == NULL)
return result;
}
result = s_pfn(pActCtx);
return result;
}
ISOLATION_AWARE_ENABLED also enables wrappers for functions in USER32 (such
as CreateWindowEx), COMCTL32 (such as PropertySheet), and COMDLG32 (such as
GetOpenFileName). These functions will activate the activation context
based on the module's manifest, call the specified function, then
deactivate the activation context. For example, the function that wraps
CreateWindowExW (from Winuser.inl):
ISOLATION_AWARE_INLINE HWND WINAPI IsolationAwareCreateWindowExW(DWORD
dwExStyle,LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int
Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE
hInstance,LPVOID lpParam)
{
HWND windowResult = NULL;
ULONG_PTR ulpCookie = 0;
const BOOL fActivateActCtxSuccess = IsolationAwarePrivateT_SqbjaYRiRY
|| IsolationAwarePrivatenPgViNgRzlnPgpgk(&ulpCookie);
if (!fActivateActCtxSuccess)
return windowResult;
__try
{
windowResult =
CreateWindowExW(dwExStyle,lpClassName,lpWindowName,dwStyle,X,Y,nWidth,nHeig h
t,hWndParent,hMenu,hInstance,lpParam);
}
__finally
{
if (!IsolationAwarePrivateT_SqbjaYRiRY)
{
const BOOL fPreserveLastError = (windowResult == NULL);
const DWORD dwLastError = fPreserveLastError ? GetLastError() :
NO_ERROR;
(void)IsolationAwareDeactivateActCtx(0, ulpCookie);
if (fPreserveLastError)
SetLastError(dwLastError);
}
}
return windowResult;
}
What does ISOLATION_AWARE_ENABLED have to do with creating Window controls
from a shell extension? Explorer will load both the 5.82 and 6.0 versions
of COMCTL32.DLL when it starts. This allows for components that rely on
version 5.82 to continue to get their expected behavior while allowing
other components to use 6.0 version. COMCTL32 5.82 and 6.0 implement most
of the same window classes (SysListView32, SysTreeView32, etc.), while
version 6.0 also implements standard window controls that are found in
USER32 (Button, Edit, ComboBox, etc.) How does Windows know which version
to use when calling CreateWindowEx? This is where the activation context
comes into play. Windows allows for side-by-side window classes and the
activation context determines which implementation of the window class to
use when a window of that class is created. See "Creating Side-By-Side
Window Classes" for more information.
<
http://msdn.microsoft.com/library/en-us/sbscs/setup/creating_side-by-... indows_classes.asp>
So why doesn't defining ISOLATION_AWARE_ENABLED work with shell extensions
that use MFC or ATL? The short answer is that the runtime libraries were
not built using ISOLATION_AWARE_ENABLED. Therefore, the runtime libraries
will not use the IsolationAware* wrappers when calling Win32 functions such
as CreateWindowEx. Consider that when you call Create on a CButton object,
you are calling into the MFC runtime to create the button, which eventually
calls CreateWindowEx without activating an activation context. The likely
outcome is that the Create call will create an instance of the Button class
that is implemented in USER32, even if you have a manifest in the calling
module that references COMCTL32 version 6.
Anyone that is creating a DLL that is loaded into a process and wants to
use the version 6 common controls will need to create and manage an
activation context. This applies to shell extensions, ActiveX controls, and
other types of add-ins, such as add-ins for Office applications. Defining
ISOLATION_AWARE_ENABLED generally can handle managing an activation context
for you without having to write any additional code, provided the
IsolationAware* functions are used to 'wrap' the underlying Win32 call with
an activation context. As we have found, ISOLATION_AWARE_ENABLED does not
wrap Win32 calls made by MFC/ATL. Therefore, it is up to a component that
is using MFC/ATL to manage its own activation context.
In the example given above, a DLL calling CButton::Create should call
ActivateActCtx to activate the activation context prior to the Create call
and then call DeactivateActCtx after the create call to deactivate the
activation context. The button will then be created using the version 6
COMCTL32 implementation of the Button class, assuming that the activation
context is created using a manifest that references COMCTL32 version 6.
For those interested in how this applies to the .NET Framework, the
Application.EnableVisualStyles instructs the Framework to create and manage
an activation context when creating windows.
I recommend reading the "Using the Activation Context API" section in the
Platform SDK for more information.
<http://msdn.microsoft.com/library/en-us/sbscs/setup/using_the_activat...
ntext_api.asp>
Dave Anderson
Microsoft Developer Support
This posting is provided "AS IS" with no warranties, and confers no rights.