home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / adsi / sampprov / regdsapi.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-29  |  35.7 KB  |  1,534 lines

  1. /*++
  2.  
  3. Copyright (c) 1996 Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     RegDSAPI.cpp
  8.  
  9. Abstract:
  10.  
  11.     Sample Provider Registry DS APIs
  12.     
  13. Author:
  14.  
  15. Environment:
  16.  
  17.     User mode
  18.  
  19. Revision History :
  20.  
  21. --*/
  22. #include "adssmp.h"
  23. #pragma hdrstop
  24. #include "string.h"
  25.  
  26. #define SAMPLEDS_REGDSPATH       L"SOFTWARE\\Microsoft\\ADs\\SampleDS\\DS"
  27. #define SAMPLEDS_REGSCHEMAPATH   L"SOFTWARE\\Microsoft\\ADs\\SampleDS\\Schema"
  28. #define SAMPLEDS_REG_TYPE        L"TYPE"
  29. #define SAMPLEDS_REG_MANPROP     L"Mandatory Properties"
  30. #define SAMPLEDS_REG_PROPERTY    L"PROPERTY"
  31. #define SAMPLEDS_REG_CLASS       L"CLASS"
  32. #define SAMPLEDS_REG_SYNTAX      L"Syntax"
  33.  
  34.  
  35. /*++
  36.  
  37. Routine Description:
  38.  
  39.     Open an object in the DS. Class of the object is also returned
  40.     in szClass if the parameter is not NULL.
  41.  
  42. Arguments:
  43.     szClass will be used to store the object class if it is not NULL.
  44.     szClass has to be a LPWSTR of length MAX_PATH.
  45.     
  46. Return Value:
  47.  
  48. --*/
  49. HRESULT
  50. SampleDSOpenObject( 
  51.     LPWSTR szRegPath,             
  52.     HANDLE *phKey,                
  53.     LPWSTR szClass,
  54.     DWORD  dwType
  55.     )
  56. {
  57.     if (!szRegPath || 
  58.         !phKey)
  59.         RRETURN(E_FAIL);
  60.  
  61.     WCHAR szFullRegPath[MAX_PATH] = L"";
  62.     
  63.     switch (dwType) {
  64.         case REG_DS:
  65.             wcscpy(
  66.                szFullRegPath,
  67.                SAMPLEDS_REGDSPATH
  68.                );
  69.             break;
  70.         case REG_SCHEMA:
  71.             wcscpy(
  72.                szFullRegPath,
  73.                SAMPLEDS_REGSCHEMAPATH
  74.                );
  75.             break;
  76.         default:
  77.             RRETURN(E_FAIL);
  78.     };
  79.  
  80.     if (*szRegPath != L'\0') 
  81.             wcscat(szFullRegPath,
  82.             szRegPath
  83.             );
  84.     
  85.     if (RegOpenKeyEx( 
  86.             HKEY_LOCAL_MACHINE, 
  87.             szFullRegPath, 
  88.             0, 
  89.             KEY_ALL_ACCESS, 
  90.             (PHKEY)phKey
  91.             ) != ERROR_SUCCESS) {
  92.         RRETURN(E_FAIL);
  93.     }
  94.     
  95.     if (szClass){
  96.         DWORD dwDataType;
  97.         DWORD dwClass = MAX_PATH * sizeof(WCHAR);
  98.         if (RegQueryValueEx(
  99.                 (HKEY)*phKey, 
  100.                 SAMPLEDS_REG_TYPE,
  101.                 NULL,
  102.                 &dwDataType,
  103.                 (BYTE*)szClass,    
  104.                 &dwClass
  105.                 ) != ERROR_SUCCESS) {
  106.             goto Error;
  107.         }
  108.         if (dwDataType != REG_SZ) {
  109.             goto Error;
  110.         }
  111.     }
  112.     RRETURN(S_OK);
  113. Error:
  114.     RegCloseKey((HKEY)*phKey);
  115.     RRETURN (E_FAIL);
  116. }
  117.  
  118.  
  119. /*++
  120.  
  121. Routine Description:
  122.  
  123.     Close an object in the DS
  124.     
  125. Arguments:
  126.  
  127. Return Value:
  128.  
  129. --*/
  130. HRESULT
  131. SampleDSCloseObject(
  132.     HANDLE hKey
  133.     )
  134. {
  135.     if (RegCloseKey((HKEY)hKey
  136.                     ) != ERROR_SUCCESS) 
  137.         RRETURN(E_FAIL);
  138.     RRETURN(S_OK);
  139. }
  140.  
  141.  
  142. /*++
  143.  
  144. Routine Description:
  145.  
  146.     Setup the enumeration handle of the objects in the DS
  147.     
  148. Arguments:
  149.  
  150. Return Value:
  151.  
  152. --*/
  153. HRESULT
  154. SampleDSRDNEnum( 
  155.     HANDLE *phEnum,
  156.     HANDLE hContainerKey
  157.     )
  158. {
  159.     if (!phEnum)
  160.         RRETURN(E_FAIL);
  161.  
  162.     LPREGDS_ENUM lprdsenum = new REGDS_ENUM;
  163.     if (lprdsenum == NULL) 
  164.         RRETURN(E_OUTOFMEMORY);
  165.     
  166.     HANDLE hKey = hContainerKey;
  167.     if (hKey == NULL) { 
  168.         if ( SampleDSOpenObject(L"", 
  169.                                 &hKey, 
  170.                                 NULL,
  171.                                 REG_DS
  172.                                 ) != ERROR_SUCCESS) {
  173.             goto Error;
  174.         }
  175.     }
  176.     
  177.     lprdsenum->dwIndex = 0;
  178.     lprdsenum->hContainerKey= hKey;
  179.  
  180.     *((LPREGDS_ENUM *) phEnum) = lprdsenum;
  181.         
  182.     RRETURN(S_OK);
  183. Error:
  184.     delete lprdsenum;
  185.     *phEnum = NULL;
  186.     RRETURN(E_FAIL);
  187. }
  188.  
  189.  
  190. /*++
  191.  
  192. Routine Description:
  193.  
  194.     Get the next object in the DS using the enumeration handle created
  195.     by SampleDSRDNRnum
  196.     
  197. Arguments:
  198.  
  199. Return Value:
  200.  
  201. --*/
  202. HRESULT
  203. SampleDSNextRDN( 
  204.     HANDLE hEnum,      
  205.     LPWSTR *pszName,  
  206.     LPWSTR *pszClass
  207.     )
  208. {
  209.     HRESULT hr = E_FAIL;
  210.     DWORD dwName = MAX_PATH;
  211.     LRESULT lResult;
  212.     FILETIME ftLastWrite;
  213.  
  214.     if (!hEnum || !pszName)
  215.         RRETURN(hr);
  216.  
  217.     *pszName = (LPWSTR) AllocProvMem(sizeof(WCHAR)*dwName);
  218.     if (*pszName == NULL)  
  219.         RRETURN(E_OUTOFMEMORY);
  220.     
  221.     lResult = RegEnumKeyEx(
  222.                    (HKEY)LPREGDS_ENUM(hEnum)->hContainerKey,
  223.                     LPREGDS_ENUM(hEnum)->dwIndex,
  224.                     *pszName, 
  225.                     &dwName,
  226.                     0, 
  227.                     NULL, 
  228.                     NULL,
  229.                     &ftLastWrite
  230.                     ); 
  231.     if (lResult != ERROR_SUCCESS) {
  232.         if (lResult == ERROR_NO_MORE_ITEMS) 
  233.             hr = S_FALSE;       // Not an error, no items left
  234.         goto Error;
  235.     } else {
  236.         LPREGDS_ENUM(hEnum)->dwIndex++;
  237.         if (pszClass != NULL) {
  238.             DWORD dwClass = MAX_PATH;
  239.             *pszClass = (LPWSTR) AllocProvMem(sizeof(WCHAR)*dwClass);
  240.             if (*pszClass == NULL) {
  241.                 hr = E_OUTOFMEMORY;
  242.                 goto Error;
  243.             }
  244.             if (SampleDSGetTypeText(
  245.                         (HKEY)LPREGDS_ENUM(hEnum)->hContainerKey,
  246.                         *pszName,
  247.                         *pszClass,
  248.                         &dwClass
  249.                         ) != S_OK) {
  250.                 goto Error;
  251.             }
  252.         } 
  253.     }
  254.     RRETURN(S_OK);
  255.  
  256. Error:
  257.     if (*pszName) {
  258.         FreeProvMem(*pszName);
  259.         *pszName = NULL;
  260.     }
  261.     if (*pszClass) {
  262.         FreeProvMem(*pszClass);
  263.         *pszClass = NULL;
  264.     }
  265.     RRETURN(hr);
  266. }
  267.  
  268. /*++
  269.  
  270. Routine Description:
  271.  
  272.     Free the enumeration handle
  273.         
  274. Arguments:
  275.  
  276. Return Value:
  277.  
  278. --*/
  279. HRESULT
  280. SampleDSFreeEnum(HANDLE hEnum)
  281. {
  282.     if (!hEnum)
  283.         RRETURN(E_FAIL);
  284.  
  285.     LPREGDS_ENUM lprdsenum = (LPREGDS_ENUM)hEnum;
  286.     if (lprdsenum->hContainerKey) {
  287.         SampleDSCloseObject(lprdsenum->hContainerKey);
  288.     }
  289.     delete lprdsenum;
  290.     RRETURN(S_OK);
  291. }
  292.  
  293.  
  294. /*++
  295.  
  296. Routine Description:
  297.  
  298.     Modify properties of an object in the DS
  299.     
  300. Arguments:
  301.  
  302. Return Value:
  303.  
  304. --*/
  305. HRESULT
  306. SampleDSModifyObject(HANDLE hKey,
  307.                      HANDLE hOperationData
  308.                      )
  309. {
  310.     if (!hKey)
  311.         RRETURN(E_FAIL);
  312.     
  313.     if (!hOperationData)
  314.         RRETURN(S_OK);
  315.  
  316.     LPSampleDS_ATTRS_INFO pAttrsInfo = (LPSampleDS_ATTRS_INFO)hOperationData;
  317.     LPSampleDS_ATTR_INFO pInfo = pAttrsInfo->pAttrInfo;
  318.     DWORD cAttrInfo = pAttrsInfo->dwAttr;
  319.     
  320.     BYTE* pbData;
  321.     DWORD dwData;
  322.     DWORD dwType;
  323.  
  324.     for (DWORD i = 0;i < cAttrInfo;i++) {
  325.         switch (pInfo->dwSyntaxId) {
  326.             case SampleDS_DATATYPE_1:
  327.                 {
  328.                 SampleDS_TYPE_1* pData = (SampleDS_TYPE_1*)pInfo->lpValue;
  329.                 pbData = (BYTE*)pData->DNString;
  330.                 dwData = (wcslen(pData->DNString) + 1) * sizeof(WCHAR);
  331.                 dwType = REG_SZ;
  332.                 break;
  333.                 }
  334.             case SampleDS_DATATYPE_2:
  335.                 {
  336.                 SampleDS_TYPE_2* pData = (SampleDS_TYPE_2*)pInfo->lpValue;
  337.                 pbData = (BYTE*)&(pData->Integer);
  338.                 dwData = sizeof(DWORD);
  339.                 dwType = REG_DWORD;
  340.                 break;
  341.                 }
  342.             default:
  343.                 RRETURN(E_FAIL);
  344.         }
  345.         if (RegSetValueEx(
  346.                     (HKEY)hKey,         
  347.                     pInfo->lpAttributeName,    
  348.                     NULL,
  349.                     dwType,    
  350.                     pbData,
  351.                     dwData
  352.                     ) != ERROR_SUCCESS)
  353.             RRETURN(E_FAIL);
  354.         pInfo++;
  355.     }
  356.     
  357.     RRETURN(NO_ERROR);
  358. }
  359.  
  360.  
  361.  
  362. /*++
  363.  
  364. Routine Description:
  365.  
  366.     Read the properties of an object in the DS
  367.     
  368. Arguments:
  369.  
  370. Return Value:
  371.  
  372. --*/
  373. HRESULT
  374. SampleDSReadObject(
  375.     HANDLE hkey,              
  376.     HANDLE *phOperationData
  377.     )
  378. {
  379.     DWORD cValues;               
  380.     LPSampleDS_ATTR_INFO pInfo = NULL;
  381.     DWORD i; 
  382.     LPWSTR pszValue = NULL;
  383.     BYTE*  pbData = NULL;
  384.     DWORD cProp = 0;
  385.  
  386.     if (RegQueryInfoKey(
  387.                 (HKEY)hkey,         
  388.                 NULL,
  389.                 NULL,
  390.                 NULL,                     
  391.                 NULL,
  392.                 NULL,
  393.                 NULL,
  394.                 &cValues,                 
  395.                 NULL,
  396.                 NULL,
  397.                 NULL,
  398.                 NULL
  399.                 ) != ERROR_SUCCESS) {
  400.         RRETURN(E_FAIL);
  401.     };
  402.  
  403.     if (cValues == 0) {
  404.         *phOperationData = NULL;
  405.         RRETURN(NO_ERROR);
  406.     }
  407.     
  408.     DWORD dwData;
  409.     DWORD dwValue;
  410.  
  411.     pInfo = (LPSampleDS_ATTR_INFO)AllocProvMem(
  412.                                       sizeof(SampleDS_ATTR_INFO)*cValues
  413.                                       );
  414.     if (!pInfo)
  415.         RRETURN(E_OUTOFMEMORY);
  416.  
  417.     for (i = 0; i < cValues; i++) { 
  418.         DWORD dwType;
  419.         pszValue = (LPWSTR)AllocProvMem(sizeof(WCHAR)*MAX_PATH);
  420.         pbData = (BYTE*)AllocProvMem(sizeof(WCHAR)*MAX_PATH);
  421.         if (pbData == NULL || pszValue == NULL) 
  422.             goto Error;
  423.                
  424.         dwData = sizeof(WCHAR) * MAX_PATH;
  425.         dwValue = sizeof(WCHAR) * MAX_PATH;
  426.  
  427.         if (RegEnumValue(
  428.                 (HKEY)hkey, 
  429.                 i, 
  430.                 pszValue, 
  431.                 &dwValue, 
  432.                 NULL, 
  433.                 &dwType,     
  434.                 pbData,     
  435.                 &dwData
  436.                 ) != ERROR_SUCCESS)
  437.             goto Error;
  438.  
  439.      
  440.         
  441.         if (!_wcsicmp(
  442.                 pszValue,
  443.                 SAMPLEDS_REG_TYPE)) {
  444.             FreeProvMem(pszValue);
  445.             FreeProvMem(pbData);
  446.             continue;
  447.         };
  448.         
  449.         switch (dwType) {
  450.             case REG_DWORD:
  451.                 {
  452.                 SampleDS_TYPE_2 *pData = NULL;
  453.                 pData = (SampleDS_TYPE_2*)AllocProvMem(
  454.                                                sizeof(SampleDS_TYPE_2));
  455.                 if (pData == NULL)
  456.                     goto Error;
  457.                 pInfo[cProp].lpValue = (BYTE*)pData;
  458.                 pData->Integer = *(DWORD*)pbData;
  459.                 pInfo[cProp].dwSyntaxId = SampleDS_DATATYPE_2;
  460.                 FreeProvMem(pbData);
  461.                 pbData = NULL;
  462.                 break;
  463.                 }
  464.             case REG_SZ:
  465.                 {
  466.                 SampleDS_TYPE_1 *pData = NULL;
  467.                 pData = (SampleDS_TYPE_1*)AllocProvMem(
  468.                                                sizeof(SampleDS_TYPE_1));
  469.                 if (pData == NULL)
  470.                     goto Error;
  471.                 pInfo[cProp].lpValue = (BYTE*)pData;
  472.                 pData->DNString = (LPWSTR)pbData;
  473.                 pInfo[cProp].dwSyntaxId = SampleDS_DATATYPE_1;
  474.                 break;
  475.                 }
  476.             default:
  477.                 goto Error;
  478.         }
  479.         pInfo[cProp].lpAttributeName = pszValue;
  480.         pInfo[cProp].dwNumberOfValues = 1;
  481.         cProp++;
  482.     }
  483.     
  484.     // Ownership has already been passed
  485.     pbData = NULL;
  486.     pszValue = NULL;
  487.  
  488.     LPSampleDS_ATTRS_INFO pAttrsInfo;
  489.     pAttrsInfo = (LPSampleDS_ATTRS_INFO)AllocProvMem(sizeof(SampleDS_ATTRS_INFO));
  490.     if (!pAttrsInfo)
  491.         goto Error;
  492.     
  493.     pAttrsInfo->pAttrInfo = pInfo;
  494.     pAttrsInfo->dwAttr = cProp;
  495.     *phOperationData = pAttrsInfo;
  496.     
  497.     RRETURN(NO_ERROR);
  498.  
  499. Error: 
  500.     for (DWORD j=0; j<cProp; j++) {
  501.         if (pInfo[j].lpAttributeName)
  502.             FreeProvMem(pInfo[j].lpAttributeName);
  503.         if (pInfo[j].lpValue) {
  504.             if (pInfo[j].dwSyntaxId == SampleDS_DATATYPE_1) {
  505.                 if (((SampleDS_TYPE_1*)(pInfo[j].lpValue))->DNString)
  506.                     FreeProvMem(((SampleDS_TYPE_1*)
  507.                                     (pInfo[j].lpValue))->DNString);
  508.             }
  509.             FreeProvMem(pInfo[j].lpValue);
  510.         }
  511.     }
  512.     if (pszValue)
  513.         FreeProvMem(pszValue);
  514.     if (pbData)
  515.         FreeProvMem(pbData);
  516.     FreeProvMem(pInfo);
  517.     RRETURN(E_FAIL);
  518. }
  519.  
  520.  
  521. /*++
  522.  
  523. Routine Description:
  524.  
  525.     Get all the property defintions from the Schema
  526.     
  527. Arguments:
  528.  
  529. Return Value:
  530.  
  531. --*/
  532. HRESULT
  533. SampleDSGetPropertyDefinition( 
  534.     LPSampleDS_ATTR_DEF* ppAttrDefsReturn,
  535.     DWORD *pnumObject)
  536. {                           
  537.     WCHAR szRegPath[MAX_PATH] = SAMPLEDS_REGSCHEMAPATH;
  538.     DWORD numEntries;
  539.     HKEY hKey;
  540.     LPSampleDS_ATTR_DEF pAttrDefsCurrent; 
  541.     LPSampleDS_ATTR_DEF pAttrDefsStart; 
  542.     LPWSTR szPropNameCur;
  543.     DWORD dwPropNameCur = MAX_PATH;
  544.     DWORD numProperties = 0;
  545.     
  546.     if( RegOpenKeyEx( 
  547.             HKEY_LOCAL_MACHINE, 
  548.             szRegPath, 
  549.             0, 
  550.             KEY_ALL_ACCESS, 
  551.             &hKey
  552.             ) != ERROR_SUCCESS) {
  553.         RRETURN(E_FAIL);
  554.     }
  555.     
  556.     if( RegQueryInfoKey(
  557.                 hKey,
  558.                 NULL,
  559.                 NULL,
  560.                 NULL,
  561.                 &numEntries,
  562.                 NULL,
  563.                 NULL,
  564.                 NULL,
  565.                 NULL,
  566.                 NULL,
  567.                 NULL,
  568.                 NULL
  569.                 ) != ERROR_SUCCESS) {
  570.         goto Error;
  571.     }
  572.     
  573.     pAttrDefsStart = (LPSampleDS_ATTR_DEF)AllocProvMem(
  574.                                     sizeof(SampleDS_ATTR_DEF)*numEntries);
  575.     if (!pAttrDefsStart)
  576.         goto Error;
  577.     pAttrDefsCurrent = pAttrDefsStart;
  578.     DWORD i;
  579.     for (i=0; i<numEntries; i++) {
  580.         szPropNameCur = (LPWSTR)AllocProvMem(sizeof(WCHAR)*dwPropNameCur);
  581.         if (!szPropNameCur)
  582.             goto Error;
  583.  
  584.         if (RegEnumKey(
  585.                 hKey,
  586.                 i,
  587.                 szPropNameCur,
  588.                 dwPropNameCur
  589.                 ) != ERROR_SUCCESS)
  590.             goto Error;
  591.  
  592.         if (SampleDSGetPropertyInfo( 
  593.                 hKey,
  594.                 szPropNameCur,
  595.                 pAttrDefsCurrent
  596.                 ) != ERROR_SUCCESS) {
  597.             FreeProvMem(szPropNameCur);
  598.             continue;
  599.         }
  600.         pAttrDefsCurrent->lpAttributeName = szPropNameCur;
  601.         numProperties++;
  602.         pAttrDefsCurrent++;
  603.     }
  604.  
  605.     // Ownership has been passed
  606.     szPropNameCur = NULL;
  607.  
  608.     if (numProperties != numEntries) {
  609.         LPSampleDS_ATTR_DEF pAttrDefsFinal; 
  610.         pAttrDefsFinal = (LPSampleDS_ATTR_DEF)AllocProvMem(
  611.                                     sizeof(SampleDS_ATTR_DEF)*numProperties);
  612.         if (!pAttrDefsFinal)
  613.             goto Error;
  614.         memcpy( 
  615.             (void*)pAttrDefsFinal,
  616.             (void*)pAttrDefsStart,
  617.             sizeof(SampleDS_ATTR_DEF)*numProperties
  618.             );
  619.         *ppAttrDefsReturn = pAttrDefsFinal;    
  620.         FreeProvMem(pAttrDefsStart);
  621.     }
  622.     else {
  623.         *ppAttrDefsReturn = pAttrDefsStart; 
  624.     }
  625.     *pnumObject = numProperties;
  626.     RegCloseKey(hKey);
  627.     RRETURN(S_OK);
  628.  
  629. Error:
  630.     RegCloseKey(hKey);
  631.     LPSampleDS_ATTR_DEF pAttrDefsDelete = pAttrDefsStart; 
  632.     for (DWORD j=0; j<numProperties; j++) {
  633.         if (pAttrDefsDelete->lpAttributeName)
  634.             FreeProvMem(pAttrDefsDelete->lpAttributeName);
  635.         pAttrDefsDelete++;
  636.     }
  637.     if (szPropNameCur)
  638.         FreeProvMem(szPropNameCur);
  639.     if (pAttrDefsStart)
  640.         FreeProvMem(pAttrDefsStart);
  641.     RRETURN(E_FAIL);
  642. }
  643.  
  644.  
  645. /*++
  646.  
  647. Routine Description:
  648.  
  649.     Get a particular property defintion from the schema
  650.  
  651. Arguments:
  652.  
  653. Return Value:
  654.  
  655. --*/
  656. HRESULT
  657. SampleDSGetPropertyDefinition( 
  658.     LPSampleDS_ATTR_DEF* ppAttrDefReturn,
  659.     LPWSTR szPropName)
  660. {                           
  661.     WCHAR szRegPath[MAX_PATH] = SAMPLEDS_REGSCHEMAPATH;
  662.     DWORD numEntries;
  663.     HKEY hKey;
  664.     LPSampleDS_ATTR_DEF pAttrDefCurrent; 
  665.     LPWSTR szPropNameCur;
  666.     DWORD i;
  667.     
  668.     if( RegOpenKeyEx( 
  669.             HKEY_LOCAL_MACHINE, 
  670.             szRegPath, 
  671.             0, 
  672.             KEY_ALL_ACCESS, 
  673.             &hKey
  674.             ) != ERROR_SUCCESS) {
  675.         RRETURN(E_FAIL);
  676.     }
  677.     
  678.     if( RegQueryInfoKey(
  679.             hKey,
  680.             NULL,
  681.             NULL,
  682.             NULL,
  683.             &numEntries,
  684.             NULL,
  685.             NULL,
  686.             NULL,
  687.             NULL,
  688.             NULL,
  689.             NULL,
  690.             NULL
  691.             ) != ERROR_SUCCESS) {
  692.         goto Error;
  693.     }
  694.     
  695.     pAttrDefCurrent= (LPSampleDS_ATTR_DEF)AllocProvMem(
  696.                                                sizeof(SampleDS_ATTR_DEF));
  697.     if (!pAttrDefCurrent)
  698.         goto Error;
  699.     szPropNameCur = (LPWSTR)AllocProvMem(sizeof(WCHAR)*MAX_PATH);
  700.     if (!szPropNameCur)
  701.         goto Error;
  702.  
  703.     for (i=0; i<numEntries; i++) {
  704.         if (RegEnumKey(hKey,
  705.             i,
  706.             szPropNameCur,
  707.             MAX_PATH) != ERROR_SUCCESS)
  708.             goto Error;
  709.  
  710.         if (!_wcsicmp(
  711.                 szPropNameCur,
  712.                 szPropName)) {
  713.             if (SampleDSGetPropertyInfo( 
  714.                                 hKey,
  715.                                 szPropNameCur,
  716.                                 pAttrDefCurrent
  717.                                 ) != ERROR_SUCCESS) 
  718.                 goto Error;
  719.             pAttrDefCurrent->lpAttributeName = szPropNameCur;
  720.             *ppAttrDefReturn = pAttrDefCurrent; 
  721.             RegCloseKey(hKey);
  722.             RRETURN(S_OK);
  723.         }
  724.     }
  725. Error:
  726.     RegCloseKey(hKey);
  727.     if (szPropNameCur)
  728.         FreeProvMem(szPropNameCur);
  729.     if (pAttrDefCurrent)
  730.         FreeProvMem(pAttrDefCurrent);
  731.     RRETURN(E_FAIL);
  732. }
  733.  
  734.  
  735. /*++
  736.  
  737. Routine Description:
  738.  
  739.     Free memory allocated by GetPropertyDefinition
  740.  
  741. Arguments:
  742.  
  743. Return Value:
  744.  
  745. --*/
  746. HRESULT    
  747. SampleDSFreePropertyDefinition(LPSampleDS_ATTR_DEF pAttrDefs,
  748.                                DWORD numObject)
  749. {
  750.     if (!pAttrDefs)
  751.         RRETURN(E_FAIL);
  752.  
  753.     LPSampleDS_ATTR_DEF pAttrDefCurrent = pAttrDefs;
  754.     for (DWORD j=0; j<numObject; j++) {
  755.         if (pAttrDefCurrent->lpAttributeName)
  756.             FreeProvMem(pAttrDefCurrent->lpAttributeName);
  757.         pAttrDefCurrent++;
  758.     }
  759.     FreeProvMem(pAttrDefs);
  760.     RRETURN(S_OK);
  761. }
  762.  
  763.  
  764. /*++
  765.  
  766. Routine Description:
  767.  
  768.     Get the type of an object in text format
  769.  
  770. Arguments:
  771.  
  772. Return Value:
  773.  
  774. --*/
  775. HRESULT
  776. SampleDSGetTypeText(HKEY hKey,
  777.                     LPWSTR szPropertyName,
  778.                     LPWSTR szClassName,
  779.                     DWORD *pdwClassName) 
  780. {
  781.     HKEY hKeyProperty;
  782.     
  783.     if (RegOpenKey(
  784.             hKey,
  785.             szPropertyName,
  786.             &hKeyProperty
  787.             ) != ERROR_SUCCESS) {
  788.         RRETURN(E_FAIL);
  789.     }
  790.     
  791.     DWORD dwType;
  792.     if (RegQueryValueEx(
  793.             hKeyProperty, 
  794.             SAMPLEDS_REG_TYPE,
  795.             NULL,
  796.             &dwType,
  797.             (BYTE*)szClassName,    
  798.             pdwClassName
  799.             ) != ERROR_SUCCESS) {
  800.         goto Error;
  801.     }
  802.  
  803.     if (dwType != REG_SZ) {
  804.         goto Error;
  805.     }
  806.     RegCloseKey(hKeyProperty);
  807.     RRETURN(S_OK);
  808. Error:
  809.     RegCloseKey(hKeyProperty);
  810.     RRETURN(E_FAIL);
  811.  
  812. }
  813.  
  814. /*++
  815.  
  816. Routine Description:
  817.  
  818.     Get the type of an object 
  819.  
  820. Arguments:
  821.  
  822. Return Value:
  823.  
  824. --*/
  825. HRESULT
  826. SampleDSGetType(HKEY hKey,
  827.                 LPWSTR szPropertyName,
  828.                 DWORD *pdwType)
  829. {
  830.     HRESULT hrReturn = S_OK;
  831.     LPWSTR szClassName;
  832.     DWORD dwClassName = MAX_PATH * sizeof(WCHAR);
  833.  
  834.     szClassName = (LPWSTR)AllocProvMem(dwClassName);
  835.     if (!szClassName) {
  836.         hrReturn = E_OUTOFMEMORY;
  837.         goto Error;
  838.     }
  839.  
  840.     if (SampleDSGetTypeText(
  841.                     hKey,
  842.                     szPropertyName,
  843.                     szClassName,
  844.                     &dwClassName
  845.                     ) == E_FAIL) {
  846.         hrReturn = E_FAIL;
  847.         goto Error;
  848.     }
  849.        
  850.     if (!_wcsicmp(
  851.             szClassName,
  852.             SAMPLEDS_REG_PROPERTY)) {
  853.         *pdwType = SAMPLEDS_PROPERTY;
  854.     }
  855.     else if (!_wcsicmp(
  856.                 szClassName,
  857.                 SAMPLEDS_REG_CLASS)) {
  858.         *pdwType = SAMPLEDS_CLASS;
  859.     }
  860.     else {
  861.         *pdwType = SAMPLEDS_UNKNOWN;
  862.     }
  863. Error:
  864.     if (szClassName)
  865.         FreeProvMem(szClassName);
  866.     RRETURN(hrReturn);
  867. }
  868.  
  869. /*++
  870.  
  871. Routine Description:
  872.  
  873.     Get information about a property from the schema
  874.  
  875. Arguments:
  876.  
  877. Return Value:
  878.  
  879. --*/
  880. HRESULT
  881. SampleDSGetPropertyInfo(HKEY hKey,
  882.                         LPWSTR szPropertyName,
  883.                         LPSampleDS_ATTR_DEF pAttrDef)
  884. {
  885.     HKEY hKeyClass;
  886.     DWORD dwSyntax;
  887.     DWORD dwType;
  888.     DWORD dwSyntaxSize = sizeof(DWORD);
  889.     DWORD dwSchemaType;
  890.  
  891.     if ((SampleDSGetType(
  892.                     hKey,
  893.                     szPropertyName,
  894.                     &dwSchemaType
  895.                     ) == E_FAIL) || 
  896.         (dwSchemaType != SAMPLEDS_PROPERTY)) 
  897.         RRETURN(E_FAIL);
  898.     
  899.     if (RegOpenKeyEx(
  900.                 hKey,
  901.                 szPropertyName,
  902.                 NULL,
  903.                 KEY_READ,
  904.                 &hKeyClass
  905.                 ) != ERROR_SUCCESS)
  906.         RRETURN(E_FAIL);
  907.  
  908.     if (RegQueryValueEx(
  909.                     hKeyClass, 
  910.                     SAMPLEDS_REG_SYNTAX,
  911.                     NULL,
  912.                     &dwType,
  913.                     (BYTE*)&dwSyntax,    
  914.                     &dwSyntaxSize
  915.                     ) == ERROR_SUCCESS) {
  916.         pAttrDef->dwSyntaxID = dwSyntax;
  917.         RegCloseKey(hKeyClass);
  918.         RRETURN(S_OK);
  919.     } 
  920.     RegCloseKey(hKeyClass);
  921.     RRETURN(E_FAIL);
  922. }
  923.  
  924.  
  925. /*++
  926.  
  927. Routine Description:
  928.  
  929.     Free the memory used by a LPWSTR_LIST
  930.  
  931. Arguments:
  932.  
  933. Return Value:
  934.  
  935. --*/
  936. void FreeList(LPWSTR_LIST pList)
  937. {
  938.     if (pList) {
  939.         if (pList->lpString) {
  940.             FreeProvStr(pList->lpString);
  941.                 }
  942.         FreeList(pList->Next);
  943.         FreeProvMem(pList);
  944.         };
  945. }
  946.  
  947. /*++
  948.  
  949. Routine Description:
  950.  
  951. Arguments:
  952.  
  953. Return Value:
  954.  
  955. --*/
  956. HRESULT
  957. SampleDSGetClassDefinition( 
  958.     LPSampleDS_CLASS_DEF* ppClassDefsReturn,
  959.     DWORD *pnumObject)
  960. {                           
  961.     WCHAR szRegPath[MAX_PATH] = SAMPLEDS_REGSCHEMAPATH;
  962.     DWORD numEntries;
  963.     HKEY hKey;
  964.     LPSampleDS_CLASS_DEF pClassDefsCurrent; 
  965.     LPSampleDS_CLASS_DEF pClassDefsStart; 
  966.     LPWSTR szClassName;
  967.     DWORD dwClassName = MAX_PATH;
  968.     DWORD numClass = 0;
  969.     
  970.     if( RegOpenKeyEx( 
  971.                 HKEY_LOCAL_MACHINE, 
  972.                 szRegPath, 
  973.                 0, 
  974.                 KEY_ALL_ACCESS, 
  975.                 &hKey
  976.                 ) != ERROR_SUCCESS) {
  977.         RRETURN(E_FAIL);
  978.     }
  979.     
  980.     if( RegQueryInfoKey(
  981.                     hKey,
  982.                     NULL,
  983.                     NULL,
  984.                     NULL,
  985.                     &numEntries,
  986.                     NULL,
  987.                     NULL,
  988.                     NULL,
  989.                     NULL,
  990.                     NULL,
  991.                     NULL,
  992.                     NULL
  993.                     ) != ERROR_SUCCESS) {
  994.         goto Error;
  995.     }
  996.     
  997.     pClassDefsStart = (LPSampleDS_CLASS_DEF)AllocProvMem(
  998.                                       sizeof(SampleDS_CLASS_DEF)*numEntries);
  999.     if (!pClassDefsStart)
  1000.         goto Error;
  1001.     pClassDefsCurrent = pClassDefsStart;
  1002.     DWORD i;
  1003.     for (i=0; i<numEntries; i++) {
  1004.         szClassName = (LPWSTR)AllocProvMem(sizeof(WCHAR)*dwClassName);
  1005.         if (!szClassName)
  1006.             goto Error;
  1007.  
  1008.         if (RegEnumKey(
  1009.                     hKey,
  1010.                     i,
  1011.                     szClassName,
  1012.                     dwClassName
  1013.                     ) != ERROR_SUCCESS)
  1014.             goto Error;
  1015.  
  1016.         if (SampleDSGetClassInfo(
  1017.                             hKey,
  1018.                             szClassName,
  1019.                             pClassDefsCurrent
  1020.                             ) != ERROR_SUCCESS) {
  1021.             FreeProvMem(szClassName);
  1022.             continue;
  1023.         }
  1024.         pClassDefsCurrent->lpClassName = szClassName;
  1025.         numClass++;
  1026.         pClassDefsCurrent++;
  1027.     }
  1028.     szClassName = NULL;
  1029.  
  1030.     if (numClass != numEntries) {
  1031.         LPSampleDS_CLASS_DEF pClassDefsFinal; 
  1032.         pClassDefsFinal = (LPSampleDS_CLASS_DEF)AllocProvMem(
  1033.                                      sizeof(SampleDS_CLASS_DEF)*numClass);
  1034.         if (!pClassDefsFinal)
  1035.             goto Error;
  1036.         memcpy( 
  1037.             (void*)pClassDefsFinal,
  1038.             (void*)pClassDefsStart,
  1039.             sizeof(SampleDS_CLASS_DEF)*numClass
  1040.             );
  1041.         *ppClassDefsReturn = pClassDefsFinal;
  1042.         FreeProvMem(pClassDefsStart);
  1043.     }
  1044.     else {
  1045.         *ppClassDefsReturn = pClassDefsStart; 
  1046.     }
  1047.     *pnumObject = numClass;
  1048.     RegCloseKey(hKey);
  1049.     RRETURN(S_OK);
  1050.  
  1051. Error:
  1052.     RegCloseKey(hKey);
  1053.     LPSampleDS_CLASS_DEF pClassDefsDelete = pClassDefsStart; 
  1054.     DWORD j;
  1055.     for (j=0; j<numClass; j++) {
  1056.         if (pClassDefsDelete->lpClassName)
  1057.             FreeProvMem(pClassDefsDelete->lpClassName);
  1058.         if (pClassDefsDelete->lpMandatoryAttributes)
  1059.             FreeList(pClassDefsDelete->lpMandatoryAttributes);
  1060.         pClassDefsDelete++;
  1061.     }
  1062.     if (szClassName)
  1063.         FreeProvMem(szClassName);
  1064.     if (pClassDefsStart)
  1065.         FreeProvMem(pClassDefsStart);
  1066.     RRETURN(E_FAIL);
  1067. }
  1068.  
  1069. /*++
  1070.  
  1071. Routine Description:
  1072.  
  1073.     Get the class defintion for a particular class 
  1074.  
  1075. Arguments:
  1076.  
  1077. Return Value:
  1078.  
  1079. --*/
  1080. HRESULT
  1081. SampleDSGetClassDefinition( 
  1082.     LPSampleDS_CLASS_DEF* ppClassDefReturn,
  1083.     LPWSTR szClassName)
  1084. {                           
  1085.     WCHAR szRegPath[MAX_PATH] = SAMPLEDS_REGSCHEMAPATH;
  1086.     DWORD numEntries;
  1087.     HKEY hKey;
  1088.     LPSampleDS_CLASS_DEF pClassDefCurrent; 
  1089.     LPWSTR szClassNameCurrent;
  1090.     DWORD i;
  1091.     
  1092.     if( RegOpenKeyEx( 
  1093.                 HKEY_LOCAL_MACHINE, 
  1094.                 szRegPath, 
  1095.                 0, 
  1096.                 KEY_ALL_ACCESS, 
  1097.                 &hKey
  1098.                 ) != ERROR_SUCCESS) {
  1099.         RRETURN(E_FAIL);
  1100.     }
  1101.     
  1102.     if( RegQueryInfoKey(
  1103.                     hKey,
  1104.                     NULL,
  1105.                     NULL,
  1106.                     NULL,
  1107.                     &numEntries,
  1108.                     NULL,
  1109.                     NULL,
  1110.                     NULL,
  1111.                     NULL,
  1112.                     NULL,
  1113.                     NULL,
  1114.                     NULL
  1115.                     ) != ERROR_SUCCESS) {
  1116.         goto Error;
  1117.     }
  1118.     
  1119.     pClassDefCurrent= (LPSampleDS_CLASS_DEF)AllocProvMem(
  1120.                                              sizeof(SampleDS_CLASS_DEF));
  1121.     if (!pClassDefCurrent)
  1122.         goto Error;
  1123.     szClassNameCurrent = (LPWSTR)AllocProvMem(sizeof(WCHAR)*MAX_PATH);
  1124.     if (!szClassNameCurrent)
  1125.         goto Error;
  1126.  
  1127.     for (i=0; i<numEntries; i++) {
  1128.         if (RegEnumKey(hKey,
  1129.             i,
  1130.             szClassNameCurrent,
  1131.             MAX_PATH) != ERROR_SUCCESS)
  1132.             goto Error;
  1133.  
  1134.         if (!_wcsicmp(szClassNameCurrent,szClassName)) {
  1135.             if (SampleDSGetClassInfo( 
  1136.                                 hKey,
  1137.                                 szClassNameCurrent,
  1138.                                 pClassDefCurrent
  1139.                                 ) != ERROR_SUCCESS)
  1140.                 goto Error;
  1141.             pClassDefCurrent->lpClassName = szClassNameCurrent;
  1142.             *ppClassDefReturn = pClassDefCurrent; 
  1143.             RegCloseKey(hKey);
  1144.             RRETURN(S_OK);
  1145.         }
  1146.     }
  1147. Error:
  1148.     RegCloseKey(hKey);
  1149.     if (szClassNameCurrent)
  1150.         FreeProvMem(szClassNameCurrent);
  1151.     if (pClassDefCurrent)
  1152.         FreeProvMem(pClassDefCurrent);
  1153.     RRETURN(E_FAIL);
  1154. }
  1155.  
  1156. /*++
  1157.  
  1158. Routine Description:
  1159.  
  1160.     Free memory allocated by GetClassDefinition
  1161.  
  1162. Arguments:
  1163.  
  1164. Return Value:
  1165.  
  1166. --*/
  1167. HRESULT    
  1168. SampleDSFreeClassDefinition(LPSampleDS_CLASS_DEF pClassDefs,
  1169.                             DWORD numObject)
  1170. {
  1171.     if (!pClassDefs)
  1172.         RRETURN(E_FAIL);
  1173.  
  1174.     LPSampleDS_CLASS_DEF pClassDefCurrent = pClassDefs;
  1175.     for (DWORD j=0; j<numObject; j++) {
  1176.         if (pClassDefCurrent->lpClassName)
  1177.             FreeProvMem(pClassDefCurrent->lpClassName);
  1178.         if (pClassDefCurrent->lpMandatoryAttributes)
  1179.             FreeList(pClassDefCurrent->lpMandatoryAttributes);
  1180.         pClassDefCurrent++;
  1181.     }
  1182.     FreeProvMem(pClassDefs);
  1183.     RRETURN(S_OK);
  1184. }
  1185.  
  1186. /*++
  1187.  
  1188. Routine Description:
  1189.  
  1190.     Get the next token in a REG_MULTISZ string returned by the 
  1191.     Regsitry getvalue function 
  1192.  
  1193. Arguments:
  1194.  
  1195. Return Value:
  1196.  
  1197. --*/
  1198. LPWSTR nexttoken(LPWSTR szCurrent)
  1199. {
  1200.     static LPWSTR szRemainder = NULL;
  1201.     LPWSTR szReturn = NULL;
  1202.  
  1203.     if (szCurrent) {
  1204.         szRemainder = szCurrent;
  1205.     } 
  1206.     else if (szRemainder == NULL) {
  1207.         return NULL;
  1208.     }
  1209.  
  1210.     if (*szRemainder) {
  1211.         szReturn = szRemainder;
  1212.         while (*++szRemainder);
  1213.         szRemainder++;
  1214.     }
  1215.     return szReturn;
  1216. }
  1217.  
  1218. /*++
  1219.  
  1220. Routine Description:
  1221.  
  1222.     Get information about a particular class from the schema
  1223.  
  1224. Arguments:
  1225.  
  1226. Return Value:
  1227.  
  1228. --*/
  1229. HRESULT
  1230. SampleDSGetClassInfo(HKEY hKey,
  1231.                      LPWSTR szClassName,
  1232.                      LPSampleDS_CLASS_DEF pClassDef)
  1233. {
  1234.     HKEY hKeyClass;
  1235.     DWORD dwType;
  1236.     LPWSTR szProperties;
  1237.     DWORD dwProperties = MAX_PATH * 3;
  1238.     LPWSTR_LIST pListStart = NULL; 
  1239.  
  1240.     DWORD dwManProp = 0;
  1241.     LPWSTR_LIST pListCurrent = NULL; 
  1242.     LPWSTR szPropCurrent = NULL;
  1243.     LPWSTR szProperty = NULL;
  1244.     LPWSTR szPropertyNew = NULL;
  1245.     
  1246.     DWORD dwSchemaType;
  1247.     if ((SampleDSGetType(
  1248.                     hKey,
  1249.                     szClassName,
  1250.                     &dwSchemaType) == E_FAIL) || 
  1251.         (dwSchemaType != SAMPLEDS_CLASS)) 
  1252.         RRETURN(E_FAIL);
  1253.     
  1254.     if (RegOpenKeyEx(
  1255.                 hKey,
  1256.                 szClassName,
  1257.                 NULL,
  1258.                 KEY_READ,
  1259.                 &hKeyClass
  1260.                 ) != ERROR_SUCCESS)
  1261.         RRETURN(E_FAIL);
  1262.  
  1263.     szProperties= (LPWSTR)AllocProvMem(sizeof(WCHAR)*dwProperties);
  1264.     if (!szProperties)
  1265.         goto Error;
  1266.  
  1267.     if (RegQueryValueEx(
  1268.                     hKeyClass, 
  1269.                     SAMPLEDS_REG_MANPROP,
  1270.                     NULL,
  1271.                     &dwType,
  1272.                     (BYTE*)szProperties,    
  1273.                     &dwProperties
  1274.                     ) != ERROR_SUCCESS) {
  1275.         goto Error;
  1276.     }
  1277.     if (dwType != REG_MULTI_SZ) {
  1278.         goto Error;
  1279.     }
  1280.  
  1281.     szPropCurrent = szProperties;
  1282.     szProperty = nexttoken(szPropCurrent);
  1283.     szPropertyNew;
  1284.     if (szProperty) {
  1285.         pListStart = (LPWSTR_LIST)AllocProvMem(sizeof(WSTR_LIST));
  1286.         if (!pListStart)
  1287.             goto Error;
  1288.         pListCurrent = pListStart;
  1289.         szPropertyNew = AllocProvStr(szProperty);
  1290.         if (!szPropertyNew)
  1291.             goto Error;
  1292.         pListCurrent->lpString = szPropertyNew;
  1293.         szProperty = nexttoken(NULL);
  1294.         dwManProp++;
  1295.         while( szProperty != NULL ) {
  1296.             LPWSTR_LIST pListNew = (LPWSTR_LIST)AllocProvMem(
  1297.                                                   sizeof(WSTR_LIST));
  1298.             if (!pListNew)
  1299.                 goto Error;
  1300.             pListCurrent->Next = pListNew;
  1301.             szPropertyNew = AllocProvStr(szProperty);
  1302.             if (!szPropertyNew)
  1303.                 goto Error;
  1304.             pListNew->lpString = szPropertyNew;
  1305.             pListCurrent = pListNew;
  1306.             szProperty = nexttoken(NULL);
  1307.             dwManProp++;
  1308.         }                              
  1309.        pListCurrent->Next = NULL;
  1310.     }
  1311.     pClassDef->lpMandatoryAttributes = pListStart;
  1312.     pClassDef->dwNumberOfMandatoryAttributes = dwManProp;
  1313.     RegCloseKey(hKeyClass);
  1314.     RRETURN(S_OK);      
  1315.  
  1316. Error:
  1317.     RegCloseKey(hKeyClass);
  1318.     if (pListStart)
  1319.         FreeList(pListStart);
  1320.     if (szProperties)
  1321.         FreeProvMem(szProperties);
  1322.     RRETURN(E_FAIL);
  1323. }
  1324.  
  1325.  
  1326. /*++
  1327.  
  1328. Routine Description:
  1329.     
  1330.     Add an object in the DS
  1331.  
  1332. Arguments:
  1333.  
  1334. Return Value:
  1335.  
  1336. --*/
  1337. HRESULT
  1338. SampleDSAddObject(HANDLE hKey,
  1339.                   LPWSTR szObject,
  1340.                   LPWSTR szClass,
  1341.                   HANDLE hOperationData
  1342.                   )
  1343. {
  1344.     if (!szObject || !szClass || !hKey)
  1345.         RRETURN(E_FAIL);
  1346.  
  1347.     HKEY hKeyNew;
  1348.     if (RegCreateKey(
  1349.                 (HKEY)hKey,
  1350.                 szObject,
  1351.                 &hKeyNew
  1352.                 ) != ERROR_SUCCESS) {
  1353.         RRETURN(E_FAIL);
  1354.     };
  1355.     
  1356.     if (RegSetValueEx(
  1357.                 hKeyNew,
  1358.                 SAMPLEDS_REG_TYPE,
  1359.                 NULL,
  1360.                 REG_SZ,
  1361.                 (BYTE*)szClass,
  1362.                 (wcslen(szClass) + 1) * sizeof(WCHAR)
  1363.                 ) != ERROR_SUCCESS) {
  1364.         RRETURN(E_FAIL);
  1365.     };
  1366.     if (hOperationData) {
  1367.         if (SampleDSModifyObject(
  1368.                             hKeyNew,
  1369.                             hOperationData
  1370.                             ) != S_OK) {
  1371.             RRETURN(E_FAIL);
  1372.         };
  1373.     };
  1374.     RRETURN(S_OK);
  1375. }
  1376.  
  1377.  
  1378. /*++
  1379.  
  1380. Routine Description:
  1381.  
  1382.     Delete a registry key and all its subkeys
  1383.  
  1384. Arguments:
  1385.  
  1386. Return Value:
  1387.  
  1388. --*/
  1389. LONG RegDeleteAllKeys(HKEY hKeyDelete,
  1390.                       LPWSTR pszSubKey)
  1391. {
  1392.     HKEY  hKeyChild;
  1393.     TCHAR szTmp[MAX_PATH];
  1394.     LONG  lResult;
  1395.     DWORD dwTmpSize = MAX_PATH;
  1396.  
  1397.     lResult = RegOpenKeyEx(
  1398.                        hKeyDelete,
  1399.                        pszSubKey,
  1400.                        NULL,
  1401.                        KEY_ALL_ACCESS,
  1402.                        &hKeyChild
  1403.                        );
  1404.     if (lResult != ERROR_SUCCESS)
  1405.         return lResult;
  1406.    
  1407.     lResult = RegEnumKey(
  1408.                      hKeyChild,
  1409.                      0,
  1410.                      szTmp,
  1411.                      dwTmpSize
  1412.                      );
  1413.  
  1414.     while (lResult != ERROR_NO_MORE_ITEMS) {
  1415.         RegDeleteAllKeys(
  1416.                  hKeyChild,
  1417.                  szTmp
  1418.                  );
  1419.  
  1420.         lResult = RegEnumKey(
  1421.                          hKeyChild,
  1422.                          0,
  1423.                          szTmp,
  1424.                          dwTmpSize
  1425.                          );
  1426.     }   
  1427.  
  1428.     RegCloseKey(hKeyChild);
  1429.     lResult = RegDeleteKey(
  1430.                        hKeyDelete,
  1431.                        pszSubKey
  1432.                        );
  1433.  
  1434.     return lResult;
  1435. }
  1436.  
  1437.  
  1438. /*++
  1439.  
  1440. Routine Description:
  1441.  
  1442.     Remove an object from the DS
  1443.  
  1444. Arguments:
  1445.  
  1446. Return Value:
  1447.  
  1448. --*/
  1449. HRESULT
  1450. SampleDSRemoveObject(HANDLE hKey,
  1451.                      LPWSTR szObject) 
  1452. {
  1453.     if (RegDeleteAllKeys(
  1454.                     (HKEY)hKey,
  1455.                     szObject
  1456.                     ) == ERROR_SUCCESS)
  1457.         RRETURN(S_OK);
  1458.     else
  1459.         RRETURN(E_FAIL);
  1460. }
  1461.  
  1462.  
  1463.  
  1464. /*++
  1465.  
  1466. Routine Description:
  1467.  
  1468.     Create Memory Buffer for operation data
  1469.  
  1470. Arguments:
  1471.  
  1472. Return Value:
  1473.  
  1474. --*/
  1475. HRESULT
  1476. SampleDSCreateBuffer(HANDLE *phOperationData)
  1477. {
  1478.     LPSampleDS_ATTRS_INFO pAttrsInfo;
  1479.     pAttrsInfo = (LPSampleDS_ATTRS_INFO)AllocProvMem(sizeof(SampleDS_ATTRS_INFO));
  1480.     if (!pAttrsInfo)
  1481.         RRETURN(E_OUTOFMEMORY);
  1482.     *phOperationData = pAttrsInfo;
  1483.     RRETURN(S_OK);
  1484. }
  1485.  
  1486.  
  1487.  
  1488. /*++
  1489.  
  1490. Routine Description:
  1491.  
  1492.     Free memroy pointed to by operationdata
  1493.  
  1494. Arguments:
  1495.  
  1496. Return Value:
  1497.  
  1498. --*/
  1499. HRESULT
  1500. SampleDSFreeBuffer(HANDLE hOperationData)
  1501. {
  1502.     if (!hOperationData)
  1503.         RRETURN(E_FAIL);
  1504.     
  1505.     LPSampleDS_ATTRS_INFO pAttrsInfo;
  1506.     pAttrsInfo = (LPSampleDS_ATTRS_INFO)hOperationData;
  1507.  
  1508.     LPSampleDS_ATTR_INFO pAttrInfo;
  1509.     DWORD cAttr;
  1510.     pAttrInfo = pAttrsInfo->pAttrInfo;
  1511.     cAttr = pAttrsInfo->dwAttr;
  1512.  
  1513.     if (pAttrInfo) {
  1514.         for (DWORD i = 0;i<cAttr;i++) {
  1515.             if (pAttrInfo->lpAttributeName)
  1516.                 FreeProvMem(pAttrInfo->lpAttributeName);
  1517.             if (pAttrInfo->lpValue) {
  1518.                 if (pAttrInfo->dwSyntaxId == SampleDS_DATATYPE_1) {
  1519.                     if (((SampleDS_TYPE_1*)(pAttrInfo->lpValue))->DNString)
  1520.                         FreeProvMem(((SampleDS_TYPE_1*)
  1521.                                         (pAttrInfo->lpValue))->DNString);
  1522.                 }
  1523.                 FreeProvMem(pAttrInfo->lpValue);
  1524.             }
  1525.             pAttrInfo++;
  1526.         }
  1527.     }
  1528.     FreeProvMem(pAttrsInfo->pAttrInfo);
  1529.     FreeProvMem(pAttrsInfo);
  1530.     RRETURN(S_OK);
  1531. }
  1532.  
  1533.  
  1534.