Member 13872723 Ответов: 1

Указание имен DSN для функции sqlconnectw в ODBC


Ниже приводится компиляция и работа:
РЦ = функция sqlconnect(ConHandle, (SQLWCHAR*)"dailyworkbook", значение sql_nts, нулевое, значение sql_nts, нулевое, значение sql_nts);

Ниже приводится компиляция, но я получаю нарушение доступа во время выполнения:
с = функция sqlconnect(ConHandle, (SQLWCHAR*)л"dailyworkbook", значение sql_nts, нулевое, значение sql_nts, нулевое, значение sql_nts);

Я озадачен. Любое понимание было бы полезно.

Что я уже пробовал:

Страницы справки в интернете. Отладка в Visual studio.

1 Ответов

Рейтинг:
2

Jochen Arndt

Я точно не знаю, почему происходит нарушение доступа, но это, вероятно, связано с тем, что UserName и Authentication параметры. Когда они есть NULL, вы также должны передать ноль вместо SQL_NTS для длины:

c = SQLConnect(ConHandle, (SQLWCHAR*)L"dailyworkbook", SQL_NTS, NULL, 0, NULL, 0);
или передать пустые строки, которые могут использовать SQL_NTS или ноль
c = SQLConnect(ConHandle, (SQLWCHAR*)L"dailyworkbook", SQL_NTS, (SQLWCHAR*)L"", SQL_NTS, (SQLWCHAR*)L"", SQL_NTS);

Если вам нужно использовать char или широкие строки, это зависит от настроек вашего проекта. Вышеизложенное предполагает, что у вас есть проект Unicode.

Я также могу только догадываться, почему вы не получили нарушение доступа с первого звонка, но я думаю, что это потенциальное объяснение:
При построении Unicode и передаче строки char соединение завершится неудачно, так как сервер не может быть найден, и функция возвращается перед использованием дополнительных параметров.


Member 13872723

Я сейчас пытаюсь:
std::wstring dsn(L"dailyworkbook");
РЦ = SQLConnectW(ConHandle, (SQLWCHAR*)ДСН.c_str(), уведомления о доставке.длина(), (SQLWCHAR*)л"", значение sql_nts, (SQLWCHAR*)л"", значение sql_nts);

Программа компилируется, но во время выполнения происходит нарушение доступа. Если я заменю второй параметр на 3/10/3000(любое сумасшедшее значение), то нарушения не произойдет, но ODBC сообщит о недопустимой длине строки или буфера. Если я заменю второй параметр на SQL_NTS/length()/strlen whatever, я получу нарушение доступа.

Jochen Arndt

А как насчет моего первого примера с нулем и 0?

В любом случае это должно работать и компилироваться (с помощью Unicode-сборок или с помощью SQLConnectW):
SQLWCHAR dsn[] = L"dailyworkbook";
rc = SQLConnect(ConHandle, dsn, SQL_NTS, NULL, 0, NULL, 0);

Уродливое приведение требуется здесь, потому что параметры не определены const, пока они не изменены функцией. Но строковые литералы и std::string::c_str() являются const. С C++ было бы лучше использовать const_cast:
std::wstring dsn(L"dailyworkbook");
rc = SQLConnect(ConHandle, const_cast<SQLWCHAR*>(dsn.c_str()), SQL_NTS, NULL, 0, NULL, 0);

Member 13872723

Привет Йохен
Извините за репост, но я все еще нахожу здесь свой путь.

Я получаю нарушение доступа к обоим из них. Если я заменю SQL_NTS на 0, то в обоих случаях нарушения доступа не будет, но odbc говорит: "[Microsoft][ODBC Driver Manager] имя источника данных не найдено и драйвер по умолчанию не указан".

Я впадаю в отчаяние. Пожалуйста, помогите мне.

Jochen Arndt

Значение sql_nts значит, нуль терминированная строка.
То есть функция сама определит длину строки, используя соответствующий (предшествующий) параметр.

Если строковый параметр равен NULL, передайте 0 (ноль) для длины.
Если параметр string является допустимой строкой (включая пустую строку), передайте правильную длину (в символах) или SQL_NTS.

Если вы передадите ноль для длины DSN, имя может быть сбито с курса и не найдено.

Documenattion и все примеры показывают его путь из моих примеров.

Так что единственный другой источник, о котором я могу думать, - это ваш Конхендл. Это также будет использоваться только после того, как DSN будет найден.
Это было правильно распределено?

Member 13872723

Дескриптор соединения инициализируется должным образом. (По крайней мере, это не ноль).
Я изменил свою сборку с Unicode на MultiByteCharSet. Снова получил нарушение доступа при использовании SQL_NTS.
Может быть, я упускаю здесь экологическую обстановку?
Заранее спасибо

Jochen Arndt

Ненулевое значение не означает, что это допустимый дескриптор.

Я предлагаю отредактировать ваш вопрос и добавить строки кода перед вызовом connect, где вы выделяете дескриптор, а также все связанные строки. Или проверьте их сами, используя пример кода по адресу https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlconnect-function?view=sql-server-2017.

Возможные источники передают неправильный размер в функцию SQLAllocHandle() и не проверяют возвращаемое значение.

Чтобы отредактировать свой вопрос, используйте зеленую ссылку "улучшить вопрос".

И удалите свое решение, потому что оно не является таковым и поэтому может быть отклонено голосованием.

Member 13872723

Я скопировал весь код из https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlconnect-function?view=sql-server-2017&viewFallbackFrom=sql-server-2017.
Все еще тот же результат samme от SqlConnect. Нарушение при использовании SQL_NTS.

Jochen Arndt

Это не значение sql_nts для уведомления о доставке, потому что это происходит также при использовании wstrlen(DSN) для местного SQLWCHAR[] или ДСН.длина() для std::wstring, которая.

Таким образом, это либо сама переданная строка, либо дескриптор, потому что другие параметры равны нулю с 0.

Нарушение доступа генерируется при доступе к памяти, которая не назначена приложению. Это означает, что указатель недействителен или указатель действителен, но смещение, используемое с этим указателем, слишком велико.

Если предположить, что указатель строки допустим и это строка с нулевым завершением (с SQL_NTS) или передается правильная длина, то это может быть только дескриптор.

Снова:
Нарушение происходит только тогда, когда DSN может быть найден. Если это не удается, функция возвращается до того, как у нее есть шанс добраться до кода, который приводит к нарушению.

Так что это может быть только ручка или где-то в драйвере.

Или исключение возникает не в вызове SQLConnect (), а в следующей строке. Вы проверили это (где это происходит)?

Пожалуйста, обратите внимание, что все, что я вижу, - это одна строка кода. Я не знаю вашего кода до и после этой строки, и у меня нет доступа к вашей базе данных или вашей системе. Если ошибка не находится в этой конкретной строке кода (что я думаю в то же время), то помочь невозможно из-за небольшой информации, которой я располагаю.

Member 13872723

Я полностью понимаю, что нарушение происходит только тогда, когда dsn может быть найден. Большое спасибо за это!!
Я отладил и подтвердил, что нарушение происходит только в SqlConnect().
Вот мой код:

тап_п() {
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;

SQLCHAR * OutConnStr = (SQLCHAR *)malloc(255);
SQLSMALLINT * OutConnStrLen = (SQLSMALLINT *)malloc(255);

// Выделить дескриптор среды
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

// Установите атрибут среды версии ODBC
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

// Выделить ручку подключения
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

// Установите тайм-аут входа в систему на 5 секунд
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);

// Подключение к источнику данных
// retcode = функция sqlconnect(hdbc, (данных sqlchar*) "Борей", значение sql_nts, (данных sqlchar*)равен null, 0, null, то 0);

std::wstring dsn(L"ddd");
// retcode = SQLConnect(hdbc, const_cast<SQLWCHAR*>(dsn.c_str()), 10,NULL, 0, NULL, 0);
retcode = функция sqlconnect(hdbc, const_cast&ЛТ;SQLWCHAR*&ГТ;(ДСН.c_str()), уведомлений о доставке.длина (М), нуль, 0, нуль, 0);

// Выделить дескриптор оператора
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

// Обрабатывать данные
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}

SQLDisconnect(hdbc);
}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
}

Member 13872723

Я нашел виновника: антивирус К7.
Я вдруг заметил, что исключение происходит в K7*.dll.
Я удалил K7, и теперь все работает нормально.
Есть идеи, почему это происходит?

Jochen Arndt

Спасибо за ваши отзывы и прекрасно слышать, что вы нашли виновника.

Не знаю почему. Вы можете сообщить им об этом.

Программное обеспечение AV подключается к нескольким низкоуровневым системным интерфейсам. Мне это не нравится. Когда он содержит ошибки, он может сделать целые системы непригодными для использования или уязвимыми. Я использую только MS own Defender, потому что они должны лучше знать, где и как зацепиться.