適用於:Excel 2013 |Office 2013 |Visualstudio
Microsoft Excel 通常會在活頁簿的一般重新計算期間呼叫 XLL 函式,如果計算是在宏的控制之下,則會呼叫其中的一部分。 請記住,函式可能不在單元格公式中,但可能是具名範圍定義或條件式格式表達式的一部分。
有兩種情況可以從 Excel 對話框呼叫函式。 其中一個是 [貼上函 式自變數] 對話框,用戶可以在其中一次建構函數調用一個自變數。 另一種是 Excel 在 [ 取代 ] 對話框中修改和重新輸入公式時。 針對 [ 貼上函 式自變數] 對話框,您可能不想讓函式正常執行。 這可能是因為執行需要很長的時間,而且您不想要讓對話方塊的使用速度變慢。
[貼上函式] 對話框和 [取代] 對話框都有 Windows 類別名稱bosa_sdm_XLn,其中 n 是數位。 Windows 提供 API 函式 GetClassName,可從 Windows 句柄 HWND 變數類型取得此名稱。 它也會提供另一個函 式 EnumWindows,針對目前開啟的每個最上層視窗呼叫 DLL) 內 (提供的回調函式一次。
回檔函式只需要執行下列步驟:
檢查此視窗的父系是否為 Excel (的目前實例,以防有多個實例執行) 。
從 Windows 傳入的句柄取得類別名稱。
檢查類別名稱是否為 n bosa_sdm_XL格式。
如果您需要區分這兩個對話框,請檢查對話框標題是否包含一些識別文字。 窗口標題是使用 Windows API 呼叫 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;
}