變更 SQL Server 驗證使用者密碼 (OLE DB)
此範例顯示如何使用 OLE DB 變更 SQL Server 驗證下,使用者帳戶的密碼。
安全性注意事項 |
---|
盡可能使用 Windows 驗證。 如果無法使用 Windows 驗證,請提示使用者在執行階段輸入認證。 請避免將認證儲存在檔案中。 如果您必須保存認證,則應該用 Win32 crypto API 加密這些認證。 |
範例
建立之前,請更新 .C++ 程式碼來指定使用者識別碼、舊密碼與新密碼。
這個應用程式會連接到電腦的預設 SQL Server 執行個體。 在某些 Windows 作業系統上,您必須將 (localhost) 或 (local) 變更為 SQL Server 執行個體的名稱。 若要連接到具名執行個體,請將連接字串從 L"(local)" 變更為 L"(local)\\name",其中 name 是具名執行個體。 根據預設,SQL Server Express 會安裝至具名執行個體。 請確認您的 INCLUDE 環境變數包含的目錄內含 sqlncli.h。
使用 ole32.lib oleaut32.lib 編譯。
若要建立此範例,您將需要已知其密碼的 SQL Server 驗證使用者帳戶。 若要允許在 SQL Server 驗證下登入,請開啟 SQL Server Management Studio、以滑鼠右鍵按一下 [物件總管] 中的 [伺服器] 節點,然後選取 [屬性]。 選取 [安全性],然後啟用 SQL Server 和 Windows 驗證模式。 若要在 SQL Server 驗證下加入使用者帳戶,請以滑鼠右鍵按一下 [物件總管] 中的 [安全性] 節點,然後選取 [加入]。
您將執行此範例的伺服器必須針對 SQL Server 驗證,至少啟用一個登入。 您也必須啟用伺服器以允許 SQL Server 驗證登入。
// compile with: ole32.lib oleaut32.lib
void InitializeAndEstablishConnection();
#define STATUSDUMP(status) case status : wprintf(L"status"); break;
#define UNICODE
#define DBINITCONSTANTS
#define INITGUID
#include <assert.h>
#include <windows.h>
#include <stdio.h>
#include <stddef.h>
#include <IOSTREAM>
#include <cguid.h>
#include <oledb.h>
#include <oledberr.h>
#include <SQLNCLI.h>
LPMALLOC pMalloc = NULL;
IDBInitialize * pIDBInitialize = NULL;
HRESULT hr;
void DumpErrorInfo (IUnknown* pObjectWithError, REFIID IID_InterfaceWithError);
void DumpErrorInfo (IUnknown* pObjectWithError, REFIID IID_InterfaceWithError, BOOL &has_sql_errors);
int main() {
// All the initialization activities in a separate function.
InitializeAndEstablishConnection();
if ( FAILED( pIDBInitialize->Uninitialize() ) )
// Uninitialize is not required, but fails if an interface was not released.
printf("Problem uninitializing.\n");
pIDBInitialize->Release();
CoUninitialize();
};
void InitializeAndEstablishConnection() {
IDBProperties * pIDBProperties = NULL;
const ULONG nInitProps = 4;
DBPROP InitProperties[nInitProps];
const ULONG nSSInitProps = 1;
DBPROP SSInitProperties[nSSInitProps];
const ULONG nPropSet = 2;
DBPROPSET rgInitPropSet[nPropSet];
// Initialize the COM library.
CoInitialize(NULL);
CoGetMalloc(1, &pMalloc);
CLSID clsid;
CLSIDFromProgID(L"SQLNCLI11", &clsid);
// Obtain access to the SQLOLEDB provider.
hr = CoCreateInstance( clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize, (void **) &pIDBInitialize);
if (FAILED(hr))
printf("Failed in CoCreateInstance().\n");
// Initialize the property values needed to establish the connection.
for (int i = 0; i < nInitProps; i++)
VariantInit(&InitProperties[i].vValue);
// Specify database name.
InitProperties[0].dwPropertyID = DBPROP_INIT_CATALOG;
InitProperties[0].vValue.vt = VT_BSTR;
// Change the following line to use any database on your server
InitProperties[0].vValue.bstrVal = SysAllocString(L"master");
InitProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
InitProperties[0].colid = DB_NULLID;
InitProperties[1].dwPropertyID = DBPROP_AUTH_USERID;
InitProperties[1].vValue.vt = VT_BSTR;
// Modify the following line to add the user ID of a SQL Server Authentication account on your server
InitProperties[1].vValue.bstrVal = SysAllocString(L"");
InitProperties[1].dwOptions = DBPROPOPTIONS_REQUIRED;
InitProperties[1].colid = DB_NULLID;
InitProperties[2].dwPropertyID = DBPROP_AUTH_PASSWORD;
InitProperties[2].vValue.vt = VT_BSTR;
// Modify the following line to add the new SQL Server Authentication password
InitProperties[2].vValue.bstrVal = SysAllocString(L"");
InitProperties[2].dwOptions = DBPROPOPTIONS_REQUIRED;
InitProperties[2].colid = DB_NULLID;
InitProperties[3].dwPropertyID = DBPROP_INIT_DATASOURCE;
InitProperties[3].vValue.vt = VT_BSTR;
InitProperties[3].vValue.bstrVal = SysAllocString(L"(local)");
InitProperties[3].dwOptions = DBPROPOPTIONS_REQUIRED;
InitProperties[3].colid = DB_NULLID;
SSInitProperties[0].dwPropertyID = SSPROP_AUTH_OLD_PASSWORD;
SSInitProperties[0].vValue.vt = VT_BSTR;
// Modify the following line to specify the existing SQL Server Authentication password
SSInitProperties[0].vValue.bstrVal = SysAllocString(L"");
SSInitProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
SSInitProperties[0].colid = DB_NULLID;
rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
rgInitPropSet[0].cProperties = nInitProps;
rgInitPropSet[0].rgProperties = InitProperties;
rgInitPropSet[1].guidPropertySet = DBPROPSET_SQLSERVERDBINIT;
rgInitPropSet[1].cProperties = nSSInitProps;
rgInitPropSet[1].rgProperties = SSInitProperties;
// Set initialization properties.
hr = pIDBInitialize->QueryInterface( IID_IDBProperties, (void **)&pIDBProperties);
if (FAILED(hr))
printf("Failed to obtain IDBProperties interface.\n");
hr = pIDBProperties->SetProperties( nPropSet, rgInitPropSet);
if (FAILED(hr))
printf("Failed to set initialization properties.\n");
pIDBProperties->Release();
// establish connection to the data source.
DWORD now = GetTickCount();
if ( FAILED(pIDBInitialize->Initialize()) ) {
printf("Problem in initializing.\n");
DumpErrorInfo(pIDBInitialize, IID_IDBInitialize);
}
DWORD tookms = GetTickCount() - now;
printf("Connection took %d ms.\n", tookms);
}
// DumpErrorInfo queries SQLOLEDB error interfaces, retrieving available status
// or error information. This version is called when SQL Server errors are not expected.
void DumpErrorInfo (IUnknown* pObjectWithError, REFIID IID_InterfaceWithError) {
BOOL has_sql_errors;
DumpErrorInfo (pObjectWithError, IID_InterfaceWithError, has_sql_errors);
}
// DumpErrorInfo queries SQLOLEDB error interfaces, retrieving available status
// or error information. This version is called when an SQL Server error could occur.
void DumpErrorInfo (IUnknown* pObjectWithError, REFIID IID_InterfaceWithError, BOOL &has_sql_errors ) {
// Interfaces used in the example.
IErrorInfo * pIErrorInfoAll = NULL;
IErrorInfo * pIErrorInfoRecord = NULL;
IErrorRecords * pIErrorRecords = NULL;
ISupportErrorInfo * pISupportErrorInfo = NULL;
ISQLErrorInfo * pISQLErrorInfo = NULL;
ISQLServerErrorInfo * pISQLServerErrorInfo = NULL;
// Number of error records.
ULONG nRecs;
ULONG nRec;
// Basic error information from GetBasicErrorInfo.
ERRORINFO errorinfo;
// IErrorInfo values.
BSTR bstrDescription;
BSTR bstrSource;
// ISQLErrorInfo parameters.
BSTR bstrSQLSTATE;
LONG lNativeError;
// ISQLServerErrorInfo parameter pointers.
SSERRORINFO * pSSErrorInfo = NULL;
OLECHAR * pSSErrorStrings = NULL;
// Hard-code an American English locale for the example.
DWORD MYLOCALEID = 0x0409;
has_sql_errors = 0;
// Only ask for error information if the interface supports it.
if (FAILED(pObjectWithError->QueryInterface(IID_ISupportErrorInfo, (void**) &pISupportErrorInfo)))
wprintf(L"SupportErrorErrorInfo interface not supported\n");
else if (FAILED(pISupportErrorInfo->InterfaceSupportsErrorInfo(IID_InterfaceWithError)))
wprintf(L"InterfaceWithError interface not supported\n");
// Do not test the return of GetErrorInfo. It can succeed and return
// a NULL pointer in pIErrorInfoAll. Simply test the pointer.
GetErrorInfo(0, &pIErrorInfoAll);
// Test to see if it's a valid OLE DB IErrorInfo interface exposing a list of records.
if (pIErrorInfoAll != NULL) {
if (SUCCEEDED(pIErrorInfoAll->QueryInterface(IID_IErrorRecords, (void**) &pIErrorRecords))) {
pIErrorRecords->GetRecordCount(&nRecs);
// Within each record, retrieve information from each of the defined interfaces.
for (nRec = 0; nRec < nRecs; nRec++) {
ULONG errorno = nRecs - nRec - 1;
// From IErrorRecords, get the HRESULT and a reference to the ISQLErrorInfo interface.
pIErrorRecords->GetBasicErrorInfo(errorno, &errorinfo);
pIErrorRecords->GetCustomErrorObject(errorno,IID_ISQLErrorInfo, (IUnknown**) &pISQLErrorInfo);
// Display the HRESULT, then use the ISQLErrorInfo.
wprintf(L"HRESULT:\t%#X\n", errorinfo.hrError);
if (pISQLErrorInfo != NULL) {
pISQLErrorInfo->GetSQLInfo(&bstrSQLSTATE, &lNativeError);
// Display SQLSTATE and native error values.
wprintf(L"SQLSTATE:\t%s\nNative Error:\t%ld\n", bstrSQLSTATE, lNativeError);
// SysFree BSTR references.
SysFreeString(bstrSQLSTATE);
// Get the ISQLServerErrorInfo interface from
// ISQLErrorInfo before releasing the reference.
pISQLErrorInfo->QueryInterface(IID_ISQLServerErrorInfo, (void**) &pISQLServerErrorInfo);
pISQLErrorInfo->Release();
}
// Test to ensure the reference is valid, then get error information from ISQLServerErrorInfo.
if (pISQLServerErrorInfo != NULL) {
pISQLServerErrorInfo->GetErrorInfo(&pSSErrorInfo, &pSSErrorStrings);
// ISQLServerErrorInfo::GetErrorInfo succeeds even when it
// has nothing to return. Test the pointers before using.
if (pSSErrorInfo) {
// Display the state and severity from the returned
// information. The error message comes from
// IErrorInfo::GetDescription.
wprintf(L"Error state:\t%d\nSeverity:\t%d\n", pSSErrorInfo->bState, pSSErrorInfo->bClass);
wprintf(L"Procedure:\t%s\nLine:\t%d\n", pSSErrorInfo->pwszProcedure, pSSErrorInfo->wLineNumber);
has_sql_errors++;
// IMalloc::Free needed to release references on returned values.
pMalloc->Free(pSSErrorStrings);
pMalloc->Free(pSSErrorInfo);
}
pISQLServerErrorInfo->Release();
}
if (SUCCEEDED(pIErrorRecords->GetErrorInfo(errno, MYLOCALEID, &pIErrorInfoRecord))) {
// Get the source and description (error message) from the record's IErrorInfo.
pIErrorInfoRecord->GetSource(&bstrSource);
pIErrorInfoRecord->GetDescription(&bstrDescription);
if (bstrSource != NULL) {
wprintf(L"Source:\t\t%s\n", bstrSource);
SysFreeString(bstrSource);
}
if (bstrDescription != NULL) {
wprintf(L"Error message:\t%s\n", bstrDescription);
SysFreeString(bstrDescription);
}
pIErrorInfoRecord->Release();
}
}
pIErrorRecords->Release();
}
else {
// IErrorInfo is valid; get the source and
// description to see what it is.
pIErrorInfoAll->GetSource(&bstrSource);
pIErrorInfoAll->GetDescription(&bstrDescription);
if (bstrSource != NULL) {
wprintf(L"Source:\t\t%s\n", bstrSource);
SysFreeString(bstrSource);
}
if (bstrDescription != NULL) {
wprintf(L"Error message:\t%s\n", bstrDescription);
SysFreeString(bstrDescription);
}
}
pIErrorInfoAll->Release();
}
else
wprintf(L"GetErrorInfo failed.\n");
if (pISupportErrorInfo != NULL)
pISupportErrorInfo->Release();
}