Access Excel Instance and Main Window Handles

Applies to: Excel 2013 | Office 2013 | Visual Studio

To program in the Windows environment, sometimes you must know the Microsoft Excel instance handle or main window handle. For example, these handles are useful when you are creating and displaying custom Windows dialog boxes.

There are two XLL-only C API functions that provide access to these handles: the xlGetInst function and the xlGetHwnd function respectively. In Win32, all handles are 32-bit integers. However, when the XLOPER was designed, Windows was a 16-bit system. Therefore, the structure only allowed for 16-bit handles. In Win32, when called with Excel4 or Excel4v, the xlGetInst function and the xlGetHwnd function return only the low part of the full 32-bit handle.

In Excel 2007 and later versions, when these functions are called with Excel12 or Excel12v, the returned XLOPER12 contains the full 32-bit handle.

Obtaining the full instance handle is simple in any version of Excel, as it is passed to the Windows callback DllMain, which is called when the DLL is loaded. If you record this instance handle in a global variable, you never need to call the xlGetInst function.

Obtaining the Main Excel Handle in Excel 2003 and Earlier

To obtain the main Excel handle in Excel 2003 and earlier 32-bit versions, you must first call the xlGetHwnd function to obtain the low word of the actual handle. Then, you must iterate the list of top-level windows to search for a match with the returned low word. The following code illustrates the technique.

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;
}

See also

Displaying Dialog Boxes from Within a DLL or XLL

C API Functions That Can Be Called Only from a DLL or XLL

Developing Excel XLLs