Initializing and Uninitializing the Data Source Object
The IDBInitialize interface contains two methods: Initialize and Uninitialize. The following sections discuss the implementation of these methods in the sample provider.
Initializing the Data Source Object
Initialize enables consumers to explicitly initialize a data source object. Consumers must set properties on the data source object before attempting to initialize it; and consumers must supply a valid directory path to the data file in IDBProperties::SetProperties. If the directory path is invalid, the sample provider returns an E_FAIL error on initialization. The source code for IDBInitialize::Initialize follows; you can find the complete source code for IDBInitialize in DBInit.cpp.
// CImpIDBInitialize::Initialize ---------------------------------------------
//
// @mfunc Initializes the DataSource object.. For this provider it requires
// that a valid path is given to where the file will be located.
//
// @rdesc HRESULT
// @flag S_OK | Path exists
// @flag E_FAIL | Invalid path
// @flag E_INVALIDARG | Invalid Parameters passed in
// @flag DB_E_ALREADYINITIALIZED | Datasource Object already initialized
//
STDMETHODIMP CImpIDBInitialize::Initialize
(
)
{
ASSERT( m_pObj );
CHAR szDataSource[MAX_PATH + MAX_PATH + 1] = {0};
HRESULT hr;
ULONG cPropSets = 0;
DBPROPSET* rgPropSets = NULL;
WCHAR* pwszDataSource = NULL;
int nPrompt = DBPROMPT_NOPROMPT;
HWND hWnd = NULL;
IDBPromptInitialize* pIDBPromptInitialize = NULL;
IDBProperties* pIDBProperties = NULL;
if(m_pObj->m_fDSOInitialized)
return ResultFromScode( DB_E_ALREADYINITIALIZED );
//Setup Properties
const ULONG cProperties = 3;
DBPROPID rgProperties[cProperties] = { DBPROP_INIT_DATASOURCE, DBPROP_INIT_PROMPT, DBPROP_INIT_HWND };
const ULONG cPropertyIDSets = 1;
DBPROPIDSET rgPropertyIDSets[cPropertyIDSets];
rgPropertyIDSets[0].guidPropertySet = DBPROPSET_DBINIT;
rgPropertyIDSets[0].rgPropertyIDs = rgProperties;
rgPropertyIDSets[0].cPropertyIDs = cProperties;
//Get the property values
hr = m_pObj->m_pUtilProp->GetProperties(PROPSET_DSO, cPropertyIDSets, rgPropertyIDSets, &cPropSets, &rgPropSets );
if(SUCCEEDED(hr))
{
pwszDataSource = V_BSTR(&rgPropSets[0].rgProperties[0].vValue);
nPrompt = V_I2(&rgPropSets[0].rgProperties[1].vValue);
#ifdef _WIN64
hWnd = (HWND)V_I8(&rgPropSets[0].rgProperties[2].vValue);
#else
hWnd = (HWND)V_I4(&rgPropSets[0].rgProperties[2].vValue);
#endif
//Convert Directory to MBCS
ConvertToMBCS(pwszDataSource, szDataSource, sizeof(szDataSource));
}
// if caller didn't supply a directory path, ask the user
if ((nPrompt == DBPROMPT_PROMPT) ||
((nPrompt == DBPROMPT_COMPLETE || nPrompt == DBPROMPT_COMPLETEREQUIRED) && (!SetCurrentDirectory(szDataSource))) )
{
//Use our current DataSource as defaults for properties
TESTC(hr = QueryInterface(IID_IDBProperties, (void**)&pIDBProperties));
//Use the Data Links Dialog to prompt...
TESTC(hr = CoCreateInstance(CLSID_DataLinks, NULL, CLSCTX_ALL, IID_IDBPromptInitialize, (void**)&pIDBPromptInitialize));
TESTC(hr = pIDBPromptInitialize->PromptDataSource(NULL, hWnd, DBPROMPTOPTIONS_PROPERTYSHEET | DBPROMPTOPTIONS_DISABLE_PROVIDER_SELECTION, 0, NULL, NULL, IID_IDBProperties, (IUnknown**)&pIDBProperties));
//Free the Previous Properties
FreeProperties(&cPropSets, &rgPropSets);
pwszDataSource = NULL;
//Now Data Links has put the user choosen properties onto our data source, we just need to
//reobtain the property values...
hr = m_pObj->m_pUtilProp->GetProperties(PROPSET_DSO, cPropertyIDSets, rgPropertyIDSets, &cPropSets, &rgPropSets );
if(SUCCEEDED(hr))
{
pwszDataSource = V_BSTR(&rgPropSets[0].rgProperties[0].vValue);
nPrompt = V_I2(&rgPropSets[0].rgProperties[1].vValue);
#ifdef _WIN64
hWnd = (HWND)V_I8(&rgPropSets[0].rgProperties[2].vValue);
#else
hWnd = (HWND)V_I4(&rgPropSets[0].rgProperties[2].vValue);
#endif
//Convert Directory to MBCS
ConvertToMBCS(pwszDataSource, szDataSource, sizeof(szDataSource));
}
}
//NOTE: We don't require DBPROP_INIT_DATASOURCE. If the DataSource property is passed
//in then we will use that to represent the current directory. This will allow the user
//to only have to specify the filename in OpenRowset, and not the full path...
if(szDataSource[0])
{
// Get the current Directory
CHAR szCurrentDir[MAX_PATH];
GetCurrentDirectory( MAX_PATH, szCurrentDir );
//See if the directory passed is valid...
if(!SetCurrentDirectory( szDataSource ))
{
hr = DB_E_ERRORSOCCURRED;
goto CLEANUP;
}
// Restore to the original directory.
SetCurrentDirectory( szCurrentDir );
wcsncpy_s( m_pObj->m_wszPath, _countof(m_pObj->m_wszPath ), pwszDataSource, MAX_PATH);
}
else
{
m_pObj->m_wszPath[0] = wEOL;
}
//We are now initialized...
m_pObj->m_fDSOInitialized = TRUE;
hr = S_OK;
CLEANUP:
FreeProperties(&cPropSets, &rgPropSets);
SAFE_RELEASE(pIDBPromptInitialize);
SAFE_RELEASE(pIDBProperties);
return hr;
}
Uninitializing the Data Source Object
Uninitialize enables consumers to return the data source object to an uninitialized state. It is an error to call IDBInitialize::Uninitialize when there are open sessions or rowsets on the data source object. The source code for IDBInitialize::Uninitialize follows.
// CImpIDBInitialize::Uninitialize ---------------------------------------------
//
// @mfunc Returns the Data Source Object to an uninitialized state
//
// @rdesc HRESULT
// @flag S_OK | The method succeeded
// @flag DB_E_OBJECTOPEN | A DBSession object was already created
//
STDMETHODIMP CImpIDBInitialize::Uninitialize
(
void
)
{
assert( m_pObj );
if (!m_pObj->m_fDSOInitialized)
{
// data source object is not initialized; do nothing
return ResultFromScode( S_OK );
}
else
{
if (!m_pObj->m_fDBSessionCreated)
{
// DSO initialized, but no DBSession has been created.
// So, reset DSO to uninitialized state
m_pObj->m_fDSOInitialized = FALSE;
return ResultFromScode( S_OK );
}
else
{
// DBSession has already been created; trying to uninit
// the DSO now is an error
return ResultFromScode( DB_E_OBJECTOPEN );
}
}
}