访问 Excel 实例和主窗口句柄
适用于:Excel 2013 | Office 2013 | Visual Studio
若要在 Windows 环境中编程,有时必须知道 Microsoft Excel 实例句柄或main窗口句柄。 例如,创建和显示自定义 Windows 对话框时,这些句柄非常有用。
有两个仅限 XLL 的 C API 函数提供对这些句柄的访问权限: xlGetInst 函数和 xlGetHwnd 函数。 在 Win32 中,所有句柄都是 32 位整数。 但是,在设计 XLOPER 时,Windows 是一个 16 位系统。 因此,结构仅允许用于 16 位句柄。 在 Win32 中,使用 Excel4 或 Excel4v 调用时, xlGetInst 函数和 xlGetHwnd 函数仅返回完整 32 位句柄的低部分。
在 Excel 2007 及更高版本中,当使用 Excel12 或 Excel12v 调用这些函数时,返回XLOPER12包含完整的 32 位句柄。
在任何版本的 Excel 中,获取完整实例句柄都很简单,因为它会传递给 Windows 回调 DllMain,该回调在加载 DLL 时调用。 如果在全局变量中记录此实例句柄,则永远不需要调用 xlGetInst 函数。
在 Excel 2003 及更早版本中获取主 Excel 句柄
若要在 Excel 2003 和早期 32 位版本中获取main Excel 句柄,必须首先调用 xlGetHwnd 函数以获取实际句柄的低字。 然后,必须循环访问顶级窗口列表,以搜索返回的低字匹配项。 以下代码演示了技术。
typedef struct _EnumStruct
{
HWND hwnd; // Return value for Excel main hWnd.
unsigned short wLoword; //Contains LowWord of the Excel main hWnd
} EnumStruct;
#define CLASS_NAME_BUFFER 50
BOOL CALLBACK EnumProc(HWND hwnd, EnumStruct * pEnum)
{
// First check the class of the window. Must be "XLMAIN".
char rgsz[CLASS_NAME_BUFFER];
GetClassName(hwnd, rgsz, CLASS_NAME_BUFFER);
if (!lstrcmpi(rgsz, "XLMAIN"))
{
// If that hits, check the loword of the window handle.
if (LOWORD((DWORD) hwnd) == pEnum->wLoword)
{
// We have a match, return Excel main hWnd.
pEnum->hwnd = hwnd;
return FALSE;
}
}
// No match - continue the enumeration.
return TRUE;
}
BOOL GetHwnd(HWND * pHwnd)
{
XLOPER x;
//
// xlGetHwnd only returns the LoWord of Excel hWnd
// so all the windows have to be enumerated to see
// which match the LoWord returned by xlGetHwnd.
//
if (Excel4(xlGetHwnd, &x, 0) == xlretSuccess)
{
EnumStruct enm;
enm.hwnd = NULL;
enm.wLoword = x.val.w;
EnumWindows((WNDENUMPROC) EnumProc, (LPARAM) &enm);
if (enm.hwnd != NULL)
{
*pHwnd = enm.hwnd;
return TRUE;
}
}
return FALSE;
}