Бьюсь несколько дней, не могу понять, в чем дело.
Следующий код прекрасно работает, если все хорошо.
Но если в процессе выполнения функций ADO возникает exception, по завершении функции main() вылетает сообщение:
---------------------------
Microsoft Visual C++
---------------------------
Unhandled exception in ADO.exe: 0xC0000005: Access Violation.
---------------------------
OK
---------------------------
Для возникновения exception достаточно изменить (LOCAL) в строке pConnection->ConnectionString на несуществующее имя компьютера.
#import"C:\Program Files\Common Files\System\ADO\msado15.dll" \
no_namespace rename("EOF", "EndOfFile")
#include <stdio.h>
#include <conio.h>
// Function declarationsinline void TESTHR(HRESULT x) {if FAILED(x) _com_issue_error(x);};
void PrintComError(_com_error &e);
///////////////////////////////////////////////////////////
// //
// Main Function //
// //
///////////////////////////////////////////////////////////void main()
{
if(FAILED(::CoInitialize(NULL)))
return;
// Define Connection object pointer.
// Initialize pointers on define.
// These are in the ADODB:: namespace
_ConnectionPtr pConnection = NULL;
_CommandPtr pCmd = NULL;
_ParameterPtr pPrm = NULL;
try
{
// Open a connection using OLE DB syntax.
TESTHR(pConnection.CreateInstance(__uuidof(Connection)));
pConnection->ConnectionString = "Provider=SQLOLEDB.1;Data Source=(LOCAL);Initial Catalog=Pubs;Integrated Security=SSPI";
pConnection->Open("","","",adConnectUnspecified);
// Create Command object for stored procedure call
TESTHR(pCmd.CreateInstance(__uuidof(Command)));
pCmd->ActiveConnection = pConnection;
pCmd->CommandText = "byroyalty";
// Define command parameter
pPrm = pCmd->CreateParameter("percentage", adInteger, adParamInput, sizeof(long), (long)100);
pCmd->Parameters->Append(pPrm);
// Execute stored procedure
_RecordsetPtr pRs = pCmd->Execute(NULL, NULL, adCmdStoredProc);
_bstr_t bstrAUID;
while (!pRs->EndOfFile)
{
bstrAUID = pRs->Fields->GetItem("au_id")->Value;
printf("%s\n", (LPCSTR) bstrAUID);
pRs->MoveNext();
}
// Cleanup objects before exit
pRs->Close();
pConnection->Close();
}
catch(_com_error &e)
{
PrintComError(e);
}
// Wait here for user to see the output..
printf("\nPress any key to continue...");
getch();
::CoUninitialize();
}
///////////////////////////////////////////////////////////
// //
// PrintComError Function //
// //
///////////////////////////////////////////////////////////void PrintComError(_com_error &e)
{
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
// Print Com errors.
printf("Error\n");
printf("\tCode = %08lx\n", e.Error());
printf("\tCode meaning = %s\n", e.ErrorMessage());
printf("\tSource = %s\n", (LPCSTR) bstrSource);
printf("\tDescription = %s\n", (LPCSTR) bstrDescription);
}
Может кто-нибудь проверить у себя выполнение этого кода?
Неужели у меня одного он падает?
Программа практически совпадает с примерами из MSDN.
Пожалуйста!
"_Stranger_" <forum@rsdn.ru> wrote in message news:503662@news.rsdn.ru... > Бьюсь несколько дней, не могу понять, в чем дело. > Следующий код прекрасно работает, если все хорошо. > Но если в процессе выполнения функций ADO возникает exception, по завершении функции main() вылетает сообщение:
Признаюсь честно, хоть это тебе и не поможет, полгода назад я оказался в таком-же положении, то есть казалось эта ошибка возникает только у меня и ни у кого более. Вот, ты первый обнаруженный мною человек, увидевший ее
Мои исследования ее ни к чему на привели, но по-моему при возникновении исключения рушится стек. Как обойти — не знаю, слава богу в моей ситуации просто не было необходимости продолжать рыть, от этого направления отказались по внешним причинам. На вопросы в форумах в меня кидались сообщениями типа "ты что, сдурел кидать исключения из COM-объекта наружу!", то есть народ просто не понимал либо не хотел понимать.
Так что прими мои соболезнования.
Если найдешь решение — буду очень рад о нем узнать.
Наверное дело в обёртках ... предлагаю ещё так сделать ...
<skipped>
То есть обложи ещё и деструктор Ptr и посмотри что падает
Попробовал.
Исключение ловится первым catch, то есть проблема не в деструкторе.
В основной программе, в которой были замечены проблемы, действия с ADO производятся в функции, декларированной так:
BOOL CDBStorage::GetApplicationID(const EL_APPINFO *pAppInfo, long &lApplicationID)
Так вот после вызова функции ADO, вызывающей исключение, pAppInfo получает некоторое новое значение, то есть pConnection->Open при возникновении в нем исключение портит стек.
Или я не прав?
Вот, ты первый обнаруженный мною человек, увидевший ее
Ага, а ты первый, кто мне поверил
Спасибо за соболезнования.
В моем случае внешних причин не предвидится. Поэтому буду продолжать рыть дальше.
Предположение, что исключение в функциях ADO рушит стек, находит подтверждение. В моем случае после вызова функций ADO в функции, имеющей входные параметры, значения этих параметров становятся неопределенными после возникновения исключения в функции ADO.
Непонятно, как с этим бороться.
Между прочим, в release версии эта программа ОТЛИЧНО работает.
Это меня радует, но не совсем, т.к. реакцию приложения на исключения ADO нужно дебажить, а в дебаге код не работает.
Если найдешь решение — буду очень рад о нем узнать.
Если мои поиски увенчаются результатом — непременно.
Немного поменял код, перенес работу с ADO в функцию.
Пожалуйста, если кому не сложно, скомпилируйте у себя проект в debug и release версиях.
И вышлите мне весь проект (*.cpp, *.dsp, *.exe) на ALegkikh_at_yandex.ru
Заранее спасибо.
#import"C:\Program Files\Common Files\System\ADO\msado15.dll" \
no_namespace rename("EOF", "EndOfFile")
#include <stdio.h>
#include <conio.h>
// Function declarationsinline void TESTHR(HRESULT x) {if FAILED(x) _com_issue_error(x);};
void PrintComError(_com_error &e);
void Test(void);
///////////////////////////////////////////////////////////
// //
// Main Function //
// //
///////////////////////////////////////////////////////////void main()
{
if(FAILED(::CoInitialize(NULL)))
return;
Test();
// Wait here for user to see the output..
printf("\nTest completed OK!\n");
getch();
::CoUninitialize();
}
///////////////////////////////////////////////////////////
// //
// Test Function //
// //
///////////////////////////////////////////////////////////void Test(void)
{
// Define Connection object pointer.
// Initialize pointers on define.
// These are in the ADODB:: namespace
_ConnectionPtr pConnection = NULL;
_CommandPtr pCmd = NULL;
_ParameterPtr pPrm = NULL;
_RecordsetPtr pRs = NULL;
try
{
// Open a connection using OLE DB syntax.
TESTHR(pConnection.CreateInstance(__uuidof(Connection)));
printf("ADO Version: %s\n\n", (LPCSTR)pConnection->Version);
pConnection->ConnectionString = "Provider=SQLOLEDB.1;Data Source=(LOCAL);Initial Catalog=Pubs;Username=sa;Password=sa";
pConnection->Open("","","",adConnectUnspecified);
// Create Command object for stored procedure call
TESTHR(pCmd.CreateInstance(__uuidof(Command)));
pCmd->ActiveConnection = pConnection;
pCmd->CommandText = "byroyalty";
// Define command parameter
pPrm = pCmd->CreateParameter("percentage", adInteger, adParamInput, sizeof(long), (long)100);
pCmd->Parameters->Append(pPrm);
// Execute stored procedure
pRs = pCmd->Execute(NULL, NULL, adCmdStoredProc);
_bstr_t bstrAUID;
while (!pRs->EndOfFile)
{
bstrAUID = pRs->Fields->GetItem("au_id")->Value;
printf("%s\n", (LPCSTR) bstrAUID);
pRs->MoveNext();
}
// Cleanup objects before exit
pRs->Close();
pConnection->Close();
}
catch(_com_error &e)
{
PrintComError(e);
}
}
///////////////////////////////////////////////////////////
// //
// PrintComError Function //
// //
///////////////////////////////////////////////////////////void PrintComError(_com_error &e)
{
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
// Print Com errors.
printf("Error\n");
printf("\tCode = %08lx\n", e.Error());
printf("\tCode meaning = %s\n", e.ErrorMessage());
printf("\tSource = %s\n", (LPCSTR) bstrSource);
printf("\tDescription = %s\n", (LPCSTR) bstrDescription);
}
В папке %ProgramFiles%\Microsoft Visual Studio\VC98\Bin есть файл с2.dll.
Как я выяснил, c2.dll идет с Processor Pack.
У меня стоял Processor Pack 5, в котором c2.dll имеет версию 13.0.9044.0.
При замене файла c2.dll на более раннюю версию, проблемы исчезают.
Например, на Processor Pack 4, в котором c2.dll имеет версию 13.0.8943.0.
Здравствуйте, _Stranger_, Вы писали:
_S_>Я победил!
_S_>В папке %ProgramFiles%\Microsoft Visual Studio\VC98\Bin есть файл с2.dll. _S_>Как я выяснил, c2.dll идет с Processor Pack. _S_>У меня стоял Processor Pack 5, в котором c2.dll имеет версию 13.0.9044.0. _S_>При замене файла c2.dll на более раннюю версию, проблемы исчезают. _S_>Например, на Processor Pack 4, в котором c2.dll имеет версию 13.0.8943.0.
_S_>Всем спасибо за участие и помощь!
Монстр!
Толко не осталось как-то полной ясности, а почему тогда
1) более новая версия работает менее правильно
2) мы с тобой — единственные пострадавшие. В конце концов сам микрософт на VB что-ли пишет? Или просто является особым извратом пользоваться ADO в приложениях на C++?
2) мы с тобой — единственные пострадавшие. В конце концов сам микрософт на VB что-ли пишет? Или просто является особым извратом пользоваться ADO в приложениях на C++?
Просто многие не ставят Processor Pack — он, в основном, нужен тем, кто пользуется ассемблерными вставками.
Да при чем тут это.
Та же ситуация воспроизведется нижеприведенным кодом если раскомментировать зануление.
Смартпоинтер выходит из области видимости когда ::CoUninitialize() уже вызвано с вытекающими.
Да при чем тут это.
Та же ситуация воспроизведется нижеприведенным кодом если раскомментировать зануление.
Смартпоинтер выходит из области видимости когда ::CoUninitialize() уже вызвано с вытекающими.
Согласен, Ваш пример действительно падает на Access Violation. Но у меня в примере вся работа с объектами ADO сосредоточена в одной функции, вызываемой из main(), смотрите код
"Юнусов Булат" <forum@rsdn.ru> wrote in message news:506488@news.rsdn.ru... > Здравствуйте, _Stranger_, Вы писали: > > Да при чем тут это. > Та же ситуация воспроизведется нижеприведенным кодом если раскомментировать зануление. > Смартпоинтер выходит из области видимости когда ::CoUninitialize() уже вызвано с вытекающими. >
Не, не в этом дело.
У меня вообще ошибка возникала в такой структуре кода:
CoInitialize
вызов функций (в несколько слоев) — внутри них и происходили чудеса, точнее по возврату из функции, которая попыталась выполнить операцию, вызвавшую ошибку (например, в селекте на та колонка указана). Совершенно очевидно, что рушился стек (то есть локальные переменные в этой функции после этого злосчастного вызова теряли значения, а уж о адресе возврата я вообще не говорю), вот только было непонятно почему так происходит
CoUninitialize
Так что как видишь не в этом дело: если ADO-операция выполняется без ошибок — все ок. А вот если возникла ошибка, приложение рушится.
Насколько я помню, это воспроизводилось даже в дебагере.
А что, после перекладывания всей адошной кухни (включая обьявления) в функцию (или даже просто "за фигурные скобки"), продолжаем получать АВ? Сильно сомневаюсь.
А что, после перекладывания всей адошной кухни (включая обьявления) в функцию (или даже просто "за фигурные скобки"), продолжаем получать АВ? Сильно сомневаюсь.
Именно так. Можете не сомневаться. При этом было установлено, что источник Access Violation находится в том, что при возникновении exception в ADO-шной функции выход из нее осуществляется некорректно, при этом повреждается стек. Отсюда и вытекающие.
В указанном примере Access Violation перестал появляться только после замены C2.DLL на более раннюю версию.
Кстати, предлагаю Вам самим попробовать заменить C2.DLL на ту версию, что идет в Processor Pack 5 и скомпилировать у себя этот