VC 操作 Excel 自動化輸出,調用 _Application::Quit() 後 Excel 進程殘留,程序退出時才關閉。註釋掉 Range::GetItem() 即可正常關閉。
GetItem() 內部創建 COM 代理對象導致引用計數未正確釋放,Excel 進程無法立即退出。具體 COM 內部機制不明,但規避該方法可解決。
BOOL CAutomationExcel::GetValue(int iRow, int iColStart, int iColStop, CStringArray& strArray) {
int iCount = iColStop - iColStart + 1;
if (iCount <= 0) return FALSE;
CString strStart = GetItemName(iRow, iColStart);
CString strEnd = GetItemName(iRow, iColStop);
_variant_t start, stop;
start.vt = VT_BSTR; start.bstrVal = strStart.AllocSysString();
stop.vt = VT_BSTR; stop.bstrVal = strEnd.AllocSysString();
// 創建二維 SafeArray (1 行 × iCount 列)
_variant_t varRet; varRet.vt = VT_ARRAY | VT_VARIANT;
SAFEARRAYBOUND sab[2] = { {1, 1}, {1, (ULONG)iCount} };
varRet.parray = SafeArrayCreate(VT_VARIANT, 2, sab);
Range range;
range.AttachDispatch(m_Range.GetRange(start, stop));
if (!range.m_lpDispatch) return FALSE;
varRet = range.GetValue2(); // 一次性讀取整塊區域
range.ReleaseDispatch();
strArray.RemoveAll();
if (iCount == 1) {
CString str; CVariantCast(varRet).GetValue(str); strArray.Add(str);
} else {
for (int i = 1; i <= iCount; ++i) {
long idx[2] = {1, i};
_variant_t tmp; SafeArrayGetElement(varRet.parray, idx, &tmp);
CString str; CVariantCast(tmp).GetValue(str); strArray.Add(str);
}
}
return TRUE;
}
GetRange(start, stop) 獲取整個區域 Range 對象。GetValue2() 直接返回 SafeArray,避免逐個 GetItem() 產生代理對象。SafeArrayGetElement 遍歷數組提取數據,類型安全。ReleaseDispatch() 及時釋放 Range 接口指針。替換後 Quit() 即時生效,Excel 進程乾淨退出,無殘留。