spddkhlp.h
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:21k
源码类别:

模拟服务器

开发平台:

C/C++

  1. /*******************************************************************************
  2. * SPDDKHLP.h *
  3. *------------*
  4. *   Description:
  5. *       This is the header file for core helper functions implementation.
  6. *
  7. *   Copyright (c) Microsoft Corporation. All rights reserved.
  8. *
  9. *******************************************************************************/
  10. #ifndef SPDDKHLP_h
  11. #define SPDDKHLP_h
  12. #ifndef SPHelper_h
  13. #include <sphelper.h>
  14. #endif
  15. #include <sapiddk.h>
  16. #ifndef SPError_h
  17. #include <SPError.h>
  18. #endif
  19. #ifndef SPDebug_h
  20. #include <SPDebug.h>
  21. #endif
  22. #ifndef _INC_LIMITS
  23. #include <limits.h>
  24. #endif
  25. #ifndef _INC_CRTDBG
  26. #include <crtdbg.h>
  27. #endif
  28. #ifndef _INC_MALLOC
  29. #include <malloc.h>
  30. #endif
  31. #ifndef _INC_MMSYSTEM
  32. #include <mmsystem.h>
  33. #endif
  34. #ifndef __comcat_h__
  35. #include <comcat.h>
  36. #endif
  37. //=== Constants ==============================================================
  38. #define sp_countof(x) ((sizeof(x) / sizeof(*(x))))
  39. #define SP_IS_BAD_WRITE_PTR(p)     ( SPIsBadWritePtr( p, sizeof(*(p)) ))
  40. #define SP_IS_BAD_READ_PTR(p)      ( SPIsBadReadPtr(  p, sizeof(*(p)) ))
  41. #define SP_IS_BAD_CODE_PTR(p)      ( ::IsBadCodePtr((FARPROC)(p) )
  42. #define SP_IS_BAD_INTERFACE_PTR(p) ( SPIsBadInterfacePtr( (p) )  )
  43. #define SP_IS_BAD_VARIANT_PTR(p)   ( SPIsBadVARIANTPtr( (p) ) )
  44. #define SP_IS_BAD_STRING_PTR(p)    ( SPIsBadStringPtr( (p) ) )
  45. #define SP_IS_BAD_OPTIONAL_WRITE_PTR(p)     ((p) && SPIsBadWritePtr( p, sizeof(*(p)) ))
  46. #define SP_IS_BAD_OPTIONAL_READ_PTR(p)      ((p) && SPIsBadReadPtr(  p, sizeof(*(p)) ))
  47. #define SP_IS_BAD_OPTIONAL_INTERFACE_PTR(p) ((p) && SPIsBadInterfacePtr(p))
  48. #define SP_IS_BAD_OPTIONAL_STRING_PTR(p)    ((p) && SPIsBadStringPtr(p))
  49. //=== Class, Enum, Struct, Template, and Union Declarations ==================
  50. //=== Inlines ================================================================
  51. /*** Pointer validation functions
  52. */
  53. // TODO:  Add decent debug output for bad parameters
  54. inline BOOL SPIsBadStringPtr( const WCHAR * psz, ULONG cMaxChars = 0xFFFF )
  55. {
  56.     BOOL IsBad = false;
  57.     __try
  58.     {
  59.         do
  60.         {
  61.             if( *psz++ == 0 ) return IsBad;
  62.         }
  63.         while( --cMaxChars );
  64.     }
  65.     __except( GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION )
  66.     {
  67.         IsBad = true;
  68.     }
  69.     return IsBad;
  70. }
  71. inline BOOL SPIsBadReadPtr( const void* pMem, UINT Size )
  72. {
  73. #ifdef _DEBUG
  74.     BOOL bIsBad = ::IsBadReadPtr( pMem, Size );
  75.     SPDBG_ASSERT(!bIsBad);
  76.     return bIsBad;
  77. #else
  78.     return ::IsBadReadPtr( pMem, Size );
  79. #endif
  80. }
  81. inline BOOL SPIsBadWritePtr( void* pMem, UINT Size )
  82. {
  83. #ifdef _DEBUG
  84.     BOOL bIsBad = ::IsBadWritePtr( pMem, Size );
  85.     SPDBG_ASSERT(!bIsBad);
  86.     return bIsBad;
  87. #else
  88.     return ::IsBadWritePtr( pMem, Size );
  89. #endif
  90. }
  91. inline BOOL SPIsBadInterfacePtr( const IUnknown* pUnknown )
  92. {
  93. #ifdef _DEBUG
  94.     BOOL bIsBad = ( ::IsBadReadPtr( pUnknown, sizeof( *pUnknown ) ) ||
  95.                     ::IsBadCodePtr( (FARPROC)((void**)pUnknown)[0] ))?
  96.                    (true):(false);
  97.     SPDBG_ASSERT(!bIsBad);
  98.     return bIsBad;
  99. #else
  100.     return ( ::IsBadReadPtr( pUnknown, sizeof( *pUnknown ) ) ||
  101.              ::IsBadCodePtr( (FARPROC)((void**)pUnknown)[0] ))?
  102.             (true):(false);
  103. #endif
  104. }
  105. inline BOOL SPIsBadVARIANTPtr( const VARIANT* pVar )
  106. {
  107. #ifdef _DEBUG
  108.     BOOL bIsBad = ::IsBadReadPtr( pVar, sizeof( *pVar ) );
  109.     SPDBG_ASSERT(!bIsBad);
  110.     return bIsBad;
  111. #else
  112.     return ::IsBadReadPtr( pVar, sizeof( *pVar ) );
  113. #endif
  114. }
  115. #ifdef __ATLCOM_H__     //--- Only enable these if ATL is being used
  116. //
  117. //  Helper functions can be used to implement GetObjectToken/SetObjectToken for objects that 
  118. //  support ISpObjectWithToken
  119. //
  120. inline HRESULT SpGenericSetObjectToken(ISpObjectToken * pCallersToken, CComPtr<ISpObjectToken> & cpObjToken)
  121. {
  122.     HRESULT hr = S_OK;
  123.     if (SP_IS_BAD_INTERFACE_PTR(pCallersToken))
  124.     {
  125.         hr = E_INVALIDARG;
  126.     }
  127.     else
  128.     {
  129.         if (cpObjToken)
  130.         {
  131.             hr = SPERR_ALREADY_INITIALIZED;
  132.         }
  133.         else
  134.         {
  135.             cpObjToken = pCallersToken;
  136.         }
  137.     }
  138.     return hr;
  139. }
  140. inline HRESULT SpGenericGetObjectToken(ISpObjectToken ** ppCallersToken, CComPtr<ISpObjectToken> & cpObjToken)
  141. {
  142.     HRESULT hr = S_OK;
  143.     if (SP_IS_BAD_WRITE_PTR(ppCallersToken))
  144.     {
  145.         hr = E_POINTER;
  146.     }
  147.     else
  148.     {
  149.         *ppCallersToken = cpObjToken;
  150.         if (*ppCallersToken)
  151.         {
  152.             (*ppCallersToken)->AddRef();
  153.         }
  154.         else
  155.         {
  156.             hr = S_FALSE;
  157.         }
  158.     }
  159.     return hr;
  160. }
  161. #endif  // __ATLCOM_H__
  162. //
  163. //  Helper class for SPSTATEINFO sturcture automatically initializes and cleans up
  164. //  the structure + provides a few helper functions.
  165. //
  166. class CSpStateInfo : public SPSTATEINFO
  167. {
  168. public:
  169.     CSpStateInfo()
  170.     {
  171.         cAllocatedEntries = NULL;
  172.         pTransitions = NULL;
  173.     }
  174.     ~CSpStateInfo()
  175.     {
  176.         ::CoTaskMemFree(pTransitions);
  177.     }
  178.     SPTRANSITIONENTRY * FirstEpsilon()
  179.     {
  180.         return pTransitions;
  181.     }
  182.     SPTRANSITIONENTRY * FirstRule()
  183.     {
  184.         return pTransitions + cEpsilons;
  185.     }
  186.     SPTRANSITIONENTRY * FirstWord()
  187.     {
  188.         return pTransitions + cEpsilons + cRules;
  189.     }
  190.     SPTRANSITIONENTRY * FirstSpecialTransition()
  191.     {
  192.         return pTransitions + cEpsilons + cRules + cWords;
  193.     }
  194. };
  195. //
  196. //  This basic queue implementation can be used to maintin linked lists of classes.  The class T
  197. //  must contain the member m_pNext which is used by this template to point to the next element.
  198. //  If the bPurgeWhenDeleted is TRUE then all of the elements in the queue will be deleted
  199. //  when the queue is deleted, otherwise they will not.
  200. //  If bMaintainCount is TRUE then a running count will be maintained, and GetCount() will be
  201. //  efficent.  If it is FALSE then a running count will not be maintained, and GetCount() will
  202. //  be an order N operation.  If you do not require a count, then 
  203. //
  204. template <class T, BOOL bPurgeWhenDeleted> class CSpBasicList;
  205. template <class T, BOOL bPurgeWhenDeleted = TRUE, BOOL bMaintainCount = FALSE>
  206. class CSpBasicQueue
  207. {
  208. public:
  209.     T     * m_pHead;
  210.     T     * m_pTail;
  211.     ULONG   m_cElements;    // Warning!  Use GetCount() -- Not maintained if bMaintainCount is FALSE.
  212.     CSpBasicQueue() 
  213.     {
  214.         m_pHead = NULL;
  215.         if (bMaintainCount)
  216.         {
  217.             m_cElements = 0;
  218.         }
  219.     }
  220.     ~CSpBasicQueue()
  221.     {
  222.         if (bPurgeWhenDeleted)
  223.         {
  224.             Purge();
  225.         }
  226.     }
  227.     HRESULT CreateNode(T ** ppNode)
  228.     {
  229.         *ppNode = new T;
  230.         if (*ppNode)
  231.         {
  232.             return S_OK;
  233.         }
  234.         else
  235.         {
  236.             return E_OUTOFMEMORY;
  237.         }
  238.     }
  239.     T * GetNext(const T * pNode)
  240.     {
  241.         return pNode->m_pNext;
  242.     }
  243.     T * Item(ULONG i)
  244.     {
  245.         T * pNode = m_pHead;
  246.         while (pNode && i)
  247.         {
  248.             i--;
  249.             pNode = pNode->m_pNext;
  250.         }
  251.         return pNode;
  252.     }
  253.     void InsertAfter(T * pPrev, T * pNewNode)
  254.     {
  255.         if (pPrev)
  256.         {
  257.             pNewNode->m_pNext = pPrev->m_pNext;
  258.             pPrev->m_pNext = pNewNode;
  259.             if (pNewNode->m_pNext == NULL)
  260.             {
  261.                 m_pTail = pNewNode;
  262.             }
  263.             if (bMaintainCount) ++m_cElements;
  264.         }
  265.         else
  266.         {
  267.             InsertHead(pNewNode);
  268.         }
  269.     }
  270.     void InsertTail(T * pNode)
  271.     {
  272.         pNode->m_pNext = NULL;
  273.         if (m_pHead)
  274.         {
  275.             m_pTail->m_pNext = pNode;
  276.         }
  277.         else
  278.         {
  279.             m_pHead = pNode;
  280.         }
  281.         m_pTail = pNode;
  282.         if (bMaintainCount) ++m_cElements;
  283.     }
  284.     void InsertHead(T * pNode)
  285.     {
  286.         pNode->m_pNext = m_pHead;
  287.         if (m_pHead == NULL)
  288.         {
  289.             m_pTail = pNode;
  290.         }
  291.         m_pHead = pNode;
  292.         if (bMaintainCount) ++m_cElements;
  293.     }
  294.     T * RemoveHead()
  295.     {
  296.         T * pNode = m_pHead;
  297.         if (pNode)
  298.         {
  299.             m_pHead = pNode->m_pNext;
  300.             if (bMaintainCount) --m_cElements;
  301.         }
  302.         return pNode;
  303.     }
  304.     T * RemoveTail()
  305.     {
  306.         T * pNode = m_pHead;
  307.         if (pNode)
  308.         {
  309.             if (pNode == m_pTail)
  310.             {
  311.                 m_pHead = NULL;
  312.             }
  313.             else
  314.             {
  315.                 T * pPrev;
  316.                 do
  317.                 {
  318.                     pPrev = pNode;
  319.                     pNode = pNode->m_pNext;
  320.                 } while ( pNode != m_pTail );
  321.                 pPrev->m_pNext = NULL;
  322.                 m_pTail = pPrev;
  323.             }
  324.             if (bMaintainCount) --m_cElements;
  325.         }
  326.         return pNode;
  327.     }
  328.     void Purge()
  329.     {
  330.         while (m_pHead)
  331.         {
  332.             T * pDie = m_pHead;
  333.             m_pHead = pDie->m_pNext;
  334.             delete pDie;
  335.         }
  336.         if (bMaintainCount) m_cElements = 0;
  337.     }
  338.     void ExplicitPurge()
  339.     {
  340.         T * pDie;
  341.         BYTE * pb;
  342.         while (m_pHead)
  343.         {
  344.             pDie = m_pHead;
  345.             m_pHead = pDie->m_pNext;
  346.             pDie->~T();
  347.             pb = reinterpret_cast<BYTE *>(pDie);
  348.             delete [] pb;
  349.         }
  350.         if (bMaintainCount) m_cElements = 0;
  351.     }
  352.     T * GetTail() const
  353.     {
  354.         if (m_pHead)
  355.         {
  356.             return m_pTail;
  357.         }
  358.         return NULL;
  359.     }
  360.     T * GetHead() const
  361.     {
  362.         return m_pHead;
  363.     }
  364.     BOOL IsEmpty() const
  365.     {
  366.         return m_pHead == NULL; 
  367.     }
  368.     BOOL Remove(T * pNode)
  369.     {
  370.         if (m_pHead == pNode)
  371.         {
  372.             m_pHead = pNode->m_pNext;
  373.             if (bMaintainCount) --m_cElements;
  374.             return TRUE;
  375.         }
  376.         else
  377.         {
  378.             T * pCur = m_pHead;
  379.             while (pCur)
  380.             {
  381.                 T * pNext = pCur->m_pNext;
  382.                 if (pNext == pNode)
  383.                 {
  384.                     if ((pCur->m_pNext = pNode->m_pNext) == NULL)
  385.                     {
  386.                         m_pTail = pCur;
  387.                     }
  388.                     if (bMaintainCount) --m_cElements;
  389.                     return TRUE;
  390.                 }
  391.                 pCur = pNext;
  392.             }
  393.         }
  394.         return FALSE;
  395.     }
  396.     void MoveAllToHeadOf(CSpBasicQueue & DestQueue)
  397.     {
  398.         if (m_pHead)
  399.         {
  400.             m_pTail->m_pNext = DestQueue.m_pHead;
  401.             if (DestQueue.m_pHead == NULL)
  402.             {
  403.                 DestQueue.m_pTail = m_pTail;
  404.             }
  405.             DestQueue.m_pHead = m_pHead;
  406.             m_pHead = NULL;
  407.             if (bMaintainCount)
  408.             {
  409.                 DestQueue.m_cElements += m_cElements;
  410.                 m_cElements = 0;
  411.             }
  412.         }
  413.     }
  414.     void MoveAllToList(CSpBasicList<T, bPurgeWhenDeleted> & List)
  415.     {
  416.         if (m_pHead)
  417.         {
  418.             m_pTail->m_pNext = List.m_pFirst;
  419.             List.m_pFirst = m_pHead;
  420.             m_pHead = NULL;
  421.         }
  422.         if (bMaintainCount)
  423.         {
  424.             m_cElements = 0;
  425.         }
  426.     }
  427.     BOOL MoveToList(T * pNode, CSpBasicList<T, bPurgeWhenDeleted> & List)
  428.     {
  429.         BOOL bFound = Remove(pNode);
  430.         if (bFound)
  431.         {
  432.             List.AddNode(pNode);
  433.         }
  434.         return bFound;
  435.     }
  436.     ULONG GetCount() const
  437.     {
  438.         if (bMaintainCount)
  439.         {
  440.             return m_cElements;
  441.         }
  442.         else
  443.         {
  444.             ULONG c = 0;
  445.             for (T * pNode = m_pHead;
  446.                  pNode;
  447.                  pNode = pNode->m_pNext, c++) {}
  448.             return c;
  449.         }
  450.     }
  451.     //
  452.     //  The following functions require the class T to implement a static function:
  453.     //
  454.     //      LONG Compare(const T * pElem1, const T * pElem2)
  455.     //
  456.     //  which returns < 0 if pElem1 is less than pElem2, 0 if they are equal, and > 0 if
  457.     //  pElem1 is greater than pElem2.
  458.     //
  459.     void InsertSorted(T * pNode)
  460.     {
  461.         if (m_pHead)
  462.         {
  463.             if (T::Compare(pNode, m_pTail) >= 0)
  464.             {
  465.                 pNode->m_pNext = NULL;
  466.                 m_pTail->m_pNext = pNode;
  467.                 m_pTail = pNode;
  468.             }
  469.             else
  470.             {
  471.                 //
  472.                 //  We don't have to worry about walking off of the end of the list here since
  473.                 //  we have already checked the tail.
  474.                 //
  475.                 T ** ppNext = &m_pHead;
  476.                 while (T::Compare(pNode, *ppNext) >= 0)
  477.                 {
  478.                     ppNext = &((*ppNext)->m_pNext);
  479.                 }
  480.                 pNode->m_pNext = *ppNext;
  481.                 *ppNext = pNode;
  482.             }
  483.         }
  484.         else
  485.         {
  486.             pNode->m_pNext = NULL;
  487.             m_pHead = m_pTail = pNode;
  488.         }
  489.         if (bMaintainCount) ++m_cElements;
  490.     }
  491.     HRESULT InsertSortedUnique(T * pNode)
  492.     {
  493.         HRESULT hr = S_OK;
  494.         if (m_pHead)
  495.         {
  496.             if (T::Compare(pNode, m_pTail) > 0)
  497.             {
  498.                 pNode->m_pNext = NULL;
  499.                 m_pTail->m_pNext = pNode;
  500.                 m_pTail = pNode;
  501.             }
  502.             else
  503.             {
  504.                 //
  505.                 //  We don't have to worry about walking off of the end of the list here since
  506.                 //  we have already checked the tail.
  507.                 //
  508.                 T ** ppNext = &m_pHead;
  509.                 while (T::Compare(pNode, *ppNext) > 0)
  510.                 {
  511.                     ppNext = &((*ppNext)->m_pNext);
  512.                 }
  513.                 if (T::Compare(pNode, *ppNext) != 0)
  514.                 {
  515.                     pNode->m_pNext = *ppNext;
  516.                     *ppNext = pNode;
  517.                 }
  518.                 else
  519.                 {
  520.                     delete pNode;
  521.                     hr = S_FALSE;
  522.                 }
  523.             }
  524.         }
  525.         else
  526.         {
  527.             pNode->m_pNext = NULL;
  528.             m_pHead = m_pTail = pNode;
  529.         }
  530.         if (bMaintainCount) ++m_cElements;
  531.         return hr;
  532.     }
  533.     //
  534.     //  These functions must support the "==" operator for the TFIND type.
  535.     //
  536.     template <class TFIND> 
  537.     T * Find(TFIND & FindVal) const 
  538.     {
  539.         for (T * pNode = m_pHead; pNode && (!(*pNode == FindVal)); pNode = pNode->m_pNext)
  540.         {}
  541.         return pNode;
  542.     }
  543.     template <class TFIND> 
  544.     T * FindNext(const T * pCurNode, TFIND & FindVal) const 
  545.     {
  546.         for (T * pNode = pCurNode->m_pNext; pNode && (!(*pNode == FindVal)); pNode = pNode->m_pNext)
  547.         {}
  548.         return pNode;
  549.     }
  550.     //
  551.     //  Searches for and removes a single list element
  552.     //  
  553.     template <class TFIND> 
  554.     T * FindAndRemove(TFIND & FindVal)
  555.     {
  556.         T * pNode = m_pHead;
  557.         if (pNode)
  558.         {
  559.             if (*pNode == FindVal)
  560.             {
  561.                 m_pHead = pNode->m_pNext;
  562.                 if (bMaintainCount) --m_cElements;
  563.             }
  564.             else
  565.             {
  566.                 T * pPrev = pNode;
  567.                 for (pNode = pNode->m_pNext;
  568.                      pNode;
  569.                      pPrev = pNode, pNode = pNode->m_pNext)
  570.                 {
  571.                     if (*pNode == FindVal)
  572.                     {
  573.                         pPrev->m_pNext = pNode->m_pNext;
  574.                         if (pNode->m_pNext == NULL)
  575.                         {
  576.                             m_pTail = pPrev;
  577.                         }
  578.                         if (bMaintainCount) --m_cElements;
  579.                         break;
  580.                     }
  581.                 }
  582.             }
  583.         }
  584.         return pNode;
  585.     }
  586.     //
  587.     //  Searches for and deletes all list elements that match
  588.     //  
  589.     template <class TFIND> 
  590.     void FindAndDeleteAll(TFIND & FindVal)
  591.     {
  592.         T * pNode = m_pHead;
  593.         while (pNode && *pNode == FindVal)
  594.         {
  595.             m_pHead = pNode->m_pNext;
  596.             delete pNode;
  597.             if (bMaintainCount) --m_cElements;
  598.             pNode = m_pHead;
  599.         }
  600.         T * pPrev = pNode;
  601.         while (pNode)
  602.         {
  603.             T * pNext = pNode->m_pNext;
  604.             if (*pNode == FindVal)
  605.             {
  606.                 pPrev->m_pNext = pNext;
  607.                 delete pNode;
  608.                 if (bMaintainCount) --m_cElements;
  609.             }
  610.             else
  611.             {
  612.                 pPrev = pNode;
  613.             }
  614.             pNode = pNext;
  615.         }
  616.         m_pTail = pPrev;    // Just always set it in case we removed the tail.
  617.     }
  618. };
  619. template <class T, BOOL bPurgeWhenDeleted = TRUE>
  620. class CSpBasicList
  621. {
  622. public:
  623.     T * m_pFirst;
  624.     CSpBasicList() : m_pFirst(NULL) {}
  625.     ~CSpBasicList()
  626.     {
  627.         if (bPurgeWhenDeleted)
  628.         {
  629.             Purge();
  630.         }
  631.     }
  632.     void Purge()
  633.     {
  634.         while (m_pFirst)
  635.         {
  636.             T * pNext = m_pFirst->m_pNext;
  637.             delete m_pFirst;
  638.             m_pFirst = pNext;
  639.         }
  640.     }
  641.     void ExplicitPurge()
  642.     {
  643.         T * pDie;
  644.         BYTE * pb;
  645.         while (m_pFirst)
  646.         {
  647.             pDie = m_pFirst;
  648.             m_pFirst = pDie->m_pNext;
  649.             pDie->~T();
  650.             pb = reinterpret_cast<BYTE *>(pDie);
  651.             delete [] pb;
  652.         }
  653.     }
  654.     HRESULT RemoveFirstOrAllocateNew(T ** ppNode)
  655.     {
  656.         if (m_pFirst)
  657.         {
  658.             *ppNode = m_pFirst;
  659.             m_pFirst = m_pFirst->m_pNext;
  660.         }
  661.         else
  662.         {
  663.             *ppNode = new T;
  664.             if (*ppNode == NULL)
  665.             {
  666.                 return E_OUTOFMEMORY;
  667.             }
  668.         }
  669.         return S_OK;
  670.     }
  671.     void AddNode(T * pNode)
  672.     {
  673.         pNode->m_pNext = m_pFirst;
  674.         m_pFirst = pNode;
  675.     }
  676.     T * GetFirst()
  677.     {
  678.         return m_pFirst;
  679.     }
  680.     T * RemoveFirst()
  681.     {
  682.         T * pNode = m_pFirst;
  683.         if (pNode)
  684.         {
  685.             m_pFirst = pNode->m_pNext;
  686.         }
  687.         return pNode;
  688.     }
  689. };
  690. #define STACK_ALLOC(TYPE, COUNT) (TYPE *)_alloca(sizeof(TYPE) * (COUNT))
  691. #define STACK_ALLOC_AND_ZERO(TYPE, COUNT) (TYPE *)memset(_alloca(sizeof(TYPE) * (COUNT)), 0, (sizeof(TYPE) * (COUNT)))
  692. #define STACK_ALLOC_AND_COPY(TYPE, COUNT, SOURCE) (TYPE *)memcpy(_alloca(sizeof(TYPE) * (COUNT)), (SOURCE), (sizeof(TYPE) * (COUNT)))
  693. inline HRESULT SpGetSubTokenFromToken(
  694.     ISpObjectToken * pToken,
  695.     const WCHAR * pszSubKeyName,
  696.     ISpObjectToken ** ppToken,
  697.     BOOL fCreateIfNotExist = FALSE)
  698. {
  699.     SPDBG_FUNC("SpGetTokenFromDataKey");
  700.     HRESULT hr = S_OK;
  701.     if (SP_IS_BAD_INTERFACE_PTR(pToken) ||
  702.         SP_IS_BAD_STRING_PTR(pszSubKeyName) ||
  703.         SP_IS_BAD_WRITE_PTR(ppToken))
  704.     {
  705.         hr = E_POINTER;
  706.     }
  707.     // First, either create or open the datakey for the new token
  708.     CComPtr<ISpDataKey> cpDataKeyForNewToken;
  709.     if (SUCCEEDED(hr))
  710.     {
  711.         if (fCreateIfNotExist)
  712.         {
  713.             hr = pToken->CreateKey(pszSubKeyName, &cpDataKeyForNewToken);
  714.         }
  715.         else
  716.         {
  717.             hr = pToken->OpenKey(pszSubKeyName, &cpDataKeyForNewToken);
  718.         }
  719.     }
  720.     // The sub token's category will be the token id of it's parent token
  721.     CSpDynamicString dstrCategoryId;
  722.     if (SUCCEEDED(hr))
  723.     {
  724.         hr = pToken->GetId(&dstrCategoryId);
  725.     }
  726.     // The sub token's token id will be it's category id + "\" the key name
  727.     CSpDynamicString dstrTokenId;
  728.     if (SUCCEEDED(hr))
  729.     {
  730.         dstrTokenId = dstrCategoryId;
  731.         dstrTokenId.Append2(L"\", pszSubKeyName);
  732.     }
  733.     // Now create the token and initalize it
  734.     CComPtr<ISpObjectTokenInit> cpTokenInit;
  735.     if (SUCCEEDED(hr))
  736.     {
  737.         hr = cpTokenInit.CoCreateInstance(CLSID_SpObjectToken);
  738.     }
  739.     if (SUCCEEDED(hr))
  740.     {
  741.         hr = cpTokenInit->InitFromDataKey(dstrCategoryId, dstrTokenId, cpDataKeyForNewToken);
  742.     }
  743.     if (SUCCEEDED(hr))
  744.     {
  745.         *ppToken = cpTokenInit.Detach();
  746.     }
  747.     SPDBG_REPORT_ON_FAIL(hr);
  748.     return hr;
  749. }
  750. template<class T>
  751. HRESULT SpCreateObjectFromSubToken(ISpObjectToken * pToken, const WCHAR * pszSubKeyName, T ** ppObject,
  752.                        IUnknown * pUnkOuter = NULL, DWORD dwClsCtxt = CLSCTX_ALL)
  753. {
  754.     SPDBG_FUNC("SpCreateObjectFromSubToken");
  755.     HRESULT hr;
  756.     CComPtr<ISpObjectToken> cpSubToken;
  757.     hr = SpGetSubTokenFromToken(pToken, pszSubKeyName, &cpSubToken);
  758.     
  759.     if (SUCCEEDED(hr))
  760.     {
  761.         hr = SpCreateObjectFromToken(cpSubToken, ppObject, pUnkOuter, dwClsCtxt);
  762.     }
  763.     SPDBG_REPORT_ON_FAIL(hr);
  764.     return hr;
  765. }
  766. #endif /* This must be the last line in the file */