UTILPROP.CPP
//-------------------------------------------------------------------- 
// Microsoft OLE DB Sample Provider 
// (C) Copyright 1994 - 1996 Microsoft Corporation.  All Rights Reserved. 
// 
// @doc 
// 
// @module UTILPROP.CPP | Properties utility object implementation 
// 
 
 
// 
// Notes - there are two main methods in this module: 
//     - CUtilProps::GetPropertyInfo, a helper function for IDBInfo::GetPropertyInfo 
//     - CUtilProps::GetProperties, a helper function for IRowsetInfo::GetProperties 
// 
// Our property implementation is simplified considerably by the fact that we 
// only support reading\getting the properties, we do not support 
// writing\setting them. This makes sense because we are a simple provider, 
// and our rowset object always creates all the interfaces it exposes. In 
// other words, there are really no properties the consumer could set. 
// 
// The implementation is very simple - we keep a global table of the 
// properties we support in s_rgprop. We search this table sequentially. 
// 
// Note that a full-featured provider would probably need to use a more 
// sophisticated implementation. We keep the entire GUID for each property in 
// our struct, which would become a waste of space if we had a lot more 
// properties. Similarly, with large numbers of properties some sort of 
// hashing would be better than the sequential search used here. 
// 
 
// Includes ------------------------------------------------------------------ 
 
#include "headers.h" 
 
 
 
// Struct containing the properties we know about. The GUID and string fields are 
// initialized in the constructor, because C++ makes it awkward to do so at declaration 
// time. So, if you change this table, be sure to make parallel changes in CUtilProp::CUtilProp. 
PROPSTRUCT s_rgprop[] = 
   { 
        /* 0 */ {DBPROP_IAccessor,FLAGS_ROWSETRO,     VT_BOOL, TRUE,   0, NULL}, 
        /* 1 */ {DBPROP_IColumnsInfo,FLAGS_ROWSETRO,     VT_BOOL, TRUE,   0, NULL}, 
        /* 2 */ {DBPROP_IRowset,FLAGS_ROWSETRW,     VT_BOOL, TRUE,   0, NULL}, 
        /* 3 */ {DBPROP_IRowsetChange,FLAGS_ROWSETRW,     VT_BOOL, TRUE,   0, NULL}, 
        /* 4 */ {DBPROP_IRowsetInfo,FLAGS_ROWSETRO,     VT_BOOL, TRUE,   0, NULL}, 
        /* 5 */ {DBPROP_DBMSNAME,FLAGS_DATASOURCE,VT_BSTR, FALSE,  0, NULL}, 
        /* 6 */ {DBPROP_DBMSVER,FLAGS_DATASOURCE,VT_BSTR, FALSE,  0, NULL}, 
        /* 7 */ {DBPROP_INIT_DATASOURCE,FLAGS_DBINITRW,VT_BSTR, FALSE,  0, NULL} 
    }; 
 
PROPSTRUCT s_rgDBInitProp[] = 
{ 
        /* 0 */ {DBPROP_INIT_DATASOURCE,FLAGS_DBINITRW,VT_BSTR, FALSE,  0, NULL}, 
}; 
 
PROPSTRUCT s_rgDataSourceInfoProp[] = 
   { 
        /* 0 */ {DBPROP_DBMSNAME,FLAGS_DATASOURCE,VT_BSTR, FALSE,  0, NULL}, 
        /* 1 */ {DBPROP_DBMSVER,FLAGS_DATASOURCE,VT_BSTR, FALSE,  0, NULL} 
    }; 
 
PROPSTRUCT s_rgRowsetProp[] = 
   { 
        /* 0 */ {DBPROP_IAccessor,FLAGS_ROWSETRO,     VT_BOOL, TRUE,   0, NULL}, 
        /* 1 */ {DBPROP_IColumnsInfo,FLAGS_ROWSETRW,     VT_BOOL, TRUE,   0, NULL}, 
        /* 2 */ {DBPROP_IRowset,FLAGS_ROWSETRW,     VT_BOOL, TRUE,   0, NULL}, 
        /* 3 */ {DBPROP_IRowsetChange,FLAGS_ROWSETRW,     VT_BOOL, TRUE,   0, NULL}, 
        /* 4 */ {DBPROP_IRowsetInfo,FLAGS_ROWSETRO,     VT_BOOL, TRUE,   0, NULL}, 
    }; 
 
// Number of supported properties per property set 
#defineNUMBER_OF_SUPPORTED_PROPERTY_SETS3 
 
#define NUMBER_OF_SUPPORTED_DBINIT_PROPERTIES1 
#defineNUMBER_OF_SUPPORTED_DATASOURCEINFO_PROPERTIES2 
#defineNUMBER_OF_SUPPORTED_ROWSET_PROPERTIES5 
 
#defineNUMBER_OF_SUPPORTED_PROPERTIES\ 
(NUMBER_OF_SUPPORTED_DBINIT_PROPERTIES +\ 
NUMBER_OF_SUPPORTED_DATASOURCEINFO_PROPERTIES +\ 
NUMBER_OF_SUPPORTED_ROWSET_PROPERTIES) 
 
 
 
// Code ---------------------------------------------------------------------- 
 
// CUtilProp::CUtilProp ---------------------------------------------------------- 
// 
// @mfunc Constructor for this class 
// 
// @rdesc NONE 
// 
CUtilProp::CUtilProp 
    ( 
    void 
    ) 
{ 
    // initialize the members of our global table that we couldn't initialize 
    // in the declaration 
s_rgprop[0].pwstrDescBuffer,L"IAccessor"; 
s_rgprop[1].pwstrDescBuffer,L"IColumnsInfo"; 
s_rgprop[2].pwstrDescBuffer,L"IRowset"; 
s_rgprop[3].pwstrDescBuffer,L"IRowsetChange"; 
s_rgprop[4].pwstrDescBuffer,L"IRowsetInfo"; 
 
    s_rgprop[5].pwstrVal = L"Sampprov"; 
s_rgprop[5].pwstrDescBuffer,L"DBMS Name"; 
 
    s_rgprop[6].pwstrVal = L"00.99.0000"; 
s_rgprop[6].pwstrDescBuffer,L"DBMS Version"; 
 
s_rgprop[7].pwstrVal = L""; 
s_rgprop[7].pwstrDescBuffer,L"Data Source"; 
 
s_rgRowsetProp[0].pwstrDescBuffer,L"IAccessor"; 
s_rgRowsetProp[1].pwstrDescBuffer,L"IColumnsInfo"; 
s_rgRowsetProp[2].pwstrDescBuffer,L"IRowset"; 
s_rgRowsetProp[3].pwstrDescBuffer,L"IRowsetChange"; 
s_rgRowsetProp[4].pwstrDescBuffer,L"IRowsetInfo"; 
 
    s_rgDataSourceInfoProp[0].pwstrVal = L"Sampprov"; 
s_rgDataSourceInfoProp[0].pwstrDescBuffer,L"DBMS Name"; 
 
    s_rgDataSourceInfoProp[1].pwstrVal = L"00.99.0000"; 
s_rgDataSourceInfoProp[1].pwstrDescBuffer,L"DBMS Version"; 
 
s_rgDBInitProp[0].pwstrVal,L""; 
s_rgDBInitProp[0].pwstrDescBuffer,L"Data Source"; 
 
    return; 
} 
 
 
// CUtilProp::~CUtilProp --------------------------------------------------------- 
// 
// @mfunc Destructor for this class 
// 
// @rdesc NONE 
// 
CUtilProp:: ~CUtilProp 
    ( 
    void 
    ) 
{ 
if ( s_rgDBInitProp[0].pwstrVal ) 
g_pIMalloc->Free( s_rgDBInitProp[0].pwstrVal ); 
 
    return; 
} 
 
 
 
// CUtilProp::GetPropIndex ---------------------------------------------------- 
// 
// @mfunc Returns index of the given property in our global table of properties 
// 
// @rdesc BOOL 
//      @flag TRUE      | found match, copied it to pulIndex out-param 
//      @flag FALSE     | no match. In this case, pulIndex has no meaning 
// 
BOOL CUtilProp::GetPropIndex 
    ( 
DBPROPIDdwPropertyID,   //@parm IN  | PROPID of desired property 
    ULONG*pulIndex//@parm OUT | index of desired property if return was TRUE 
    ) 
{ 
    ULONG cNumberOfProperties; 
    assert( pulIndex ); 
 
    for (cNumberOfProperties = 0;  
cNumberOfProperties < NUMBER_OF_SUPPORTED_PROPERTIES;  
cNumberOfProperties++) 
    { 
        if (dwPropertyID == s_rgprop[cNumberOfProperties].dwPropertyID ) 
        { 
            // found a match 
            *pulIndex = cNumberOfProperties; 
            return TRUE; 
         } 
    } 
    // found no matches 
    return FALSE; 
} 
 
 
 
// CUtilProp::LoadDBPROPINFO  ---------------------------------------------------- 
// 
// @mfunc Helper for GetPropertyInfo. Loads field of DBPROPINFO structure. 
// 
// @rdesc BOOL 
//      @flag TRUE          | Method succeeded 
//      @flag FALSE         | Method failed (couldn't allocate memory) 
// 
BOOL CUtilProp::LoadDBPROPINFO 
    ( 
    PROPSTRUCT*pPropStruct, 
    DBPROPINFO*pPropInfo 
    ) 
{ 
    // asserts 
    assert( pPropStruct ); 
    assert( pPropInfo ); 
 
    // init the variant 
    VariantInit( &pPropInfo->vValues ); 
 
    // set the easy fields.. 
    pPropInfo->dwPropertyID= pPropStruct->dwPropertyID; 
    pPropInfo->dwFlags= pPropStruct->dwFlags; 
    pPropInfo->vtType= pPropStruct->vtType; 
 
    switch (pPropStruct->vtType) 
    { 
    case VT_BOOL: 
V_VT( &pPropInfo->vValues ) = VT_BOOL; 
V_BOOL( &pPropInfo->vValues ) = pPropStruct->boolVal; 
break; 
         
case VT_I4: 
V_VT( &pPropInfo->vValues ) = VT_I4; 
V_I4( &pPropInfo->vValues ) = pPropStruct->longVal; 
break; 
         
case VT_BSTR: 
V_VT( &pPropInfo->vValues ) = VT_BSTR; 
 
V_BSTR( &pPropInfo->vValues ) = SysAllocString( pPropStruct->pwstrVal ); 
 
if (NULL == V_BSTR( &pPropInfo->vValues )) 
            { 
VariantClear( &pPropInfo->vValues ); 
return FALSE; 
            } 
break; 
         
default: 
assert( !"LoadDBPROPINFO unknown variant type!\n\r" ); 
break; 
       } 
    // all went well 
    return TRUE; 
} 
 
 
// CUtilProp::LoadDBPROP  ---------------------------------------------------- 
// 
// @mfunc Helper for GetProperties. Loads field of DBPROP structure. 
// 
// @rdesc BOOL 
//      @flag TRUE          | Method succeeded 
//      @flag FALSE         | Method failed (couldn't allocate memory) 
// 
BOOL CUtilProp::LoadDBPROP 
    ( 
    PROPSTRUCT*pPropStruct, 
    DBPROP*pPropSupport 
    ) 
{ 
    // asserts 
    assert( pPropStruct ); 
    assert( pPropSupport ); 
 
    // init the variant 
    VariantInit( &pPropSupport->vValue ); 
 
    // set the easy fields.. 
    pPropSupport->dwPropertyID  = pPropStruct->dwPropertyID; 
    pPropSupport->colid= DB_NULLID; 
 
    // set pPropSupport->vValue based on Variant type 
    switch (pPropStruct->vtType) 
    { 
    case VT_BOOL: 
V_VT( &pPropSupport->vValue ) = VT_BOOL; 
V_BOOL( &pPropSupport->vValue ) = pPropStruct->boolVal; 
break; 
         
    case VT_I4: 
    V_VT( &pPropSupport->vValue ) = VT_I4; 
V_I4( &pPropSupport->vValue ) = pPropStruct->longVal; 
break; 
         
    case VT_BSTR: 
    V_VT( &pPropSupport->vValue ) = VT_BSTR; 
 
V_BSTR( &pPropSupport->vValue ) = SysAllocString( pPropStruct->pwstrVal ); 
 
        if (NULL == V_BSTR( &pPropSupport->vValue )) 
            { 
VariantClear( &pPropSupport->vValue ); 
return FALSE; 
            } 
break; 
         
default: 
assert( !"LoadDBPROP unknown variant type!\n\r" ); 
break; 
    } 
    // all went well 
    return TRUE; 
} 
 
 
 
// CUtilProp::GetPropertyInfo  ----------------------------------------- 
// 
// @mfuncReturns information about rowset and data source properties  
//supported by the provider 
// 
// @rdesc HRESULT 
//      @flag S_OK          | The method succeeded 
//      @flag E_INVALIDARG  | pcPropertyIDSets or prgPropertyInfo was NULL 
//      @flag E_OUTOFMEMORY | Out of memory 
// 
 
STDMETHODIMP CUtilProp::GetPropertyInfo 
    ( 
    ULONGcPropertyIDSets,//@parm IN | # properties 
    const DBPROPIDSETrgPropertyIDSets[],//@parm IN | Array of property sets 
ULONG*pcPropertyInfoSets,//@parm OUT | # DBPROPSET structures 
DBPROPINFOSET**prgPropertyInfoSets,//@parm OUT | DBPROPSET structures property  
//| information returned 
WCHAR**ppDescBuffer//@parm OUT| Property descriptions 
    ) 
{ 
    ULONGcNumberOfPropertySets, cNumberOfProperties; 
ULONGcCount; 
    ULONGcProps = 0; 
    DBPROPINFO*pPropInfo; 
    DBPROPINFOSET*pPropInfoSet; 
    BOOLfRet; 
 
    // asserts 
    assert( s_rgprop ); 
 
    // check params 
    if (!pcPropertyInfoSets || !prgPropertyInfoSets) 
        return ResultFromScode( E_INVALIDARG ); 
 
    if ((cPropertyIDSets != 0) && !rgPropertyIDSets) 
        return ResultFromScode( E_INVALIDARG ); 
 
    // if no restriction array, count our properties 
    if (cPropertyIDSets == 0) 
    { 
        cProps = NUMBER_OF_SUPPORTED_PROPERTY_SETS; 
    } 
    // restriction array specified, so get the count 
    else 
    { 
        if (cPropertyIDSets > NUMBER_OF_SUPPORTED_PROPERTY_SETS) 
return ( E_INVALIDARG ); 
else 
cProps = cPropertyIDSets; 
    } 
 
    // init out params 
    *pcPropertyInfoSets= 0; 
    *prgPropertyInfoSets= NULL; 
 
    // use task memory allocater to alloc a DBPROPINFOSET struct 
    pPropInfoSet = (DBPROPINFOSET*) g_pIMalloc->Alloc 
(cProps * 
sizeof( DBPROPINFOSET )); 
    if (!pPropInfoSet) 
        return ResultFromScode( E_OUTOFMEMORY ); 
 
    memset( pPropInfoSet, 0, (cProps * sizeof( DBPROPINFOSET ))); 
 
 
// For each supported Property Set 
for (cNumberOfPropertySets=0; cNumberOfPropertySets < cProps; cNumberOfPropertySets++) 
{ 
 
// If no restrictions return all properties from the three supported property sets 
if (cPropertyIDSets == 0) 
{ 
if (cNumberOfPropertySets == 0) 
pPropInfoSet[cNumberOfPropertySets].guidPropertySet = DBPROPSET_DBINIT; 
else if (cNumberOfPropertySets == 1) 
pPropInfoSet[cNumberOfPropertySets].guidPropertySet = DBPROPSET_DATASOURCEINFOALL; 
else if (cNumberOfPropertySets == 2) 
pPropInfoSet[cNumberOfPropertySets].guidPropertySet = DBPROPSET_ROWSET; 
} 
else  
{ 
pPropInfoSet[cNumberOfPropertySets].guidPropertySet =  
rgPropertyIDSets[cNumberOfPropertySets].guidPropertySet; 
} 
 
// Check supported property sets 
if (IsEqualGUID(pPropInfoSet[cNumberOfPropertySets].guidPropertySet,  
DBPROPSET_DBINIT)) 
{ 
cNumberOfProperties = NUMBER_OF_SUPPORTED_DBINIT_PROPERTIES; 
} 
else if (IsEqualGUID(pPropInfoSet[cNumberOfPropertySets].guidPropertySet,  
DBPROPSET_DATASOURCEINFOALL)) 
{ 
cNumberOfProperties = NUMBER_OF_SUPPORTED_DATASOURCEINFO_PROPERTIES; 
} 
else if (IsEqualGUID(pPropInfoSet[cNumberOfPropertySets].guidPropertySet,  
DBPROPSET_ROWSET)) 
{ 
cNumberOfProperties = NUMBER_OF_SUPPORTED_ROWSET_PROPERTIES; 
} 
else  
{ 
cNumberOfProperties = 0; 
} 
 
if (0 != cNumberOfProperties) 
{ 
    // use task memory allocater to alloc array of DBPROPINFO structs 
pPropInfo = (DBPROPINFO*) g_pIMalloc->Alloc 
( cNumberOfProperties *  
sizeof( DBPROPINFO )); 
 
if (!pPropInfo) 
return ResultFromScode( E_OUTOFMEMORY ); 
 
memset( pPropInfo, 0,  
(cNumberOfProperties * sizeof( DBPROPINFO ))); 
} 
 
    // for each prop in our table.. 
for (cCount=0; cCount < cNumberOfProperties; cCount++) 
{ 
 
// init the Variant right up front 
// that way we can VariantClear with no worried (if we need to) 
VariantInit( &pPropInfo[cCount].vValues ); 
 
// Check supported property sets 
if (IsEqualGUID(pPropInfoSet[cNumberOfPropertySets].guidPropertySet,  
DBPROPSET_DBINIT)) 
{ 
// load up their DBPROPINFO from our table 
fRet = LoadDBPROPINFO( &s_rgDBInitProp[cCount], &pPropInfo[cCount] ); 
} 
else if (IsEqualGUID(pPropInfoSet[cNumberOfPropertySets].guidPropertySet,  
DBPROPSET_DATASOURCEINFOALL)) 
{ 
// load up their DBPROPINFO from our table 
fRet = LoadDBPROPINFO( &s_rgDataSourceInfoProp[cCount], &pPropInfo[cCount] ); 
} 
else if (IsEqualGUID(pPropInfoSet[cNumberOfPropertySets].guidPropertySet, 
DBPROPSET_ROWSET)) 
{ 
// load up their DBPROPINFO from our table 
fRet = LoadDBPROPINFO( &s_rgRowsetProp[cCount], &pPropInfo[cCount] ); 
} 
 
if (!fRet) 
{ 
ULONG ulFor; 
 
// something went wrong 
// clear all variants used so far.. 
for (ulFor = 0; ulFor < cCount; ulFor++) 
{ 
VariantClear( &pPropInfo[ulFor].vValues ); 
} 
// .. delete the pPropInfo array, return failure 
g_pIMalloc->Free( pPropInfo ); 
return ResultFromScode( E_OUTOFMEMORY ); 
} 
pPropInfoSet[cNumberOfPropertySets].rgPropertyInfos[cCount] =  
pPropInfo[cCount]; 
}// for each property 
}// for each property set 
 
// set count of properties and property information 
    *pcPropertyInfoSets= cProps; 
    *prgPropertyInfoSets= pPropInfoSet; 
 
    return ResultFromScode( S_OK ); 
} 
 
// CUtilProp::GetProperties ---------------------------------------------------- 
// 
// @mfunc Returns current settings of all properties supported by the DSO/rowset 
// 
// @rdesc HRESULT 
//      @flag S_OK          | The method succeeded 
//      @flag E_INVALIDARG  | pcProperties or prgPropertyInfo was NULL 
//      @flag E_OUTOFMEMORY | Out of memory 
// 
STDMETHODIMP CUtilProp::GetProperties 
    ( 
ULONGcPropertyIDSets,//@parm IN | # of restiction property IDs 
const DBPROPIDSETrgPropertyIDSets[],//@parm IN | restriction guids 
ULONG*              pcPropertySets,//@parm OUT | count of properties returned 
DBPROPSET**prgPropertySets//@parm OUT | property information returned 
    ) 
{ 
    ULONGcNumberOfPropertySets, cNumberOfProperties; 
ULONGcCount; 
    ULONGcProps = 0; 
    DBPROP*pProp; 
    DBPROPSET*pPropSet; 
    BOOLfRet; 
 
    // asserts 
    assert( s_rgprop ); 
 
    // check params 
    if (!pcPropertySets || !prgPropertySets) 
        return ResultFromScode( E_INVALIDARG ); 
 
    if ((cPropertyIDSets != 0) && !rgPropertyIDSets) 
        return ResultFromScode( E_INVALIDARG ); 
 
    // if no restriction array, count our properties 
    if (cPropertyIDSets == 0) 
    { 
        cProps = NUMBER_OF_SUPPORTED_PROPERTY_SETS; 
    } 
    // restriction array specified, so get the count 
    else 
    { 
        if (cPropertyIDSets > NUMBER_OF_SUPPORTED_PROPERTY_SETS) 
return ( E_INVALIDARG ); 
else 
cProps = cPropertyIDSets; 
    } 
 
    // init out params 
    *pcPropertySets= 0; 
    *prgPropertySets= NULL; 
 
    // use task memory allocater to alloc a DBPROPINFOSET struct 
    pPropSet = (DBPROPSET*) g_pIMalloc->Alloc 
(cProps * 
sizeof( DBPROPSET )); 
    if (!pPropSet) 
        return ResultFromScode( E_OUTOFMEMORY ); 
 
    memset( pPropSet, 0, (cProps * sizeof( DBPROPSET ))); 
 
 
// For each supported Property Set 
for (cNumberOfPropertySets=0; cNumberOfPropertySets < cProps; cNumberOfPropertySets++) 
{ 
 
// If no restrictions return all properties from the two supported property sets 
if (cPropertyIDSets == 0) 
{ 
if (cNumberOfPropertySets == 0) 
pPropSet[cNumberOfPropertySets].guidPropertySet = DBPROPSET_DATASOURCEINFOALL; 
else if (cNumberOfPropertySets == 1) 
pPropSet[cNumberOfPropertySets].guidPropertySet = DBPROPSET_ROWSET; 
} 
else  
{ 
pPropSet[cNumberOfPropertySets].guidPropertySet =  
rgPropertyIDSets[cNumberOfPropertySets].guidPropertySet; 
} 
 
// Check supported property sets 
if (IsEqualGUID(pPropSet[cNumberOfPropertySets].guidPropertySet,  
DBPROPSET_DBINIT)) 
{ 
cNumberOfProperties = NUMBER_OF_SUPPORTED_DBINIT_PROPERTIES; 
} 
else if (IsEqualGUID(pPropSet[cNumberOfPropertySets].guidPropertySet,  
DBPROPSET_DATASOURCEINFOALL)) 
{ 
cNumberOfProperties = NUMBER_OF_SUPPORTED_DATASOURCEINFO_PROPERTIES; 
} 
else if (IsEqualGUID(pPropSet[cNumberOfPropertySets].guidPropertySet,  
DBPROPSET_ROWSET)) 
{ 
cNumberOfProperties = NUMBER_OF_SUPPORTED_ROWSET_PROPERTIES; 
} 
else  
{ 
cNumberOfProperties = 0; 
} 
 
if (0 != cNumberOfProperties) 
{ 
    // use task memory allocater to alloc array of DBPROP structs 
pProp = (DBPROP*) g_pIMalloc->Alloc 
( cNumberOfProperties *  
sizeof( DBPROP )); 
 
if (!pProp) 
{ 
g_pIMalloc->Free( pPropSet ); 
return ResultFromScode( E_OUTOFMEMORY ); 
} 
 
memset( pProp, 0,  
(cNumberOfProperties * sizeof( DBPROP ))); 
} 
 
    // for each prop in our table.. 
for (cCount=0; cCount < cNumberOfProperties; cCount++) 
{ 
 
// init the Variant right up front 
// that way we can VariantClear with no worried (if we need to) 
VariantInit( &pProp[cCount].vValue ); 
 
// Check supported property sets 
if (IsEqualGUID(pPropSet[cNumberOfPropertySets].guidPropertySet,  
DBPROPSET_DBINIT)) 
{ 
// load up their DBPROP from our table 
fRet = LoadDBPROP( &s_rgDBInitProp[cCount], &pProp[cCount] ); 
} 
else if (IsEqualGUID(pPropSet[cNumberOfPropertySets].guidPropertySet,  
DBPROPSET_DATASOURCEINFOALL)) 
{ 
// load up their DBPROP from our table 
fRet = LoadDBPROP( &s_rgDataSourceInfoProp[cCount], &pProp[cCount] ); 
} 
else if (IsEqualGUID(pPropSet[cNumberOfPropertySets].guidPropertySet, 
DBPROPSET_ROWSET)) 
{ 
// load up their DBPROP from our table 
fRet = LoadDBPROP( &s_rgRowsetProp[cCount], &pProp[cCount] ); 
} 
 
if (!fRet) 
{ 
ULONG ulFor; 
 
// something went wrong 
// clear all variants used so far.. 
for (ulFor = 0; ulFor < cCount; ulFor++) 
{ 
VariantClear( &pProp[ulFor].vValue ); 
} 
// .. delete the pProp array, return failure 
g_pIMalloc->Free( pProp ); 
g_pIMalloc->Free( pPropSet ); 
return ResultFromScode( E_OUTOFMEMORY ); 
} 
}// for each property 
pPropSet[cNumberOfPropertySets].rgProperties = pProp; 
}// for each property set 
 
// set count of properties and property information 
    *pcPropertySets= cProps; 
    *prgPropertySets= pPropSet; 
 
    return ResultFromScode( S_OK ); 
} 
 
 
// CUtilProp::SetProperties ---------------------------------------------------- 
// 
// @mfunc Set current settings of properties supported by the DSO/rowset 
// 
// @rdesc HRESULT 
//      @flag S_OK          | The method succeeded 
//      @flag E_INVALIDARG  | pcProperties or prgPropertyInfo was NULL 
//      @flag E_OUTOFMEMORY | Out of memory 
// 
STDMETHODIMP CUtilProp::SetProperties 
    ( 
ULONGcPropertyIDSets,//@parm IN# of DBPROPSET 
DBPROPSETrgPropertyIDSets[]//@parm INOUTArray of property sets 
) 
{ 
// Quick Exit with 0 PropertyIDSets 
if ( cPropertyIDSets == 0 ) 
return ResultFromScode( S_OK ); 
 
    // Check params 
    if ((0 != cPropertyIDSets) && (NULL == rgPropertyIDSets)) 
        return ResultFromScode( E_INVALIDARG ); 
 
    if (1 != cPropertyIDSets) 
        return ResultFromScode( E_FAIL ); 
 
    if (!IsEqualGUID(rgPropertyIDSets[0].guidPropertySet,DBPROPSET_DBINIT)) 
        return ResultFromScode( E_FAIL ); 
 
if (rgPropertyIDSets[0].cProperties == 0) 
return ResultFromScode( S_OK ); 
 
// If rg.cProperties is not 0 and rg.rgProperties is NULL, this is 
// an error. 
if (rgPropertyIDSets[0].rgProperties == NULL) 
return ResultFromScode(E_INVALIDARG); 
 
switch(rgPropertyIDSets[0].rgProperties->dwPropertyID) 
{ 
case DBPROP_INIT_DATASOURCE: 
 
    // get the directory path string and convert it to ANSI 
s_rgDBInitProp[0].pwstrVal = (WCHAR *) g_pIMalloc->Alloc(MAX_PATH); 
 
WideCharToMultiByte( CP_ACP, 0, V_BSTR( &rgPropertyIDSets[0].rgProperties->vValue ), -1, 
                 (char *)s_rgDBInitProp[0].pwstrVal, MAX_PATH, NULL, NULL ); 
 
return ResultFromScode( S_OK ); 
} 
return ResultFromScode( E_FAIL ); 
}