After migrating an application from C++ Builder 4 to C++builder 6, the excel COM automation started to crash with error EAccessViolation at address 00000800 when calling the Variant.OlePropertySet(), OlePropertyGet() or OleFunction() methods, as in the following code :
[code lang=cpp]
Variant xlApp = Variant::CreateObject(« Excel.Application »);
xlApp.OlePropertySet(« Visible », true); // causes the EAccessViolation
Variant workbooks = xlApp.OlePropertyGet(« Workbooks »);
Variant currentWorkbook ClasseurCourant = workbooks.OleFunction(« Open », L »C:\\MyExcelFile.xls »);
[/code]
This code was working fine with Builder 4, it was also working fine when used in a brand new application, but it always crashed in the converted app. Given that many developers reported the same error, with no known fix, and that one couldn’t expect support for a 12 years old IDE, I eventually fixed the issue by bypassing the Borland Wrappers and using directly COM.
COM is always a nightmare to work with in C++, but Microsoft had my back and provided a code sample at https://support.microsoft.com/fr-fr/kb/216686
[code lang=cpp]
// AutoWrap() – Automation helper function…
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) {
MessageBox(NULL, « NULL IDispatch passed to AutoWrap() », « Error », 0x10010);
_exit(0);
}
// 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);
MessageBox(NULL, buf, « AutoWrap() », 0x10010);
_exit(0);
return hr;
}
// Allocate memory for arguments…
VARIANT *pArgs = new VARIANT[cArgs+1];
// Extract arguments…
for(int i=0; i
if(FAILED(hr)) {
sprintf(buf, « IDispatch::Invoke(\ »%s\ »=%08lx) failed w/err 0x%08lx », szName, dispID, hr);
MessageBox(NULL, buf, « AutoWrap() », 0x10010);
_exit(0);
return hr;
}
// End variable-argument section…
va_end(marker);
delete [] pArgs;
return hr;
}
[/code]
Then, using the AutoWrap function, the Excel Workbook opening code cand eventually be rewritten as :
[code lang=cpp]
TVariant xlApp(Variant::CreateObject(« Excel.Application »));
// Based on sample from https://support.microsoft.com/fr-fr/kb/216686
AutoWrap(DISPATCH_PROPERTYPUT, NULL, xlApp, L »Visible », 1, TVariant(1));
// Get Workbooks collection
TVariant workbooks;
{
TVariant result;
AutoWrap(DISPATCH_PROPERTYGET, &result, xlApp, L »Workbooks », 0);
workbooks = result.pdispVal;
}
TVariant currentWorkbook;
{
TVariant result;
AutoWrap(DISPATCH_METHOD, &result, workbooks, L »Open », 1, TVariant(L »C:\\Users\\nicolas\\Desktop\\TACHES NON PREVUES.xls »));
currentWorkbook = result.pdispVal;
}
[/code]
Président et fondateur de NeoLegal, développe des solutions logicielles qui facilitent le quotidien des professionnels du droit des sociétés.