Вызов функций XLL из мастера функций или диалоговых окон замены

Область применения: Excel 2013 | Office 2013 | Visual Studio

Microsoft Excel обычно вызывает функции XLL во время обычного пересчета книги или ее части, если вычисление находится под контролем макроса. Помните, что функция может не находиться в формуле ячейки, но может быть частью определения именованного диапазона или выражения условного форматирования.

Существует два обстоятельства, когда функцию можно вызвать из диалогового окна Excel. Одним из них является диалоговое окно Вставка аргументов функции , в котором пользователи могут создавать функцию, вызывая по одному аргументу за раз. Другой — это когда формулы изменяются и повторно вводятся Excel в диалоговом окне Заменить . В диалоговом окне Вставка аргументов функции может не потребоваться нормальное выполнение функции. Это может быть связано с тем, что выполнение занимает много времени, и вы не хотите замедлять использование диалогового окна.

В диалоговом окне Вставка функции и в диалоговом окне Заменить имя класса Windows bosa_sdm_XLn, где n — это число. Windows предоставляет функцию API GetClassName, которая получает это имя из дескриптора Windows типа переменной HWND. Он также предоставляет другую функцию , EnumWindows, которая вызывает предоставленную функцию обратного вызова (в библиотеке DLL) один раз для каждого открытого окна верхнего уровня.

Функция обратного вызова должна выполнять только следующие действия:

  1. Проверьте, является ли родительским элементом этого окна текущий экземпляр Excel (если запущено несколько экземпляров).

  2. Получите имя класса из дескриптора, переданного Windows.

  3. Проверьте, имеет ли имя класса форму bosa_sdm_XLn.

  4. Если необходимо различать два диалоговых окна, проверка, если заголовок диалогового окна содержит некоторый идентифицирующие текст. Заголовок окна получается с помощью вызова Api Windows GetWindowText.

В следующем коде C++ показан класс и обратный вызов для передачи в Windows, который выполняет эти действия. Это вызывается функциями, которые вызывают тест специально для любого из соответствующих диалоговых окон.

Примечание.

Заголовки окон будущих версий Excel могут измениться и сделать этот код недействительным. Обратите внимание также, что установка window_title_text значения NULL вызывает игнорирование заголовка окна в поиске обратного вызова.

#define CLASS_NAME_BUFFSIZE  50
#define WINDOW_TEXT_BUFFSIZE  50
// Data structure used as input to xldlg_enum_proc(), called by
// called_from_paste_fn_dlg(), called_from_replace_dlg(), and
// called_from_Excel_dlg(). These functions tell the caller whether
// the current worksheet function was called from one or either of
// these dialog boxes.
typedef struct
{
  bool is_dlg;
  short low_hwnd;
  char *window_title_text; // set to NULL if don't care
}
  xldlg_enum_struct;
// The callback function called by Windows for every top-level window.
BOOL CALLBACK xldlg_enum_proc(HWND hwnd, xldlg_enum_struct *p_enum)
{
// Check if the parent window is Excel.
// Note: Because of the change from MDI (Excel 2010)
// to SDI (Excel 2013), comment out this step in Excel 2013.
  if(LOWORD((DWORD)GetParent(hwnd)) != p_enum->low_hwnd)
    return TRUE; // keep iterating
  char class_name[CLASS_NAME_BUFFSIZE + 1];
//  Ensure that class_name is always null terminated for safety.
  class_name[CLASS_NAME_BUFFSIZE] = 0;
  GetClassName(hwnd, class_name, CLASS_NAME_BUFFSIZE);
//  Do a case-insensitve comparison for the Excel dialog window
//  class name with the Excel version number truncated.
  size_t len; // The length of the window's title text
  if(_strnicmp(class_name, "bosa_sdm_xl", 11) == 0)
  {
// Check if a searching for a specific title string
    if(p_enum->window_title_text) 
    {
// Get the window's title and see if it matches the given text.
      char buffer[WINDOW_TEXT_BUFFSIZE + 1];
      buffer[WINDOW_TEXT_BUFFSIZE] = 0;
      len = GetWindowText(hwnd, buffer, WINDOW_TEXT_BUFFSIZE);
      if(len == 0) // No title
      {
        if(p_enum->window_title_text[0] != 0)
          return TRUE; // No match, so keep iterating
      }
// Window has a title so do a case-insensitive comparison of the
// title and the search text, if provided.
      else if(p_enum->window_title_text[0] != 0
      && _stricmp(buffer, p_enum->window_title_text) != 0)
        return TRUE; // Keep iterating
    }
    p_enum->is_dlg = true;
    return FALSE; // Tells Windows to stop iterating.
  }
  return TRUE; // Tells Windows to continue iterating.
}

Диалоговое окно Вставка функции не имеет заголовка, поэтому следующая функция передает строку заголовка поиска "", то есть пустую строку, обратному вызову, чтобы указать, что условие соответствия заключается в том, что окно не должно иметь заголовка.

bool called_from_paste_fn_dlg(void)
{
    XLOPER xHwnd;
// Calls Excel4, which only returns the low part of the Excel
// main window handle. This is OK for the search however.
    if(Excel4(xlGetHwnd, &xHwnd, 0))
        return false; // Couldn't get it, so assume not
// Search for bosa_sdm_xl* dialog box with no title string.
    xldlg_enum_struct es = {FALSE, xHwnd.val.w, ""};
    EnumWindows((WNDENUMPROC)xldlg_enum_proc, (LPARAM)&es);
    return es.is_dlg;
}

См. также

Доступ к коду XLL в Excel

Вызов Excel из библиотеки DLL или XLL

Разработка XLL-файлов для Excel