📄 s15_02.cpp
字号:
// S15_02.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
BOOL g_bPrompt; // 是否提示用户选择数据源
// 错误处理有关函数
#define __LONGSTRING(string) L##string
#define LONGSTRING(string) __LONGSTRING(string)
// 如果错误则跳转到CLEANUP.
#define CHECK_HR(hr) if(FAILED(hr)) goto CLEANUP
// 如果错误则跳转到CLEANUP, 并显示所有错误信息.
#define XCHECK_HR(hr) \
{ \
fwprintf(stderr, LONGSTRING(#hr) L"\n"); \
if(FAILED(HandleResult(hr, LONGSTRING(__FILE__), __LINE__))) \
goto CLEANUP; \
}
// 处理返回的HRESULT值.
HRESULT HandleResult(HRESULT hrReturned, LPCWSTR pwszFile, ULONG ulLine);
// 显示单个错误记录的错误信息. 包括来自ISQLErrorInfo的.
HRESULT DisplayErrorRecord(HRESULT hrReturned, ULONG iRecord,
IErrorRecords *pIErrorRecords,
LPCWSTR pwszFile, ULONG ulLine);
// 如果不支持IErrorInfo, 则显示基本的错误信息.
HRESULT DisplayErrorInfo(HRESULT hrReturned, IErrorInfo *pIErrorInfo,
LPCWSTR pwszFile, ULONG ulLine);
// 如果支持ISQLErrorInfo, 则获取SQL错误字符串和本地错误代码.
HRESULT GetSqlErrorInfo(ULONG iRecord, IErrorRecords *pIErrorRecords,
BSTR *pBstr, LONG *plNativeError);
// OLE DB ODBC提供程序的CLSID
extern const MSDASQLDECLSPEC GUID CLSID_MSDASQL = {0xC8B522CBL,0x5CF3,0x11CE,{0xAD,0xE5,0x00,0xAA,0x00,0x44,0x77,0x3D}};
// 创建数据源对象.
HRESULT CreateDataSource(IUnknown **ppUnkDataSource);
// 初始化数据源对象.
HRESULT DoInitialization(IUnknown *pIUnknown);
// 初始化单个属性结构DBPROP.
void AddProperty(DBPROP * pProp, DBPROPID dwPropertyID,
//VARTYPE vtType,
VARIANT vValue,
DBPROPOPTIONS dwOptions = DBPROPOPTIONS_REQUIRED,
DBID colid = DB_NULLID);
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = NULL;
IDBInitialize* pIDBInitialize = NULL;
//初始化COM库.
CoInitialize(NULL);
g_bPrompt = FALSE;
// 创建并初始化数据源对象.
//XCHECK_HR(hr = CreateDataSource((IUnknown**)&pIDBInitialize));
if( FAILED(hr = CreateDataSource((IUnknown**)&pIDBInitialize)) )
{
printf("失败: 创建数据源对象失败!!\n");
goto EXIT;
}
else
{
printf("成功: 创建数据源对象成功!!\n");
goto EXIT;
}
//CLEANUP:
EXIT:
if( pIDBInitialize ) pIDBInitialize->Release();
//清除COM库.
CoUninitialize();
return 0;
}
HRESULT CreateDataSource(IUnknown ** ppUnkDataSource)
{
HRESULT hr;
IDataInitialize * pIDataInitialize = NULL;
IDBPromptInitialize * pIDBPromptInitialize = NULL;
IDBInitialize * pIDBInitialize = NULL;
CLSID clsid = CLSID_MSDASQL;
//使用数据连接(Data Links)用户界面, 提示用户选择一个连接的提供程序.
if( g_bPrompt )
{
//创建数据连接组件对象, 并获取它的IDBPromptInitialize接口.
XCHECK_HR(hr = CoCreateInstance(
CLSID_DataLinks, // clsid--Data Links UI
NULL, // pUnkOuter
CLSCTX_INPROC_SERVER, // dwClsContext
IID_IDBPromptInitialize, // riid
(void**)&pIDBPromptInitialize)); // ppvObj
//提示用户选择一个要创建的数据提供程序.
XCHECK_HR(hr = pIDBPromptInitialize->PromptDataSource(
NULL, // pUnkOuter
GetDesktopWindow(), // hWndParent
DBPROMPTOPTIONS_PROPERTYSHEET, // dwPromptOptions
0, // cSourceTypeFilter
NULL, // rgSourceTypeFilter
NULL, // pwszszzProviderFilter
IID_IDBInitialize, // riid
(IUnknown**)&pIDBInitialize)); // ppDataSource
// 已经从数据连接对象获取了数据提供程序数据源对象.
// 这个对象已经包含有初始化属性集, 于是我们可以直接对其初始化.
XCHECK_HR(hr = pIDBInitialize->Initialize());
}
//不使用数据连接组件, 而直接创建OLE DB ODBC提供程序数据源对象.
else
{
// 创建OLE DB ODBC提供程序数据源对象.
XCHECK_HR(hr = CoCreateInstance(
CLSID_MSDASQL, // clsid--provider
NULL, // pUnkOuter
CLSCTX_INPROC_SERVER, // dwClsContext
IID_IDBInitialize, // riid
(LPVOID*)&pIDBInitialize)); // ppDataSource
// 初始化数据源对象.
CHECK_HR(hr = DoInitialization(pIDBInitialize));
}
CLEANUP:
*ppUnkDataSource = pIDBInitialize;
if( pIDataInitialize )
pIDataInitialize->Release();
if( pIDBPromptInitialize )
pIDBPromptInitialize->Release();
return hr;
}
HRESULT DoInitialization(IUnknown* pIUnknown)
{
HRESULT hr;
IDBInitialize * pIDBInitialize = NULL;
IDBProperties * pIDBProperties = NULL;
HWND hWnd = GetDesktopWindow();
//const ULONG cProperties = 2;
const ULONG cProperties = 4;
DBPROP rgProperties[cProperties];
DBPROPSET rgPropSets[1];
VARIANT vValue;
// 设置初始化属性.
// 提示用户提供所需的初始化属性.
//vValue.vt = VT_I2; vValue.lVal = DBPROMPT_COMPLETE;
//AddProperty(&rgProperties[0], DBPROP_INIT_PROMPT, vValue );
//vValue.vt = VT_I4; vValue.lVal = (LONG)hWnd;
//AddProperty(&rgProperties[1], DBPROP_INIT_HWND, vValue);
// 直接指定初始化属性, 而不提示用户.
// 指定不提示用户选择初始化属性.
vValue.vt = VT_I2; vValue.lVal = DBPROMPT_NOPROMPT;
AddProperty(&rgProperties[0], DBPROP_INIT_PROMPT, vValue);
// 提定用户名.
vValue.vt = VT_BSTR; vValue.bstrVal=SysAllocString((LPOLESTR)L"");
AddProperty(&rgProperties[1], DBPROP_AUTH_USERID, vValue);
// 指定用户口令.
vValue.vt = VT_BSTR; vValue.bstrVal=SysAllocString((LPOLESTR)L"");
AddProperty(&rgProperties[2], DBPROP_AUTH_PASSWORD, vValue);
// 指定数据源名称.
vValue.vt = VT_BSTR; vValue.bstrVal=SysAllocString((LPOLESTR)L"ENorthwind");
AddProperty(&rgProperties[3], DBPROP_INIT_DATASOURCE, vValue);
rgPropSets[0].rgProperties = rgProperties;
rgPropSets[0].cProperties = cProperties;
rgPropSets[0].guidPropertySet = DBPROPSET_DBINIT;
// 获取设置属性的接口: IDBProperties.
XCHECK_HR(hr = pIUnknown->QueryInterface(IID_IDBProperties,
(void**)&pIDBProperties));
XCHECK_HR(hr = pIUnknown->QueryInterface(IID_IDBInitialize,
(void**)&pIDBInitialize));
// 设置初始化属性.
XCHECK_HR(hr = pIDBProperties->SetProperties(1, rgPropSets));
// 初始化数据源对象..
XCHECK_HR(hr = pIDBInitialize->Initialize());
CLEANUP:
if( pIDBProperties )
pIDBProperties->Release();
if( pIDBInitialize )
pIDBInitialize->Release();
return hr;
}
/////////////////////////////////////////////////////////////////
// 函数: AddProperty
//
// 这个函数初始化属性结构(DBPROP)pProp.
//
////////////////////////////////////////////////////////////////
void AddProperty(DBPROP * pProp,
DBPROPID dwPropertyID,
VARIANT vValue,
DBPROPOPTIONS dwOptions,
DBID colid)
{
pProp->dwPropertyID = dwPropertyID;
pProp->dwOptions = dwOptions;
pProp->dwStatus = DBPROPSTATUS_OK;
pProp->colid = DB_NULLID;
pProp->vValue = vValue;
}
////////////////////////////////////////////////////////////////////////
// 函数: HandleResult
//
// 这个函数主要对返回码进行处理. 它根据对错误的支持程序, 进行不同的处理.
//
////////////////////////////////////////////////////////////////////////
HRESULT HandleResult(HRESULT hrReturned,
LPCWSTR pwszFile,
ULONG ulLine)
{
HRESULT hr;
IErrorInfo * pIErrorInfo = NULL;
IErrorRecords * pIErrorRecords = NULL;
ULONG cRecords;
ULONG iErr;
// 如果提供的返回码是错误码.
if( FAILED(hrReturned) )
{
// 通过使用自动化函数GetErrorInfo来获取自动化错误接口IErrorInfo.
hr = GetErrorInfo(0, &pIErrorInfo);
// 成功获取错误对象中的IErrorInfo接口指针.
if( SUCCEEDED(hr) && pIErrorInfo )
{
// OLE DB对自动化错误模式进行了扩展, 允许错误对象支持
// IErIErrorRecords接口, 而这个接口可输出多个错误记录.
hr = pIErrorInfo->QueryInterface(IID_IErrorRecords,
(void**)&pIErrorRecords);
if( SUCCEEDED(hr) )
{
// 获取错误对象的记录数.
CHECK_HR(hr = pIErrorRecords->GetRecordCount(&cRecords));
// 在错误记录集中循环, 显示每个记录信息.
for( iErr = 0; iErr < cRecords; iErr++ )
{
DisplayErrorRecord(hrReturned, iErr, pIErrorRecords,
pwszFile, ulLine);
}
}
// 如果错误对象不支持IErrorRecords接口,
// 则显示错误的基本信息(由IErrorInfo提供).
else
{
DisplayErrorInfo(hrReturned, pIErrorInfo, pwszFile, ulLine);
}
}
// 如果没有错误对象(不支持IErrorInfo接口), 则显示返回码(HRESULT)..
else
{
wprintf(L"\nNo Error Info posted; HResult: 0x%08x\n"
L"File: %s, Line: %d\n", hrReturned, pwszFile, ulLine);
}
}
CLEANUP:
if( pIErrorInfo )
pIErrorInfo->Release();
if( pIErrorRecords )
pIErrorRecords->Release();
return hrReturned;
}
////////////////////////////////////////////////////////////////////////
// 函数: DisplayErrorRecord
//
// 这个函数显示从IErrorRecords接口获取的单个错误记录信息.
// 也包括从ISQLErrorInfo接口获取的信息(如果支持).
//
////////////////////////////////////////////////////////////////////////
HRESULT DisplayErrorRecord(HRESULT hrReturned,
ULONG iRecord,
IErrorRecords * pIErrorRecords,
LPCWSTR pwszFile,
ULONG ulLine)
{
HRESULT hr;
IErrorInfo * pIErrorInfo = NULL;
BSTR bstrDescription = NULL;
BSTR bstrSource = NULL;
BSTR bstrSQLInfo = NULL;
static LCID lcid = GetUserDefaultLCID();
LONG lNativeError = 0;
ERRORINFO ErrorInfo;
// 获取错误记录的IErrorInfo接口指针.
CHECK_HR(hr = pIErrorRecords->GetErrorInfo(iRecord, lcid, &pIErrorInfo));
// 获取这个错误的描述.
CHECK_HR(hr = pIErrorInfo->GetDescription(&bstrDescription));
// 获取这个错误的源(产生错误的对象).
CHECK_HR(hr = pIErrorInfo->GetSource(&bstrSource));
// 获取这个错误记录的基本信息.
CHECK_HR(hr = pIErrorRecords->GetBasicErrorInfo(iRecord, &ErrorInfo));
// 如果错误对象支持ISQLErrorInfo, 则获取相关信息.
GetSqlErrorInfo(iRecord, pIErrorRecords, &bstrSQLInfo, &lNativeError);
// 显示错误信息.
if( bstrSQLInfo ) // 如果支持ISQLErrorInfo.
{
wprintf(L"\nErrorRecord: HResult: 0x%08x\nDescription: %s\n"
L"SQLErrorInfo: %s\nSource: %s\nFile: %s, Line: %d\n",
ErrorInfo.hrError,
bstrDescription,
bstrSQLInfo,
bstrSource,
pwszFile,
ulLine);
}
else // 如果不支持ISQLErrorInfo.
{
wprintf(L"\nErrorRecord: HResult: 0x%08x\nDescription: %s\n"
L"Source: %s\nFile: %s, Line: %d\n",
ErrorInfo.hrError,
bstrDescription,
bstrSource,
pwszFile,
ulLine);
}
CLEANUP:
if( pIErrorInfo ) pIErrorInfo->Release();
SysFreeString(bstrDescription);
SysFreeString(bstrSource);
SysFreeString(bstrSQLInfo);
return hr;
}
////////////////////////////////////////////////////////////////////////
// 函数: DisplayErrorInfo
//
// 这个函数显示错误对象的基本错误信息(不支持IErrorRecords时使用).
//
////////////////////////////////////////////////////////////////////////
HRESULT DisplayErrorInfo(HRESULT hrReturned,
IErrorInfo * pIErrorInfo,
LPCWSTR pwszFile,
ULONG ulLine)
{
HRESULT hr;
BSTR bstrDescription = NULL;
BSTR bstrSource = NULL;
// 获取错误的描述.
CHECK_HR(hr = pIErrorInfo->GetDescription(&bstrDescription));
// 获取这个错误的源(产生错误的对象). -- This will be the window title.
CHECK_HR(hr = pIErrorInfo->GetSource(&bstrSource));
// 显示错误信息.
wprintf(L"\nErrorInfo: HResult: 0x%08x, Description: %s\nSource: %s\n"
L"File: %s, Line: %d\n",
hrReturned,
bstrDescription,
bstrSource,
pwszFile,
ulLine);
CLEANUP:
SysFreeString(bstrDescription);
SysFreeString(bstrSource);
return hr;
}
////////////////////////////////////////////////////////////////////////
// GetSqlErrorInfo
//
// If the error object supports ISQLErrorInfo, get the SQL error
// string and native error code for this error.
//
////////////////////////////////////////////////////////////////////////
HRESULT GetSqlErrorInfo(ULONG iRecord,
IErrorRecords * pIErrorRecords,
BSTR * pBstr,
LONG * plNativeError)
{
HRESULT hr;
ISQLErrorInfo * pISQLErrorInfo = NULL;
LONG lNativeError = 0;
// Attempt to get the ISQLErrorInfo interface for this error
// record through GetCustomErrorObject. Note that ISQLErrorInfo
// is not mandatory, so failure is acceptable here.
// See ISQLErrorInfo
CHECK_HR(hr = pIErrorRecords->GetCustomErrorObject(
iRecord, // iRecord
IID_ISQLErrorInfo, // riid
(IUnknown**)&pISQLErrorInfo // ppISQLErrorInfo
));
// If we obtained the ISQLErrorInfo interface, get the SQL
// error string and native error code for this error.
if( pISQLErrorInfo )
hr = pISQLErrorInfo->GetSQLInfo(pBstr, &lNativeError);
CLEANUP:
if( plNativeError )
*plNativeError = lNativeError;
if( pISQLErrorInfo )
pISQLErrorInfo->Release();
return hr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -