C ++未处理的异常 - 堆已损坏

时间:2014-09-19 16:09:24

标签: excel visual-c++ automation

我正在努力解决间歇性的C ++应用程序崩溃问题。 我不是C ++程序员,但我的任务是解决这个问题,所以非常希望你能帮助我。

通常应用程序运行良好,然后偶尔崩溃,但有例外。

从运行exe进入调试时,突出显示的代码行似乎有问题 - 请看第一个屏幕截图。

我在第二个屏幕截图中扩展了一些本地人。

这行代码调用函数'ClearVariant',该函数的代码如下:

/*
*  ClearVariant
*
*  Zeros a variant structure without regard to current contents
*/
void CXLAutomation::ClearVariant(VARIANTARG *pvarg)
{
    pvarg->vt = VT_EMPTY;
    pvarg->wReserved1 = 0;
    pvarg->wReserved2 = 0;
    pvarg->wReserved3 = 0;
    pvarg->lVal = 0;

}

整个cpp文件位于帖子的末尾。 OpenExcelFile是导致此问题的功能 - 正如您可以从屏幕截图中的调用堆栈中那样。

Exception - debugger screen shot

Exception - locals expanded

// XLAutomation.cpp: implementation of the CXLAutomation class.
//This is C++ modification of the AutoXL C-sample from 
//Microsoft Excel97 Developer Kit, Microsoft Press 1997 
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
//#include "XLAutomationTester.h"
#include "XLAutomation.h"
#include <ole2ver.h>
#include <string.h>
#include <winuser.h>
#include <stdio.h>
#include <string>


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
/*
 *  Arrays of argument information, which are used to build up the arg list
 *  for an IDispatch call.  These arrays are statically allocated to reduce
 *  complexity, but this code could be easily modified to perform dynamic
 *  memory allocation.
 *
 *  When arguments are added they are placed into these arrays.  The
 *  Vargs array contains the argument values, and the lpszArgNames array
 *  contains the name of the arguments, or a NULL if the argument is unnamed.
 *  Flags for the argument such as NOFREEVARIANT are kept in the wFlags array.
 *
 *  When Invoke is called, the names in the lpszArgNames array are converted
 *  into the DISPIDs expected by the IDispatch::Invoke function.  The
 *  IDispatch::GetIDsOfNames function is used to perform the conversion, and
 *  the resulting IDs are placed in the DispIds array.  There is an additional
 *  slot in the DispIds and lpszArgNames arrays to allow for the name and DISPID
 *  of the method or property being invoked.
 *  
 *  Because these arrays are static, it is important to call the ClearArgs()
 *  function before setting up arguments.  ClearArgs() releases any memory
 *  in use by the argument array and resets the argument counters for a fresh
 *  Invoke.
 */
//int           m_iArgCount;
//int           m_iNamedArgCount;
//VARIANTARG    m_aVargs[MAX_DISP_ARGS];
//DISPID        m_aDispIds[MAX_DISP_ARGS + 1];      // one extra for the member name
//LPOLESTR  m_alpszArgNames[MAX_DISP_ARGS + 1]; // used to hold the argnames for GetIDs
//WORD      m_awFlags[MAX_DISP_ARGS];
//////////////////////////////////////////////////////////////////////

CXLAutomation::CXLAutomation()
{
    m_pdispExcelApp = NULL;
    m_pdispWorkbook = NULL;
    m_pdispWorksheet = NULL;
    m_pdispActiveChart = NULL;
    InitOLE();
    StartExcel();
    //SetExcelVisible(TRUE);
    //CreateWorkSheet();
    //CreateXYChart();
}

CXLAutomation::CXLAutomation(BOOL bVisible)
{
    m_pdispExcelApp = NULL;
    m_pdispWorkbook = NULL;
    m_pdispWorksheet = NULL;
    m_pdispActiveChart = NULL;
    InitOLE();
    StartExcel();
    SetExcelVisible(bVisible);
    CreateWorkSheet();
    //CreateXYChart();
}

CXLAutomation::~CXLAutomation()
{
    //ReleaseExcel();
    ReleaseDispatch();
    OleUninitialize();
}

BOOL CXLAutomation::InitOLE()
{
    DWORD dwOleVer;

    dwOleVer = CoBuildVersion();

    // check the OLE library version
    if (rmm != HIWORD(dwOleVer)) 
    {
        MessageBox(NULL, _T("Incorrect version of OLE libraries."), "Failed", MB_OK | MB_ICONSTOP);
        return FALSE;
    }

    // could also check for minor version, but this application is
    // not sensitive to the minor version of OLE

    // initialize OLE, fail application if we can't get OLE to init.
    if (FAILED(OleInitialize(NULL))) 
    {
        MessageBox(NULL, _T("Cannot initialize OLE."), "Failed", MB_OK | MB_ICONSTOP);
        return FALSE;
    }


    return TRUE;

}

BOOL CXLAutomation::StartExcel()
{
    CLSID clsExcelApp;

    // if Excel is already running, return with current instance
    if (m_pdispExcelApp != NULL)
        return TRUE;

    /* Obtain the CLSID that identifies EXCEL.APPLICATION
     * This value is universally unique to Excel versions 5 and up, and
     * is used by OLE to identify which server to start.  We are obtaining
     * the CLSID from the ProgID.
     */
    if (FAILED(CLSIDFromProgID(L"Excel.Application", &clsExcelApp))) 
    {
        MessageBox(NULL, _T("Cannot obtain CLSID from ProgID"), "Failed", MB_OK | MB_ICONSTOP);
        return FALSE;
    }

    // start a new copy of Excel, grab the IDispatch interface
    if (FAILED(CoCreateInstance(clsExcelApp, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void**)&m_pdispExcelApp))) 
    {
        MessageBox(NULL, _T("Cannot start an instance of Excel for Automation."), "Failed", MB_OK | MB_ICONSTOP);
        return FALSE;
    }

    return TRUE;

}

/*******************************************************************
 *
 *                              INVOKE
 *
 *******************************************************************/

/*
 *  INVOKE
 *
 *  Invokes a method or property.  Takes the IDispatch object on which to invoke,
 *  and the name of the method or property as a String.  Arguments, if any,
 *  must have been previously setup using the AddArgumentXxx() functions.
 *
 *  Returns TRUE if the call succeeded.  Returns FALSE if an error occurred.
 *  A messagebox will be displayed explaining the error unless the DISP_NOSHOWEXCEPTIONS
 *  flag is specified.  Errors can be a result of unrecognized method or property
 *  names, bad argument names, invalid types, or runtime-exceptions defined
 *  by the recipient of the Invoke.
 *
 *  The argument list is reset via ClearAllArgs() if the DISP_FREEARGS flag is
 *  specified.  If not specified, it is up to the caller to call ClearAllArgs().
 *
 *  The return value is placed in pvargReturn, which is allocated by the caller.
 *  If no return value is required, pass NULL.  It is up to the caller to free
 *  the return value (ReleaseVariant()).
 *
 *  This function calls IDispatch::GetIDsOfNames for every invoke.  This is not
 *  very efficient if the same method or property is invoked multiple times, since
 *  the DISPIDs for a particular method or property will remain the same during
 *  the lifetime of an IDispatch object.  Modifications could be made to this code
 *  to cache DISPIDs.  If the target application is always the same, a similar
 *  modification is to statically browse and store the DISPIDs at compile-time, since
 *  a given application will return the same DISPIDs in different sessions.
 *  Eliminating the extra cross-process GetIDsOfNames call can result in a
 *  signficant time savings.
 */


BOOL CXLAutomation::ExlInvoke(IDispatch *pdisp, LPOLESTR szMember, VARIANTARG * pvargReturn,
            WORD wInvokeAction, WORD wFlags)
{
    HRESULT hr;
    DISPPARAMS dispparams;
    unsigned int uiArgErr;
    EXCEPINFO excep;

    // Get the IDs for the member and its arguments.  GetIDsOfNames expects the
    // member name as the first name, followed by argument names (if any).
    m_alpszArgNames[0] = szMember;
    hr = pdisp->GetIDsOfNames( IID_NULL, m_alpszArgNames,
                                1 + m_iNamedArgCount, LOCALE_SYSTEM_DEFAULT, m_aDispIds);
    if (FAILED(hr)) 
    {
        if (!(wFlags & DISP_NOSHOWEXCEPTIONS))
            ShowException(szMember, hr, NULL, 0);
        return FALSE;
    }

    if (pvargReturn != NULL)
        ClearVariant(pvargReturn);

    // if doing a property put(ref), we need to adjust the first argument to have a
    // named arg of DISPID_PROPERTYPUT.
    if (wInvokeAction & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)) 
    {
        m_iNamedArgCount = 1;
        m_aDispIds[1] = DISPID_PROPERTYPUT;
        pvargReturn = NULL;
    }

    dispparams.rgdispidNamedArgs = m_aDispIds + 1;
    dispparams.rgvarg = m_aVargs;
    dispparams.cArgs = m_iArgCount;
    dispparams.cNamedArgs = m_iNamedArgCount;

    excep.pfnDeferredFillIn = NULL;

    hr = pdisp->Invoke(m_aDispIds[0], IID_NULL, LOCALE_SYSTEM_DEFAULT,
                                wInvokeAction, &dispparams, pvargReturn, &excep, &uiArgErr);

    if (wFlags & DISP_FREEARGS)
        ClearAllArgs();

    if (FAILED(hr)) 
    {
        // display the exception information if appropriate:
        if (!(wFlags & DISP_NOSHOWEXCEPTIONS))
            ShowException(szMember, hr, &excep, uiArgErr);

        // free exception structure information
        SysFreeString(excep.bstrSource);
        SysFreeString(excep.bstrDescription);
        SysFreeString(excep.bstrHelpFile);

        return FALSE;
    }
    return TRUE;
}

/*
 *  ClearVariant
 *
 *  Zeros a variant structure without regard to current contents
 */
void CXLAutomation::ClearVariant(VARIANTARG *pvarg)
{
    pvarg->vt = VT_EMPTY;
    pvarg->wReserved1 = 0;
    pvarg->wReserved2 = 0;
    pvarg->wReserved3 = 0;
    pvarg->lVal = 0;

}

/*
 *  ClearAllArgs
 *
 *  Clears the existing contents of the arg array in preparation for
 *  a new invocation.  Frees argument memory if so marked.
 */
void CXLAutomation::ClearAllArgs()
{
    int i;

    for (i = 0; i < m_iArgCount; i++) 
    {
        if (m_awFlags[i] & DISPARG_NOFREEVARIANT)
            // free the variant's contents based on type
            ClearVariant(&m_aVargs[i]);
        else
            //ClearVariant(&m_aVargs[i]);
            ReleaseVariant(&m_aVargs[i]);
    }

    m_iArgCount = 0;
    m_iNamedArgCount = 0;

}


void  CXLAutomation::ReleaseVariant(VARIANTARG *pvarg)
{
    VARTYPE vt;
    VARIANTARG *pvargArray;
    long lLBound, lUBound, l;

    vt = pvarg->vt & 0xfff;     // mask off flags

    // check if an array.  If so, free its contents, then the array itself.
    if (V_ISARRAY(pvarg)) 
    {
        // variant arrays are all this routine currently knows about.  Since a
        // variant can contain anything (even other arrays), call ourselves
        // recursively.
        if (vt == VT_VARIANT) 
        {
            SafeArrayGetLBound(pvarg->parray, 1, &lLBound);
            SafeArrayGetUBound(pvarg->parray, 1, &lUBound);

            if (lUBound > lLBound) 
            {
                lUBound -= lLBound;

                SafeArrayAccessData(pvarg->parray, (void**)&pvargArray);

                for (l = 0; l < lUBound; l++) 
                {
                    ReleaseVariant(pvargArray);
                    pvargArray++;
                }

                SafeArrayUnaccessData(pvarg->parray);
            }
        }
        else 
        {
            return ;//1; //  non-variant type

            // MessageBox(NULL, _T("ReleaseVariant: Array contains non-variant type"), "Failed", MB_OK | MB_ICONSTOP);
        }

        // Free the array itself.
        SafeArrayDestroy(pvarg->parray);
    }
    else 
    {
        switch (vt) 
        {
            case VT_DISPATCH:
                //(*(pvarg->pdispVal->lpVtbl->Release))(pvarg->pdispVal);
                pvarg->pdispVal->Release();
                break;

            case VT_BSTR:
                SysFreeString(pvarg->bstrVal);
                break;

            case VT_I2:
            case VT_BOOL:
            case VT_R8:
            case VT_ERROR:      // to avoid erroring on an error return from Excel
                // no work for these types
                break;

            default:

                return;// 2; //unknonw type
                // MessageBox(NULL, _T("ReleaseVariant: Unknown type"), "Failed", MB_OK | MB_ICONSTOP);
                break;
        }
    }

    ClearVariant(pvarg);
    return ;//0;

}

BOOL CXLAutomation::SetExcelVisible(BOOL bVisible)
{
    if (m_pdispExcelApp == NULL)
        return FALSE;

    ClearAllArgs();
    AddArgumentBool(NULL, 0, bVisible);
    return ExlInvoke(m_pdispExcelApp, L"Visible", NULL, DISPATCH_PROPERTYPUT, DISP_FREEARGS);

}

BOOL CXLAutomation::SetExcelFileValidation(BOOL bFileValidation)
{
    if (m_pdispExcelApp == NULL)
        return FALSE;

    ClearAllArgs();
    AddArgumentBool(NULL, 0, bFileValidation);
    return ExlInvoke(m_pdispExcelApp, L"FileValidation", NULL, DISPATCH_PROPERTYPUT, DISP_FREEARGS);

}
/*******************************************************************
 *
 *                     ARGUMENT CONSTRUCTOR FUNCTIONS
 *
 *  Each function adds a single argument of a specific type to the list
 *  of arguments for the current invoke.  If appropriate, memory may be
 *  allocated to represent the argument.  This memory will be
 *  automatically freed the next time ClearAllArgs() is called unless
 *  the NOFREEVARIANT flag is specified for a particular argument.  If
 *  NOFREEVARIANT is specified it is the responsibility of the caller
 *  to free the memory allocated for or contained within the argument.
 *
 *  Arguments may be named.  The name string must be a C-style string
 *  and it is owned by the caller.  If dynamically allocated, the caller
 *  must free the name string.
 *
 *******************************************************************/

/*
 *  Common code used by all variant types for setting up an argument.
 */

void CXLAutomation::AddArgumentCommon(LPOLESTR lpszArgName, WORD wFlags, VARTYPE vt)
{
    ClearVariant(&m_aVargs[m_iArgCount]);

    m_aVargs[m_iArgCount].vt = vt;
    m_awFlags[m_iArgCount] = wFlags;

    if (lpszArgName != NULL) 
    {
        m_alpszArgNames[m_iNamedArgCount + 1] = lpszArgName;
        m_iNamedArgCount++;
    }
}   


BOOL CXLAutomation::AddArgumentDispatch(LPOLESTR lpszArgName, WORD wFlags, IDispatch * pdisp)
{
    AddArgumentCommon(lpszArgName, wFlags, VT_DISPATCH);
    m_aVargs[m_iArgCount++].pdispVal = pdisp;
    return TRUE;
}


BOOL CXLAutomation::AddArgumentInt2(LPOLESTR lpszArgName, WORD wFlags, int i)
{
    AddArgumentCommon(lpszArgName, wFlags, VT_I2);
    m_aVargs[m_iArgCount++].iVal = i;
    return TRUE;
}


BOOL CXLAutomation::AddArgumentBool(LPOLESTR lpszArgName, WORD wFlags, BOOL b)
{
    AddArgumentCommon(lpszArgName, wFlags, VT_BOOL);
    // Note the variant representation of True as -1
    m_aVargs[m_iArgCount++].boolVal = b ? -1 : 0;
    return TRUE;
}

BOOL CXLAutomation::AddArgumentDouble(LPOLESTR lpszArgName, WORD wFlags, double d)
{
    AddArgumentCommon(lpszArgName, wFlags, VT_R8);
    m_aVargs[m_iArgCount++].dblVal = d;
    return TRUE;
}


BOOL CXLAutomation::ReleaseExcel()
{
    if (m_pdispExcelApp == NULL)
        return TRUE;

    // Tell Excel to quit, since for automation simply releasing the IDispatch
    // object isn't enough to get the server to shut down.

    // Note that this code will hang if Excel tries to display any message boxes.
    // This can occur if a document is in need of saving.  The CreateChart() code
    // always clears the dirty bit on the documents it creates, avoiding this problem.
    ClearAllArgs();
    ExlInvoke(m_pdispExcelApp, L"Quit", NULL, DISPATCH_METHOD, 0);

    // Even though Excel has been told to Quit, we still need to release the
    // OLE object to account for all memory.
    ReleaseDispatch();

    return TRUE;

}

//Create an empty workshet
BOOL CXLAutomation::CreateWorkSheet()
{
    if(NULL == m_pdispExcelApp)
        return FALSE;

    BOOL fResult;
    VARIANTARG varg1, varg2;
    IDispatch *pdispRange = NULL;
    IDispatch *pdispActiveSheet = NULL;
    IDispatch *pdispActiveCell = NULL;
    IDispatch *pdispCrt = NULL;



    // Set wb = [application].Workbooks.Add(template := xlWorksheet)
    ClearAllArgs();
    if (!ExlInvoke(m_pdispExcelApp, L"Workbooks", &varg1, DISPATCH_PROPERTYGET, 0))
        return FALSE;


    ClearAllArgs();
    AddArgumentInt2(L"Template", 0, xlWorksheet);
    fResult = ExlInvoke(varg1.pdispVal, L"Add", &varg2, DISPATCH_METHOD, 0);
    ReleaseVariant(&varg1);
    if (!fResult)
        return FALSE;
    m_pdispWorkbook = varg2.pdispVal;

    // Set ws = wb.Worksheets(1)
    ClearAllArgs();
    AddArgumentInt2(NULL, 0, 1);
    if (!ExlInvoke(m_pdispWorkbook, L"Worksheets", &varg2, DISPATCH_PROPERTYGET, 0))
        goto CreateWsBail;
    m_pdispWorksheet = varg2.pdispVal;

    fResult = TRUE;

CreateWsExit:

    if (pdispRange != NULL)
        pdispRange->Release();
    if (pdispCrt != NULL)
        pdispCrt->Release();
    return fResult;

CreateWsBail:
    fResult = FALSE;
    goto CreateWsExit;

}

/*
 *  OLE and IDispatch use a BSTR as the representation of strings.
 *  This constructor automatically copies the passed-in C-style string
 *  into a BSTR.  It is important to not set the NOFREEVARIANT flag
 *  for this function, otherwise the allocated BSTR copy will probably
 *  get lost and cause a memory leak.
 */

BOOL CXLAutomation::AddArgumentOLEString(LPOLESTR lpszArgName, WORD wFlags, LPOLESTR lpsz)
{
    BSTR b;

    b = SysAllocString(lpsz);
    if (!b)
        return FALSE;
    AddArgumentCommon(lpszArgName, wFlags, VT_BSTR);
    m_aVargs[m_iArgCount++].bstrVal = b;
    return TRUE;

}

BOOL CXLAutomation::AddArgumentCString(LPOLESTR lpszArgName, WORD wFlags, CString szStr)
{
    BSTR b;

    b = szStr.AllocSysString();
    if (!b)
        return FALSE;
    AddArgumentCommon(lpszArgName, wFlags, VT_BSTR);
    m_aVargs[m_iArgCount++].bstrVal = b;

    return TRUE;
}

/*
 *  Constructs an 1-dimensional array containing variant strings.  The strings
 *  are copied from an incoming array of C-Strings.
 */
BOOL CXLAutomation::AddArgumentCStringArray(LPOLESTR lpszArgName, WORD wFlags, LPOLESTR *paszStrings, int iCount)
{
    SAFEARRAY *psa;
    SAFEARRAYBOUND saBound;
    VARIANTARG *pvargBase;
    VARIANTARG *pvarg;
    int i, j;

    saBound.lLbound = 0;
    saBound.cElements = iCount;

    psa = SafeArrayCreate(VT_VARIANT, 1, &saBound);
    if (psa == NULL)
        return FALSE;

    SafeArrayAccessData(psa, (void**) &pvargBase);

    pvarg = pvargBase;
    for (i = 0; i < iCount; i++) 
    {
        // copy each string in the list of strings
        ClearVariant(pvarg);
        pvarg->vt = VT_BSTR;
        if ((pvarg->bstrVal = SysAllocString(*paszStrings++)) == NULL) 
        {
            // memory failure:  back out and free strings alloc'ed up to
            // now, and then the array itself.
            pvarg = pvargBase;
            for (j = 0; j < i; j++) 
            {
                SysFreeString(pvarg->bstrVal);
                pvarg++;
            }
            SafeArrayDestroy(psa);
            return FALSE;
        }
        pvarg++;
    }

    SafeArrayUnaccessData(psa);

    // With all memory allocated, setup this argument
    AddArgumentCommon(lpszArgName, wFlags, VT_VARIANT | VT_ARRAY);
    m_aVargs[m_iArgCount++].parray = psa;
    return TRUE;

}

//Clean up: release dipatches
void CXLAutomation::ReleaseDispatch()
{
    if(NULL != m_pdispExcelApp)
    {
        m_pdispExcelApp->Release();
        m_pdispExcelApp = NULL;
    }

    if(NULL != m_pdispWorksheet)
    {
        m_pdispWorksheet->Release();
        m_pdispWorksheet = NULL;
    }

    if(NULL != m_pdispWorkbook)
    {
        m_pdispWorkbook->Release();
        m_pdispWorkbook = NULL;
    }

    if(NULL != m_pdispActiveChart)
    {
        m_pdispActiveChart->Release();
        m_pdispActiveChart = NULL;
    }

}

void CXLAutomation::ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr)
{
    TCHAR szBuf[512];

    switch (GetScode(hr)) 
    {
        case DISP_E_UNKNOWNNAME:
            wsprintf(szBuf, "%s: Unknown name or named argument.", szMember);
            break;

        case DISP_E_BADPARAMCOUNT:
            wsprintf(szBuf, "%s: Incorrect number of arguments.", szMember);
            break;

        case DISP_E_EXCEPTION:
            wsprintf(szBuf, "%s: Error %d: ", szMember, pexcep->wCode);
            if (pexcep->bstrDescription != NULL)
                lstrcat(szBuf, (char*)pexcep->bstrDescription);
            else
                lstrcat(szBuf, "<<No Description>>");
            break;

        case DISP_E_MEMBERNOTFOUND:
            wsprintf(szBuf, "%s: method or property not found.", szMember);
            break;

        case DISP_E_OVERFLOW:
            wsprintf(szBuf, "%s: Overflow while coercing argument values.", szMember);
            break;

        case DISP_E_NONAMEDARGS:
            wsprintf(szBuf, "%s: Object implementation does not support named arguments.",
                        szMember);
            break;

        case DISP_E_UNKNOWNLCID:
            wsprintf(szBuf, "%s: The locale ID is unknown.", szMember);
            break;

        case DISP_E_PARAMNOTOPTIONAL:
            wsprintf(szBuf, "%s: Missing a required parameter.", szMember);
            break;

        case DISP_E_PARAMNOTFOUND:
            wsprintf(szBuf, "%s: Argument not found, argument %d.", szMember, uiArgErr);
            break;

        case DISP_E_TYPEMISMATCH:
            wsprintf(szBuf, "%s: Type mismatch, argument %d.", szMember, uiArgErr);
            break;

        default:
            wsprintf(szBuf, "%s: Unknown error occured.", szMember);
            break;
    }

    MessageBox(NULL, szBuf, "OLE Error", MB_OK | MB_ICONSTOP);

}

//Open Microsoft Excel file and switch to the firs available worksheet. 
BOOL CXLAutomation::OpenExcelFile(CString szFileName)
{
    //Leave if the file cannot be open
    if(NULL == m_pdispExcelApp)
        return FALSE;
    if(szFileName.IsEmpty())
        return FALSE;
    VARIANTARG varg1, vargWorkbook, vargWorksheet;

    SetExcelFileValidation(FALSE);


    ClearAllArgs();
    if (!ExlInvoke(m_pdispExcelApp, L"Workbooks", &varg1, DISPATCH_PROPERTYGET, 0))
        return FALSE;

    ClearAllArgs();
    AddArgumentCString(L"Filename", 0, szFileName);
    if (!ExlInvoke(varg1.pdispVal, L"Open", &vargWorkbook, DISPATCH_PROPERTYGET, DISP_FREEARGS))
        return FALSE;

    //Now let's get the first worksheet of this workbook
    ClearAllArgs();
    AddArgumentInt2(NULL, 0, 1);
    if (!ExlInvoke(vargWorkbook.pdispVal, L"Worksheets", &vargWorksheet, DISPATCH_PROPERTYGET, DISP_FREEARGS))
        return FALSE;

    //Close the empty worksheet
    ClearAllArgs();
    //if (!ExlInvoke(m_pdispWorkbook, L"Close", NULL, DISPATCH_PROPERTYGET, DISP_FREEARGS))
    //  return FALSE;

    SetExcelVisible(TRUE);

    //Remember the newly open worksheet 
    m_pdispWorkbook = vargWorkbook.pdispVal;
    m_pdispWorksheet = vargWorksheet.pdispVal;

    ReleaseDispatch();
    return TRUE;
}

2 个答案:

答案 0 :(得分:2)

乍一看,似乎你的pvarg可能不完全一致/没有提供预期的结果。 clear函数不进行检查,因此无论如何都会写入。或尝试。

但如果没有对所有相关代码进行全面彻底的审视,那么这可能是一种严重的过度简化。

在此处添加此项,因为您的项目在Freelancer上已关闭,谁知道,无论如何,它可能会帮助您或其他人在未来的日期思考正确的方向。

答案 1 :(得分:1)

我通过根本不使用那个MS类库来修复问题 - 它太复杂了,容易出问题。

我找到了一个简单的代码示例here,并根据我的需要进行了调整。 我已经添加了代码来打开我需要的Excel文件,这里是我希望能帮助有类似问题的人的源代码。

无论是谁投票支持这个问题 - 请重新考虑并重新投票。

// Start server and get IDispatch...
   IDispatch *pXlApp;
   hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&pXlApp);
   if(FAILED(hr)) {
      ::MessageBox(NULL, "Excel not registered properly", "Error", 0x10010);
      return -2;
   }

   // Make it visible (i.e. app.visible = 1)
   {
      VARIANT x;
      x.vt = VT_I4;
      x.lVal = 1;
      AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlApp, L"Visible", 1, x);
   }

   // Get Workbooks collection
   IDispatch *pXlBooks;
   {
      VARIANT result;
      VariantInit(&result);
      AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"Workbooks", 0);
      pXlBooks = result.pdispVal;
   }
   // Open Excel file
   {
   VARIANT result;
    VariantInit(&result);
    VARIANT fname;
    fname.vt = VT_BSTR;
    std::string str = GetAppPath() + "\\test.xlsm";
    fname.bstrVal=::SysAllocString(CA2W (str.c_str ()));
    AutoWrap(DISPATCH_METHOD, &result, pXlBooks, L"Open", 1, fname);
   }

   // Release references...
   pXlBooks->Release();
   pXlApp->Release();