home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / activexcontrol / basectl / include / extobj.h < prev    next >
C/C++ Source or Header  |  1997-10-04  |  10KB  |  489 lines

  1. #ifndef __EXTOBJ_H
  2. #define __EXTOBJ_H
  3. ////
  4. //
  5. // ExpandoObject header file
  6. //
  7. //
  8. //
  9. #include "IPServer.H"
  10.  
  11. ////
  12. //
  13. // IDispatchEx
  14. //
  15. ////
  16.  
  17. ////
  18. //
  19. // the GUID
  20. //
  21.  
  22. // {A0AAC450-A77B-11cf-91D0-00AA00C14A7C}
  23. DEFINE_GUID(IID_IDispatchEx, 0xa0aac450, 0xa77b, 0x11cf, 0x91, 0xd0, 0x0, 0xaa, 0x0, 0xc1, 0x4a, 0x7c);
  24.  
  25. ////
  26. //
  27. // IDispatchEx flags:
  28. //
  29.  
  30. enum
  31. {
  32.     fdexNil = 0x00,                // empty
  33.     fdexDontCreate = 0x01,        // don't create slot if non-existant otherwise do
  34.     fdexInitNull = 0x02,        // init a new slot to VT_NULL as opposed to VT_EMPTY
  35.     fdexCaseSensitive = 0x04,    // match names as case sensitive
  36. };
  37.  
  38. ////
  39. //
  40. // This is the interface for extensible IDispatch objects.
  41. //
  42.  
  43. class IDispatchEx : public IDispatch
  44. {
  45. public:
  46.     // Get dispID for names, with options
  47.     virtual HRESULT STDMETHODCALLTYPE GetIDsOfNamesEx(
  48.         REFIID riid,
  49.         LPOLESTR *prgpsz,
  50.         UINT cpsz,
  51.         LCID lcid,
  52.         DISPID *prgid,
  53.         DWORD grfdex
  54.     ) = 0;
  55.  
  56.     // Enumerate dispIDs and their associated "names".
  57.     // Returns S_FALSE if the enumeration is done, NOERROR if it's not, an
  58.     // error code if the call fails.
  59.     virtual HRESULT STDMETHODCALLTYPE GetNextDispID(
  60.         DISPID id,
  61.         DISPID *pid,
  62.         BSTR *pbstrName
  63.     ) = 0;
  64. };
  65.  
  66. ////
  67. //
  68. // Globals and definitions
  69. //
  70. ////
  71.  
  72. #define NUM_EXPANDO_DISPIDS        250
  73. #define    NUM_CORE_DISPIDS        250
  74. #define NUM_RESERVED_EXTENDER_DISPIDS (NUM_CORE_DISPIDS + NUM_EXPANDO_DISPIDS)
  75. #define EXTENDER_DISPID_BASE ((ULONG)(0x80010000))
  76. #define IS_EXTENDER_DISPID(x) ( ( (ULONG)(x) & 0xFFFF0000 ) == EXTENDER_DISPID_BASE )
  77.  
  78. ////
  79. //
  80. // Slot: the state of a value slot
  81. //
  82.  
  83. inline WCHAR ToUpper(WCHAR ch)   
  84. {
  85.     if (ch>='a' && ch <= 'z')  
  86.         return ch - 'a' + 'A';
  87.     else
  88.         return ch;
  89.  
  90. }
  91.  
  92. class CExpandoObjectSlot
  93. {
  94. public:
  95.     ////
  96.     //
  97.     // Constructor/Destructor
  98.     //
  99.  
  100.     // because these monsters are malloc'ed, we need a manual constructor and destructor methods
  101.     void Construct()
  102.     {
  103.         m_name = NULL;
  104.         m_next = -1;
  105.         VariantInit(&m_value);
  106.         // set hash and dispId to dummy values
  107.         m_hash = 0;
  108.         m_dispId = DISPID_UNKNOWN;
  109.     }
  110.  
  111.     void Destruct()
  112.     {
  113.         if (m_name)
  114.             SysFreeString(m_name);
  115.         VariantClear(&m_value);
  116.     }
  117.  
  118. private:
  119.     // the constructors and destructors are private because they should never be called ...
  120.     // we could use in-place construction if we wanted to be clever ...
  121.     CExpandoObjectSlot()
  122.     {
  123.     }
  124.  
  125.     ~CExpandoObjectSlot()
  126.     {
  127.     }
  128.  
  129. public:
  130.     ////
  131.     //
  132.     // Init the slot
  133.     //
  134.  
  135.     HRESULT Init(LPOLESTR name, LCID lcid, DISPID dispId, VARIANT* value)
  136.     {
  137.         // allocate the string
  138.         m_name = SysAllocString(name);
  139.         if (m_name == NULL)
  140.             return E_OUTOFMEMORY;
  141.  
  142.         // compute the hash: uses the standard OLE string hashing function
  143.         // note that this function is case insensitive
  144.         m_hash = LHashValOfName(lcid, name);
  145.  
  146.         // set the dispId
  147.         m_dispId = dispId;
  148.  
  149.         // Copy the variant value
  150.         return VariantCopy(&m_value, value);
  151.     }
  152.  
  153.     ////
  154.     //
  155.     // Name information
  156.     //
  157.  
  158.     // get the name
  159.     BSTR Name()
  160.     { return m_name; }
  161.  
  162.     // compare two names
  163.     BOOL CompareName(LPOLESTR name, ULONG hash, BOOL caseSensitive)
  164.     {
  165.         // hash should be the same, length should be the same, and strings should compare
  166.         // BUGBUG robwell 8May96 These functions are probably verboten.
  167.         if (hash != m_hash)
  168.             return FALSE;
  169.  
  170.         if (!name)
  171.             return !m_name;
  172.  
  173.         WCHAR *c1 = name;
  174.         WCHAR *c2 = m_name;
  175.  
  176.         // Travel down both strings until we reach a mismatched character
  177.         // or the end of one (or both) of the strings
  178.  
  179.         if (caseSensitive)
  180.             while (*c1 && *c2 && *c1++==*c2++);
  181.         else
  182.             while (*c1 && *c2 && ToUpper(*c1++)==ToUpper(*c2++));
  183.  
  184.         // The strings match if we reached the end of both without a mismatch
  185.         return !*c1 && !*c2;
  186.      }
  187.  
  188.     ////
  189.     //
  190.     // DispId information
  191.     //
  192.  
  193.     // get the dispatch id
  194.     DISPID DispId()
  195.     { return m_dispId; }
  196.  
  197.     ////
  198.     //
  199.     // Get and set the property values
  200.     //
  201.  
  202.     HRESULT Get(VARIANT* result)
  203.     { return VariantCopy(result, &m_value); }
  204.  
  205.     HRESULT Set(VARIANT* value)
  206.     { return VariantCopy(&m_value, value); }
  207.  
  208.     ////
  209.     //
  210.     // List management
  211.     //
  212.  
  213.     CExpandoObjectSlot* Next(CExpandoObjectSlot* base)
  214.     { return m_next == -1? NULL: &base[m_next]; }
  215.  
  216.     CExpandoObjectSlot* Insert(CExpandoObjectSlot* base, LONG& prev)
  217.     {
  218.         m_next = prev;
  219.         prev = this - base;
  220.         return this;
  221.     }
  222.  
  223. private:
  224.     // the DispId
  225.     DISPID        m_dispId;
  226.     // the name
  227.     LPOLESTR    m_name;
  228.     // the name hash
  229.     ULONG        m_hash;
  230.     // the property value
  231.     VARIANT        m_value;
  232.     // the hash bucket link (index based)
  233.     LONG        m_next;
  234. };
  235.  
  236. // NB: CExpandoObject implements a crippled version of aggegation.
  237. // It delegates all IUnknown calls to its controlling IUnknown, and has no
  238. // private IUnknown interface.
  239. // If you want the CExpandoObject to go away, simply call delete on it.
  240. class CExpandoObject: public IDispatchEx
  241. {
  242. public:
  243.  
  244.     ////
  245.     //
  246.     // Constructor/Destructor
  247.     //
  248.  
  249.     CExpandoObject(IUnknown *punkOuter, IDispatch *pdisp, ULONG dispIdBase = EXTENDER_DISPID_BASE + NUM_CORE_DISPIDS) 
  250.     {
  251.         // remember our controlling outer
  252.         m_punkOuter = punkOuter;
  253.  
  254.         // remember the IDispatch to try first for IDispatch functionality
  255.         m_pdisp = pdisp;
  256.         
  257.         // clear the name hash table
  258.         ClearHashTable();
  259.         // set the total slots and the table of slots to 0 and empty respectively)
  260.         m_totalSlots = 0;
  261.         m_slotTableSize = 0;
  262.         m_slots = NULL;
  263.         m_dispIdBase = dispIdBase;
  264.     }
  265.  
  266.     STDMETHODIMP_(ULONG) AddRef()
  267.     {
  268.         return m_punkOuter->AddRef();
  269.     }
  270.  
  271.     STDMETHODIMP_(ULONG)Release()
  272.     {
  273.         return m_punkOuter->Release();
  274.     }
  275.  
  276.     STDMETHODIMP QueryInterface(REFIID riid, void **ppvObjOut)
  277.     {
  278.         return m_punkOuter->QueryInterface(riid, ppvObjOut);
  279.     }
  280.  
  281.     virtual ~CExpandoObject(void)
  282.     {
  283.         FreeAllSlots();
  284.     }
  285.  
  286.  
  287.     // Copy all of the properties from obj 
  288.        CloneProperties(CExpandoObject& obj);
  289.  
  290.     ////
  291.     //
  292.     //
  293.     // Utility functions
  294.     //
  295.  
  296.     // free all slots
  297.     void FreeAllSlots();
  298.  
  299.     // IDispatch methods
  300.     virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo);
  301.     virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(
  302.         UINT itinfo,
  303.         LCID lcid,
  304.         ITypeInfo **pptinfo
  305.     );
  306.     virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(
  307.         REFIID riid,
  308.         LPOLESTR *prgpsz,
  309.         UINT cpsz,
  310.         LCID lcid,
  311.         DISPID *prgdispID
  312.     );
  313.     virtual HRESULT STDMETHODCALLTYPE Invoke(
  314.         DISPID dispID,
  315.         REFIID riid,
  316.         LCID lcid,
  317.         WORD wFlags,
  318.         DISPPARAMS *pdispparams,
  319.         VARIANT *pvarRes,
  320.         EXCEPINFO *pexcepinfo,
  321.         UINT *puArgErr
  322.     );
  323.  
  324.     // IDispatchEx methods
  325.  
  326.     // Get dispID for names, with options
  327.     virtual HRESULT STDMETHODCALLTYPE GetIDsOfNamesEx(
  328.         REFIID riid,
  329.         LPOLESTR *prgpsz,
  330.         UINT cpsz,
  331.         LCID lcid,
  332.         DISPID *prgid,
  333.         DWORD grfdex
  334.     );
  335.  
  336.     // Enumerate dispIDs and their associated "names".
  337.     // Returns S_FALSE if the enumeration is done, NOERROR if it's not, an
  338.     // error code if the call fails.
  339.     virtual HRESULT STDMETHODCALLTYPE GetNextDispID(
  340.         DISPID id,
  341.         DISPID *pid,
  342.         BSTR *pbstrName
  343.     );
  344.  
  345. private:
  346.     ////
  347.     //
  348.     // Implementation constants
  349.     //
  350.  
  351.     enum
  352.     {
  353.         kSlotHashTableSize = 10,
  354.         kInitialSlotTableSize = 4,
  355.         kMaxTotalSlots = NUM_EXPANDO_DISPIDS
  356.     };
  357.  
  358.     ////
  359.     //
  360.     // Utility functions
  361.     //
  362.  
  363.     //
  364.     CExpandoObjectSlot* GetHashTableHead(UINT hashIndex)
  365.     {
  366.         LONG index;
  367.  
  368.         return (index = m_hashTable[hashIndex]) == -1? NULL: &m_slots[index];
  369.     }
  370.  
  371.     // get the ID of from a slot name
  372.     HRESULT GetIDOfName(LPOLESTR name, LCID lcid, BOOL caseSensitive, DISPID* id);
  373.     // add a slot to the object
  374.     HRESULT AddSlot(LPOLESTR name, LCID lcid, BOOL caseSensitive, VARIANT* initialValue, DISPID* id);
  375.     // allocate a slot from the slot table
  376.     CExpandoObjectSlot* AllocSlot();
  377.     // clear the hash table
  378.     void ClearHashTable()
  379.     {
  380.         UINT i;
  381.  
  382.         for (i=0; i<kSlotHashTableSize; ++i)
  383.             m_hashTable[i] = -1;
  384.     }
  385.  
  386.     ////
  387.     //
  388.     // Slot operations
  389.     //
  390.     // DISPIDS start at kInitialDispId so we need to offset them by that amount
  391.     // in this code.
  392.     //
  393.  
  394.     HRESULT GetSlot(DISPID id, VARIANT* result)
  395.     {
  396.         if ((ULONG) id < m_dispIdBase || (ULONG) id >= (m_totalSlots+m_dispIdBase))
  397.             return DISP_E_MEMBERNOTFOUND;
  398.  
  399.         return m_slots[id-m_dispIdBase].Get(result);
  400.     }
  401.  
  402.     HRESULT SetSlot(DISPID id, VARIANT* result)
  403.     {
  404.         if ((ULONG) id < m_dispIdBase || (ULONG) id >= (m_totalSlots+m_dispIdBase))
  405.             return DISP_E_MEMBERNOTFOUND;
  406.  
  407.         return m_slots[id-m_dispIdBase].Set(result);
  408.     }
  409.  
  410.     ////
  411.     //
  412.     // Iteration operations
  413.     //
  414.  
  415.     UINT    NumDispIds()
  416.     { return m_totalSlots; }
  417.  
  418.     DISPID    First()
  419.     { return m_dispIdBase; }
  420.  
  421.     DISPID    Last()
  422.     { return m_totalSlots + m_dispIdBase - 1; }
  423.  
  424.     BOOL    ValidDispId(DISPID id)
  425.     { return id >= First() && id <= Last(); }
  426.  
  427.     HRESULT    Next(DISPID key, CExpandoObjectSlot*& slot)
  428.     {
  429.         // zero restarts the enumerator
  430.         if (key == 0)
  431.         {
  432.             // if there are no slots we are done
  433.             if (NumDispIds() == 0)
  434.                 return S_FALSE;
  435.  
  436.             // return the first slot
  437.             slot = &m_slots[0];
  438.             return NOERROR;
  439.         }
  440.         else
  441.         if (key == Last())
  442.         {
  443.             // the key was the last slot so we are done
  444.             return S_FALSE;
  445.         }
  446.         else
  447.         if (ValidDispId(key))
  448.         {
  449.             // return the next slot
  450.             slot = &m_slots[key-m_dispIdBase+1];
  451.             return NOERROR;
  452.         }
  453.         else
  454.             // the key must be invalid
  455.             return E_INVALIDARG;
  456.     }
  457.  
  458.     ////
  459.     //
  460.     // The local state of the object
  461.     //
  462.  
  463.     // the objects reference count
  464.     ULONG    m_ref;
  465.  
  466.     // the base of objectIds
  467.     ULONG    m_dispIdBase;
  468.  
  469.     // the hash table of slots - for fast GetIDSofNames lookup
  470.     LONG    m_hashTable[kSlotHashTableSize];
  471.  
  472.     // the number of slots (and the next dispId to allocate)
  473.     UINT    m_totalSlots;
  474.  
  475.     // the size of the allocated array of slots
  476.     UINT    m_slotTableSize;
  477.  
  478.     // a pointer to the allocated array of slots
  479.     CExpandoObjectSlot* m_slots;
  480.  
  481.     // controlling unknown
  482.     IUnknown *m_punkOuter;
  483.  
  484.     // controlling IDispatch
  485.     IDispatch *m_pdisp;
  486. };
  487.  
  488. #endif // __EXTOBJ_H
  489.