共用方式為


從 DLL 或 XLL 呼叫 Excel

適用於:Excel 2013 |Office 2013 |Visual Studio

Microsoft Excel 可讓您的 DLL 存取內建 Excel 命令、工作表函數和宏工作表函式。 這些可從 Visual Basic for Applications (VBA) 呼叫的 DLL 命令和函式,以及 Excel 直接呼叫的已註冊 XLL 命令和函式取得。

Excel4、Excel4v、Excel12 和 Excel12v 函式

Excel 可讓您的 DLL 透過回呼函式 Excel4、Excel4vExcel12 和 Excel12v 來存取命令和函式

Excel4Excel4v 函式是在 Excel 第 4 版中引進的。 它們會使用 XLOPER 數據結構。 Excel 2007 導入了兩個新的回呼函式 Excel12Excel12v,可使用 XLOPER12 數據結構。 Excel4Excel4v 函式是由連結庫 Xlcall32.lib 匯出,其必須包含在您的 DLL 或 XLL 專案中。 Excel12Excel12v 包含在 SDK C++原始程式檔Xlcall.cpp中,如果您想要使用 XLOPER12 結構來存取 Excel 功能,則必須包含在您的專案中。

下列程式代碼顯示這四個函式的函式原型。 前三個自變數相同,不同之處在於第二個自變數是第一個配對中 XLOPER 的指標,以及第二個配對中 XLOPER12 的指標。 呼叫慣例 會在Excel4Excel12 中_cdecl,以允許變數自變數清單。 省略號代表Excel4的 XLOPER 值指標,以及Excel12的XLOPER12值。 指標數目等於 count 參數的值。

Excel 的所有版本

int _cdecl Excel4(int xlfn, LPXLOPER operRes, int count,... );

int pascal Excel4v(int xlfn, LPXLOPER operRes, int count, LPXLOPER opers[]);

從 Excel 2007 開始

int _cdecl Excel12(int xlfn, LPXLOPER12 operRes, int count,... );

int pascal Excel12v(int xlfn, LPXLOPER12 operRes, int count, LPXLOPER12 opers[]);

若要讓 DLL 能夠呼叫 Excel4Excel4vExcel12Excel12v,Excel 必須將控制權傳遞給 DLL。 這表示這些 C API 回呼只能在下列案例中呼叫:

  • 從 Excel 直接或透過 VBA 呼叫的 XLL 命令內。

  • 從 Excel 直接或透過 VBA 呼叫的 XLL 工作表或宏工作表函式內。

在下列案例中,您無法呼叫 Excel C API:

  • 例如,從操作系統事件 (,從 DllMain 函式) 。

  • 從 DLL 建立的背景線程。

傳回值

這四個函式都會傳回整數值,告知呼叫端是否已成功呼叫函式或命令。 傳回的值可以是下列其中一項:

傳回值 在 Xlcall.h 中定義為 描述
0 xlretSuccess 已成功執行函式或命令。 這並不表示執行沒有錯誤。 例如,Excel4 可能會在呼叫函式 FIND 時傳回 xlretSuccess,即使它評估為 #VALUE!,因為找不到搜尋文字。 您應該檢查傳回之 XLOPER/XLOPER12 的類型和值,這有可能發生。
1 xlretAbort 用戶按兩下 [取消 ] 按鈕或按下 ESC 鍵,已停止命令宏。
2 xlretInvXlfn 提供的函式或命令碼無效。 當呼叫函式沒有呼叫函式或命令的許可權時,就會發生此錯誤。 例如,工作表函式無法呼叫宏工作表資訊函式或命令函式。
4 xlretInvCount 呼叫中提供的自變數數目不正確。
8 xlretInvXloper 一或多個自變數 XLOPERXLOPER12 值未正確格式或填入。
16 xlretStackOvfl Excel 偵測到作業可能會溢出其堆疊的風險,因此不會呼叫 函式。
32 xlretFailed 命令或函式因為其他傳回值之一未描述的原因而失敗。 例如,需要太多記憶體的作業會因為此錯誤而失敗。 嘗試使用 xlCoerce 函數將非常大的參考轉換成 xltypeMulti 陣列時,可能會發生這種情況。
64 xlretUncalced 作業嘗試擷取未計算儲存格的值。 若要在 Excel 中保留重新計算完整性,不允許工作表函式執行此動作。 不過,註冊為宏工作表函式的 XLL 命令和函式可以存取未計算的數據格值。
128 xlretNotThreadSafe (從 Excel 2007 開始) 註冊為安全線程的 XLL 工作表函式嘗試呼叫不安全線程的 C API 函式。 例如,安全線程函式無法呼叫 XLM 函 式 xlfGetCell
256 xlRetInvAsynchronousContext (從 Excel 2010 開始) 異步函式句柄無效。
512 xlretNotClusterSafe (從 Excel 2010 開始) 叢集不支援呼叫。

如果函式傳回數據表中其中一個失敗值, (亦即,它不會傳回 xlretSuccess) ,XLOPERXLOPER12 傳回值也會設定 為 #VALUE!。 在某些情況下,檢查此情況可能足以測試是否成功,但您應該注意,呼叫可以同時傳回 xlretSuccess#VALUE!。

如果對 C API 的呼叫導致 xlretUncalcedxlretAbort,則 DLL 或 XLL 程式代碼應該先將控制權傳回 Excel,再進行任何其他 C API 呼叫, (呼叫 xlfree 函式,以釋放 XLOPER 中 Excel 配置的記憶體資源,並 XLOPER12 值) 。

命令或函式列舉自變數:xlfn

xlfn 自變數是回調函式的第一個自變數,並且是 32 位帶正負號的整數。 其值應該是 SDK 頭檔 Xlcall.h 中定義的其中一個函式或命令列舉,如下列範例所示。

// Excel function numbers. 
#define xlfCount 0
#define xlfIsna 2
#define xlfIserror 3
#define xlfSum 4
#define xlfAverage 5
#define xlfMin 6
#define xlfMax 7
#define xlfRow 8
#define xlfColumn 9
#define xlfNa 10
...
// Excel command numbers. 
#define xlcBeep (0 | xlCommand)
#define xlcOpen (1 | xlCommand)
#define xlcOpenLinks (2 | xlCommand)
#define xlcCloseAll (3 | xlCommand)
#define xlcSave (4 | xlCommand)
#define xlcSaveAs (5 | xlCommand)
#define xlcFileDelete (6 | xlCommand)
#define xlcPageSetup (7 | xlCommand)
#define xlcPrint (8 | xlCommand)
#define xlcPrinterSetup (9 | xlCommand)
...

所有工作表和宏工作表函式的範圍從 0 (xlfCount) 到0x0fff十六進位,雖然 Excel 2013 中指派的最高指派數位是 547 十進位,0x0223十六進位 (xlfFloor_precise) 。

雖然 Excel 2013 中指派的最高指派數位0x8328十六進位 ( (xlcHideallInkannots) 0x8fff,但所有命令函式都位於 xlcBeep) 0x8000 十六進位0x8328範圍中。 這些會在頭檔中定義為 (n | xlCommand) ,其中 n 是大於或等於0的小數,而 xlCommand 則定義為0x8000十六進位。

叫用使用對話框的Excel命令

某些命令程式代碼會對應至 Excel 中使用對話框的動作。 例如, xlcFileDelete 會採用單一自變數:檔名或遮罩。 這可以使用對話框叫用,讓用戶有機會取消或修改刪除作業。 它也可以在沒有對話框的情況下呼叫,在此情況下,檔案或檔案會在沒有任何進一步互動的情況下刪除,前提是它們存在且呼叫端具有許可權。 若要在其對話框表單中呼叫這類命令,命令列舉必須使用位 OR 運算搭配 xlPrompt) 0x1000 (。

下列程式代碼範例會刪除目前目錄中符合 mask my_data*.bak的檔案,只有在自變數為 true 時才會顯示對話方塊。

bool delete_my_backup_files(bool show_dialog)
{
    XLOPER12 xResult, xFilter;
    xFilter.xltype = xltypeStr;
    xFilter.val.str = L"\014my_data*.bak"; // String length: 14 octal
    int cmd;
    if(show_dialog)
        cmd = xlcFileDelete | xlPrompt;
    else
        cmd = xlcFileDelete;
// xResult should be Boolean TRUE if successful, in which
// case return true; otherwise, false.
    return (Excel12(cmd, &xResult, 1, &xFilter) == xlretSuccess
        && xResult.xltype == xltypeBool
        && xResult.val.xbool == 1);
}

在國際版本中呼叫函式和命令

您可以設定 Excel 以各種語言顯示函式和 XLM 命令名稱。 某些 C API 命令和函式會在解譯為函式或命令名稱的字串上運作。 例如, xlcFormula 會採用要放在指定儲存格中的字串自變數。 若要讓載入宏使用所有語言設定,您可以提供英文字串名稱,並在函式或命令列舉中設定 xlIntl) 位0x2000 (。

下列程式代碼範例會將 的 =SUM(X1:X100) 對等專案放在使用中工作表的儲存格 A2 中。 請注意,它會使用 Framework 函式 TempActiveRef 來建立暫時的外部參考 XLOPER。 公式會以正確的地區設定決定語言顯示在 A2 中 (例如, =SOMME(X1:X100) 如果語言是法文) 。

int WINAPI InternationlExample(void)
{
    XLOPER12 xSum, xResult;
    xSum.xltype = xltypeStr;
    xSum.val.str = L"\015=SUM(X1:X100)";
    Excel12(xlcFormula | xlIntl, &xResult, 2,
        &xSum, TempActiveRef(2,2,1,1));
    return 1;
}

注意事項

因為不需要呼叫 Excel12 的結果,所以零 (NULL) 可以傳遞為第二個自變數,而不是 xResult 的位址。 下一節會進一步討論此問題。

DLL-Only 函式和命令

Excel 支持少數只能從 DLL 或 XLL 存取的函式。 這些會在頭檔中定義為 (n | xlSpecial) ,其中 n 是大於或等於0的小數,並 xlSpecial 定義為0x4000十六進位。 下表列出這些函式,並記載於 API 函數參考中。

函數 n xlSpecial 描述
xlFree 0 xlSpecial 釋放 Excel 配置的記憶體資源。
xlStack 1 xlSpecial 傳回 Excel 堆疊上的可用空間。
xlCoerce 2 xlSpecial XLOPERXLOPER12 類型之間轉換
xlSet 3 xlSpecial 提供快速的方法來設定單元格值。
xlSheetId 4 xlSpecial 從其內部識別碼取得工作表名稱。
xlSheetNm 5 xlSpecial 從工作表的名稱取得工作表內部識別碼。
xlAbort 6 xlSpecial 驗證使用者是按下 [取消 ] 按鈕還是按下 ESC 鍵。
xlGetInst 7 xlSpecial 取得 Excel 實例句柄。
xlGetHwnd 8 xlSpecial 取得 Excel 主視窗句柄。
xlGetName 9 xlSpecial 取得 DLL 的路徑和檔名。
xlEnableXLMsgs 10 xlSpecial 此函式已被取代,不再需要呼叫。
xlDisableXLMsgs 11 xlSpecial 此函式已被取代,不再需要呼叫。
xlDefineBinaryName 12 xlSpecial 定義永續性二進位記憶體名稱。
xlGetBinaryName 13 xlSpecial 取得永續性二進位記憶體名稱的數據。

傳回值 XLOPER/XLOPER12: operRes

operRes 自變數是回呼的第二個自變數,也是 XLOPER (Excel4Excel4v) 或XLOPER12 (Excel12 和 Excel12v) 的指標。 成功呼叫之後,它會包含函式或命令的傳回值。 如果不需要傳回值,則 operRes 可以設定為零 (NULL 指標) 。 系統會覆寫 先前的 operRes 內容,因此必須先釋放先前所指向的任何記憶體,才能呼叫 ,以避免記憶體流失。

例如,如果無法呼叫函式或命令 (,如果自變數) 不正確,則 operRes 會設定為錯誤 #VALUE!。 如果成功,命令一律會傳回 布爾值 TRUE ;如果失敗或使用者取消,則傳回 FALSE

後續自變數的數目:計數

count 自 變數 是回呼的第三個自變數,是 32 位帶正負號的整數。 它應該設定為後續自變數的數目,從 1 算起。 如果函式或命令不接受任何自變數,則應該設定為零。 在 Microsoft Office Excel 2003 中,任何函式可接受的自變數數目上限為 30,雖然大部分的自變數都少於此數目。 從 Excel 2007 開始,任何函式可以接受的自變數數目上限已增加到 255。

使用 Excel4Excel12 時, count 是要傳遞之 XLOPERXLOPER12 值的指標數目。 您應該非常小心,不要傳遞比計數設定的值少的自 變數 。 這會導致 Excel 直接讀入堆疊,並嘗試處理無效的 XLOPERXLOPER12 值,這可能會導致應用程式當機。

使用 Excel4vExcel12v 時, countXLOPER 指標數位的大小,或 是XLOPER12 傳遞為下一個和最後一個自變數的值。 同樣地,您應該非常小心,不要傳遞小於 大小計數 元素的陣列,因為這會導致數位的界限溢出。

將自變數傳遞至 C API 函式

Excel4Excel12 都會採用可變長度自變數清單,在計數之後,分別解譯為 XLOPERXLOPER12值的指標。 Excel4vExcel12v 會在 count 之後採用單一自變數,這是 Excel4v 案例中 XLOPER 值之指標數位的指標,並在 Excel12v 的情況下XLOPER12值。

數位表單 Excel4vExcel12v可讓您在自變數數目為變數時,以全新方式撰寫 C API 呼叫的程式代碼。 下列範例顯示的函式會採用可變大小的數字數位數組,並透過 C API 使用 Excel 工作表函數來計算總和、平均、最小和最大值。

void Excel12v_example(double *dbl_array, int size, double &sum, double &average, double &min, double &max)
{
// 30 is the limit in Excel 2003. 255 is the limit in Excel 2007.
// Use the lower limit to be safe, although it is better to make
// the function version-aware and use the correct limit.
    if(size < 1 || size > 30)
        return;
// Create an array of XLOPER12 values.
    XLOPER12 *xOpArray = (XLOPER12 *)malloc(size * sizeof(XLOPER12));
// Create an array of pointers to XLOPER12 values.
    LPXLOPER12 *xPtrArray =
        (LPXLOPER12 *)malloc(size * sizeof(LPXLOPER12));
// Initialize and populate the array of XLOPER12 values
// and set up the pointers in the pointer array.
    for(int i = 0; i < size; i++)
    {
        xOpArray[i].xltype = xltypeNum;
        xOpArray[i].val.num = dbl_array[i];
        xPtrArray[i] = xOpArray + i;
    }
    XLOPER12 xResult;
    int retval;
    int fn[4] = {xlfSum, xlfAverage, xlfMin, xlfMax};
    double *result_ptr[4] = {&sum, &average, &min, &max};
    for(i = 0; i < 4; i++)
    {
        retval = Excel12v(fn[i], &xResult, size, xPtrArray);
        if(retval == xlretSuccess && xResult.xltype == xltypeNum)
            *result_ptr[i] = xResult.val.num;
    }
    free(xPtrArray);
    free(xOpArray);
}

在上述程式代碼中,將 XLOPER12 值的參考取代為 XLOPER,並將 Excel12v 取代為 Excel4v,將會產生可搭配所有 Excel 版本使用的函式。 Excel 函 式 SUMAVERAGEMINMAX 的這項作業非常簡單,因此以 C 撰寫它們的程式代碼會更有效率,並避免準備自變數和呼叫 Excel 的額外負荷。 不過,Excel 包含的許多函式都比較複雜,因此在某些情況下,這種方法很有用。

xlfRegister 主題提供另一個使用 Excel4vExcel12v 的範例。 註冊 XLL 工作表函式時,您可以為 [ 貼上 函式] 對話框中使用的每個自變數提供描述性字串。 因此,提供給 xlfRegister 的總自變數數目取決於 XLL 函式所採用的自變數數目,而且會因一個函式而異。

當您一律使用相同數目的自變數呼叫 C API 函式或命令時,您想要避免為這些自變數建立指標陣列的額外步驟。 在這些情況下,使用 Excel4Excel12 會更簡單且更簡潔。 例如,註冊 XLL 函式和命令時,您必須提供 DLL 或 XLL 的完整路徑和檔名。 您可以在呼叫 xlfGetName 時取得檔名,然後使用 xlFree 的呼叫來釋放它,如下列 Excel4Excel12 範例所示。

XLOPER xDllName;
if(Excel4(xlfGetName, &xDllName, 0) == xlretSuccess)
{
    // Use the name, and 
    // then free the memory that Excel allocated for the string.
    Excel4(xlFree, 0, 1, &xDllName);
}
XLOPER12 xDllName;
if(Excel12(xlfGetName, &xDllName, 0) == xlretSuccess)
{
    // Use the name, and
    // then free the memory that Excel allocated for the string.
    Excel12(xlFree, 0, 1, &xDllName);
}

在實務 上,Excel12v_example函式可藉由建立單一 xltypeMultiXLOPER12 自變數,以及使用 Excel12 呼叫 C API,以更有效率地撰寫程式代碼,如下列範例所示。

void Excel12_example(double *dbl_array, int size, double &sum, double &average, double &min, double &max)
{
// In this implementation, the upper limit is the largest
// single column array (equals 2^20, or 1048576, rows in Excel 2007).
    if(size < 1 || size > 1048576)
        return;
// Create an array of XLOPER12 values.
    XLOPER12 *xOpArray = (XLOPER12 *)malloc(size * sizeof(XLOPER12));
// Create and initialize an xltypeMulti array
// that represents a one-column array.
    XLOPER12 xOpMulti;
    xOpMulti.xltype = xltypeMulti;
    xOpMulti.val.array.lparray = xOpArray;
    xOpMulti.val.array.columns = 1;
    xOpMulti.val.array.rows = size;
// Initialize and populate the array of XLOPER12 values.
    for(int i = 0; i < size; i++)
    {
        xOpArray[i].xltype = xltypeNum;
        xOpArray[i].val.num = dbl_array[i];
    }
    XLOPER12 xResult;
    int fn[4] = {xlfSum, xlfAverage, xlfMin, xlfMax};
    double *result_ptr[4] = {&sum, &average, &min, &max};
    for(i = 0; i < 4; i++)
    {
        Excel12(fn[i], &xResult, 1, &xOpMulti);
        if(xResult.xltype == xltypeNum)
            *result_ptr[i] = xResult.val.num;
    }
    free(xOpArray);
}

注意事項

在此情況下, 會忽略 Excel12 的傳回值。 程序代碼會改為檢查傳回 的XLOPER12 是否為 xltypeNum ,以判斷呼叫是否成功。

XLCallVer

除了回呼 Excel4Excel4vExcel12Excel12v 之外,Excel 還會導出 XLCallVer 函式,此函式會傳回目前執行的 C API 版本。

函式原型如下所示:

int pascal XLCallVer(void);

您可以從任何 XLL 命令或函式呼叫這個安全線程的函式。

在 Excel 97 到 Excel 2003 中, XLCallVer 會傳回 1280 = 0x0500十六進制 = 5 x 256,這表示 Excel 第 5 版。 從 Excel 2007 開始,它會傳回 3072 = 0x0c00 十六進位 = 12 x 256,這同樣表示第 12 版。

雖然您可以使用此值來判斷新的 C API 是否可在運行時間使用,但您可能想要使用 Excel4(xlfGetWorkspace, &version, 1, &arg)來偵測執行中的 Excel 版本,其中 arg 是設為 2 的數值 XLOPER 。 函式會傳回字串 XLOPER 版本,然後可以強制轉為整數。 依賴 Excel 版本而非 C API 版本的原因是,載入宏可能也需要偵測 Excel 2000、Excel 2002 和 Excel 2003 之間有差異。 例如,已對某些統計數據函式的精確度進行變更。

另請參閱