首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

VC++ Excel 自動化:Quit() 無法關閉進程的根因與安全數組解決方案

     編輯:關於C語言

問題現象

VC 操作 Excel 自動化輸出,調用 _Application::Quit() 後 Excel 進程殘留,程序退出時才關閉。註釋掉 Range::GetItem() 即可正常關閉。

根因分析

GetItem() 內部創建 COM 代理對象導致引用計數未正確釋放,Excel 進程無法立即退出。具體 COM 內部機制不明,但規避該方法可解決。

解決方案:用 SafeArray 批量讀取替代 GetItem


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 進程乾淨退出,無殘留。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved