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 / cgenobj.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-29  |  17.0 KB  |  809 lines

  1. /*++ 
  2.  
  3. Copyright (c) 1996 Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     CGenObj.cpp
  8.  
  9. Abstract:
  10.  
  11.     Microsoft ADs DS Provider Generic Object
  12.  
  13. Author:
  14.  
  15. Environment:
  16.  
  17.     User mode
  18.  
  19. Revision History :
  20.  
  21. --*/
  22. #include "adssmp.h"
  23. #pragma hdrstop
  24.  
  25. DEFINE_IDispatch_Implementation(CSampleDSGenObject)
  26. DEFINE_IADs_Implementation(CSampleDSGenObject)
  27.  
  28.  
  29. CSampleDSGenObject::CSampleDSGenObject():_pPropertyCache(NULL)
  30. {
  31.     VariantInit(&_vFilter);
  32. }
  33.  
  34. HRESULT
  35. CSampleDSGenObject::CreateGenericObject(
  36.     BSTR Parent,
  37.     BSTR CommonName,
  38.     BSTR ClassName,
  39.     DWORD dwObjectState,
  40.     REFIID riid,
  41.     void **ppvObj
  42.     )
  43. {
  44.     CSampleDSGenObject FAR * pGenObject = NULL;
  45.     HRESULT hr = S_OK;
  46.  
  47.     hr = AllocateGenObject(&pGenObject);
  48.     BAIL_ON_FAILURE(hr);
  49.  
  50.     hr = pGenObject->InitializeCoreObject(
  51.                 Parent,
  52.                 CommonName,
  53.                 ClassName,
  54.                 L"",
  55.                 CLSID_SampleDSGenObject,
  56.                 dwObjectState
  57.                 );
  58.     BAIL_ON_FAILURE(hr);
  59.  
  60.     hr = pGenObject->QueryInterface(riid, ppvObj);
  61.     BAIL_ON_FAILURE(hr);
  62.  
  63.     pGenObject->Release();
  64.  
  65.     RRETURN(hr);
  66.  
  67. error:
  68.  
  69.     delete pGenObject;
  70.  
  71.     RRETURN(hr);
  72. }
  73.  
  74. CSampleDSGenObject::~CSampleDSGenObject( )
  75. {
  76.  
  77.     delete _pDispMgr;
  78.     delete _pPropertyCache;
  79.  
  80. }
  81.  
  82. STDMETHODIMP
  83. CSampleDSGenObject::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  84. {
  85.     if (IsEqualIID(iid, IID_IUnknown))
  86.     {
  87.         *ppv = (IADs FAR *) this;
  88.     }
  89.     else if (IsEqualIID(iid, IID_IADsContainer))
  90.     {
  91.         *ppv = (IADsContainer FAR *) this;
  92.     }
  93.     else if (IsEqualIID(iid, IID_IADs))
  94.     {
  95.         *ppv = (IADs FAR *) this;
  96.     }
  97.     else if (IsEqualIID(iid, IID_IDispatch))
  98.     {
  99.         *ppv = (IADs FAR *) this;
  100.     }
  101.     else
  102.     {
  103.         *ppv = NULL;
  104.         return E_NOINTERFACE;
  105.     }
  106.     AddRef();
  107.     return NOERROR;
  108. }
  109.  
  110.  
  111. HRESULT
  112. CSampleDSGenObject::SetInfo()
  113. {
  114.     HRESULT hr = S_OK;
  115.  
  116.     if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  117.  
  118.         hr = SampleDSCreateObject();
  119.         BAIL_ON_FAILURE(hr);
  120.  
  121.         //
  122.         // If the create succeded, set the object type to bound
  123.         //
  124.  
  125.         SetObjectState(ADS_OBJECT_BOUND);
  126.  
  127.     }else {
  128.  
  129.         hr = SampleDSSetObject();
  130.         BAIL_ON_FAILURE(hr);
  131.     }
  132.  
  133. error:
  134.  
  135.     RRETURN(hr);
  136. }
  137.  
  138.  
  139. HRESULT
  140. CSampleDSGenObject::SampleDSSetObject()
  141. {
  142.     WCHAR szSampleDSPathName[MAX_PATH];
  143.     HANDLE hObject = NULL;
  144.     HRESULT hr = S_OK;
  145.     HANDLE hOperationData = NULL;
  146.  
  147.  
  148.     hr = BuildDSPathFromADsPath(
  149.                 _ADsPath,
  150.                 szSampleDSPathName
  151.                 );
  152.     BAIL_ON_FAILURE(hr);
  153.  
  154.     
  155.     hr = SampleDSOpenObject(
  156.                     szSampleDSPathName,
  157.                     &hObject,
  158.                     NULL,
  159.                     REG_DS
  160.                     );
  161.     BAIL_ON_FAILURE(hr);
  162.  
  163.     hr = SampleDSCreateBuffer(&hOperationData);
  164.     BAIL_ON_FAILURE(hr);
  165.     
  166.     hr = _pPropertyCache->SampleDSMarshallProperties(
  167.                             hOperationData
  168.                             );
  169.     
  170.     BAIL_ON_FAILURE(hr);
  171.     hr = SampleDSModifyObject(hObject,
  172.                               hOperationData
  173.                              );
  174. error:
  175.     if (hObject) {
  176.         hr = SampleDSCloseObject(hObject);
  177.     }
  178.     if (hOperationData) {
  179.         SampleDSFreeBuffer(hOperationData);
  180.     }
  181.     RRETURN(hr);
  182. }
  183.  
  184. HRESULT
  185. CSampleDSGenObject::SampleDSCreateObject()
  186. {
  187.     WCHAR szSampleDSParentName[MAX_PATH];
  188.     HANDLE hOperationData = NULL;
  189.     HANDLE hObject = NULL;
  190.     HRESULT hr = S_OK;
  191.  
  192.     hr = BuildDSPathFromADsPath(
  193.                 _Parent,
  194.                 szSampleDSParentName
  195.                 );
  196.     BAIL_ON_FAILURE(hr);
  197.  
  198.     hr = SampleDSOpenObject(
  199.                     szSampleDSParentName,
  200.                     &hObject,
  201.                     NULL,
  202.                     REG_DS
  203.                     );
  204.     BAIL_ON_FAILURE(hr);
  205.  
  206.     hr = SampleDSCreateBuffer(&hOperationData);
  207.     BAIL_ON_FAILURE(hr);
  208.     
  209.     hr = _pPropertyCache->SampleDSMarshallProperties(
  210.                             hOperationData
  211.                             );
  212.     BAIL_ON_FAILURE(hr);
  213.     
  214.     hr = SampleDSAddObject(
  215.                 hObject,
  216.                 _Name,
  217.                 _ADsClass,
  218.                 hOperationData
  219.                 );
  220.     
  221. error:
  222.     if (hObject) {
  223.         hr = SampleDSCloseObject(hObject);
  224.     }
  225.     if (hOperationData) {
  226.         SampleDSFreeBuffer(hOperationData);
  227.     }
  228.  
  229.     RRETURN(hr);
  230. }
  231.  
  232.  
  233. HRESULT
  234. CSampleDSGenObject::GetInfo()
  235. {
  236.     RRETURN(GetInfo(TRUE));
  237. }
  238.  
  239. HRESULT
  240. CSampleDSGenObject::GetInfo(
  241.     BOOL fExplicit
  242. ){
  243.     HANDLE hObject = NULL;
  244.     HRESULT hr = S_OK;
  245.     WCHAR szDSPathName[MAX_PATH];
  246.     HANDLE hOperationData = NULL;
  247.  
  248.     if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  249.         hr = E_ADS_OBJECT_UNBOUND;
  250.         BAIL_ON_FAILURE(hr);
  251.     }
  252.  
  253.     hr = BuildDSPathFromADsPath(
  254.                 _ADsPath,
  255.                 szDSPathName
  256.                 );
  257.     BAIL_ON_FAILURE(hr);
  258.  
  259.     hr = SampleDSOpenObject(
  260.                     szDSPathName,
  261.                     &hObject,
  262.                     NULL,
  263.                     REG_DS
  264.                     );
  265.     BAIL_ON_FAILURE(hr);
  266.  
  267.     hr = SampleDSReadObject(
  268.         hObject,
  269.         &hOperationData
  270.     );
  271.     BAIL_ON_FAILURE(hr);
  272.             
  273.     hr = _pPropertyCache->SampleDSUnMarshallProperties(hOperationData,
  274.                                                        fExplicit
  275.                                                        );
  276.     BAIL_ON_FAILURE(hr);
  277. error:
  278.  
  279.     if (hObject) {
  280.         hr = SampleDSCloseObject(hObject);
  281.     }
  282.     if (hOperationData) {
  283.         SampleDSFreeBuffer(hOperationData);
  284.     }
  285.  
  286.     RRETURN(hr);
  287. }
  288.  
  289. /* IADsContainer methods */
  290.  
  291. STDMETHODIMP
  292. CSampleDSGenObject::get_Count(long FAR* retval)
  293. {
  294.     RRETURN(E_NOTIMPL);
  295. }
  296.  
  297. STDMETHODIMP
  298. CSampleDSGenObject::get_Filter(THIS_ VARIANT FAR* pVar)
  299. {
  300.     VariantInit(pVar);
  301.     RRETURN(VariantCopy(pVar, &_vFilter));
  302. }
  303.  
  304. STDMETHODIMP
  305. CSampleDSGenObject::put_Filter(THIS_ VARIANT Var)
  306. {
  307.     RRETURN(VariantCopy(&_vFilter, &Var));
  308. }
  309.  
  310. STDMETHODIMP
  311. CSampleDSGenObject::put_Hints(THIS_ VARIANT Var)
  312. {
  313.     RRETURN( E_NOTIMPL);
  314. }
  315.  
  316. STDMETHODIMP
  317. CSampleDSGenObject::get_Hints(THIS_ VARIANT FAR* pVar)
  318. {
  319.     RRETURN(E_NOTIMPL);
  320. }
  321.  
  322. STDMETHODIMP
  323. CSampleDSGenObject::GetObject(
  324.     BSTR ClassName,
  325.     BSTR RelativeName,
  326.     IDispatch * FAR* ppObject
  327.     )
  328. {
  329.     RRETURN(::RelativeGetObject(_ADsPath,
  330.                                 ClassName,
  331.                                 RelativeName,
  332.                                 ppObject,
  333.                                 FALSE));
  334. }
  335.  
  336. STDMETHODIMP
  337. CSampleDSGenObject::get__NewEnum(
  338.     THIS_ IUnknown * FAR* retval
  339.     )
  340. {
  341.     HRESULT hr;
  342.     IUnknown FAR* punkEnum=NULL;
  343.     IEnumVARIANT * penum = NULL;
  344.  
  345.  
  346.     *retval = NULL;
  347.  
  348.     hr = CSampleDSGenObjectEnum::Create(
  349.                 (CSampleDSGenObjectEnum **)&penum,
  350.                 _ADsPath,
  351.                 _vFilter
  352.                 );
  353.     BAIL_ON_FAILURE(hr);
  354.  
  355.     hr = penum->QueryInterface(
  356.                 IID_IUnknown,
  357.                 (VOID FAR* FAR*)retval
  358.                 );
  359.     BAIL_ON_FAILURE(hr);
  360.  
  361.     if (penum) {
  362.         penum->Release();
  363.     }
  364.  
  365.     RRETURN(NOERROR);
  366.  
  367. error:
  368.  
  369.     if (penum) {
  370.         delete penum;
  371.     }
  372.  
  373.     RRETURN(hr);
  374. }
  375.  
  376.  
  377. STDMETHODIMP
  378. CSampleDSGenObject::Create(
  379.     THIS_ BSTR ClassName,
  380.     BSTR RelativeName,
  381.     IDispatch * FAR* ppObject
  382.     )
  383. {
  384.     HRESULT hr = S_OK;
  385.     IADs * pADs  = NULL;
  386.     WCHAR szDSTreeName[MAX_PATH];
  387.     DWORD dwSyntaxId = 0;
  388.  
  389.     //
  390.     // Get the TreeName for this object
  391.     //
  392.  
  393.     hr = BuildDSTreeNameFromADsPath(
  394.                 _ADsPath,
  395.                 szDSTreeName
  396.                 );
  397.     BAIL_ON_FAILURE(hr);
  398.  
  399.  
  400.     //
  401.     // Validate if this class really exists in the schema
  402.     // and validate that this object can be created in this
  403.     // container
  404.     //
  405.  
  406.     hr = CSampleDSGenObject::CreateGenericObject(
  407.                     _ADsPath,
  408.                     RelativeName,
  409.                     ClassName,
  410.                     ADS_OBJECT_UNBOUND,
  411.                     IID_IDispatch,
  412.                     (void **)ppObject
  413.                     );
  414.     BAIL_ON_FAILURE(hr);
  415.  
  416. error:
  417.  
  418.     RRETURN(hr);
  419. }
  420.  
  421. STDMETHODIMP
  422. CSampleDSGenObject::Delete(
  423.     THIS_ BSTR bstrClassName,
  424.     BSTR bstrRelativeName
  425.     )
  426. {
  427.     WCHAR szDSPathName[MAX_PATH];
  428.     HRESULT hr = S_OK;
  429.     DWORD dwStatus = 0;
  430.     HANDLE hParentObject = NULL;
  431.  
  432.     hr = BuildDSPathFromADsPath(
  433.                 _ADsPath,
  434.                 szDSPathName
  435.                 );
  436.     BAIL_ON_FAILURE(hr);
  437.     
  438.     hr = SampleDSOpenObject(
  439.                     szDSPathName,
  440.                     &hParentObject,
  441.                     NULL,
  442.                     REG_DS
  443.                     );
  444.     BAIL_ON_FAILURE(hr);
  445.  
  446.     hr= SampleDSRemoveObject(
  447.                 hParentObject,
  448.                 bstrRelativeName);
  449.     BAIL_ON_FAILURE(hr);
  450.  
  451.  
  452. error:
  453.     if (hParentObject) {
  454.         dwStatus = SampleDSCloseObject(hParentObject);
  455.     }
  456.     RRETURN(hr);
  457. }
  458.  
  459. STDMETHODIMP
  460. CSampleDSGenObject::CopyHere(
  461.     THIS_ BSTR SourceName,
  462.     BSTR NewName,
  463.     IDispatch * FAR* ppObject
  464.     )
  465. {
  466.     RRETURN(E_NOTIMPL);
  467. }
  468.  
  469. STDMETHODIMP
  470. CSampleDSGenObject::MoveHere(
  471.     THIS_ BSTR SourceName,
  472.     BSTR NewName,
  473.     IDispatch * FAR* ppObject
  474.     )
  475. {
  476.     RRETURN(E_NOTIMPL);
  477. }
  478.  
  479. HRESULT
  480. CSampleDSGenObject::AllocateGenObject(CSampleDSGenObject ** ppGenObject)
  481. {
  482.     CSampleDSGenObject FAR * pGenObject = NULL;
  483.     CDispatchMgr FAR * pDispMgr = NULL;
  484.     CPropertyCache FAR * pPropertyCache = NULL;
  485.     HRESULT hr = S_OK;
  486.  
  487.     pGenObject = new CSampleDSGenObject();
  488.     if (pGenObject == NULL) {
  489.         hr = E_OUTOFMEMORY;
  490.     }
  491.     BAIL_ON_FAILURE(hr);
  492.  
  493.     pDispMgr = new CDispatchMgr;
  494.     if (pDispMgr == NULL) {
  495.         hr = E_OUTOFMEMORY;
  496.     }
  497.     BAIL_ON_FAILURE(hr);
  498.  
  499.     hr = LoadTypeInfoEntry(pDispMgr,
  500.                            LIBID_ADs,
  501.                            IID_IADs,
  502.                            (IADs *)pGenObject,
  503.                            DISPID_REGULAR
  504.                            );
  505.     BAIL_ON_FAILURE(hr);
  506.  
  507.     hr = LoadTypeInfoEntry(pDispMgr,
  508.                            LIBID_ADs,
  509.                            IID_IADsContainer,
  510.                            (IADsContainer *)pGenObject,
  511.                            DISPID_NEWENUM
  512.                            );
  513.     BAIL_ON_FAILURE(hr);
  514.  
  515.     hr = CPropertyCache::createpropertycache(
  516.                         (CCoreADsObject FAR *)pGenObject,
  517.                         &pPropertyCache
  518.                         );
  519.     BAIL_ON_FAILURE(hr);
  520.  
  521.  
  522.  
  523.     pGenObject->_pPropertyCache = pPropertyCache;
  524.     pGenObject->_pDispMgr = pDispMgr;
  525.     *ppGenObject = pGenObject;
  526.     
  527.     RRETURN(hr);
  528.  
  529. error:
  530.     delete  pDispMgr;
  531.     RRETURN(hr);
  532. }
  533.  
  534. STDMETHODIMP
  535. CSampleDSGenObject::Get(
  536.     THIS_ BSTR bstrName,
  537.     VARIANT FAR* pvProp
  538.     )
  539. {
  540.     HRESULT hr = S_OK;
  541.     DWORD dwSyntaxId;
  542.     DWORD dwNumValues;
  543.     LPSampleDSOBJECT pNdsSrcObjects = NULL;
  544.  
  545.     //
  546.     // retrieve data object from cache; if one exists
  547.     //
  548.  
  549.     if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  550.  
  551.         hr = _pPropertyCache->unboundgetproperty(
  552.                     bstrName,
  553.                     &dwSyntaxId,
  554.                     &dwNumValues,
  555.                     &pNdsSrcObjects
  556.                     );
  557.         BAIL_ON_FAILURE(hr);
  558.  
  559.     }else {
  560.  
  561.         hr = _pPropertyCache->getproperty(
  562.                     bstrName,
  563.                     &dwSyntaxId,
  564.                     &dwNumValues,
  565.                     &pNdsSrcObjects
  566.                     );
  567.         BAIL_ON_FAILURE(hr);
  568.     }
  569.  
  570.  
  571.     //
  572.     // translate the Nds objects to variants
  573.     //
  574.  
  575.     hr = SampleDSTypeToVarTypeCopyConstruct(
  576.                 pNdsSrcObjects,
  577.                 dwNumValues,
  578.                 pvProp
  579.                 );
  580.     BAIL_ON_FAILURE(hr);
  581.  
  582. error:
  583.     if (pNdsSrcObjects) {
  584.  
  585.         SampleDSTypeFreeSampleDSObjects(
  586.             pNdsSrcObjects,
  587.             dwNumValues
  588.             );
  589.     }
  590.  
  591.     RRETURN(hr);
  592. }
  593.  
  594.  
  595. STDMETHODIMP
  596. CSampleDSGenObject::Put(
  597.     THIS_ BSTR bstrName,
  598.     VARIANT vProp
  599.     )
  600. {
  601.     HRESULT hr = S_OK;
  602.     DWORD dwSyntaxId  = 0;
  603.     DWORD dwIndex = 0;
  604.     LPSampleDSOBJECT pNdsDestObjects = NULL;
  605.     WCHAR szSampleDSTreeName[MAX_PATH];
  606.     DWORD dwNumValues = 0;
  607.  
  608.     VARIANT * pVarArray = NULL;
  609.     VARIANT * pvProp = NULL;
  610.  
  611.     //
  612.     // Issue: How do we handle multi-valued support
  613.     //
  614.  
  615.     if ((V_VT(&vProp) &  VT_VARIANT) &&  V_ISARRAY(&vProp)) {
  616.  
  617.         hr  = ConvertSafeArrayToVariantArray(
  618.                     vProp,
  619.                     &pVarArray,
  620.                     &dwNumValues
  621.                     );
  622.         BAIL_ON_FAILURE(hr);
  623.         pvProp = pVarArray;
  624.  
  625.     }else {
  626.  
  627.         dwNumValues = 1;
  628.         pvProp = &vProp;
  629.     }
  630.  
  631.     //
  632.     // Get the TreeName for this object
  633.     //
  634.  
  635.     hr = BuildDSPathFromADsPath(
  636.                 _ADsPath,
  637.                 szSampleDSTreeName
  638.                 );
  639.     BAIL_ON_FAILURE(hr);
  640.     
  641.     //
  642.     // check if the variant maps to the syntax of this property
  643.     //
  644.     switch (vProp.vt) {
  645.         case VT_BSTR:
  646.                 dwSyntaxId = SampleDS_DATATYPE_1;
  647.                 break;
  648.         case VT_I4:
  649.                 dwSyntaxId = SampleDS_DATATYPE_2;
  650.                 break;
  651.         default:
  652.                 hr = E_FAIL;
  653.                 goto error;
  654.         }
  655.                 hr = VarTypeToSampleDSTypeCopyConstruct(
  656.                     dwSyntaxId,
  657.                     pvProp,
  658.                     dwNumValues,
  659.                     &pNdsDestObjects
  660.                     );
  661.     BAIL_ON_FAILURE(hr);
  662.  
  663.     //
  664.     // Find this property in the cache
  665.     //
  666.  
  667.     hr = _pPropertyCache->findproperty(
  668.                         bstrName,
  669.                         &dwIndex
  670.                         );
  671.  
  672.     //
  673.     // If this property does not exist in the
  674.     // cache, add this property into the cache.
  675.     //
  676.  
  677.  
  678.     if (FAILED(hr)) {
  679.         hr = _pPropertyCache->addproperty(
  680.                     bstrName,
  681.                     dwSyntaxId,
  682.                     dwNumValues,
  683.                     pNdsDestObjects
  684.                     );
  685.         //
  686.         // If the operation fails for some reason
  687.         // move on to the next property
  688.         //
  689.         BAIL_ON_FAILURE(hr);
  690.  
  691.     }
  692.  
  693.     //
  694.     // Now update the property in the cache
  695.     //
  696.  
  697.     hr = _pPropertyCache->putproperty(
  698.                     bstrName,
  699.                     dwSyntaxId,
  700.                     dwNumValues,
  701.                     pNdsDestObjects
  702.                     );
  703.     BAIL_ON_FAILURE(hr);
  704.  
  705. error:
  706.  
  707.     if (pNdsDestObjects) {
  708.         SampleDSTypeFreeSampleDSObjects(
  709.                 pNdsDestObjects,
  710.                 dwNumValues
  711.                 );
  712.  
  713.     }
  714.  
  715.  
  716.     if (pVarArray) {
  717.  
  718.         DWORD i = 0;
  719.  
  720.         for (i = 0; i < dwNumValues; i++) {
  721.             VariantClear(pVarArray + i);
  722.         }
  723.         FreeProvMem(pVarArray);
  724.     }
  725.  
  726.     RRETURN(hr);
  727. }
  728.  
  729.  
  730. HRESULT
  731. ConvertSafeArrayToVariantArray(
  732.     VARIANT varSafeArray,
  733.     VARIANT ** ppVarArray,
  734.     PDWORD pdwNumVariants
  735.     )
  736. {
  737.     HRESULT hr = S_OK;
  738.     DWORD dwSLBound = 0;
  739.     DWORD dwSUBound = 0;
  740.     DWORD i = 0;
  741.     DWORD dwNumVariants = 0;
  742.     VARIANT * pVarArray = NULL;
  743.  
  744.     *pdwNumVariants = 0;
  745.     *ppVarArray  = 0;
  746.  
  747.     if(!((V_VT(&varSafeArray) &  VT_VARIANT) &&  V_ISARRAY(&varSafeArray))) {
  748.         return(E_FAIL);
  749.     }
  750.  
  751.     //
  752.     // Check that there is only one dimension in this array
  753.     //
  754.  
  755.     if ((V_ARRAY(&varSafeArray))->cDims != 1) {
  756.         hr = E_FAIL;
  757.         BAIL_ON_FAILURE(hr);
  758.     }
  759.     //
  760.     // Check that there is atleast one element in this array
  761.     //
  762.  
  763.     if ((V_ARRAY(&varSafeArray))->rgsabound[0].cElements == 0){
  764.         hr = E_FAIL;
  765.         BAIL_ON_FAILURE(hr);
  766.     }
  767.  
  768.     hr = SafeArrayGetLBound(V_ARRAY(&varSafeArray),
  769.                             1,
  770.                             (long FAR *)&dwSLBound
  771.                             );
  772.     BAIL_ON_FAILURE(hr);
  773.  
  774.     hr = SafeArrayGetUBound(V_ARRAY(&varSafeArray),
  775.                             1,
  776.                             (long FAR *)&dwSUBound
  777.                             );
  778.     BAIL_ON_FAILURE(hr);
  779.  
  780.     dwNumVariants = dwSUBound - dwSLBound + 1;
  781.     pVarArray = (VARIANT*)AllocProvMem(
  782.                                 sizeof(VARIANT)*dwNumVariants
  783.                                 );
  784.     if (!pVarArray) {
  785.         hr = E_OUTOFMEMORY;
  786.         BAIL_ON_FAILURE(hr);
  787.     }
  788.  
  789.     for (i = dwSLBound; i <= dwSUBound; i++) {
  790.  
  791.         VariantInit(pVarArray + i);
  792.         hr = SafeArrayGetElement(V_ARRAY(&varSafeArray),
  793.                                 (long FAR *)&i,
  794.                                 (pVarArray + i)
  795.                                 );
  796.         CONTINUE_ON_FAILURE(hr);
  797.     }
  798.  
  799.     *ppVarArray = pVarArray;
  800.     *pdwNumVariants = dwNumVariants;
  801.  
  802. error:
  803.  
  804.     RRETURN(hr);
  805. }
  806.  
  807.  
  808.  
  809.