REGDSAPI.CPP

/*++ 

Copyright (c) 1996 Microsoft Corporation

Module Name:

RegDSAPI.cpp

Abstract:

Sample Provider Registry DS APIs

Author:

Environment:

User mode

Revision History :

--*/
#include "adssmp.h"
#pragma hdrstop
#include "string.h"

#define SAMPLEDS_REGDSPATH L"SOFTWARE\\Microsoft\\ADs\\SampleDS\\DS"
#define SAMPLEDS_REGSCHEMAPATH L"SOFTWARE\\Microsoft\\ADs\\SampleDS\\Schema"
#define SAMPLEDS_REG_TYPE L"TYPE"
#define SAMPLEDS_REG_MANPROP L"Mandatory Properties"
#define SAMPLEDS_REG_PROPERTY L"PROPERTY"
#define SAMPLEDS_REG_CLASS L"CLASS"
#define SAMPLEDS_REG_SYNTAX L"Syntax"


/*++

Routine Description:

Open an object in the DS. Class of the object is also returned
in szClass if the parameter is not NULL.

Arguments:
szClass will be used to store the object class if it is not NULL.
szClass has to be a LPWSTR of length MAX_PATH.

Return Value:

--*/
HRESULT
SampleDSOpenObject(
LPWSTR szRegPath,
HANDLE *phKey,
LPWSTR szClass,
DWORD dwType
)
{
if (!szRegPath ||
!phKey)
RRETURN(E_FAIL);

WCHAR szFullRegPath[MAX_PATH] = L"";

switch (dwType) {
case REG_DS:
wcscpy(
szFullRegPath,
SAMPLEDS_REGDSPATH
);
break;
case REG_SCHEMA:
wcscpy(
szFullRegPath,
SAMPLEDS_REGSCHEMAPATH
);
break;
default:
RRETURN(E_FAIL);
};

if (*szRegPath != L'\0')
wcscat(szFullRegPath,
szRegPath
);

if (RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
szFullRegPath,
0,
KEY_ALL_ACCESS,
(PHKEY)phKey
) != ERROR_SUCCESS) {
RRETURN(E_FAIL);
}

if (szClass){
DWORD dwDataType;
DWORD dwClass = MAX_PATH * sizeof(WCHAR);
if (RegQueryValueEx(
(HKEY)*phKey,
SAMPLEDS_REG_TYPE,
NULL,
&dwDataType,
(BYTE*)szClass,
&dwClass
) != ERROR_SUCCESS) {
goto Error;
}
if (dwDataType != REG_SZ) {
goto Error;
}
}
RRETURN(S_OK);
Error:
RegCloseKey((HKEY)*phKey);
RRETURN (E_FAIL);
}


/*++

Routine Description:

Close an object in the DS

Arguments:

Return Value:

--*/
HRESULT
SampleDSCloseObject(
HANDLE hKey
)
{
if (RegCloseKey((HKEY)hKey
) != ERROR_SUCCESS)
RRETURN(E_FAIL);
RRETURN(S_OK);
}


/*++

Routine Description:

Setup the enumeration handle of the objects in the DS

Arguments:

Return Value:

--*/
HRESULT
SampleDSRDNEnum(
HANDLE *phEnum,
HANDLE hContainerKey
)
{
if (!phEnum)
RRETURN(E_FAIL);

LPREGDS_ENUM lprdsenum = new REGDS_ENUM;
if (lprdsenum == NULL)
RRETURN(E_OUTOFMEMORY);

HANDLE hKey = hContainerKey;
if (hKey == NULL) {
if ( SampleDSOpenObject(L"",
&hKey,
NULL,
REG_DS
) != ERROR_SUCCESS) {
goto Error;
}
}

lprdsenum->dwIndex = 0;
lprdsenum->hContainerKey= hKey;

*((LPREGDS_ENUM *) phEnum) = lprdsenum;

RRETURN(S_OK);
Error:
delete lprdsenum;
*phEnum = NULL;
RRETURN(E_FAIL);
}


/*++

Routine Description:

Get the next object in the DS using the enumeration handle created
by SampleDSRDNRnum

Arguments:

Return Value:

--*/
HRESULT
SampleDSNextRDN(
HANDLE hEnum,
LPWSTR *pszName,
LPWSTR *pszClass
)
{
HRESULT hr = E_FAIL;
DWORD dwName = MAX_PATH;
LRESULT lResult;
FILETIME ftLastWrite;

if (!hEnum || !pszName)
RRETURN(hr);

*pszName = (LPWSTR) AllocProvMem(sizeof(WCHAR)*dwName);
if (*pszName == NULL)
RRETURN(E_OUTOFMEMORY);

lResult = RegEnumKeyEx(
(HKEY)LPREGDS_ENUM(hEnum)->hContainerKey,
LPREGDS_ENUM(hEnum)->dwIndex,
*pszName,
&dwName,
0,
NULL,
NULL,
&ftLastWrite
);
if (lResult != ERROR_SUCCESS) {
if (lResult == ERROR_NO_MORE_ITEMS)
hr = S_FALSE; // Not an error, no items left
goto Error;
} else {
LPREGDS_ENUM(hEnum)->dwIndex++;
if (pszClass != NULL) {
DWORD dwClass = MAX_PATH;
*pszClass = (LPWSTR) AllocProvMem(sizeof(WCHAR)*dwClass);
if (*pszClass == NULL) {
hr = E_OUTOFMEMORY;
goto Error;
}
if (SampleDSGetTypeText(
(HKEY)LPREGDS_ENUM(hEnum)->hContainerKey,
*pszName,
*pszClass,
&dwClass
) != S_OK) {
goto Error;
}
}
}
RRETURN(S_OK);

Error:
if (*pszName) {
FreeProvMem(*pszName);
*pszName = NULL;
}
if (*pszClass) {
FreeProvMem(*pszClass);
*pszClass = NULL;
}
RRETURN(hr);
}

/*++

Routine Description:

Free the enumeration handle

Arguments:

Return Value:

--*/
HRESULT
SampleDSFreeEnum(HANDLE hEnum)
{
if (!hEnum)
RRETURN(E_FAIL);

LPREGDS_ENUM lprdsenum = (LPREGDS_ENUM)hEnum;
if (lprdsenum->hContainerKey) {
SampleDSCloseObject(lprdsenum->hContainerKey);
}
delete lprdsenum;
RRETURN(S_OK);
}


/*++

Routine Description:

Modify properties of an object in the DS

Arguments:

Return Value:

--*/
HRESULT
SampleDSModifyObject(HANDLE hKey,
HANDLE hOperationData
)
{
if (!hKey)
RRETURN(E_FAIL);

if (!hOperationData)
RRETURN(S_OK);

LPSampleDS_ATTRS_INFO pAttrsInfo = (LPSampleDS_ATTRS_INFO)hOperationData;
LPSampleDS_ATTR_INFO pInfo = pAttrsInfo->pAttrInfo;
DWORD cAttrInfo = pAttrsInfo->dwAttr;

BYTE* pbData;
DWORD dwData;
DWORD dwType;

for (DWORD i = 0;i < cAttrInfo;i++) {
switch (pInfo->dwSyntaxId) {
case SampleDS_DATATYPE_1:
{
SampleDS_TYPE_1* pData = (SampleDS_TYPE_1*)pInfo->lpValue;
pbData = (BYTE*)pData->DNString;
dwData = (wcslen(pData->DNString) + 1) * sizeof(WCHAR);
dwType = REG_SZ;
break;
}
case SampleDS_DATATYPE_2:
{
SampleDS_TYPE_2* pData = (SampleDS_TYPE_2*)pInfo->lpValue;
pbData = (BYTE*)&(pData->Integer);
dwData = sizeof(DWORD);
dwType = REG_DWORD;
break;
}
default:
RRETURN(E_FAIL);
}
if (RegSetValueEx(
(HKEY)hKey,
pInfo->lpAttributeName,
NULL,
dwType,
pbData,
dwData
) != ERROR_SUCCESS)
RRETURN(E_FAIL);
pInfo++;
}

RRETURN(NO_ERROR);
}



/*++

Routine Description:

Read the properties of an object in the DS

Arguments:

Return Value:

--*/
HRESULT
SampleDSReadObject(
HANDLE hkey,
HANDLE *phOperationData
)
{
DWORD cValues;
LPSampleDS_ATTR_INFO pInfo = NULL;
DWORD i;
LPWSTR pszValue = NULL;
BYTE* pbData = NULL;
DWORD cProp = 0;

if (RegQueryInfoKey(
(HKEY)hkey,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&cValues,
NULL,
NULL,
NULL,
NULL
) != ERROR_SUCCESS) {
RRETURN(E_FAIL);
};

if (cValues == 0) {
*phOperationData = NULL;
RRETURN(NO_ERROR);
}

DWORD dwData;
DWORD dwValue;

pInfo = (LPSampleDS_ATTR_INFO)AllocProvMem(
sizeof(SampleDS_ATTR_INFO)*cValues
);
if (!pInfo)
RRETURN(E_OUTOFMEMORY);

for (i = 0; i < cValues; i++) {
DWORD dwType;
pszValue = (LPWSTR)AllocProvMem(sizeof(WCHAR)*MAX_PATH);
pbData = (BYTE*)AllocProvMem(sizeof(WCHAR)*MAX_PATH);
if (pbData == NULL || pszValue == NULL)
goto Error;

dwData = sizeof(WCHAR) * MAX_PATH;
dwValue = sizeof(WCHAR) * MAX_PATH;

if (RegEnumValue(
(HKEY)hkey,
i,
pszValue,
&dwValue,
NULL,
&dwType,
pbData,
&dwData
) != ERROR_SUCCESS)
goto Error;



if (!_wcsicmp(
pszValue,
SAMPLEDS_REG_TYPE)) {
FreeProvMem(pszValue);
FreeProvMem(pbData);
continue;
};

switch (dwType) {
case REG_DWORD:
{
SampleDS_TYPE_2 *pData = NULL;
pData = (SampleDS_TYPE_2*)AllocProvMem(
sizeof(SampleDS_TYPE_2));
if (pData == NULL)
goto Error;
pInfo[cProp].lpValue = (BYTE*)pData;
pData->Integer = *(DWORD*)pbData;
pInfo[cProp].dwSyntaxId = SampleDS_DATATYPE_2;
FreeProvMem(pbData);
pbData = NULL;
break;
}
case REG_SZ:
{
SampleDS_TYPE_1 *pData = NULL;
pData = (SampleDS_TYPE_1*)AllocProvMem(
sizeof(SampleDS_TYPE_1));
if (pData == NULL)
goto Error;
pInfo[cProp].lpValue = (BYTE*)pData;
pData->DNString = (LPWSTR)pbData;
pInfo[cProp].dwSyntaxId = SampleDS_DATATYPE_1;
break;
}
default:
goto Error;
}
pInfo[cProp].lpAttributeName = pszValue;
pInfo[cProp].dwNumberOfValues = 1;
cProp++;
}

// Ownership has already been passed
pbData = NULL;
pszValue = NULL;

LPSampleDS_ATTRS_INFO pAttrsInfo;
pAttrsInfo = (LPSampleDS_ATTRS_INFO)AllocProvMem(sizeof(SampleDS_ATTRS_INFO));
if (!pAttrsInfo)
goto Error;

pAttrsInfo->pAttrInfo = pInfo;
pAttrsInfo->dwAttr = cProp;
*phOperationData = pAttrsInfo;

RRETURN(NO_ERROR);

Error:
for (DWORD j=0; j<cProp; j++) {
if (pInfo[j].lpAttributeName)
FreeProvMem(pInfo[j].lpAttributeName);
if (pInfo[j].lpValue) {
if (pInfo[j].dwSyntaxId == SampleDS_DATATYPE_1) {
if (((SampleDS_TYPE_1*)(pInfo[j].lpValue))->DNString)
FreeProvMem(((SampleDS_TYPE_1*)
(pInfo[j].lpValue))->DNString);
}
FreeProvMem(pInfo[j].lpValue);
}
}
if (pszValue)
FreeProvMem(pszValue);
if (pbData)
FreeProvMem(pbData);
FreeProvMem(pInfo);
RRETURN(E_FAIL);
}


/*++

Routine Description:

Get all the property defintions from the Schema

Arguments:

Return Value:

--*/
HRESULT
SampleDSGetPropertyDefinition(
LPSampleDS_ATTR_DEF* ppAttrDefsReturn,
DWORD *pnumObject)
{
WCHAR szRegPath[MAX_PATH] = SAMPLEDS_REGSCHEMAPATH;
DWORD numEntries;
HKEY hKey;
LPSampleDS_ATTR_DEF pAttrDefsCurrent;
LPSampleDS_ATTR_DEF pAttrDefsStart;
LPWSTR szPropNameCur;
DWORD dwPropNameCur = MAX_PATH;
DWORD numProperties = 0;

if( RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
szRegPath,
0,
KEY_ALL_ACCESS,
&hKey
) != ERROR_SUCCESS) {
RRETURN(E_FAIL);
}

if( RegQueryInfoKey(
hKey,
NULL,
NULL,
NULL,
&numEntries,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
) != ERROR_SUCCESS) {
goto Error;
}

pAttrDefsStart = (LPSampleDS_ATTR_DEF)AllocProvMem(
sizeof(SampleDS_ATTR_DEF)*numEntries);
if (!pAttrDefsStart)
goto Error;
pAttrDefsCurrent = pAttrDefsStart;
DWORD i;
for (i=0; i<numEntries; i++) {
szPropNameCur = (LPWSTR)AllocProvMem(sizeof(WCHAR)*dwPropNameCur);
if (!szPropNameCur)
goto Error;

if (RegEnumKey(
hKey,
i,
szPropNameCur,
dwPropNameCur
) != ERROR_SUCCESS)
goto Error;

if (SampleDSGetPropertyInfo(
hKey,
szPropNameCur,
pAttrDefsCurrent
) != ERROR_SUCCESS) {
FreeProvMem(szPropNameCur);
continue;
}
pAttrDefsCurrent->lpAttributeName = szPropNameCur;
numProperties++;
pAttrDefsCurrent++;
}

// Ownership has been passed
szPropNameCur = NULL;

if (numProperties != numEntries) {
LPSampleDS_ATTR_DEF pAttrDefsFinal;
pAttrDefsFinal = (LPSampleDS_ATTR_DEF)AllocProvMem(
sizeof(SampleDS_ATTR_DEF)*numProperties);
if (!pAttrDefsFinal)
goto Error;
memcpy(
(void*)pAttrDefsFinal,
(void*)pAttrDefsStart,
sizeof(SampleDS_ATTR_DEF)*numProperties
);
*ppAttrDefsReturn = pAttrDefsFinal;
FreeProvMem(pAttrDefsStart);
}
else {
*ppAttrDefsReturn = pAttrDefsStart;
}
*pnumObject = numProperties;
RegCloseKey(hKey);
RRETURN(S_OK);

Error:
RegCloseKey(hKey);
LPSampleDS_ATTR_DEF pAttrDefsDelete = pAttrDefsStart;
for (DWORD j=0; j<numProperties; j++) {
if (pAttrDefsDelete->lpAttributeName)
FreeProvMem(pAttrDefsDelete->lpAttributeName);
pAttrDefsDelete++;
}
if (szPropNameCur)
FreeProvMem(szPropNameCur);
if (pAttrDefsStart)
FreeProvMem(pAttrDefsStart);
RRETURN(E_FAIL);
}


/*++

Routine Description:

Get a particular property defintion from the schema

Arguments:

Return Value:

--*/
HRESULT
SampleDSGetPropertyDefinition(
LPSampleDS_ATTR_DEF* ppAttrDefReturn,
LPWSTR szPropName)
{
WCHAR szRegPath[MAX_PATH] = SAMPLEDS_REGSCHEMAPATH;
DWORD numEntries;
HKEY hKey;
LPSampleDS_ATTR_DEF pAttrDefCurrent;
LPWSTR szPropNameCur;
DWORD i;

if( RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
szRegPath,
0,
KEY_ALL_ACCESS,
&hKey
) != ERROR_SUCCESS) {
RRETURN(E_FAIL);
}

if( RegQueryInfoKey(
hKey,
NULL,
NULL,
NULL,
&numEntries,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
) != ERROR_SUCCESS) {
goto Error;
}

pAttrDefCurrent= (LPSampleDS_ATTR_DEF)AllocProvMem(
sizeof(SampleDS_ATTR_DEF));
if (!pAttrDefCurrent)
goto Error;
szPropNameCur = (LPWSTR)AllocProvMem(sizeof(WCHAR)*MAX_PATH);
if (!szPropNameCur)
goto Error;

for (i=0; i<numEntries; i++) {
if (RegEnumKey(hKey,
i,
szPropNameCur,
MAX_PATH) != ERROR_SUCCESS)
goto Error;

if (!_wcsicmp(
szPropNameCur,
szPropName)) {
if (SampleDSGetPropertyInfo(
hKey,
szPropNameCur,
pAttrDefCurrent
) != ERROR_SUCCESS)
goto Error;
pAttrDefCurrent->lpAttributeName = szPropNameCur;
*ppAttrDefReturn = pAttrDefCurrent;
RegCloseKey(hKey);
RRETURN(S_OK);
}
}
Error:
RegCloseKey(hKey);
if (szPropNameCur)
FreeProvMem(szPropNameCur);
if (pAttrDefCurrent)
FreeProvMem(pAttrDefCurrent);
RRETURN(E_FAIL);
}


/*++

Routine Description:

Free memory allocated by GetPropertyDefinition

Arguments:

Return Value:

--*/
HRESULT
SampleDSFreePropertyDefinition(LPSampleDS_ATTR_DEF pAttrDefs,
DWORD numObject)
{
if (!pAttrDefs)
RRETURN(E_FAIL);

LPSampleDS_ATTR_DEF pAttrDefCurrent = pAttrDefs;
for (DWORD j=0; j<numObject; j++) {
if (pAttrDefCurrent->lpAttributeName)
FreeProvMem(pAttrDefCurrent->lpAttributeName);
pAttrDefCurrent++;
}
FreeProvMem(pAttrDefs);
RRETURN(S_OK);
}


/*++

Routine Description:

Get the type of an object in text format

Arguments:

Return Value:

--*/
HRESULT
SampleDSGetTypeText(HKEY hKey,
LPWSTR szPropertyName,
LPWSTR szClassName,
DWORD *pdwClassName)
{
HKEY hKeyProperty;

if (RegOpenKey(
hKey,
szPropertyName,
&hKeyProperty
) != ERROR_SUCCESS) {
RRETURN(E_FAIL);
}

DWORD dwType;
if (RegQueryValueEx(
hKeyProperty,
SAMPLEDS_REG_TYPE,
NULL,
&dwType,
(BYTE*)szClassName,
pdwClassName
) != ERROR_SUCCESS) {
goto Error;
}

if (dwType != REG_SZ) {
goto Error;
}
RegCloseKey(hKeyProperty);
RRETURN(S_OK);
Error:
RegCloseKey(hKeyProperty);
RRETURN(E_FAIL);

}

/*++

Routine Description:

Get the type of an object

Arguments:

Return Value:

--*/
HRESULT
SampleDSGetType(HKEY hKey,
LPWSTR szPropertyName,
DWORD *pdwType)
{
HRESULT hrReturn = S_OK;
LPWSTR szClassName;
DWORD dwClassName = MAX_PATH * sizeof(WCHAR);

szClassName = (LPWSTR)AllocProvMem(dwClassName);
if (!szClassName) {
hrReturn = E_OUTOFMEMORY;
goto Error;
}

if (SampleDSGetTypeText(
hKey,
szPropertyName,
szClassName,
&dwClassName
) == E_FAIL) {
hrReturn = E_FAIL;
goto Error;
}

if (!_wcsicmp(
szClassName,
SAMPLEDS_REG_PROPERTY)) {
*pdwType = SAMPLEDS_PROPERTY;
}
else if (!_wcsicmp(
szClassName,
SAMPLEDS_REG_CLASS)) {
*pdwType = SAMPLEDS_CLASS;
}
else {
*pdwType = SAMPLEDS_UNKNOWN;
}
Error:
if (szClassName)
FreeProvMem(szClassName);
RRETURN(hrReturn);
}

/*++

Routine Description:

Get information about a property from the schema

Arguments:

Return Value:

--*/
HRESULT
SampleDSGetPropertyInfo(HKEY hKey,
LPWSTR szPropertyName,
LPSampleDS_ATTR_DEF pAttrDef)
{
HKEY hKeyClass;
DWORD dwSyntax;
DWORD dwType;
DWORD dwSyntaxSize = sizeof(DWORD);
DWORD dwSchemaType;

if ((SampleDSGetType(
hKey,
szPropertyName,
&dwSchemaType
) == E_FAIL) ||
(dwSchemaType != SAMPLEDS_PROPERTY))
RRETURN(E_FAIL);

if (RegOpenKeyEx(
hKey,
szPropertyName,
NULL,
KEY_READ,
&hKeyClass
) != ERROR_SUCCESS)
RRETURN(E_FAIL);

if (RegQueryValueEx(
hKeyClass,
SAMPLEDS_REG_SYNTAX,
NULL,
&dwType,
(BYTE*)&dwSyntax,
&dwSyntaxSize
) == ERROR_SUCCESS) {
pAttrDef->dwSyntaxID = dwSyntax;
RegCloseKey(hKeyClass);
RRETURN(S_OK);
}
RegCloseKey(hKeyClass);
RRETURN(E_FAIL);
}


/*++

Routine Description:

Free the memory used by a LPWSTR_LIST

Arguments:

Return Value:

--*/
void FreeList(LPWSTR_LIST pList)
{
if (pList) {
if (pList->lpString) {
FreeProvStr(pList->lpString);
}
FreeList(pList->Next);
FreeProvMem(pList);
};
}

/*++

Routine Description:

Arguments:

Return Value:

--*/
HRESULT
SampleDSGetClassDefinition(
LPSampleDS_CLASS_DEF* ppClassDefsReturn,
DWORD *pnumObject)
{
WCHAR szRegPath[MAX_PATH] = SAMPLEDS_REGSCHEMAPATH;
DWORD numEntries;
HKEY hKey;
LPSampleDS_CLASS_DEF pClassDefsCurrent;
LPSampleDS_CLASS_DEF pClassDefsStart;
LPWSTR szClassName;
DWORD dwClassName = MAX_PATH;
DWORD numClass = 0;

if( RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
szRegPath,
0,
KEY_ALL_ACCESS,
&hKey
) != ERROR_SUCCESS) {
RRETURN(E_FAIL);
}

if( RegQueryInfoKey(
hKey,
NULL,
NULL,
NULL,
&numEntries,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
) != ERROR_SUCCESS) {
goto Error;
}

pClassDefsStart = (LPSampleDS_CLASS_DEF)AllocProvMem(
sizeof(SampleDS_CLASS_DEF)*numEntries);
if (!pClassDefsStart)
goto Error;
pClassDefsCurrent = pClassDefsStart;
DWORD i;
for (i=0; i<numEntries; i++) {
szClassName = (LPWSTR)AllocProvMem(sizeof(WCHAR)*dwClassName);
if (!szClassName)
goto Error;

if (RegEnumKey(
hKey,
i,
szClassName,
dwClassName
) != ERROR_SUCCESS)
goto Error;

if (SampleDSGetClassInfo(
hKey,
szClassName,
pClassDefsCurrent
) != ERROR_SUCCESS) {
FreeProvMem(szClassName);
continue;
}
pClassDefsCurrent->lpClassName = szClassName;
numClass++;
pClassDefsCurrent++;
}
szClassName = NULL;

if (numClass != numEntries) {
LPSampleDS_CLASS_DEF pClassDefsFinal;
pClassDefsFinal = (LPSampleDS_CLASS_DEF)AllocProvMem(
sizeof(SampleDS_CLASS_DEF)*numClass);
if (!pClassDefsFinal)
goto Error;
memcpy(
(void*)pClassDefsFinal,
(void*)pClassDefsStart,
sizeof(SampleDS_CLASS_DEF)*numClass
);
*ppClassDefsReturn = pClassDefsFinal;
FreeProvMem(pClassDefsStart);
}
else {
*ppClassDefsReturn = pClassDefsStart;
}
*pnumObject = numClass;
RegCloseKey(hKey);
RRETURN(S_OK);

Error:
RegCloseKey(hKey);
LPSampleDS_CLASS_DEF pClassDefsDelete = pClassDefsStart;
DWORD j;
for (j=0; j<numClass; j++) {
if (pClassDefsDelete->lpClassName)
FreeProvMem(pClassDefsDelete->lpClassName);
if (pClassDefsDelete->lpMandatoryAttributes)
FreeList(pClassDefsDelete->lpMandatoryAttributes);
pClassDefsDelete++;
}
if (szClassName)
FreeProvMem(szClassName);
if (pClassDefsStart)
FreeProvMem(pClassDefsStart);
RRETURN(E_FAIL);
}

/*++

Routine Description:

Get the class defintion for a particular class

Arguments:

Return Value:

--*/
HRESULT
SampleDSGetClassDefinition(
LPSampleDS_CLASS_DEF* ppClassDefReturn,
LPWSTR szClassName)
{
WCHAR szRegPath[MAX_PATH] = SAMPLEDS_REGSCHEMAPATH;
DWORD numEntries;
HKEY hKey;
LPSampleDS_CLASS_DEF pClassDefCurrent;
LPWSTR szClassNameCurrent;
DWORD i;

if( RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
szRegPath,
0,
KEY_ALL_ACCESS,
&hKey
) != ERROR_SUCCESS) {
RRETURN(E_FAIL);
}

if( RegQueryInfoKey(
hKey,
NULL,
NULL,
NULL,
&numEntries,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
) != ERROR_SUCCESS) {
goto Error;
}

pClassDefCurrent= (LPSampleDS_CLASS_DEF)AllocProvMem(
sizeof(SampleDS_CLASS_DEF));
if (!pClassDefCurrent)
goto Error;
szClassNameCurrent = (LPWSTR)AllocProvMem(sizeof(WCHAR)*MAX_PATH);
if (!szClassNameCurrent)
goto Error;

for (i=0; i<numEntries; i++) {
if (RegEnumKey(hKey,
i,
szClassNameCurrent,
MAX_PATH) != ERROR_SUCCESS)
goto Error;

if (!_wcsicmp(szClassNameCurrent,szClassName)) {
if (SampleDSGetClassInfo(
hKey,
szClassNameCurrent,
pClassDefCurrent
) != ERROR_SUCCESS)
goto Error;
pClassDefCurrent->lpClassName = szClassNameCurrent;
*ppClassDefReturn = pClassDefCurrent;
RegCloseKey(hKey);
RRETURN(S_OK);
}
}
Error:
RegCloseKey(hKey);
if (szClassNameCurrent)
FreeProvMem(szClassNameCurrent);
if (pClassDefCurrent)
FreeProvMem(pClassDefCurrent);
RRETURN(E_FAIL);
}

/*++

Routine Description:

Free memory allocated by GetClassDefinition

Arguments:

Return Value:

--*/
HRESULT
SampleDSFreeClassDefinition(LPSampleDS_CLASS_DEF pClassDefs,
DWORD numObject)
{
if (!pClassDefs)
RRETURN(E_FAIL);

LPSampleDS_CLASS_DEF pClassDefCurrent = pClassDefs;
for (DWORD j=0; j<numObject; j++) {
if (pClassDefCurrent->lpClassName)

FreeProvMem(pClassDefCurrent->lpClassName); 
if (pClassDefCurrent->lpMandatoryAttributes)
FreeList(pClassDefCurrent->lpMandatoryAttributes);
pClassDefCurrent++;
}
FreeProvMem(pClassDefs);
RRETURN(S_OK);
}

/*++

Routine Description:

Get the next token in a REG_MULTISZ string returned by the
Regsitry getvalue function

Arguments:

Return Value:

--*/
LPWSTR nexttoken(LPWSTR szCurrent)
{
static LPWSTR szRemainder = NULL;
LPWSTR szReturn = NULL;

if (szCurrent) {
szRemainder = szCurrent;
}
else if (szRemainder == NULL) {
return NULL;
}

if (*szRemainder) {
szReturn = szRemainder;
while (*++szRemainder);
szRemainder++;
}
return szReturn;
}

/*++

Routine Description:

Get information about a particular class from the schema

Arguments:

Return Value:

--*/
HRESULT
SampleDSGetClassInfo(HKEY hKey,
LPWSTR szClassName,
LPSampleDS_CLASS_DEF pClassDef)
{
HKEY hKeyClass;
DWORD dwType;
LPWSTR szProperties;
DWORD dwProperties = MAX_PATH * 3;
LPWSTR_LIST pListStart = NULL;

DWORD dwManProp = 0;
LPWSTR_LIST pListCurrent = NULL;
LPWSTR szPropCurrent = NULL;
LPWSTR szProperty = NULL;
LPWSTR szPropertyNew = NULL;

DWORD dwSchemaType;
if ((SampleDSGetType(
hKey,
szClassName,
&dwSchemaType) == E_FAIL) ||
(dwSchemaType != SAMPLEDS_CLASS))
RRETURN(E_FAIL);

if (RegOpenKeyEx(
hKey,
szClassName,
NULL,
KEY_READ,
&hKeyClass
) != ERROR_SUCCESS)
RRETURN(E_FAIL);

szProperties= (LPWSTR)AllocProvMem(sizeof(WCHAR)*dwProperties);
if (!szProperties)
goto Error;

if (RegQueryValueEx(
hKeyClass,
SAMPLEDS_REG_MANPROP,
NULL,
&dwType,
(BYTE*)szProperties,
&dwProperties
) != ERROR_SUCCESS) {
goto Error;
}
if (dwType != REG_MULTI_SZ) {
goto Error;
}

szPropCurrent = szProperties;
szProperty = nexttoken(szPropCurrent);
szPropertyNew;
if (szProperty) {
pListStart = (LPWSTR_LIST)AllocProvMem(sizeof(WSTR_LIST));
if (!pListStart)
goto Error;
pListCurrent = pListStart;
szPropertyNew = AllocProvStr(szProperty);
if (!szPropertyNew)
goto Error;
pListCurrent->lpString = szPropertyNew;
szProperty = nexttoken(NULL);
dwManProp++;
while( szProperty != NULL ) {
LPWSTR_LIST pListNew = (LPWSTR_LIST)AllocProvMem(
sizeof(WSTR_LIST));
if (!pListNew)
goto Error;
pListCurrent->Next = pListNew;
szPropertyNew = AllocProvStr(szProperty);
if (!szPropertyNew)
goto Error;
pListNew->lpString = szPropertyNew;
pListCurrent = pListNew;
szProperty = nexttoken(NULL);
dwManProp++;
}
pListCurrent->Next = NULL;
}
pClassDef->lpMandatoryAttributes = pListStart;
pClassDef->dwNumberOfMandatoryAttributes = dwManProp;
RegCloseKey(hKeyClass);
RRETURN(S_OK);

Error:
RegCloseKey(hKeyClass);
if (pListStart)
FreeList(pListStart);
if (szProperties)
FreeProvMem(szProperties);
RRETURN(E_FAIL);
}


/*++

Routine Description:

Add an object in the DS

Arguments:

Return Value:

--*/
HRESULT
SampleDSAddObject(HANDLE hKey,
LPWSTR szObject,
LPWSTR szClass,
HANDLE hOperationData
)
{
if (!szObject || !szClass || !hKey)
RRETURN(E_FAIL);

HKEY hKeyNew;
if (RegCreateKey(
(HKEY)hKey,
szObject,
&hKeyNew
) != ERROR_SUCCESS) {
RRETURN(E_FAIL);
};

if (RegSetValueEx(
hKeyNew,
SAMPLEDS_REG_TYPE,
NULL,
REG_SZ,
(BYTE*)szClass,
(wcslen(szClass) + 1) * sizeof(WCHAR)
) != ERROR_SUCCESS) {
RRETURN(E_FAIL);
};
if (hOperationData) {
if (SampleDSModifyObject(
hKeyNew,
hOperationData
) != S_OK) {
RRETURN(E_FAIL);
};
};
RRETURN(S_OK);
}


/*++

Routine Description:

Delete a registry key and all its subkeys

Arguments:

Return Value:

--*/
LONG RegDeleteAllKeys(HKEY hKeyDelete,
LPWSTR pszSubKey)
{
HKEY hKeyChild;
TCHAR szTmp[MAX_PATH];
LONG lResult;
DWORD dwTmpSize = MAX_PATH;

lResult = RegOpenKeyEx(
hKeyDelete,
pszSubKey,
NULL,
KEY_ALL_ACCESS,
&hKeyChild
);
if (lResult != ERROR_SUCCESS)
return lResult;

lResult = RegEnumKey(
hKeyChild,
0,
szTmp,
dwTmpSize
);

while (lResult != ERROR_NO_MORE_ITEMS) {
RegDeleteAllKeys(
hKeyChild,
szTmp
);

lResult = RegEnumKey(
hKeyChild,
0,
szTmp,
dwTmpSize
);
}

RegCloseKey(hKeyChild);
lResult = RegDeleteKey(
hKeyDelete,
pszSubKey
);

return lResult;
}


/*++

Routine Description:

Remove an object from the DS

Arguments:

Return Value:

--*/
HRESULT
SampleDSRemoveObject(HANDLE hKey,
LPWSTR szObject)
{
if (RegDeleteAllKeys(
(HKEY)hKey,
szObject
) == ERROR_SUCCESS)
RRETURN(S_OK);
else
RRETURN(E_FAIL);
}



/*++

Routine Description:

Create Memory Buffer for operation data

Arguments:

Return Value:

--*/
HRESULT
SampleDSCreateBuffer(HANDLE *phOperationData)
{
LPSampleDS_ATTRS_INFO pAttrsInfo;
pAttrsInfo = (LPSampleDS_ATTRS_INFO)AllocProvMem(sizeof(SampleDS_ATTRS_INFO));
if (!pAttrsInfo)
RRETURN(E_OUTOFMEMORY);
*phOperationData = pAttrsInfo;
RRETURN(S_OK);
}



/*++

Routine Description:

Free memroy pointed to by operationdata

Arguments:

Return Value:

--*/
HRESULT
SampleDSFreeBuffer(HANDLE hOperationData)
{
if (!hOperationData)
RRETURN(E_FAIL);

LPSampleDS_ATTRS_INFO pAttrsInfo;
pAttrsInfo = (LPSampleDS_ATTRS_INFO)hOperationData;

LPSampleDS_ATTR_INFO pAttrInfo;
DWORD cAttr;
pAttrInfo = pAttrsInfo->pAttrInfo;
cAttr = pAttrsInfo->dwAttr;

if (pAttrInfo) {
for (DWORD i = 0;i<cAttr;i++) {
if (pAttrInfo->lpAttributeName)
FreeProvMem(pAttrInfo->lpAttributeName);
if (pAttrInfo->lpValue) {
if (pAttrInfo->dwSyntaxId == SampleDS_DATATYPE_1) {
if (((SampleDS_TYPE_1*)(pAttrInfo->lpValue))->DNString)
FreeProvMem(((SampleDS_TYPE_1*)
(pAttrInfo->lpValue))->DNString);
}
FreeProvMem(pAttrInfo->lpValue);
}
pAttrInfo++;
}
}
FreeProvMem(pAttrsInfo->pAttrInfo);
FreeProvMem(pAttrsInfo);
RRETURN(S_OK);
}