MS Excel SDK issue: Can't use ToolTip in Tree-View control in XLL add-in

106 views Asked by At

I have a dialog window with a Tree-View control where the user can drag the items to rearrange the tree.

It looks and behaves differently when it is used in an executable and in an MS Excel add-in XLL.

It looks like this during a drag operation when used in an executable(this is the desired look):

enter image description here

But when I use the same dialog in an MS Excel add-in XLL(where it is displayed when user selects a command) it looks like this(notice the missing tooltip, and icons for expanded items):

enter image description here

What could be causing this? Is there a way I can make the dialog look like the way it does when used in an executable?


I suspect it has to do with the ComCtl32.dll version, as the following returns version 6.16 when called from the executable, but 5.82 when called from XLL:

HINSTANCE hinstDll = LoadLibrary(lpszDllName);
DLLGETVERSIONPROC pDllGetVersion =
    (DLLGETVERSIONPROC)GetProcAddress(hinstDll, "DllGetVersion");

I have the following manifest in the .cpp file.

#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")

// Enable Visual Style
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
1

There are 1 answers

17
RbMm On BEST ANSWER

if we in DLL have resource of type RT_MANIFEST with name ISOLATIONAWARE_MANIFEST_RESOURCE_ID (note that for EXE need use CREATEPROCESS_MANIFEST_RESOURCE_ID) the loader create activation context for our DLL (and save it in LDR_DATA_TABLE_ENTRY.EntryPointActivationContext) but it activate it only before call our DLL entry point, and just deactivate it after it return. really - in process we have many DLLs - from which DLL need activate context ? the system activate activation context from EXE only. and from DLL - temporary, during call it Entry point. however we need use this activation context (from our DLL) during create a window etc.

so strategy is next:

get and save our activation context on DLL_PROCESS_ATTACH:

// global variables
HANDLE g_hActCtx;
BOOLEAN g_bActCtxValid;

case DLL_PROCESS_ATTACH:
    //...
    g_bActCtxValid = GetCurrentActCtx(&g_hActCtx) != FALSE;
    //...

when we need create window, dialog, etc - we need activate saved context:

ULONG_PTR Cookie;
if (ActivateActCtx(g_hActCtx, &Cookie))
{
    CreateWindowExW(..);
    DeactivateActCtx(0, Cookie);
}

and finally, on DLL unload - release context:

case DLL_PROCESS_DETACH:
    if (g_bActCtxValid)ReleaseActCtx(g_hActCtx);

note that this already not once answered here - for example. but with one difference - in all other solutions used CreateActCtx api (with dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID, lpResourceName = ISOLATIONAWARE_MANIFEST_RESOURCE_ID, hModule = &__ImageBase) - this call create activation context again for our DLL. but i instead this prefer use already created by system activation context for our DLL (this is current context inside DllMain). so not duplicate, but reference already created. GetCurrentActCtx instead CreateActCtx