Я пишу программу для анализа документа Word и экспорта данных в рабочую книгу Excel с использованием OLE-автоматизации (я полагаю, не-MFC). Прекрасно работает в Debug, но не в Release (особенно, если включена оптимизация). Ошибка в том, что произошел сбой вызова IDispatch :: Invoke, а именно:
0x80020004 DISP_E_PARAMNOTFOUND Parameter not found
Я проверил StackOverflow на наличие некоторых предложений, и основным кажется неинициализированные переменные. Это может быть то, что происходит, но я все еще не понимаю этот конкретный случай. Я сузил это до одной функции в моей программе Automation::Dispatch::Invoke
который отвечает за наконец-то звонить IDispatch::Invoke
, Аргументы передаются в Automation::Dispatch::Invoke
верны, так что проблема где-то в его коде.
Глядя на базовый код (из MSDN), из которого я его адаптировал, я смог заставить его работать и сузить точную линию проблемы. Ниже показан код, который не работает, но в комментариях указана строка, которую я переместил, чтобы она заработала (найдите 2 строки с <--- Problem line
комментарий). В режиме отладки расположение этой строки не имеет значения, и она работает в любом месте.
У меня вопрос, что это исправляет, и с чего начать? Спасибо и дайте мне знать, если я смогу прояснить вопрос.
HRESULT Automation::Dispatch::Invoke(int cmd, std::string name, std::vector<VARIANT> values)
{
USES_CONVERSION;
HRESULT result;
/* Get DISPID for name passed */
DISPID dispID;
LPOLESTR nameOle=A2OLE(name.c_str());
result=pObjectInt->GetIDsOfNames(IID_NULL, &nameOle, 1, LOCALE_USER_DEFAULT, &dispID);
if (FAILED(result)) {
return result;
}
/* Reverse elements in values vector so they are invoked in the correct order */
std::reverse(values.begin(), values.end());
/* Allocate memory for object values */
VARIANT *pValues=new VARIANT[values.size() + 1];
for (unsigned int i=0; i < values.size(); ++i) {
pValues[i]=values[i];
}
/* Build DISPPARAMS */
DISPPARAMS dispParams= {NULL, NULL, 0, 0};
/* DISPID dispidNamed=DISPID_PROPERTYPUT; <--- PROBLEM LINE moved here makes it work */
dispParams.cArgs=values.size();
dispParams.rgvarg=pValues;
/* Handle special-case for property-puts */
if (cmd==DISPATCH_PROPERTYPUT) {
DISPID dispidNamed=DISPID_PROPERTYPUT; /* <--- PROBLEM LINE here */
dispParams.cNamedArgs=1;
dispParams.rgdispidNamedArgs=&dispidNamed;
}
/* Make the call */
if (cmd==DISPATCH_METHOD || cmd==DISPATCH_PROPERTYPUT) {
result=pObjectInt->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, cmd, &dispParams, NULL, NULL, NULL);
}
else {
VariantInit(&objectData);
result=pObjectInt->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, cmd, &dispParams, &objectData, NULL, NULL);
}
delete[] pValues;
return result;
}
В этом коде:
if (cmd==DISPATCH_PROPERTYPUT) {
DISPID dispidNamed=DISPID_PROPERTYPUT; /* <--- PROBLEM LINE here */
dispParams.cNamedArgs=1;
dispParams.rgdispidNamedArgs=&dispidNamed;
}
dispidNamed
является локальной переменной для блока кода, в котором она находится (т. е. область, ограниченная {
}
).
После }
достигается, он перестает существовать. затем rgdispidNamedArgs
является висящим указателем, потому что он больше не указывает на переменную, которая существует.
Вам не повезло в режиме отладки, что он не вызвал ошибку раньше.