⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s15_02.cpp

📁 本书分为五个部分
💻 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 + -