MS Excel SDK 问题:无法在 XLL 加载项的树视图控件中使用工具提示
MS Excel SDK issue: Can't use ToolTip in Tree-View control in XLL add-in
我有一个带有树视图控件的对话框 window,用户可以在其中拖动项目以重新排列树。
它在可执行文件和 MS Excel 加载项 XLL 中使用时的外观和行为不同。
在可执行文件中使用时在拖动操作期间看起来像这样(这是所需的外观):
但是当我在 MS Excel 加载项 XLL 中使用相同的对话框时(当用户选择命令时显示的地方)它看起来像这样(注意缺少的工具提示和展开项目的图标):
这可能是什么原因造成的?有没有办法让对话框看起来像在可执行文件中使用时的样子?
我怀疑它与 ComCtl32.dll 版本有关,如下所示 returns 从可执行文件调用时为 6.16 版,但从 XLL 调用时为 5.82 版:
HINSTANCE hinstDll = LoadLibrary(lpszDllName);
DLLGETVERSIONPROC pDllGetVersion =
(DLLGETVERSIONPROC)GetProcAddress(hinstDll, "DllGetVersion");
我在 .cpp 文件中有以下清单。
#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
如果我们在 DLL 中有名称为 ISOLATIONAWARE_MANIFEST_RESOURCE_ID
的 RT_MANIFEST
类型的资源(注意对于 EXE需要使用 CREATEPROCESS_MANIFEST_RESOURCE_ID
) 加载程序为我们的 DLL 创建激活上下文(并将其保存在 LDR_DATA_TABLE_ENTRY.EntryPointActivationContext
中)但它仅在调用我们的 之前激活它DLL入口点,在它return之后停用它。真的 - 在过程中我们有许多 DLL - DLL 需要从中激活上下文?系统仅从 EXE 激活激活上下文。从 DLL - 临时的,在调用它的入口点。但是我们需要在创建 window 等
期间使用此激活上下文(来自我们的 DLL)
接下来是策略:
获取并保存我们在 DLL_PROCESS_ATTACH:
上的激活上下文
// global variables
HANDLE g_hActCtx;
BOOLEAN g_bActCtxValid;
case DLL_PROCESS_ATTACH:
//...
g_bActCtxValid = GetCurrentActCtx(&g_hActCtx) != FALSE;
//...
当我们需要创建 window、对话框等时 - 我们需要激活保存的上下文:
ULONG_PTR Cookie;
if (ActivateActCtx(g_hActCtx, &Cookie))
{
CreateWindowExW(..);
DeactivateActCtx(0, Cookie);
}
最后,在 DLL 上卸载 - 释放上下文:
case DLL_PROCESS_DETACH:
if (g_bActCtxValid)ReleaseActCtx(g_hActCtx);
请注意,此问题尚未在此处回答 - example。但有一个区别 - 在所有其他解决方案中使用 CreateActCtx
api(使用 dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID, lpResourceName = ISOLATIONAWARE_MANIFEST_RESOURCE_ID, hModule = &__ImageBase
) - 此调用为我们的 [=34 再次创建激活上下文 =]动态链接库。但我更喜欢使用已经由系统激活上下文为我们的 DLL 创建的(这是 DllMain 中的当前上下文)。所以不重复,但参考已经创建。 GetCurrentActCtx
而不是 CreateActCtx
我有一个带有树视图控件的对话框 window,用户可以在其中拖动项目以重新排列树。
它在可执行文件和 MS Excel 加载项 XLL 中使用时的外观和行为不同。
在可执行文件中使用时在拖动操作期间看起来像这样(这是所需的外观):
但是当我在 MS Excel 加载项 XLL 中使用相同的对话框时(当用户选择命令时显示的地方)它看起来像这样(注意缺少的工具提示和展开项目的图标):
这可能是什么原因造成的?有没有办法让对话框看起来像在可执行文件中使用时的样子?
我怀疑它与 ComCtl32.dll 版本有关,如下所示 returns 从可执行文件调用时为 6.16 版,但从 XLL 调用时为 5.82 版:
HINSTANCE hinstDll = LoadLibrary(lpszDllName);
DLLGETVERSIONPROC pDllGetVersion =
(DLLGETVERSIONPROC)GetProcAddress(hinstDll, "DllGetVersion");
我在 .cpp 文件中有以下清单。
#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
如果我们在 DLL 中有名称为 ISOLATIONAWARE_MANIFEST_RESOURCE_ID
的 RT_MANIFEST
类型的资源(注意对于 EXE需要使用 CREATEPROCESS_MANIFEST_RESOURCE_ID
) 加载程序为我们的 DLL 创建激活上下文(并将其保存在 LDR_DATA_TABLE_ENTRY.EntryPointActivationContext
中)但它仅在调用我们的 之前激活它DLL入口点,在它return之后停用它。真的 - 在过程中我们有许多 DLL - DLL 需要从中激活上下文?系统仅从 EXE 激活激活上下文。从 DLL - 临时的,在调用它的入口点。但是我们需要在创建 window 等
接下来是策略:
获取并保存我们在 DLL_PROCESS_ATTACH:
上的激活上下文// global variables
HANDLE g_hActCtx;
BOOLEAN g_bActCtxValid;
case DLL_PROCESS_ATTACH:
//...
g_bActCtxValid = GetCurrentActCtx(&g_hActCtx) != FALSE;
//...
当我们需要创建 window、对话框等时 - 我们需要激活保存的上下文:
ULONG_PTR Cookie;
if (ActivateActCtx(g_hActCtx, &Cookie))
{
CreateWindowExW(..);
DeactivateActCtx(0, Cookie);
}
最后,在 DLL 上卸载 - 释放上下文:
case DLL_PROCESS_DETACH:
if (g_bActCtxValid)ReleaseActCtx(g_hActCtx);
请注意,此问题尚未在此处回答 - example。但有一个区别 - 在所有其他解决方案中使用 CreateActCtx
api(使用 dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID, lpResourceName = ISOLATIONAWARE_MANIFEST_RESOURCE_ID, hModule = &__ImageBase
) - 此调用为我们的 [=34 再次创建激活上下文 =]动态链接库。但我更喜欢使用已经由系统激活上下文为我们的 DLL 创建的(这是 DllMain 中的当前上下文)。所以不重复,但参考已经创建。 GetCurrentActCtx
而不是 CreateActCtx