適用於:Excel 2013 |Office 2013 |Visual Studio
如果您想要建立有效率且穩定的 XLL,記憶體管理是最重要的考慮。 如果無法妥善管理記憶體,可能會導致Microsoft Excel 中發生一系列的問題,從低效率的記憶體配置和初始化、小型記憶體流失等次要問題,到 Excel 不穩定等主要問題。
記憶體管理錯誤是嚴重載入宏相關問題最常見的來源。 因此,您應該使用記憶體管理的一致且妥善思考的策略來建置專案。
透過引進多線程活頁簿重新計算,記憶體管理在 Microsoft Office Excel 2007 中變得更複雜。 如果您想要建立和匯出安全線程工作表函式,您必須管理在多個線程爭用存取權時可能發生的衝突。
下列三種數據結構類型有記憶體考慮:
- XLOPERs 和 XLOPER12s
- 不在 XLOPER 或 XLOPER12 中的字串
- FP 和 FP12 陣 列
XLOPER/XLOPER12記憶體
XLOPER/ XLOPER12數據結構有幾個子類型,其中包含記憶體區塊的指標,也就是 xltypeStr) (字串串、xltypeMulti) (陣列,以及 xltypeRef) (外部參考。 另請注意, xltypeMulti 陣列可以包含字串 XLOPER/ XLOPER12, 進而指向其他記憶體區塊。
您可以透過數種方式建立 XLOPER/ XLOPER12 :
- 由 Excel 在準備要傳遞至 XLL 函式的自變數時使用
- 在 C API 呼叫中傳回 XLOPER 或 XLOPER12 時由 Excel 提供
- 建立要傳遞至 C API 呼叫的自變數時,由 DLL 提供
- 建立 XLL 函式傳回值時,由您的 DLL 傳回值
其中一個記憶體指標類型內的記憶體區塊可以透過數種方式配置:
- 它可以是 DLL 內任何函式程式碼外部的靜態區塊,在此情況下,您不需要配置或釋放記憶體。
- 它可以是 DLL 內某些函式程式代碼內的靜態區塊,在此情況下,您不需要配置或釋放記憶體。
- DLL 可以透過數種可能的方式動態配置和釋放它: malloc 和 free、 new 和 delete 等等。
- Excel 可以動態配置它。
假設 XLOPER/ XLOPER12 記憶體的可能來源數目,以及 XLOPER/ XLOPER12 可能已指派該記憶體的情況數目,此主旨看起來可能非常困難並不令人意外。 不過,如果您遵循數個規則和指導方針,複雜度可能會大幅降低。
使用 XLOPER/XLOPER12的規則
請勿嘗試釋放記憶體或覆寫以自變數形式傳遞至 XLL 函式XLOPER12的 XLOPER/ 。 您應該將這類自變數視為唯讀。 For more information, see "Returning XLOPER or XLOPER12 by Modifying Arguments in Place" in Known Issues in Excel XLL Development.
如果 Excel 已為 XLOPER/ 設定記憶體,XLOPER12在呼叫 C API 時傳回您的 DLL:
- 當您不再需要使用 xlFree 呼叫的 XLOPER/ XLOPER12時,必須釋放記憶體。 請勿使用任何其他方法,例如free或delete來釋放記憶體。
- 如果傳回的類型是 xltypeMulti,請勿覆寫陣列內的任何 XLOPER/ XLOPER12,特別是當它們包含字串時,尤其是您嘗試以字串覆寫的位置。
- 如果您想要將 XLOPER/ XLOPER12 傳回至 Excel 作為 DLL 函式的傳回值,您必須告訴 Excel,Excel 必須在完成時釋放記憶體。
您只能在建立為 C API 呼叫傳回值的 XLOPER/ XLOPER12上呼叫 xlFree。
如果您的 DLL 已為 XLOPER/ XLOPER12 配置記憶體,而您想要以 DLL 函式的傳回值傳回 Excel,您必須告訴 Excel DLL 必須釋放記憶體。
記憶體管理的指導方針
- 在您用來配置和釋放記憶體的方法中,在 DLL 中保持一致。 避免混合方法。 一個不錯的方法是在記憶體類別或結構中包裝您正在使用的方法,您可以在其中變更所使用的方法,而不需要在許多位置改變程序代碼。
- 當您在 DLL 中建立 xltypeMulti 陣列時,請以您為字串配置記憶體的方式保持一致:一律動態配置它們的記憶體,或一律使用靜態記憶體。 如果您這樣做,當您釋放記憶體時,您會知道您必須一律釋放或永不釋放字串。
- 當您複製 Excel 建立的 XLOPER/ XLOPER12時,請建立 Excel 配置記憶體的深層複本。
- 請勿將 Excel 配置的字串 XLOPER/ XLOPER12s 放在 xltypeMulti 陣列內。 建立字串的深層複本,並將指標儲存至陣列中的複本。
釋放 XLOPER/XLOPER12 記憶體 Excel-Allocated
請考慮下列 XLL 命令,此命令會使用 xlGetName 取得包含 DLL 路徑和檔名的字串,並使用 xlcAlert 將它顯示在警示對話框中。
int WINAPI show_DLL_name(void)
{
XLOPER12 xDllName;
if(Excel12(xlfGetName, &xDllName, 0) == xlretSuccess)
{
// Display the name.
Excel12(xlcAlert, 0, 1, &xDllName);
// Free the memory that Excel allocated for the string.
Excel12(xlFree, 0, 1, &xDllName);
}
return 1;
}
當函式不再需要 xDllName 所指向的記憶體時,可以使用 xlFree 函式的呼叫來釋放它,這是僅限 DLL 的 C API 函式之一。
xlFree 函式完整記載於函式參考一節中 (請參閱只能從 DLL 或 XLL) 呼叫的 C API 函式,但請注意下列事項:
- 您可以在 xlFree 的單一呼叫中將指標傳遞至多個 XLOPER/ XLOPER12,僅受限於 Excel 2003 中執行中 Excel (30 中支援的函數自變數數目,從 Excel 2007) 開始為 255。
- xlFree 會將包含的指標設定為 NULL ,以確保嘗試釋放已釋放的 XLOPER/ XLOPER12 是安全的。 xlFree 是唯一修改其自變數的 C API 函式。
- 您可以在用於 C API 呼叫傳回值的任何 XLOPER/ XLOPER12上安全地呼叫 xlFree,無論其是否包含記憶體指標。
傳回 Excel 要釋放的 XLOPER/XLOPER12s
假設您想要修改上一節中的範例命令,並將它變更為工作表函式,該工作表函式會在傳遞 Booleantrue 自變數時傳回 DLL 路徑和檔名,否則 #N/A 。 很明顯地,您無法在將字串記憶體傳回Excel之前,呼叫 xlFree 來釋放字串記憶體。 不過,如果未在某個時間點釋出,則每次呼叫函式時,載入宏會流失記憶體。 若要解決此問題,您可以在 XLOPER/ XLOPER12的 xltype 欄位中設定位,在 xlcall.h 中定義為 xlbitXLFree。 設定此設定會告訴 Excel,當傳回的記憶體完成複製出值時,它必須釋放該記憶體。
範例
下列程式代碼範例顯示上一節中的 XLL 命令已轉換成 XLL 工作表函式。
LPXLOPER12 WINAPI get_DLL_name(int calculation_trigger)
{
static XLOPER12 xRtnValue; // Not thread-safe
Excel12(xlfGetName, &xRtnValue, 0);
// If xlfGetName failed, xRtnValue will be #VALUE!
if(xRtnValue.xltype == xltypeStr)
{
// Tell Excel to free the string memory after
// it has copied out the return value.
xRtnValue.xltype |= xlbitXLFree;
}
return &xRtnValue;
}
使用 XLOPER/ XLOPER12的 XLL 函式必須宣告為採用 XLOPER/ XLOPER12的指標並傳回。 在此範例中,函式內的靜態 XLOPER12 使用並不安全線程。 您可能不正確地將此函式註冊為安全線程,但您可能會在另一個線程完成之前,讓某個線程覆寫 xRtnValue 。
您必須在呼叫配置它的 Excel 回呼之後,設定 xlbitXLFree 。 如果您在此之前設定它,它會被覆寫,而且沒有您想要的效果。 如果您想要在對另一個 C API 函式的呼叫中使用值做為自變數,然後再將它傳回至工作表,您應該在任何這類呼叫之後設定這個位。 否則,您會混淆不會遮罩此位的函式,然後再檢查 XLOPER/ XLLOPER12 類型。
傳回要由 DLL 釋放的 XLOPER/XLOPER12s
當您的 XLL 已配置 XLOPER/ XLOPER12的記憶體,並想要將它傳回 Excel 時,就會發生類似的問題。 Excel 會辨識可在 XLOPER/ XLOPER12的 xltype 欄位中設定的另一個位,在 xlcall.h 中定義為 xlbitDLLFree。
當 Excel 收到具有此位集的 XLOPERXLOPER12時,它會嘗試呼叫應該由 XLOPER/ ) xlAutoFree (XLL 所導出的函式,或針對XLOPER12的) 呼叫 xlAutoFree12 (。 此函式會在函式參考中更完整地描述 (請參閱 載入宏管理員和 XLL 介面函 式) ,但此處提供最低實作的範例。 其目的是要以與原先配置方式一致的方式釋放 XLOPER/ XLOPER12 記憶體。
範例
下列範例函式與上一個函式相同,不同之處在於它包含 DLL 名稱前面的文字「此 DLL 的完整路徑名稱為 」。
#include <string.h>
LPXLOPER12 WINAPI get_DLL_name_2(int calculation_trigger)
{
static XLOPER12 xRtnValue; // Not thread-safe
Excel12(xlfGetName, &xRtnValue, 0);
// If xlfGetName failed, xRtnValue will be #VALUE!
if(xRtnValue.xltype != xltypeStr)
return &xRtnValue;
// Make a copy of the DLL path and file name.
wchar_t *leader = L"The full pathname for this DLL is ";
size_t leader_len = wcslen(leader);
size_t dllname_len = xRtnValue.val.str[0];
size_t msg_len = leader_len + dllname_len;
wchar_t *msg_text = (wchar_t *)malloc(msg_len + 1);
wcsncpy_s(msg_text + 1, leader, leader_len);
wcsncpy_s(msg_text + 1 + leader_len, xRtnValue.val.str + 1,
dllname_len);
msg_text[0] = msg_len;
// Now the original string has been copied Excel can free it.
Excel12(xlFree, 0, 1, &xRtnValue);
// Now reuse the XLOPER12 for the new string.
xRtnValue.val.str = msg_text;
// Tell Excel to call back into the DLL to free the string
// memory after it has copied out the return value.
xRtnValue.xltype = xltypeStr | xlbitDLLFree;
return &xRtnValue;
}
匯出先前函式之 XLL 中 xlAutoFree12 的最小足夠實作會如下所示。
void WINAPI xlAutoFree12(LPXLOPER12 p_oper)
{
if(p_oper->xltype == (xltypeStr | xlbitDLLFree))
free(p_oper->val.str);
}
只有在 XLL 只傳回 XLOPER12 字串,而且這些字串只使用 malloc 配置時,此實作才足夠。 請注意,測試
if(p_oper->xltype == xltypeStr)
在此情況下會失敗,因為 已設定 xlbitDLLFree 。
一般而言,應該實 作 xlAutoFree 和 xlAutoFree12 ,以便釋放與 XLL 建立 之 xltypeMulti 陣列和 xltypeRef 外部參考相關聯的記憶體。
您可以決定實作 XLL 函式,讓它們全部傳回動態配置的 XLOPER和 XLOPER12。 在此情況下,無論子類型為何,您都必須在所有這類 XLOPER和 XLOPER12上設定 xlbitDLLFree。 您也需要實作 xlAutoFree 和 xlAutoFree12 ,以便釋放此記憶體,以及 XLOPER/ XLOPER12內指向的任何記憶體。 這種方法是讓傳回值線程安全的一種方式。 例如,可以重寫先前的函式,如下所示。
#include <string.h>
LPXLOPER12 WINAPI get_DLL_name_3(int calculation_trigger)
{
// Thread-safe
LPXLOPER12 pxRtnValue = (LPXLOPER12)malloc(sizeof(XLOPER12));
Excel12(xlfGetName, pxRtnValue, 0);
// If xlfGetName failed, pxRtnValue will be #VALUE!
if(pxRtnValue->xltype != xltypeStr)
{
// Even though an error type does not point to memory,
// Excel needs to pass this oper to xlAutoFree12 to
// free pxRtnValue itself.
pxRtnValue->xltype |= xlbitDLLFree;
return pxRtnValue;
}
// Make a copy of the DLL path and file name.
wchar_t *leader = L"The full pathname for this DLL is ";
size_t leader_len = wcslen(leader);
size_t dllname_len = pxRtnValue->val.str[0];
size_t msg_len = leader_len + dllname_len;
wchar_t *msg_text = (wchar_t *)malloc(msg_len + 1);
wcsncpy_s(msg_text + 1, leader, leader_len);
wcsncpy_s(msg_text + 1 + leader_len, pxRtnValue->val.str + 1,
dllname_len);
msg_text[0] = msg_len;
// Now the original string has been copied Excel can free it.
Excel12(xlFree, 0, 1, pxRtnValue);
// Now reuse the XLOPER12 for the new string.
pxRtnValue->val.str = msg_text;
pxRtnValue->xltype = xltypeStr | xlbitDLLFree;
return pxRtnValue;
}
void WINAPI xlAutoFree12(LPXLOPER12 p_oper)
{
if(p_oper->xltype == (xltypeStr | xlbitDLLFree))
free(p_oper->val.str);
free(p_oper);
}
如需 xlAutoFree 和 xlAutoFree12 的詳細資訊,請參閱 xlAutoFree/xlAutoFree12。
傳回Modify-in-Place自變數
Excel 允許 XLL 函式藉由就地修改自變數來傳回值。 您只能使用以指標形式傳入的自變數來執行此動作。 若要像這樣運作,必須以告知 Excel 將修改哪個自變數的方式註冊函式。
所有可透過指標傳遞但特別適用於下列類型的數據類型,都支援這個傳回值的方法:
- 長度計數和以 Null 結尾的 ASCII 位元組字串
- 從 Excel 2007 開始 (長度計數和以 Null 結尾的 Unicode 寬字元字串)
- FP 浮點陣列
- 從 Excel 2007 開始 (FP12 浮點陣列)
注意事項
您不應該嘗試以這種方式傳回 XLOPER或 XLOPER12s。 如需詳細資訊,請 參閱 Excel XLL 開發中的已知問題。
使用這項技術的優點是 Excel 會配置傳回值的記憶體,而不是只使用 return 語句。 Excel 完成讀取傳回的數據之後,就會釋放記憶體。 這會將記憶體管理工作從 XLL 函式中移除。 這項技術是安全線程:如果 Excel 在不同的線程上同時呼叫,每個線程上的每個函數調用都有自己的緩衝區。
它特別適用於先前列出的數據類型,因為簡單字串和 FPFP12/ 陣列不存在呼叫回 DLL 以釋放 XLOPER/ XLOPER12的記憶體傳回後所存在的機制。 因此,傳回 DLL 建立的字串或浮點陣列時,您有下列選擇:
- 將永續性指標設定為動態配置的緩衝區,並傳回指標。 在下一次呼叫函式 (1 時,) 檢查指標是否為 Null, (2) 釋放上一個呼叫所配置的資源,並將指標重設為 null, (3) 針對新配置的記憶體區塊重複使用指標。
- 在不需要釋放的靜態緩衝區中建立字串和陣列,並傳回該緩衝區的指標。
- 就地修改自變數,將您的字串或陣列直接寫入 Excel 所設定的空間中。
否則,您必須建立 XLOPER/ XLOPER12,並使用 xlbitDLLFree 和 xlAutoFree/ xlAutoFree12 來釋放資源。
在您傳遞與傳回值相同類型的自變數時,最後一個選項可能是最簡單的選項。 要記住的重點是緩衝區大小有限,您必須非常小心,不要溢位它們。 發生此錯誤可能會使 Excel 當機。 接下來會討論字串和 FPFP12/ 陣列的緩衝區大小。
字串
字串記憶體管理的問題,可說是應用程式和載入宏不穩定的最常見原因。根據處理字串的各種方式,或許可以理解:以 null 終止或長度計算 (或兩者) ;靜態或動態緩衝區;固定長度或幾乎無限制的長度;操作系統受控記憶體 (例如 OLE Bstr) 或 Unmanaged 字串;依此類推。
C/C++程序設計人員最熟悉以 Null 結尾的字串。 標準 C 連結庫的設計目的是要使用這類字串。 程序代碼中的靜態字串常值會編譯成以 Null 結尾的字串。 或者,Excel 會使用長度計算的字串,這些字串不是一般以 Null 終止。 這些事實的組合需要在 DLL/XLL 中,針對如何處理字串和字串記憶體,採用清楚且一致的方法。
最常見的問題如下:
- 將 Null 或無效指標傳遞至預期有有效指標且不會或無法檢查指標本身有效性的函式。
- 未或無法根據所寫入的字串長度檢查緩衝區長度的函式,使字串緩衝區的界限溢位。
- 嘗試釋放靜態、已釋放或未以與釋放方式一致的方式配置的字串緩衝區內存。
- 因配置字串而導致的記憶體流失,然後不會釋放,通常是在經常呼叫的函式中。
字串規則
如同 XLOPER/ XLOPER,您應該遵循一些規則和指導方針。 指導方針與上一節中所提供的相同。 這裡的規則是專門針對字串的規則延伸。
規則:
- 請勿嘗試釋放記憶體或覆寫字串 XLOPER/ XLOPER12或以自變數形式傳遞給 XLL 函式的簡單長度計數或以 Null 結尾的字串。 您應該將這類自變數視為唯讀。
- Excel 會為字串 XLOPER/ 配置記憶體,XLOPER12 C API 回調函式的傳回值、使用 xlFree 來釋放它,或是從 XLL 函式將 xlbitXLFree 傳回 Excel 時設定 xlbitXLFree。
- DLL 會在其中動態配置 XLOPER/ XLOPER12的字串緩衝區、以與您在完成時配置的方式一致的方式釋放它;如果從 XLL 函式傳回 Excel,然後在 xlAutoFree/ xlAutoFree12 中釋放它,則設定 xlbitDLLFree。
- 如果 Excel 已在呼叫 C API 時,為傳回至 DLL 的 xltypeMulti 陣列配置記憶體,請勿覆寫數位內的任何字串 XLOPER/ XLOPER12s。 這類陣列只能使用 xlFree 釋放,如果由 XLL 函式傳回,則必須藉由設定 xlbitXLFree 來釋放。
支援的字串類型
C API xltypeStr XLOPER/XLOPER12s
位元組字串: XLOPER | 寬字元字串: XLOPER12 |
---|---|
Excel 的所有版本 | 從 Excel 2007 開始 |
最大長度:255 個延伸 ASCII 位元組 | 最大長度 32,767 Unicode 字元 |
第一 (不帶正負號的) 位元組 = 長度 | 第一個 Unicode 字元 = 長度 |
重要事項
請勿假設 XLOPER 或 XLOPER12 字串的 null 終止。
C/C++字串
位元組字串 | 寬字元字串 |
---|---|
以 Null 結尾的 (字元 *) “C” 最大長度:255 個延伸 ASCII 位元組 | 以 Null 結尾的 (wchar_t *) “C%” 最大長度 32,767 個 Unicode 字元 |
長度計數 (不帶正負號的字元 *) “D” | 長度計算 (wchar_t *) “D%” |
xltypeMulti XLOPER/XLOPER12 陣列中的字串
在數種情況下,Excel 會建立 xltypeMulti 陣列以用於 DLL/XLL。 數個 XLM 資訊函式會傳回這類數位。 例如,C API 函 式 xlfGetWorkspace 在傳遞自變數 44 時,會傳回數位列,其中包含描述所有目前已註冊 DLL 程式的字串。 C API 函 式 xlfDialogBox 會傳回其陣列自變數的修改複本,其中包含字串的深層複本。 XLL 遇到 xltypeMulti 陣列的最常見方式可能是將它當做自變數傳遞至 XLL 函式,或是從範圍參考將其強制轉換成此類型。 在後者的情況下,Excel 會在來源數據格中建立字串的深層複本,並指向數位內的字串。
當您想要在 DLL 中修改這些字串時,您應該建立自己的深層複本。 當您建立自己的 xltypeMulti 陣列時,不應該將 Excel 配置的字串 XLOPER/ XLOPER12放在其中。 您稍後不會正確釋放這些風險,或完全不會釋出這些風險。 同樣地,您應該建立字串的深層複本,並將指標儲存至陣列中的複本。
範例
下列範例函式會建立長度計算 Unicode 字串的動態配置複本。 請注意,呼叫端最終必須使用 delete[] 釋放在此範例中配置的記憶體,而且不會假設來源字串為 Null 終止。 為了安全起因,複製字串會視需要被截斷,而且不會終止 Null。
#include <string.h>
#define MAX_V12_STRBUFFLEN 32678
wchar_t * deep_copy_wcs(const wchar_t *p_source)
{
if(!p_source)
return NULL;
size_t source_len = p_source[0];
bool truncated = false;
if(source_len >= MAX_V12_STRBUFFLEN)
{
source_len = MAX_V12_STRBUFFLEN - 1; // Truncate the copy
truncated = true;
}
wchar_t *p_copy = new wchar_t[source_len + 1];
wcsncpy_s(p_copy, p_source, source_len + 1);
if(truncated)
p_copy[0] = source_len;
return p_copy;
}
然後,這個函式可以安全地用來複製 XLOPER12,如下列可導出的 XLL 函式所示,如果是字串,則會傳回其自變數的複本。 所有其他類型都會以零長度字串傳回。 請注意,不會處理範圍—函式會傳回 #VALUE!。 函式必須註冊為採用類型U自變數,以便以值形式傳入參考。 這相當於內建工作表函 式 T () ,不同之處在於 AsText 也會將錯誤轉換成長度為零的字串。 此程式代碼範例假設 xlAutoFree12 會使用 delete 釋放傳入的指標及其內容。
LPXLOPER12 WINAPI AsText(LPXLOPER12 pArg)
{
LPXLOPER12 pRtnVal = new XLOPER12;
// If the input was an array, only operate on the top-left element.
LPXLOPER *pTemp;
if(pArg->xltype == xltypeMulti)
pTemp = pArg->val.array.lparray;
else
pTemp = pArg;
switch(pTemp->xltype)
{
case xltypeErr:
case xltypeNum:
case xltypeMissing:
case xltypeNil:
case xltypeBool:
pRtnVal->xltype = xltypeStr | xlbitDLLFree;
pRtnVal->val.str = deep_copy_wcs(L"\000");
return pRtnVal;
case xltypeStr:
pRtnVal->xltype = xltypeStr | xlbitDLLFree;
pRtnVal->val.str = deep_copy_wcs(pTemp->val.str);
return pRtnVal;
default: // xltypeSRef, xltypeRef, xltypeFlow, xltypeInt
pRtnVal->xltype = xltypeErr | xlbitDLLFree;
pRtnVal->val.err = xlerrValue;
return pRtnVal;
}
}
傳回修改就地字串自變數
註冊為 類型 F、 G、 F%和 G% 的 自變數可以就地修改。 當 Excel 準備這些類型的字串自變數時,它會建立最大長度緩衝區。 然後,它會將自變數字串複製到其中,即使此字串非常短。 這可讓 XLL 函式將其傳回值直接寫入相同的記憶體中。
針對這些類型所設定的緩衝區大小如下:
- 位元組字串: 256 位元組,包括長度計數器 (類型 G) 或 null-terminat (類型 F) 。
- Unicode 字串: 32,768 個寬字元 (65,536 個字節) 包括長度計數器 (類型 G%) 或 null 終止 (類型 F%) 。
注意事項
您無法直接從 Visual Basic for Applications (VBA) 呼叫這類函式,因為您無法確定已配置夠大的緩衝區。 如果您已明確傳遞夠大的緩衝區,則只能安全地從另一個 DLL 呼叫這類函式。
以下是使用標準連結庫函式 wcsrev 反轉傳入 Null 終止寬字元字串的 XLL 函式範例。 在此情況下,自變數會註冊為類型 F%。
void WINAPI reverse_text_xl12(wchar_t *text)
{
_wcsrev(text);
}
永續性記憶體 (二進位名稱)
二進位名稱會定義二進位檔區塊,也就是與活頁簿一起儲存的非結構化數據區塊。 它們是使用 xlDefineBinaryName 函式所建立,而且會使用 xlGetBinaryName 函式來擷取數據。 這兩個函式都會在函式參考中詳細說明 (請參閱 只能從 DLL 或 XLL) 呼叫的 C API 函式,並同時使用 xltypeBigDataXLOPER/ XLOPER12。
如需限制二進位名稱實際應用的已知問題相關信息,請參閱 Excel XLL 開發中的已知問題。
Excel Stack
Excel 與其載入的所有 DLL 共用其堆疊空間。 堆疊空間通常足以供一般使用,而且只要您遵循一些指導方針,就不需要擔心它:
- 請勿將非常大的結構當做自變數傳遞給堆疊上的函式。 請改為傳遞指標或參考。
- 請勿傳回堆疊上的大型結構。 傳回靜態或動態配置記憶體的指標,或使用以傳址方式傳遞的自變數。
- 請勿在函式程式代碼中宣告非常大的自動變數結構。 如果您需要,請將它們宣告為靜態。
- 除非您確定遞歸的深度一律為淺層,否則請勿以遞歸方式呼叫函式。 請嘗試改用迴圈。
當 DLL 使用 C API 回呼 Excel 時,Excel 會先檢查堆疊上是否有足夠的空間,以進行最差的使用量呼叫。 如果它認為空間可能不足,則呼叫將會失敗,以確保安全,即使實際上可能有足夠的空間供該特定呼叫使用。 在此情況下,回呼會傳回 xlretFailed 程式代碼。 若要一般使用 C API 和堆疊,這不太可能是 C API 呼叫失敗的原因。
如果您擔心,或只是好奇,或想要排除堆疊空間不足,作為無法解釋失敗的原因,您可以藉由呼叫 xlStack 函式來找出有多少堆棧空間。