Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Dans ce démarrage rapide, vous construisez une application console Windows C++ avec Visual Studio 2022 et versions ultérieures. L’application se connecte à Azure SQL Database, à une base de données SQL dans Microsoft Fabric ou à SQL Server à l’aide du pilote Microsoft OLE DB Driver 19 for SQL Server. Il exécute une requête paramétrée sur les données de l’échantillon AdventureWorksLT et vérifie le résultat.
Logiciels requis
- Visual Studio 2022 et les versions ultérieures avec la charge de travail Développement d’applications de bureau en C++. Cette charge de travail installe l’invite de commandes x64 Native Tools utilisée dans ce démarrage rapide. Pour les instructions de l’ouverture, voir Utiliser un raccourci d’invite de commande développeur hébergé 64 bits.
- Microsoft OLE DB Driver 19 pour SQL Server. Installez le pilote x64 et sélectionnez à la fois les composants clients et le kit de développement logiciel (SDK).
Créer une base de données SQL
Créer ou connecter une base de données SQL sur l’une des plateformes suivantes :
Pour ce démarrage rapide, sélectionnez ou chargez les données d’échantillon AdventureWorksLT .
Pour un conteneur SQL Server, créez le conteneur et chargez les données d’exemple en une seule commande :
sqlcmd create mssql --accept-eula --using https://aka.ms/AdventureWorksLT.bak
Pour une instance SQL Server existante, restaurez une AdventureWorksLT sauvegarde à partir de bases de données d’exemple AdventureWorks.
L’application cliente OLE DB dans ce démarrage rapide fonctionne sous Windows. Un conteneur SQL Server peut s’exécuter sur un autre hôte pris en charge.
Vérifiez le pilote
Ouvrez une invite de commandes des outils natifs x64 pour votre version de Visual Studio, puis exécutez la commande suivante :
Important
Les commandes de ce démarrage rapide utilisent la syntaxe de l’invite de commande. Exécutez-les dans une invite de commandes x64 Native Tools, où l’invite se termine par >. Ne les exécutez pas dans PowerShell, où l’invite commence par PS.
reg query HKCR\MSOLEDBSQL19
La commande affiche le fournisseur enregistré MSOLEDBSQL19 .
Configurez la connexion
Définissez OLEDB_CONNECTION_STRING dans l’invite de commandes des outils natifs x64. L'application lit la chaîne de connexion depuis l'environnement et ne l'affiche pas.
Pour Azure SQL Database ou SQL Database dans Fabric, utilisez l’authentification interactive de Microsoft Entra. Remplacez les placeholders par le serveur, la base de données et l’identifiant utilisateur Microsoft Entra de votre ressource SQL :
set "OLEDB_CONNECTION_STRING=Provider=MSOLEDBSQL19;Data Source=tcp:<server>,1433;Initial Catalog=<database>;Authentication=ActiveDirectoryInteractive;User ID=<user_id>;Use Encryption for Data=Mandatory;Trust Server Certificate=false;"
Pour la base de données SQL dans Fabric, votre identité nécessite une autorisation de lecture pour l’élément de la base de données. L’authentification SQL n’est pas prise en charge. Pour plus d’informations, consultez Authentication dans la base de données SQL dans Microsoft Fabric.
Pour une instance SQL Server existante qui accepte l’authentification Windows, utilisez Integrated Security=SSPI:
set "OLEDB_CONNECTION_STRING=Provider=MSOLEDBSQL19;Data Source=tcp:<server>,1433;Initial Catalog=<database>;Integrated Security=SSPI;Use Encryption for Data=Mandatory;Trust Server Certificate=false;"
Pour une instance ou un conteneur SQL Server acceptant l’authentification SQL, utilisez Authentication=SqlPassword:
set "OLEDB_USER_ID=<user_id>"
set "OLEDB_PASSWORD=<password>"
set "OLEDB_CONNECTION_STRING=Provider=MSOLEDBSQL19;Data Source=tcp:<server>,1433;Initial Catalog=<database>;Authentication=SqlPassword;User ID=%OLEDB_USER_ID%;Password=%OLEDB_PASSWORD%;Use Encryption for Data=Mandatory;Trust Server Certificate=false;"
Le certificat SQL Server doit correspondre le nom du serveur et la chaîne à une autorité de certification (CA) en laquelle le client Windows a confiance. Pour un conteneur SQL Server, configurez la sécurité de la couche de transport (TLS) dans le conteneur et enregistrez l’autorité de certification émettrice sur le client Windows avant d’exécuter l’application. Pour plus d’informations, voir Chiffrer les connexions vers SQL Server sur Linux et Configurer le Moteur de base de données SQL Server pour chiffrer les connexions.
Créer l’application
Créez un répertoire de projets :
mkdir oledb-quickstart cd oledb-quickstartCréez un fichier nommé
oledb-quickstart.cppavec le code suivant :#include <windows.h> #include <oledb.h> #include <msdasc.h> #include <msoledbsql.h> #include <cstddef> #include <iomanip> #include <iostream> #include <string> template <typename T> void Release(T*& pointer) { if (pointer != nullptr) { pointer->Release(); pointer = nullptr; } } struct ParameterData { DBSTATUS status; DBLENGTH length; LONG value; }; constexpr std::size_t productNameCharacters = 51; struct RowData { DBSTATUS productIdStatus; DBLENGTH productIdLength; LONG productId; DBSTATUS nameStatus; DBLENGTH nameLength; wchar_t name[productNameCharacters]; }; std::wstring ReadEnvironmentVariable(const wchar_t* name) { const DWORD length = GetEnvironmentVariableW(name, nullptr, 0); if (length == 0) return {}; std::wstring value(length, L'\0'); const DWORD copied = GetEnvironmentVariableW( name, value.data(), length); if (copied == 0 || copied >= length) return {}; value.resize(copied); return value; } int wmain() { const std::wstring connectionString = ReadEnvironmentVariable(L"OLEDB_CONNECTION_STRING"); if (connectionString.empty()) { std::wcerr << L"Set OLEDB_CONNECTION_STRING before running.\n"; return 1; } HRESULT result = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if (FAILED(result)) { std::wcerr << L"COM initialization failed: 0x" << std::hex << result << L'\n'; return 1; } IDataInitialize* dataInitialize = nullptr; IDBInitialize* dbInitialize = nullptr; IDBCreateSession* createSession = nullptr; IDBCreateCommand* createCommand = nullptr; ICommandText* commandText = nullptr; ICommandWithParameters* commandParameters = nullptr; IAccessor* parameterAccessor = nullptr; IRowset* rowset = nullptr; IAccessor* rowAccessor = nullptr; HACCESSOR parameterHandle = DB_NULL_HACCESSOR; HACCESSOR rowHandle = DB_NULL_HACCESSOR; HROW* rows = nullptr; DBCOUNTITEM rowCount = 0; bool initialized = false; do { result = CoCreateInstance( CLSID_MSDAINITIALIZE, nullptr, CLSCTX_INPROC_SERVER, IID_IDataInitialize, reinterpret_cast<void**>(&dataInitialize)); if (FAILED(result)) break; result = dataInitialize->GetDataSource( nullptr, CLSCTX_INPROC_SERVER, connectionString.c_str(), IID_IDBInitialize, reinterpret_cast<IUnknown**>(&dbInitialize)); if (FAILED(result)) break; result = dbInitialize->Initialize(); if (FAILED(result)) break; initialized = true; result = dbInitialize->QueryInterface( IID_IDBCreateSession, reinterpret_cast<void**>(&createSession)); if (FAILED(result)) break; result = createSession->CreateSession( nullptr, IID_IDBCreateCommand, reinterpret_cast<IUnknown**>(&createCommand)); if (FAILED(result)) break; result = createCommand->CreateCommand( nullptr, IID_ICommandText, reinterpret_cast<IUnknown**>(&commandText)); if (FAILED(result)) break; result = commandText->SetCommandText( DBGUID_DBSQL, const_cast<wchar_t*>( L"SELECT TOP (5) ProductID, Name " L"FROM SalesLT.Product " L"WHERE ProductID > ? " L"ORDER BY ProductID;")); if (FAILED(result)) break; result = commandText->QueryInterface( IID_ICommandWithParameters, reinterpret_cast<void**>(&commandParameters)); if (FAILED(result)) break; DB_UPARAMS parameterOrdinal = 1; wchar_t parameterType[] = L"int"; DBPARAMBINDINFO parameterInfo = {}; parameterInfo.pwszDataSourceType = parameterType; parameterInfo.ulParamSize = sizeof(LONG); parameterInfo.dwFlags = DBPARAMFLAGS_ISINPUT; parameterInfo.bPrecision = 10; result = commandParameters->SetParameterInfo( 1, ¶meterOrdinal, ¶meterInfo); if (FAILED(result)) break; result = commandText->QueryInterface( IID_IAccessor, reinterpret_cast<void**>(¶meterAccessor)); if (FAILED(result)) break; DBBINDING parameterBinding = {}; parameterBinding.iOrdinal = 1; parameterBinding.obStatus = offsetof(ParameterData, status); parameterBinding.obLength = offsetof(ParameterData, length); parameterBinding.obValue = offsetof(ParameterData, value); parameterBinding.dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE; parameterBinding.dwMemOwner = DBMEMOWNER_CLIENTOWNED; parameterBinding.eParamIO = DBPARAMIO_INPUT; parameterBinding.cbMaxLen = sizeof(LONG); parameterBinding.wType = DBTYPE_I4; parameterBinding.bPrecision = 10; DBBINDSTATUS parameterBindStatus = DBBINDSTATUS_OK; result = parameterAccessor->CreateAccessor( DBACCESSOR_PARAMETERDATA, 1, ¶meterBinding, sizeof(ParameterData), ¶meterHandle, ¶meterBindStatus); if (FAILED(result) || parameterBindStatus != DBBINDSTATUS_OK) { if (SUCCEEDED(result)) result = E_FAIL; break; } ParameterData parameter = { DBSTATUS_S_OK, sizeof(LONG), 0 }; DBPARAMS parameters = { ¶meter, 1, parameterHandle }; result = commandText->Execute( nullptr, IID_IRowset, ¶meters, nullptr, reinterpret_cast<IUnknown**>(&rowset)); if (FAILED(result)) break; result = rowset->QueryInterface( IID_IAccessor, reinterpret_cast<void**>(&rowAccessor)); if (FAILED(result)) break; DBBINDING rowBindings[2] = {}; rowBindings[0].iOrdinal = 1; rowBindings[0].obStatus = offsetof(RowData, productIdStatus); rowBindings[0].obLength = offsetof(RowData, productIdLength); rowBindings[0].obValue = offsetof(RowData, productId); rowBindings[0].dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE; rowBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED; rowBindings[0].eParamIO = DBPARAMIO_NOTPARAM; rowBindings[0].cbMaxLen = sizeof(LONG); rowBindings[0].wType = DBTYPE_I4; rowBindings[0].bPrecision = 10; rowBindings[1].iOrdinal = 2; rowBindings[1].obStatus = offsetof(RowData, nameStatus); rowBindings[1].obLength = offsetof(RowData, nameLength); rowBindings[1].obValue = offsetof(RowData, name); rowBindings[1].dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE; rowBindings[1].dwMemOwner = DBMEMOWNER_CLIENTOWNED; rowBindings[1].eParamIO = DBPARAMIO_NOTPARAM; rowBindings[1].cbMaxLen = productNameCharacters * sizeof(wchar_t); rowBindings[1].wType = DBTYPE_WSTR; DBBINDSTATUS rowBindStatus[2] = { DBBINDSTATUS_OK, DBBINDSTATUS_OK }; result = rowAccessor->CreateAccessor( DBACCESSOR_ROWDATA, 2, rowBindings, sizeof(RowData), &rowHandle, rowBindStatus); if (FAILED(result) || rowBindStatus[0] != DBBINDSTATUS_OK || rowBindStatus[1] != DBBINDSTATUS_OK) { if (SUCCEEDED(result)) result = E_FAIL; break; } DBCOUNTITEM productsPrinted = 0; while (true) { result = rowset->GetNextRows( DB_NULL_HCHAPTER, 0, 1, &rowCount, &rows); if (FAILED(result) || rowCount == 0) break; RowData row = {}; result = rowset->GetData(rows[0], rowHandle, &row); if (FAILED(result) || row.productIdStatus != DBSTATUS_S_OK || row.productIdLength != sizeof(LONG) || row.nameStatus != DBSTATUS_S_OK || row.nameLength == 0 || row.nameLength % sizeof(wchar_t) != 0 || row.nameLength >= sizeof(row.name)) { result = E_FAIL; break; } row.name[row.nameLength / sizeof(wchar_t)] = L'\0'; if (productsPrinted == 0) { std::wcout << L"Connected with MSOLEDBSQL19.\n\n"; std::wcout << std::left << std::setw(12) << L"Product ID" << L"Name\n"; std::wcout << std::setw(12) << L"----------" << L"----\n"; } std::wcout << std::left << std::setw(12) << row.productId << row.name << L'\n'; ++productsPrinted; result = rowset->ReleaseRows( rowCount, rows, nullptr, nullptr, nullptr); CoTaskMemFree(rows); rows = nullptr; rowCount = 0; if (FAILED(result)) break; } if (FAILED(result)) break; if (productsPrinted == 0) { result = E_FAIL; break; } } while (false); if (rows != nullptr) { if (rowset != nullptr && rowCount != 0) rowset->ReleaseRows(rowCount, rows, nullptr, nullptr, nullptr); CoTaskMemFree(rows); } if (rowHandle != DB_NULL_HACCESSOR && rowAccessor != nullptr) rowAccessor->ReleaseAccessor(rowHandle, nullptr); if (parameterHandle != DB_NULL_HACCESSOR && parameterAccessor != nullptr) parameterAccessor->ReleaseAccessor(parameterHandle, nullptr); Release(rowAccessor); Release(rowset); Release(parameterAccessor); Release(commandParameters); Release(commandText); Release(createCommand); Release(createSession); if (initialized) dbInitialize->Uninitialize(); Release(dbInitialize); Release(dataInitialize); CoUninitialize(); if (FAILED(result)) { std::wcerr << L"OLE DB operation failed: 0x" << std::hex << result << L'\n'; return 1; } return 0; }
La chaîne de connexion est passée à IDataInitialize::GetDataSource. Cette API utilise les noms de mots-clés espacés Use Encryption for Data et Trust Server Certificate. Les chaînes de connexion demandent le chiffrement et nécessitent une validation des certificats.
La requête utilise un point d’interrogation comme marqueur de paramètre. L’application lie l’ID produit minimal 0 comme un int SQL Server, lit jusqu’à cinq lignes de SalesLT.Product, et affiche l’ID produit et le nom.
Générer et exécuter l’application
Dans la même invite de commandes x64 Native Tools, recherchez le fichier d’en-tête du SDK OLE DB installé et stockez le répertoire correspondant dans
OLEDB_INCLUDE:for /f "delims=" %i in ('where /r "%ProgramFiles%\Microsoft SQL Server\Client SDK\OLEDB" msoledbsql.h') do for %j in ("%~dpi.") do set "OLEDB_INCLUDE=%~fj"Affichez le répertoire sélectionné, et vérifiez qu’il contient l’en-tête :
echo %OLEDB_INCLUDE% dir "%OLEDB_INCLUDE%\msoledbsql.h"Compilez l’application :
cl /std:c++17 /EHsc /W4 /I"%OLEDB_INCLUDE%" oledb-quickstart.cpp /link ole32.lib oleaut32.libExécutez l’application :
oledb-quickstart.exeEffacer la chaîne de connexion de l’invite de commande actuelle :
set OLEDB_CONNECTION_STRING= set OLEDB_USER_ID= set OLEDB_PASSWORD=
Les lignes de produits peuvent varier selon la version d’AdventureWorksLT. La sortie ressemble à l’exemple suivant :
Connected with MSOLEDBSQL19.
Product ID Name
---------- ----
680 HL Road Frame - Black, 58
706 HL Road Frame - Red, 58
707 Sport-100 Helmet, Red
708 Sport-100 Helmet, Black
709 Mountain Bike Socks, M