336 lines
11 KiB
C++
336 lines
11 KiB
C++
//---------------------------------------------------------------------------
|
|
// Microsoft OLE DB Programmer's Reference Sample
|
|
// Copyright (C) 1998 By Microsoft Corporation.
|
|
//
|
|
// @doc
|
|
//
|
|
// @module DATASOURCE.CPP
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Includes
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
#include "prsample.h" // Programmer's Reference Sample includes
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// myCreateDataSource
|
|
//
|
|
// This function creates an OLE DB DataSource object for a
|
|
// provider selected by the user, sets initialization properties
|
|
// for the DataSource, and initializes the DataSource. The
|
|
// function returns a pointer to the DataSource object's
|
|
// IUnknown in *ppUnkDataSource.
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT myCreateDataSource
|
|
(
|
|
IUnknown ** ppUnkDataSource
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
IDataInitialize * pIDataInitialize = NULL;
|
|
IDBPromptInitialize * pIDBPromptInitialize = NULL;
|
|
IDBInitialize * pIDBInitialize = NULL;
|
|
CLSID clsid = CLSID_MSDASQL;
|
|
|
|
// Use the Microsoft Data Links UI to create the DataSource
|
|
// object; this will allow the user to select the provider
|
|
// to connect to and to set the initialization properties
|
|
// for the DataSource object, which will be created by the
|
|
// Data Links UI.
|
|
if( g_dwFlags & USE_PROMPTDATASOURCE )
|
|
{
|
|
// Create the Data Links UI object and obtain the
|
|
// IDBPromptInitialize interface from it
|
|
XCHECK_HR(hr = CoCreateInstance(
|
|
CLSID_DataLinks, //clsid -- Data Links UI
|
|
NULL, //pUnkOuter
|
|
CLSCTX_INPROC_SERVER, //dwClsContext
|
|
IID_IDBPromptInitialize, //riid
|
|
(void**)&pIDBPromptInitialize //ppvObj
|
|
));
|
|
|
|
// Invoke the Data Links UI to allow the user to select
|
|
// the provider and set initialization properties for
|
|
// the DataSource object that this will create
|
|
XCHECK_HR(hr = pIDBPromptInitialize->PromptDataSource(
|
|
NULL, //pUnkOuter
|
|
GetDesktopWindow(), //hWndParent
|
|
DBPROMPTOPTIONS_PROPERTYSHEET, //dwPromptOptions
|
|
0, //cSourceTypeFilter
|
|
NULL, //rgSourceTypeFilter
|
|
NULL, //pwszszzProviderFilter
|
|
IID_IDBInitialize, //riid
|
|
(IUnknown**)&pIDBInitialize //ppDataSource
|
|
));
|
|
|
|
// We've obtained a DataSource object from the Data Links UI. This
|
|
// object has had its initialization properties set, so all we
|
|
// need to do is Initialize it
|
|
XCHECK_HR(hr = pIDBInitialize->Initialize());
|
|
}
|
|
// We are not using the Data Links UI to create the DataSource object.
|
|
// Instead, we will enumerate the providers installed on this system
|
|
// through the OLE DB Enumerator and will allow the user to select
|
|
// the ProgID of the provider for which we will create a DataSource
|
|
// object.
|
|
else
|
|
{
|
|
// Use the OLE DB Enumerator to obtain a rowset of installed providers,
|
|
// then allow the user to select a provider from this rowset
|
|
CHECK_HR(hr = myCreateEnumerator(CLSID_OLEDB_ENUMERATOR, &clsid));
|
|
|
|
// We will create the DataSource object through the OLE DB service
|
|
// component IDataInitialize interface, so we need to create an
|
|
// instance of the data initialization object
|
|
XCHECK_HR(hr = CoCreateInstance(
|
|
CLSID_MSDAINITIALIZE, //clsid -- data initialize
|
|
NULL, //pUnkOuter
|
|
CLSCTX_INPROC_SERVER, //dwClsContext
|
|
IID_IDataInitialize, //riid
|
|
(void**)&pIDataInitialize //ppvObj
|
|
));
|
|
|
|
// Use IDataInitialize::CreateDBInstance to create an uninitialized
|
|
// DataSource object for the chosen provider. By using this service
|
|
// component method, the service component manager can provide
|
|
// additional functionality beyond what is natively supported by the
|
|
// provider if the consumer requests that functionality
|
|
XCHECK_HR(hr = pIDataInitialize->CreateDBInstance(
|
|
clsid, //clsid -- provider
|
|
NULL, //pUnkOuter
|
|
CLSCTX_INPROC_SERVER, //dwClsContext
|
|
NULL, //pwszReserved
|
|
IID_IDBInitialize, //riid
|
|
(IUnknown**)&pIDBInitialize //ppDataSource
|
|
));
|
|
|
|
// Initialize the DataSource object by setting any required
|
|
// initialization properties and calling IDBInitialize::Initialize
|
|
CHECK_HR(hr = myDoInitialization(pIDBInitialize));
|
|
}
|
|
|
|
CLEANUP:
|
|
*ppUnkDataSource = pIDBInitialize;
|
|
if( pIDataInitialize )
|
|
pIDataInitialize->Release();
|
|
if( pIDBPromptInitialize )
|
|
pIDBPromptInitialize->Release();
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// myDoInitialization
|
|
//
|
|
// This function sets initialization properties that tell the
|
|
// provider to prompt the user for any information required to
|
|
// initialize the provider, then calls the provider's
|
|
// initialization function.
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT myDoInitialization
|
|
(
|
|
IUnknown * pIUnknown
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
IDBInitialize * pIDBInitialize = NULL;
|
|
IDBProperties * pIDBProperties = NULL;
|
|
HWND hWnd = GetDesktopWindow();
|
|
|
|
const ULONG cProperties = 2;
|
|
DBPROP rgProperties[cProperties];
|
|
DBPROPSET rgPropSets[1];
|
|
|
|
// In order to initialize the DataSource object most providers require
|
|
// some initialization properties to be set by the consumer. For instance,
|
|
// these might include the data source to connect to and the user ID and
|
|
// password to use to establish identity. We will ask the provider to
|
|
// prompt the user for this required information by setting the following
|
|
// properties:
|
|
myAddProperty(&rgProperties[0],DBPROP_INIT_PROMPT,VT_I2,DBPROMPT_COMPLETE);
|
|
#ifdef _WIN64
|
|
myAddProperty(&rgProperties[1],DBPROP_INIT_HWND, VT_I8, (LONG_PTR)hWnd);
|
|
#else
|
|
myAddProperty(&rgProperties[1],DBPROP_INIT_HWND, VT_I4, (LONG_PTR)hWnd);
|
|
#endif
|
|
|
|
rgPropSets[0].rgProperties = rgProperties;
|
|
rgPropSets[0].cProperties = cProperties;
|
|
rgPropSets[0].guidPropertySet = DBPROPSET_DBINIT;
|
|
|
|
// Obtain the needed interfaces
|
|
XCHECK_HR(hr = pIUnknown->QueryInterface(IID_IDBProperties,
|
|
(void**)&pIDBProperties));
|
|
XCHECK_HR(hr = pIUnknown->QueryInterface(IID_IDBInitialize,
|
|
(void**)&pIDBInitialize));
|
|
|
|
// If a provider requires initialization properties, it must support the
|
|
// properties that we are setting (_PROMPT and _HWND). However, some
|
|
// providers do not need initialization properties and may therefore
|
|
// not support the _PROMPT and _HWND properties. Because of this, we will
|
|
// not check the return value from SetProperties
|
|
hr = pIDBProperties->SetProperties(1, rgPropSets);
|
|
|
|
// Now that we've set our properties, initialize the provider
|
|
XCHECK_HR(hr = pIDBInitialize->Initialize());
|
|
|
|
CLEANUP:
|
|
if( pIDBProperties )
|
|
pIDBProperties->Release();
|
|
if( pIDBInitialize )
|
|
pIDBInitialize->Release();
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// myGetProperty
|
|
//
|
|
// This function gets the BOOL value for the specified property
|
|
// and returns the result in *pbValue.
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT myGetProperty
|
|
(
|
|
IUnknown * pIUnknown,
|
|
REFIID riid,
|
|
DBPROPID dwPropertyID,
|
|
REFGUID guidPropertySet,
|
|
BOOL * pbValue
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DBPROPID rgPropertyIDs[1];
|
|
DBPROPIDSET rgPropertyIDSets[1];
|
|
|
|
ULONG cPropSets = 0;
|
|
DBPROPSET * rgPropSets = NULL;
|
|
|
|
IDBProperties * pIDBProperties = NULL;
|
|
ISessionProperties * pISesProps = NULL;
|
|
ICommandProperties * pICmdProps = NULL;
|
|
IRowsetInfo * pIRowsetInfo = NULL;
|
|
|
|
// Initialize the output value
|
|
*pbValue = FALSE;
|
|
|
|
// Set up the property ID array
|
|
rgPropertyIDs[0] = dwPropertyID;
|
|
|
|
// Set up the Property ID Set
|
|
rgPropertyIDSets[0].rgPropertyIDs = rgPropertyIDs;
|
|
rgPropertyIDSets[0].cPropertyIDs = 1;
|
|
rgPropertyIDSets[0].guidPropertySet = guidPropertySet;
|
|
|
|
// Get the property value for this property from the provider, but
|
|
// don't try to display extended error information, since this may
|
|
// not be a supported property: a failure is, in fact, expected if
|
|
// the property is not supported
|
|
if( riid == IID_IDBProperties )
|
|
{
|
|
XCHECK_HR(hr = pIUnknown->QueryInterface(IID_IDBProperties,
|
|
(void**)&pIDBProperties));
|
|
CHECK_HR(hr = pIDBProperties->GetProperties(
|
|
1, //cPropertyIDSets
|
|
rgPropertyIDSets, //rgPropertyIDSets
|
|
&cPropSets, //pcPropSets
|
|
&rgPropSets //prgPropSets
|
|
));
|
|
}
|
|
else if( riid == IID_ISessionProperties )
|
|
{
|
|
XCHECK_HR(hr = pIUnknown->QueryInterface(IID_ISessionProperties,
|
|
(void**)&pISesProps));
|
|
CHECK_HR(hr = pISesProps->GetProperties(
|
|
1, //cPropertyIDSets
|
|
rgPropertyIDSets, //rgPropertyIDSets
|
|
&cPropSets, //pcPropSets
|
|
&rgPropSets //prgPropSets
|
|
));
|
|
}
|
|
else if( riid == IID_ICommandProperties )
|
|
{
|
|
XCHECK_HR(hr = pIUnknown->QueryInterface(IID_ICommandProperties,
|
|
(void**)&pICmdProps));
|
|
CHECK_HR(hr = pICmdProps->GetProperties(
|
|
1, //cPropertyIDSets
|
|
rgPropertyIDSets, //rgPropertyIDSets
|
|
&cPropSets, //pcPropSets
|
|
&rgPropSets //prgPropSets
|
|
));
|
|
}
|
|
else
|
|
{
|
|
XCHECK_HR(hr = pIUnknown->QueryInterface(IID_IRowsetInfo,
|
|
(void**)&pIRowsetInfo));
|
|
CHECK_HR(hr = pIRowsetInfo->GetProperties(
|
|
1, //cPropertyIDSets
|
|
rgPropertyIDSets, //rgPropertyIDSets
|
|
&cPropSets, //pcPropSets
|
|
&rgPropSets //prgPropSets
|
|
));
|
|
}
|
|
|
|
// Return the value for this property to the caller if
|
|
// it's a VT_BOOL type value, as expected
|
|
if( V_VT(&rgPropSets[0].rgProperties[0].vValue) == VT_BOOL )
|
|
*pbValue = V_BOOL(&rgPropSets[0].rgProperties[0].vValue);
|
|
|
|
CLEANUP:
|
|
if( rgPropSets )
|
|
{
|
|
CoTaskMemFree(rgPropSets[0].rgProperties);
|
|
CoTaskMemFree(rgPropSets);
|
|
}
|
|
if( pIDBProperties )
|
|
pIDBProperties->Release();
|
|
if( pISesProps )
|
|
pISesProps->Release();
|
|
if( pICmdProps )
|
|
pICmdProps->Release();
|
|
if( pIRowsetInfo )
|
|
pIRowsetInfo->Release();
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// myAddProperty
|
|
//
|
|
// This function initializes the property structure pProp
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
void myAddProperty
|
|
(
|
|
DBPROP * pProp,
|
|
DBPROPID dwPropertyID,
|
|
VARTYPE vtType,
|
|
LONG_PTR lValue,
|
|
DBPROPOPTIONS dwOptions
|
|
)
|
|
{
|
|
// Set up the property structure
|
|
pProp->dwPropertyID = dwPropertyID;
|
|
pProp->dwOptions = dwOptions;
|
|
pProp->dwStatus = DBPROPSTATUS_OK;
|
|
pProp->colid = DB_NULLID;
|
|
V_VT(&pProp->vValue) = vtType;
|
|
|
|
// Since VARIANT data is a union, we can place the value in any
|
|
// member (except for VT_DECIMAL, which is a union with the whole
|
|
// VARIANT structure -- but we know we're not passing VT_DECIMAL)
|
|
if (vtType != VT_I8)
|
|
V_I4(&pProp->vValue) = (LONG)lValue;
|
|
else
|
|
V_I8(&pProp->vValue) = lValue;
|
|
}
|