You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Visual C++(COM)设置Excel单元格区域颜色报错求助

问题描述

使用Visual C++通过COM操作Excel,已成功打开Excel并获取单元格区域,但设置单元格区域颜色时返回“Object is not connected to server”错误。相关代码如下:

// AutoWrap函数代码
HRESULT AutoWrap(int autoType, VARIANT* pvResult, IDispatch* pDisp, LPOLESTR ptName, int cArgs...) {
// Begin variable-argument list...
va_list marker;
va_start(marker, cArgs);

if (!pDisp) {
    return E_INVALIDARG;
}

// Variables used...
DISPPARAMS dp = { NULL, NULL, 0, 0 };
DISPID dispidNamed = DISPID_PROPERTYPUT;
DISPID dispID;
HRESULT hr;
char buf[200];
char szName[200];

// Convert down to ANSI
WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);

// Get DISPID for name passed...
hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);
if (FAILED(hr)) {
    sprintf(buf, "IDispatch::GetIDsOfNames(\"%s\") failed w/err 0x%08lx", szName, hr);        
    return hr;
}

// Allocate memory for arguments...
VARIANT* pArgs = new VARIANT[cArgs + 1];
// Extract arguments...
for (int i = 0; i < cArgs; i++) {
    pArgs[i] = va_arg(marker, VARIANT);
}

// Build DISPPARAMS
dp.cArgs = cArgs;
dp.rgvarg = pArgs;

// Handle special-case for property-puts!
if (autoType & DISPATCH_PROPERTYPUT) {
    dp.cNamedArgs = 1;
    dp.rgdispidNamedArgs = &dispidNamed;
}

// Make the call!
hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, autoType, &dp, pvResult, NULL, NULL);
if (FAILED(hr)) {
    sprintf(buf, "IDispatch::Invoke(\"%s\")=%08lx failed w/err 0x%08lx", szName, dispID, hr);        
    return hr;
}
// End variable-argument section...
va_end(marker);

delete[] pArgs;

return hr;
}

// OpenExcel函数代码
HRESULT OpenExcel(const CATUnicodeString usFilePath, CATBoolean bVisibility)
{
HRESULT hr = E_FAIL;
if (!_pExcelApp)
{
    if(FAILED(Initialize(bVisibility)))
        return hr;
}

VARIANT vResult,vResult2;
VariantInit(&vResult);

hr = AutoWrap(DISPATCH_PROPERTYGET, &vResult, _pExcelApp, L"Workbooks", 0);
if (FAILED(hr))
    return hr;

_pExcelBooks = vResult.pdispVal;

CATBSTR bstrFilePath;
usFilePath.ConvertToBSTR(&bstrFilePath);

VARIANT vFileName;
vFileName.vt = VT_BSTR;
vFileName.bstrVal = bstrFilePath;

VariantInit(&vResult2);
hr = AutoWrap(DISPATCH_PROPERTYGET, &vResult2, _pExcelBooks, L"Open", 1,vFileName);
if (FAILED(hr))
{
    VariantClear(&vFileName);
    return hr;
}

_pExcelBook = vResult2.pdispVal;
VariantClear(&vFileName);
VariantClear(&vResult2);
VariantClear(&vResult);


return hr;
}

// Initialize函数代码
HRESULT Initialize(CATBoolean bVisibility)
{
CoInitializeEx(NULL, COINITBASE_MULTITHREADED);

CLSID clsid;
HRESULT hr = E_FAIL;

LPCOLESTR progID = L"Excel.Application";
hr = CLSIDFromProgID(progID, &clsid);
if (FAILED(hr))
    return hr;

hr = CoCreateInstance(clsid,NULL,CLSCTX_LOCAL_SERVER, IID_IDispatch, (void**)&_pExcelApp);
if (FAILED(hr))
{
    _pExcelApp = NULL;
    return hr;
}

hr = SetVisibility(bVisibility);
return hr;
}

// SetVisibility函数代码
HRESULT SetVisibility(CATBoolean bVisibility)
{
HRESULT hr = E_FAIL;
if (!_pExcelApp)
{
    return hr;
}

VARIANT vVar;
vVar.vt = VT_I4;
vVar.lVal = bVisibility;

hr = AutoWrap(DISPATCH_PROPERTYPUT, NULL, _pExcelApp, L"Visible", 1, vVar);

return hr;
}

// SetProperty函数代码
HRESULT SetProperty(CATUnicodeString usRange)
{
HRESULT hr = E_FAIL;
IDispatch* _pExcelRange;
CATBSTR bstrRange;
usRange.ConvertToBSTR(&bstrRange);

VARIANT parm;
parm.vt = VT_BSTR;
parm.bstrVal = bstrRange;

VARIANT result;
VariantInit(&result);
hr = AutoWrap(DISPATCH_PROPERTYGET, &result, _pExcelSheet, L"Range", 1, parm);
VariantClear(&parm);

_pExcelRange = result.pdispVal;
{
    IDispatch* pXlInside;
    {
        VARIANT result;
        VariantInit(&result);
        hr = AutoWrap(DISPATCH_PROPERTYGET, &result, _pExcelRange, L"Interior", 0);
        pXlInside = result.pdispVal;
        VariantClear(&result);
        if (FAILED(hr))
            return hr;            
    }
    {
        VARIANT color;
        color.vt = VT_I4;
        color.lVal = long(RGB(255, 255, 0));
        VARIANT result;
        VariantInit(&result);
        hr = AutoWrap(DISPATCH_PROPERTYPUT, &result, pXlInside, L"Color", 1, color); //This returns "Object is not connected to server error"

        VariantClear(&result);
        VariantClear(&color);
        if (FAILED(hr))
            return hr;
    }        
    pXlInside->Release();
    _pExcelRange->Release();  
    
}
return hr;
}

调用代码:

int main()
{
    OpenExcel("FilePath");
    SetProperty("A1:G1");
}
错误分析与修复方案

1. 线程模型不匹配

Excel的COM对象属于单线程单元(STA),但代码中使用COINITBASE_MULTITHREADED(多线程单元MTA)初始化COM库,跨单元调用会导致对象代理连接异常,触发“Object is not connected to server”错误。

修复:将Initialize函数中的COM初始化改为STA模型:

HRESULT Initialize(CATBoolean bVisibility)
{
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    if (FAILED(hr))
        return hr;

    CLSID clsid;
    LPCOLESTR progID = L"Excel.Application";
    hr = CLSIDFromProgID(progID, &clsid);
    if (FAILED(hr))
        return hr;

    hr = CoCreateInstance(clsid,NULL,CLSCTX_LOCAL_SERVER, IID_IDispatch, (void**)&_pExcelApp);
    if (FAILED(hr))
    {
        _pExcelApp = NULL;
        CoUninitialize();
        return hr;
    }

    hr = SetVisibility(bVisibility);
    return hr;
}

2. Workbooks.Open调用类型错误

Workbooks.Open是方法而非属性,代码中使用DISPATCH_PROPERTYGET调用会导致返回的Workbook对象引用无效,后续依赖该对象的操作都会失败。

修复:将OpenExcel中调用Open的类型改为DISPATCH_METHOD,同时初始化_pExcelSheet全局变量:

HRESULT OpenExcel(const CATUnicodeString usFilePath, CATBoolean bVisibility)
{
    HRESULT hr = E_FAIL;
    if (!_pExcelApp)
    {
        if(FAILED(Initialize(bVisibility)))
            return hr;
    }

    VARIANT vResult;
    VariantInit(&vResult);

    // 获取Workbooks集合
    hr = AutoWrap(DISPATCH_PROPERTYGET, &vResult, _pExcelApp, L"Workbooks", 0);
    if (FAILED(hr))
        return hr;
    _pExcelBooks = vResult.pdispVal;
    VariantClear(&vResult);

    CATBSTR bstrFilePath;
    usFilePath.ConvertToBSTR(&bstrFilePath);

    VARIANT vFileName;
    vFileName.vt = VT_BSTR;
    vFileName.bstrVal = bstrFilePath;

    // 使用DISPATCH_METHOD调用Open方法
    hr = AutoWrap(DISPATCH_METHOD, &vResult, _pExcelBooks, L"Open", 1, vFileName);
    if (FAILED(hr))
    {
        VariantClear(&vFileName);
        return hr;
    }
    _pExcelBook = vResult.pdispVal;
    VariantClear(&vFileName);
    VariantClear(&vResult);

    // 初始化_pExcelSheet,获取活动工作表
    hr = AutoWrap(DISPATCH_PROPERTYGET, &vResult, _pExcelBook, L"ActiveSheet", 0);
    if (FAILED(hr))
        return hr;
    _pExcelSheet = vResult.pdispVal;
    VariantClear(&vResult);

    return hr;
}

3. _pExcelSheet未初始化

SetProperty函数中直接使用_pExcelSheet但未赋值,导致获取Range的操作实际是基于空指针,后续对象链全部无效。

修复:在OpenExcel中从打开的Workbook获取工作表对象(如上述代码中的ActiveSheet),确保_pExcelSheet有效。

4. Variant清理与引用计数问题

获取Range和Interior对象后,未及时清理Variant或处理引用计数,可能导致对象提前释放。

修复:调整SetProperty中的Variant清理时机,并增加空指针检查:

HRESULT SetProperty(CATUnicodeString usRange)
{
    HRESULT hr = E_FAIL;
    if (!_pExcelSheet)
        return hr;

    IDispatch* _pExcelRange = nullptr;
    CATBSTR bstrRange;
    usRange.ConvertToBSTR(&bstrRange);

    VARIANT parm;
    parm.vt = VT_BSTR;
    parm.bstrVal = bstrRange;

    VARIANT result;
    VariantInit(&result);
    hr = AutoWrap(DISPATCH_PROPERTYGET, &result, _pExcelSheet, L"Range", 1, parm);
    VariantClear(&parm);
    if (FAILED(hr))
        return hr;

    _pExcelRange = result.pdispVal;
    VariantClear(&result); // 保存指针后清理Variant

    IDispatch* pXlInside = nullptr;
    VariantInit(&result);
    hr = AutoWrap(DISPATCH_PROPERTYGET, &result, _pExcelRange, L"Interior", 0);
    if (FAILED(hr))
    {
        _pExcelRange->Release();
        return hr;
    }
    pXlInside = result.pdispVal;
    VariantClear(&result);

    VARIANT color;
    color.vt = VT_I4;
    color.lVal = static_cast<long>(RGB(255, 255, 0));
    // 设置Color无需返回值,pvResult传NULL
    hr = AutoWrap(DISPATCH_PROPERTYPUT, nullptr, pXlInside, L"Color", 1, color);
    VariantClear(&color);

    // 释放对象
    if (pXlInside)
        pXlInside->Release();
    if (_pExcelRange)
        _pExcelRange->Release();

    return hr;
}

5. 程序结束时释放资源

主函数中需释放所有全局COM对象并调用CoUninitialize,避免资源泄漏:

int main()
{
    OpenExcel(L"你的Excel文件路径", TRUE);
    SetProperty(L"A1:G1");

    // 释放全局COM对象
    if (_pExcelSheet)
        _pExcelSheet->Release();
    if (_pExcelBook)
        _pExcelBook->Release();
    if (_pExcelBooks)
        _pExcelBooks->Release();
    if (_pExcelApp)
        _pExcelApp->Release();
    CoUninitialize();

    return 0;
}

内容的提问来源于stack exchange,提问作者usmanharoon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 11:23:10