C ++未处理的exception – 堆已损坏

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

通常应用程序运行良好,然后有时会崩溃,例外。

当从运行exe进入debugging时,高亮显示的代码行似乎是错误的 – 请参阅第一个屏幕截图。

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

这行代码调用一个函数“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文件在post的末尾。 OpenExcelFile是导致这个问题的函数 – 就像你可以从屏幕截图中的调用栈一样。

例外 - 调试器屏幕截图

例外 - 当地人扩大

 // 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; } 

乍一看,你的pvarg可能不完全一致/不提供所期望的。 明确的function没有检查,所以它只会写,不pipe。 或者尝试。

但是,如果没有对所有涉及的代码进行全面彻底的审查,这可能是一个过分简化的过程。

如果您的项目在自由职业者处closures,您可以在此处添加此信息,但是谁知道,无论如何,这可能会帮助您或其他人在未来的date朝着正确的方向思考。

我通过不使用这个MS类库来解决这个问题 – 它太复杂了,容易出现问题。

我在这里find一个简单的代码示例,并根据我的需要进行调整。 我已经添加了代码来打开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 (ie 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();