访问 Excel 实例和主窗口句柄

适用于:Excel 2013 | Office 2013 | Visual Studio

若要在 Windows 环境中编程,有时必须知道 Microsoft Excel 实例句柄或main窗口句柄。 例如,创建和显示自定义 Windows 对话框时,这些句柄非常有用。

有两个仅限 XLL 的 C API 函数提供对这些句柄的访问权限: xlGetInst 函数和 xlGetHwnd 函数。 在 Win32 中,所有句柄都是 32 位整数。 但是,在设计 XLOPER 时,Windows 是一个 16 位系统。 因此,结构仅允许用于 16 位句柄。 在 Win32 中,使用 Excel4Excel4v 调用时, 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;
}

另请参阅

在 DLL 或 XLL 内显示对话框

只能从 DLL 或 XLL 调用的 C API 函数

开发 Excel XLL