您遇到的问题是 Excel 函数向导会在您输入参数值时重复调用该函数。
为了避免这种情况,您的函数需要检测函数向导的存在并相应地进行。
我有一些 C++ 代码可以在生产中稳健地执行此操作。希望您可以将其移植到 C#。它使用 Windows API。您需要注意函数向导与特定的 Excel 会话相关;特别注意Excel2013。
typedef struct _EnumStruct
{
bool wizard;
DWORD pid;
} EnumStruct, FAR* LPEnumStruct;
BOOL CALLBACK EnumProc(HWND hwnd, LPEnumStruct pEnum)
{
static const char szFunctionWizardClass[] = "bosa_sdm_XL";
static const char szFunctionWizardCaption[] = "Function Arguments";
char szClass[sizeof(szFunctionWizardClass)];
char szCaption[sizeof(szFunctionWizardCaption)];
if (GetClassName(hwnd, (LPSTR)szClass, sizeof(szFunctionWizardClass))){
if (CompareString(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, (LPSTR)szClass, (lstrlen((LPSTR)szClass) > lstrlen(szFunctionWizardClass)) ? lstrlen(szFunctionWizardClass) : -1, szFunctionWizardClass, -1) == CSTR_EQUAL){
// Do the process IDs match? (The former way of checking parent windows doesn't work in Excel2013).
DWORD pid = NULL;
GetWindowThreadProcessId(hwnd, &pid);
if (pid == pEnum->pid){
// Check the window caption
if (::GetWindowText(hwnd, szCaption, sizeof(szFunctionWizardCaption))){
if (CompareString(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, (LPSTR)szCaption, (lstrlen((LPSTR)szCaption) > lstrlen(szFunctionWizardCaption)) ? lstrlen(szFunctionWizardCaption) : -1, szFunctionWizardCaption, -1) == CSTR_EQUAL){
pEnum->wizard = TRUE;
return FALSE;
}
}
}
}
}
// Continue the enumeration
return TRUE;
}
bool Excel12::calledFromFunctionWizard()
{
EnumStruct enm;
enm.wizard = FALSE;
enm.pid = GetProcessId(GetCurrentProcess());
EnumWindows((WNDENUMPROC)EnumProc, (LPARAM)((LPEnumStruct)&enm));
return enm.wizard;
}