comLib.cpp
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:78k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* comLib.cpp - COM library (VxDCOM) */
  2. /* Copyright (c) 1999 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 03f,03jan02,nel  Remove refs to T2OLE and OLE2T.
  7. 03e,17dec01,nel  Add include symbol for diab build.
  8. 03d,02nov01,nel  Fix docs build.
  9. 03c,19oct01,nel  SPR#71077. Fix error code returned by IIDFromString.
  10. 03b,19oct01,nel  SPR#71068. Fix StringFromCLSID parameter checking.
  11. 03a,17sep01,nel  SPR#70351. Check input parameters on StringFromGUID2.
  12. 02z,17sep01,nel  SPR#70350. Correct length count given by StringFromGUID2 to
  13.                  include null terminator.
  14. 02y,13sep01,nel  SPR#70299. Add checking to VariantCopy on source parameter
  15.                  for invalid VARIANT.
  16. 02x,12sep01,nel  SPR#70277. Fix parameter checking on CLSIDFromAscii.
  17. 02w,14aug01,nel  SPR#69615. CoCreateGUID check for NULL parameter.
  18. 02v,14aug01,nel  SPR#69609. SysAllocString should return NULL when passed a
  19.                  NULL BSTR as input.
  20. 02u,08aug01,nel  SPR#69514. Correct SysAllocStringLen so that it doesn't add
  21.                  two extra nulls.
  22. 02t,07aug01,dbs  use multi-qi in comCoreLib funcs
  23. 02s,06aug01,dbs  simplify vxcomGUID2String
  24. 02r,02aug01,nel  SPR#69373. Add extra checking to VariantInit and
  25.                  VariantClear.
  26. 02q,30jul01,nel  SPR#69346. Add check to VariantClear for VT_IUNKNOWN.
  27. 02p,26jul01,nel  SPR#68698. Add numeric-to-string, string-to-numeric
  28.                  capability to VariantChangeType.
  29. 02o,26jul01,nel  SPR#69289. Fix memory leak in SafeArrayDestroy.
  30. 02n,23jul01,nel  Correct return codes for CoCreateInstance docs.
  31. 02m,16jul01,dbs  correct definition of comLibInit func
  32. 02l,13jul01,dbs  fix up includes
  33. 02k,03jul01,nel  Remove IID_IMalloc because it's now defined in
  34.                  comCoreTypes.idl
  35. 02j,27jun01,nel  Add in extra SAFEARRAY API.
  36. 02i,27jun01,dbs  fix include paths and names
  37. 02h,20jun01,nel  Remove dependencies on rpcDceTypes.h.
  38. 02g,02may01,nel  SPR#66227. Correct format of comments for refgen.
  39. 02f,08feb01,nel  SPR#63885. SAFEARRAYs added. 
  40. 02e,30may00,nel  Add more variant support
  41. 02d,06apr00,nel  use kernel level routine to access TCB structure for task
  42. 02c,01mar00,nel  Correct vxdcomGUID2String so that it can correctly convert
  43.                  signed int to unsigned ints
  44. 02b,11feb00,dbs  IIDs moved to idl directory
  45. 02a,02feb00,dbs  add some Variant-related APIs
  46. 01z,07jan00,nel  Remove dependency on taskTcb to conform to new protection
  47.                  scheme
  48. 01y,16nov99,nel  Corrected new name of pComLocal in WIND_TCB
  49. 01x,13oct99,dbs  add manpage/reference material
  50. 01w,19aug99,aim  change assert to VXDCOM_ASSERT
  51. 01v,13aug99,aim  moved globals to vxdcomGlobals.h
  52. 01u,28jul99,drm  Adding g_defaultServerPriority global.
  53. 01t,21jul99,dbs  fix string-length in OLE2T helper
  54. 01s,16jul99,aim  changed Free to Dealloc
  55. 01r,15jul99,dbs  add assertion-checking to T2OLE support macros
  56. 01q,17jun99,dbs  change argtypes of comMemAlloc
  57. 01p,04jun99,dbs  remove public registry APIs
  58. 01o,03jun99,dbs  fix CoCreateGuid() for non-VxWorks builds
  59. 01n,03jun99,dbs  remove reliance on TLS
  60. 01m,28may99,dbs  simplify allocator strategy
  61. 01l,28may99,aim  fixed scoping on array access in SysAllocString
  62. 01k,24may99,dbs  add BSTR marshaling policy variable
  63. 01j,20may99,dbs  add SysAllocStringByteLen() API
  64. 01i,10may99,drm  removed code in CoCreateGuid() which sets guid to GUID_NULL
  65. 01h,07may99,drm  documentation updates
  66. 02g,03may99,drm  adding preliminary priority scheme support
  67. 02f,29apr99,dbs  fix warnings under -Wall
  68. 02e,29apr99,dbs  must include MemPool.h
  69. 02d,28apr99,dbs  add more mem-alloc funcs
  70. 02c,27apr99,dbs  allocate all BSTRs from same pool
  71. 02b,27apr99,dbs  add alloc helper funcs
  72. 02a,26apr99,aim  added TRACE_CALL
  73. 01z,23apr99,dbs  use streams properly
  74. 01y,15apr99,dbs  improve hard-coded arrays
  75. 01x,14apr99,dbs  export registry-instance function to comShow
  76. 01w,14apr99,dbs  add return-value to GuidMap::erase()
  77. 01v,14apr99,dbs  use GuidMap's internal mutex
  78. 01u,14apr99,dbs  add check for T2OLE macro
  79. 01t,13apr99,dbs  add VxMutex into GuidMap class
  80. 01s,13apr99,dbs  replace std-lib with comUtilLib containers
  81. 01r,13apr99,dbs  fix Win32 compatibility in CoCreateGuid, fix indent
  82.                  style, add semi-colons to VXDCOM_DEBUG usage
  83. 01q,08apr99,drm  adding diagnostic output using VXDCOM_DEBUG ;
  84. 01p,01apr99,dbs  add CComBSTR methods
  85. 01o,24mar99,drm  removing show routine
  86. 01n,19mar99,drm  added CoCreateGuid()
  87. 01m,09mar99,dbs  remove use of std::string
  88. 01l,03mar99,dbs  fix GuidMap to use correct find() method
  89. 01k,01mar99,dbs  add GUID_NULL definition
  90. 01j,19feb99,dbs  add more wide-char support
  91. 01i,11feb99,dbs  ensure all memory is allocated through task-allocator
  92. 01h,10feb99,dbs  tidy up per-task data items
  93. 01g,04feb99,dbs  change wchar_t to OLECHAR
  94. 01f,03feb99,dbs  add wide/ascii converters
  95. 01e,20jan99,dbs  fix lib-init function name
  96. 01d,20jan99,dbs  rename and move to main VOBs
  97. 01c,11jan99,dbs  reduce STL usage
  98. 01b,08jan99,dbs  Alloc registry from heap so it always works at
  99.                  startup.
  100. 01a,18dec98,dbs  created
  101. */
  102. #include <stdio.h>
  103. #include <stdlib.h>
  104. #include <string.h>
  105. #include "comLib.h"
  106. #include "private/comMisc.h"
  107. #include "private/comSysLib.h"
  108. #include "MemoryStream.h"
  109. #include "TaskAllocator.h"
  110. #include "TraceCall.h"
  111. #include "comCoreLib.h"
  112. /*
  113. DESCRIPTION
  114. This library provides a subset of the Win32 COM API calls, in order to
  115. support the implementation of COM in the VxWorks environment.
  116. */
  117. /* Include symbol for diab */
  118. extern "C" int include_vxcom_comLib (void)
  119.     {
  120.     return 0;
  121.     }
  122. /* Well-known GUIDs that are defined by COM... */
  123. const GUID GUID_NULL =
  124.     {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}};
  125. /**************************************************************************
  126. *
  127. * comLibInit - VxWorks COM library init function
  128. *
  129. * This function initialises the VxWorks enhanced COM library.
  130. *
  131. * RETURNS:
  132. * is
  133. * i OK
  134. * On success
  135. * i ERROR
  136. * If some failure occurs
  137. * ie
  138. */
  139. int comLibInit ()
  140.     {
  141.     return 0;
  142.     }
  143. /**************************************************************************
  144. *
  145. * CoCreateInstance - create an in-process instance of an object class
  146. *
  147. * This function is used to create an instance of a local object (an
  148. * <in-proc server>) under VxDCOM. The only valid value of
  149. * 'dwClsContext' is CLSCTX_INPROC_SERVER.
  150. *
  151. * RETURNS:
  152. * is
  153. * i S_OK
  154. * On success
  155. * i E_NOINTERFACE
  156. * If the class does not support the requested interface
  157. * i REG_E_CLASSNOTREG
  158. * If 'dwClsContext' is invalid or the class isn't registered in the registry.
  159. * ie
  160. */
  161. HRESULT CoCreateInstance
  162.     (
  163.     REFCLSID rclsid, /* CLSID of the object */
  164.     IUnknown* pUnkOuter, /* pointer to aggregating object */
  165.     DWORD dwClsContext, /* context */
  166.     REFIID riid, /* IID of desired interface */
  167.     void** ppv /* variable to receive interface ptr */
  168.     )
  169.     {
  170.     if (ppv == NULL)
  171.         return E_POINTER;
  172.     MULTI_QI mqi[] = { { &riid, 0, S_OK } };
  173.     // Create instance...
  174.     HRESULT hr = comInstanceCreate (rclsid,
  175.                                     pUnkOuter,
  176.                                     dwClsContext,
  177.                                     0,
  178.                                     1,
  179.                                     mqi);
  180.     if (FAILED (hr))
  181.         return hr;
  182.     // Get resulting interface pointer out...
  183.     if (ppv)
  184.         *ppv = mqi[0].pItf;
  185.     return mqi[0].hr;
  186.     }
  187. /**************************************************************************
  188. *
  189. * CoInitialize - initialize COM runtime support to APARTMENTTHREADED
  190. *
  191. * This function is provided for compatibility with the COM standard. Since
  192. * VxDCOM does not support the apartment-threading model this function always 
  193. * returns E_INVALIDARG.
  194. *
  195. * RETURNS: E_INVALIDARG under all conditions
  196. */
  197. HRESULT CoInitialize 
  198.     (
  199.     void*  pv /* Reserved. Must be NULL */
  200.     )
  201.     {
  202.     return CoInitializeEx (pv, COINIT_APARTMENTTHREADED);
  203.     }
  204. /**************************************************************************
  205. *
  206. * CoInitializeEx - initialize COM runtime support
  207. *
  208. * This function must be called with the 'dwCoInit' argument set to
  209. * COINIT_MULTITHREADED, as there is no apartment-threading model in
  210. * the VxWorks COM implementation.
  211. *
  212. * RETURNS:
  213. * is
  214. * i S_OK
  215. * On success
  216. * i E_INVALIDARG
  217. * If the caller asks for apartment threading.
  218. * ie
  219. */
  220. HRESULT CoInitializeEx 
  221.     (
  222.     void*  pv,  /* Reserved, must be NULL */
  223.     DWORD  dwCoInit /* Must be CoINIT_MULTITHREADED */
  224.     )
  225.     {
  226.     // Must be multi-threaded initialization...
  227.     if (dwCoInit & COINIT_APARTMENTTHREADED)
  228. return E_INVALIDARG;
  229.     return S_OK;
  230.     }
  231. /**************************************************************************
  232. *
  233. * CoUninitialize - un-initialize the COM runtime for this task.
  234. *
  235. * Provided for compatibility with COM standard only.
  236. *
  237. * RETURNS: None
  238. */
  239. void CoUninitialize ()
  240.     {
  241.     }
  242. /**************************************************************************
  243. *
  244. * CoGetCurrentProcess - Returns a value that is unique to the current thread.
  245. *
  246. * Returns a value that is unique to the current thread.
  247. *
  248. * RETURNS: A unique DWORD identifying the current thread.
  249. */
  250. DWORD CoGetCurrentProcess ()
  251.     {
  252.     static DWORD s_nextTaskId = 0;
  253.     
  254.     if (comSysLocalGet () == 0)
  255.         {
  256.         comSysLocalSet (++s_nextTaskId);
  257.         }
  258.     return (DWORD) comSysLocalGet ();
  259.     }
  260. /**************************************************************************
  261. *
  262. * CLSIDFromAscii - Convert an ASCII string-format CLSID to a real CLSID structure.
  263. *
  264. * This function converts an ASCII string-format CLSID to a real CLSID 
  265. * structure. The ASCII string must be of the following format
  266. * {ABCDEFGH-IJKL-MNOP-QRST-UVWXYZ123456}.
  267. *
  268. * RETURNS:
  269. * is
  270. * i S_OK
  271. * On success
  272. * i CO_E_CLASSSTRING
  273. * If the string is of the wrong format
  274. * i E_POINTER
  275. * If a NULL pointer is given for a parameter.
  276. * ie
  277. */
  278. HRESULT CLSIDFromAscii
  279.     (
  280.     const char* s, /* The string to convert. */
  281.     LPCLSID             pClsid /* The resultant CLSID structure. */
  282.     )
  283.     {
  284.     TRACE_CALL;
  285.     CLSID               clsid;
  286.     char                cs [GUID_STRING_LEN];
  287.     int                 i,j;
  288.     if (s == NULL)
  289. {
  290. return E_POINTER;
  291. }
  292.     if (pClsid == NULL)
  293. {
  294. return E_POINTER;
  295. }
  296.     if (strlen (s) != 38)
  297. {
  298. return CO_E_CLASSSTRING;
  299. }
  300.     if ((s [0] == '{') && (s [37] == '}'))
  301. strncpy (cs, s + 1, 36);
  302.     else
  303. return CO_E_CLASSSTRING;
  304.     // read string-format of CLSID into structure
  305.     char * pCheck = NULL;
  306.     cs [8] = 0;
  307.     clsid.Data1 = strtoul (cs, &pCheck, 16);
  308.     if (*pCheck)
  309. {
  310. return CO_E_CLASSSTRING;
  311. }
  312.     cs [13] = 0;
  313.     clsid.Data2 = strtoul (cs + 9, &pCheck, 16);
  314.     if (*pCheck)
  315. {
  316. return CO_E_CLASSSTRING;
  317. }
  318.     cs [18] = 0;
  319.     clsid.Data3 = strtoul (cs + 14, &pCheck, 16);
  320.     if (*pCheck)
  321. {
  322. return CO_E_CLASSSTRING;
  323. }
  324.     for (i = 34, j = 7; i >= 24; i -= 2)
  325.         {
  326.         cs [i + 2] = 0;
  327.         clsid.Data4 [j--] = strtoul (cs + i, &pCheck, 16);
  328. if (*pCheck)
  329.     {
  330.     return CO_E_CLASSSTRING;
  331.     }
  332.         }
  333.     for (i = 21; i >= 19; i -= 2)
  334.         {
  335.         cs [i + 2] = 0;
  336.         clsid.Data4 [j--] = strtoul (cs + i, &pCheck, 16);
  337. if (*pCheck)
  338.     {
  339.     return CO_E_CLASSSTRING;
  340.     }
  341.         }
  342.     *pClsid = clsid;
  343.     return S_OK;
  344.     }
  345. /**************************************************************************
  346. *
  347. * CoGetMalloc - Gets a pointer to the task-allocator for this task.
  348. *
  349. * Gets a pointer to the task-allocator for the current task, which is always
  350. * the system allocator. If there is already one then it simply adds a
  351. * reference to it, if not then it creates a new one.
  352. *
  353. * RETURNS: 
  354. * is
  355. * iE_INVALIDARG
  356. * dwMemContext != 1.
  357. * iE_OUTOFMEMORY
  358. * This isn't enough free memory to create the task-allocator.
  359. * iS_OK
  360. * Success
  361. * ie
  362. */
  363. HRESULT CoGetMalloc 
  364.     (
  365.     DWORD               dwMemContext,   /* Must be 1 */
  366.     IMalloc**           ppMalloc        /* Interface pointer to task-allocator */
  367.     )
  368.     {
  369.     return comCoGetMalloc (dwMemContext, ppMalloc);
  370.     }
  371. /**************************************************************************
  372. *
  373. * CoTaskMemAlloc - Allocates a block of memory for use by VxDCOM functions
  374. *
  375. * Allocates a block of memory for use by VxDCOM functions. The initial 
  376. * contents of the memory block are undefined. CoGetMalloc need not be
  377. * called prior to calling this function.
  378. *
  379. * RETURNS: pointer to block of memory or NULL on error.
  380. */
  381. void* CoTaskMemAlloc 
  382.     (
  383.     ULONG  cb /* Size in bytes. */
  384.     )
  385.     {
  386.     IMalloc*    pMalloc;
  387.     void*       pv;
  388.     if (FAILED (CoGetMalloc (1, &pMalloc)))
  389.         return 0;
  390.     pv = pMalloc->Alloc (cb);
  391.     pMalloc->Release ();
  392.     return pv;
  393.     }
  394. /**************************************************************************
  395. *
  396. * CoTaskMemRealloc - Changes the size of a memory block.
  397. * Changes the size of a memory block previously allocated using 
  398. * CoTaskMemAlloc.
  399. * RETURNS: Pointer to reallocated memory block or NULL on error.
  400. */
  401. void* CoTaskMemRealloc 
  402.     (
  403.     LPVOID pv,  /* Pointer to memory block. */
  404.     ULONG  cb /* New size of memory block in bytes. */
  405.     )
  406.     {
  407.     IMalloc*    pMalloc;
  408.     void*       ptr;
  409.     if (FAILED (CoGetMalloc (1, &pMalloc)))
  410.         return 0;
  411.     ptr = pMalloc->Realloc (pv, cb);
  412.     pMalloc->Release ();
  413.     return ptr;
  414.     }
  415. /* resolve clashes in networking headers */
  416. #ifdef Free
  417. #undef Free
  418. #endif
  419. /**************************************************************************
  420. *
  421. * CoTaskMemFree - Frees a block of task memory.
  422. * This function frees a block of memory previously allocated using 
  423. * CoTaskMemAlloc.
  424. *
  425. * RETURNS: None.
  426. */
  427. void CoTaskMemFree 
  428.     (
  429.     LPVOID  pv /* Pointer to memory block */
  430.     )
  431.     {
  432.     IMalloc*    pMalloc;
  433.     if (pv == 0)
  434.         return;
  435.     if (FAILED (CoGetMalloc (1, &pMalloc)))
  436.         return;
  437.     pMalloc->Free (pv);
  438.     pMalloc->Release ();
  439.     }
  440. /**************************************************************************
  441. *
  442. * CoCreateGuid - create a GUID
  443. *
  444. * This routine creates a new GUID and copies it into the GUID pointed to
  445. * by the <pGuid> argument if successful.  If the routine encounters an
  446. * error creating the GUID, the GUID pointed to by <pGuid> will be left
  447. * unchanged.
  448. *
  449. * RETURNS:
  450. * is
  451. * i S_OK
  452. * If successful
  453. * i RPC_S_UUID_NO_ADDRESS
  454. * If a hardware ethernet address cannot be obtained
  455. * i E_POINTER
  456. * If pGuid is NULL
  457. * i RPC_S_INTERNAL_ERROR
  458. * For all other errors.
  459. * ie
  460. */
  461. HRESULT CoCreateGuid 
  462.     (
  463.     GUID* pGuid /* ptr to GUID where result will be returned */
  464.     )
  465.     {
  466.     if (pGuid == NULL)
  467.         {
  468.         return E_POINTER;
  469.         }
  470.     comSysGuidCreate (pGuid);
  471.     return S_OK;
  472.     }
  473. /**************************************************************************
  474. *
  475. * WriteClassStm - Writes a CLSID to a stream.
  476. *
  477. * This function writes a CLSID to a stream.
  478. *
  479. * RETURNS:
  480. * is
  481. * i S_OK
  482. * On Success
  483. * i E_FAIL
  484. * On failure
  485. * ie
  486. */
  487. HRESULT WriteClassStm
  488.     (
  489.     IStream *           pStm,           /* IStream to store in. */
  490.     REFCLSID            rclsid          /* CLSID to be stored in stream */
  491.     )
  492.     {
  493.     TRACE_CALL;
  494.     ULONG               nb;
  495.     return pStm->Write (&rclsid, sizeof (CLSID), &nb);
  496.     }
  497. /**************************************************************************
  498. *
  499. * ReadClassStm - Reads a CLSID from a stream.
  500. *
  501. * This function reads a CLSID from a stream.
  502. *
  503. * RETURNS:
  504. * is
  505. * i S_OK
  506. * On success
  507. * i E_FAIL
  508. * On failure
  509. * ie
  510. */
  511. HRESULT ReadClassStm
  512.     (
  513.     IStream *           pStm,           /* stream holding the CLSID */
  514.     CLSID *             pclsid          /* output CLSID */
  515.     )
  516.     {
  517.     TRACE_CALL;
  518.     ULONG               nb;
  519.     return pStm->Read (pclsid, sizeof (CLSID), &nb);
  520.     }
  521. /**************************************************************************
  522. *
  523. * CLSIDFromString - Convert a wide string-format CLSID to a CLSID structure.
  524. *
  525. * This function converts a wide string-format CLSID to a CLSID structure.
  526. * The string must be of the following format 
  527. * {ABCDEFGH-IJKL-MNOP-QRST-UVWXYZ123456}.
  528. *
  529. * This function differs from the standard OLE function in that it doesn't
  530. * check that the CLSID is in the registry.
  531. *
  532. * RETURNS:
  533. * is
  534. * i S_OK
  535. * On success
  536. * i CO_E_CLASSSTRING
  537. * If the string is in the wrong format
  538. * i E_POINTER
  539. * If a NULL pointer is given for a parameter.
  540. * ie
  541. */
  542. HRESULT CLSIDFromString 
  543.     (
  544.     LPCOLESTR wszClsid, /* Wide string to convert */
  545.     LPCLSID             pClsid /* Pointer to CLSID which will contain result */
  546.     )
  547.     {
  548.     TRACE_CALL;
  549.     char                s [GUID_STRING_LEN];
  550.     if (wszClsid == NULL)
  551. {
  552. return E_POINTER;
  553. }
  554.     // convert to ascii from wide-string
  555.     vxcom_wcstombs (s, wszClsid, sizeof (s));
  556.     // use utility function to get conversion
  557.     return CLSIDFromAscii (s, pClsid);
  558.     }
  559. /**************************************************************************
  560. *
  561. * vxcomGUID2String - Helper function that converts a GUID to string format.
  562. *
  563. * Helper function that converts a GUID to string format.
  564. *
  565. * RETURNS: The converted GUID as an ASCII string.
  566. *
  567. *.NOMANUAL
  568. */
  569. const char * vxcomGUID2String
  570.     (
  571.     REFGUID guid /* GUID to convert */
  572.     )
  573.     {
  574.     static char s [GUID_STRING_LEN];
  575.     comCoreGUID2String (&guid, s);
  576.     
  577.     return s;
  578.     }
  579. /**************************************************************************
  580. *
  581. * StringFromGUID2 - basic GUID -> string conversion utility.
  582. *
  583. * This function converts a GUID structure into a wide string representation.
  584. * lpsz must point to a valid wide string buffer allocated by CoTaskMemAlloc.
  585. *
  586. * RETURNS: The length of the resultant string or 0 is the buffer is to small 
  587. * to hold the resultant string.
  588. */
  589. int StringFromGUID2
  590.     (
  591.     REFGUID rguid, /* IID to be converted */
  592.     LPOLESTR lpsz, /* resulting string */
  593.     int cbMax /* max size of returned string */
  594.     )
  595.     {
  596.     TRACE_CALL;
  597.     char sGuid [GUID_STRING_LEN];
  598.     if (lpsz == NULL)
  599. return 0;
  600.     strcpy (sGuid, (vxcomGUID2String (rguid)));
  601.     // Check that result will fit.
  602.     if (cbMax < (strlen (sGuid) + 1))
  603. return 0;
  604.     // Trim to match available output space
  605.     if ((size_t)cbMax < sizeof (sGuid))
  606. sGuid [cbMax] = 0;
  607.     // Convert to wide-char...
  608.     vxcom_mbstowcs (lpsz, sGuid, strlen (sGuid) + 1);
  609.     // Return num chars in string...
  610.     return strlen (sGuid) + 1;
  611.     }
  612. /**************************************************************************
  613. *
  614. * StringFromCLSID - converts a CLSID to a wide-string format.
  615. * This function converts a CLSID to a wide-string format. This routine 
  616. * allocates the correct amount of memory and returns it via ppsz. This
  617. * memory must be released using CoTaskMemFree.
  618. *
  619. * RETURNS:
  620. * is
  621. * i S_OK
  622. * On success
  623. * i E_OUTOFMEMORY
  624. * If not enough memory could be allocated to hold the string.
  625. * ie
  626. */
  627. HRESULT StringFromCLSID
  628.     (
  629.     REFCLSID rclsid, /* CLSID to be converted */
  630.     LPOLESTR* ppsz /* output var to receive string */
  631.     )
  632.     {
  633.     TRACE_CALL;
  634.     /* Check for NULL parameter */
  635.     if (ppsz == NULL)
  636. return E_POINTER;
  637.     *ppsz = (LPOLESTR) CoTaskMemAlloc (GUID_STRING_LEN * sizeof (OLECHAR));
  638.     if (*ppsz == NULL)
  639.         {
  640.         return E_OUTOFMEMORY;
  641.         }
  642.     StringFromGUID2 (rclsid, *ppsz, GUID_STRING_LEN);
  643.     return S_OK;
  644.     }
  645. /**************************************************************************
  646. *
  647. * StringFromIID - converts a IID to a wide-string format.
  648. * This function converts a IID to a wide-string format. This routine 
  649. * allocates the correct amount of memory and returns it via ppsz. This
  650. * memory must be released using CoTaskMemFree.
  651. *
  652. * RETURNS:
  653. * is
  654. * i S_OK
  655. * On success
  656. * i E_OUTOFMEMORY
  657. * If not enough memory could be allocated to hold the string.
  658. * ie
  659. */
  660. HRESULT StringFromIID
  661.     (
  662.     REFIID riid, /* IID to be converted */
  663.     LPOLESTR* ppsz /* output var to receive string */
  664.     )
  665.     {
  666.     TRACE_CALL;
  667.     *ppsz = (LPOLESTR) CoTaskMemAlloc (GUID_STRING_LEN * sizeof (OLECHAR));
  668.     if (*ppsz == NULL)
  669.         {
  670.         return E_OUTOFMEMORY;
  671.         }
  672.     StringFromGUID2 (riid, *ppsz, GUID_STRING_LEN);
  673.     return S_OK;
  674.     }
  675. /**************************************************************************
  676. *
  677. * IIDFromString - Convert a wide string-format IID to a IID structure.
  678. *
  679. * This function converts a wide string-format IID to a IID structure.
  680. * The string must be of the following format 
  681. * {ABCDEFGH-IJKL-MNOP-QRST-UVWXYZ123456}.
  682. *
  683. * RETURNS:
  684. * is
  685. * i S_OK
  686. * On success.
  687. * i E_INVALIDARG
  688. * If the string is in the wrong format or the return pointer is invalid.
  689. * ie
  690. */
  691. HRESULT IIDFromString
  692.     (
  693.     LPCOLESTR lpsz, /* string representation of IID */
  694.     LPIID piid /* pointer to IID */
  695.     )
  696.     {
  697.     TRACE_CALL;
  698.     HRESULT hr;
  699.     hr = CLSIDFromString (lpsz, piid);
  700.     if (hr == CO_E_CLASSSTRING)
  701. return E_INVALIDARG;
  702.     return hr;
  703.     }
  704. /**************************************************************************
  705. *
  706. * IsEqualGUID - Tests if two GUIDs are equivalent.
  707. *
  708. * This function tests if two GUIDs are equivalent.
  709. *
  710. * RETURNS:
  711. * is
  712. * i S_OK
  713. * On success
  714. * i CO_E_CLASSSTRING
  715. * If the string is in the wrong format.
  716. * ie
  717. */
  718. BOOL IsEqualGUID 
  719.     (
  720.     REFGUID             guid1, /* GUID to compare to guid2 */
  721.     REFGUID             guid2 /* GUID to compare to guid1 */
  722.     )
  723.     {
  724.     TRACE_CALL;
  725.     return (guid1 == guid2) ? TRUE : FALSE;
  726.     }
  727. /**************************************************************************
  728. *
  729. * IsEqualCLSID - Tests if two CLSIDs are equivalent.
  730. *
  731. * This function tests if two CLSIDs are equivalent.
  732. *
  733. * RETURNS:
  734. * is
  735. * i S_OK
  736. * On success
  737. * i CO_E_CLASSSTRING
  738. * If the string is in the wrong format.
  739. * ie
  740. */
  741. BOOL IsEqualCLSID 
  742.     (
  743.     REFCLSID            clsid1, /* CLSID to compare to clsid2 */
  744.     REFCLSID            clsid2 /* CLSID to compare to clsid1 */
  745.     )
  746.     {
  747.     TRACE_CALL;
  748.     return IsEqualGUID (clsid1, clsid2);
  749.     }
  750. /**************************************************************************
  751. *
  752. * IsEqualIID - Tests if two IIDs are equivalent.
  753. *
  754. * This function tests if two IIDs are equivalent.
  755. *
  756. * RETURNS:
  757. * is
  758. * i S_OK
  759. * On success
  760. * i CO_E_CLASSSTRING
  761. * If the string is in the wrong format.
  762. * ie
  763. */
  764. BOOL IsEqualIID 
  765.     (
  766.     REFIID              iid1, /* IID to compare to iid2 */
  767.     REFIID              iid2 /* IID to compare to iid1 */
  768.     )
  769.     {
  770.     TRACE_CALL;
  771.     return IsEqualGUID (iid1, iid2);
  772.     }
  773. /*
  774. *
  775. * This section implements the BSTR data type, named after the 'Basic
  776. * String' type from MSVisual Basic. It is a counted wide-string, but
  777. * with the byte-count stored before the character array, and the
  778. * address of a BSTR is considered to be the address of the character
  779. * array. Hence, the count-word is 'in front of' the pointer that
  780. * points to it:-
  781. *
  782. * DWORD wchar wchar wchar wchar wchar
  783. *       ^
  784. *       BSTR points here...
  785. *
  786. */
  787. /**************************************************************************
  788. *
  789. * SysAllocString - Allocates a new string and copies the existing string into it.
  790. *
  791. * This function allocates a new string and copies the existing string to
  792. * it.
  793. *
  794. * RETURNS: A pointer to the new string or NULL if memory can't be 
  795. * allocated or psz was NULL.
  796. */
  797. BSTR SysAllocString 
  798.     (
  799.     const OLECHAR*  psz /* String to copy into new string */
  800.     )
  801.     {
  802.     if (psz == NULL)
  803.         return NULL;
  804.     // Count the characters, not incl terminating NULL...
  805.     const OLECHAR* pChar = psz;
  806.     size_t len=0;
  807.     while (*pChar++)
  808. ++len;
  809.     // Get a string
  810.     BSTR bstr = SysAllocStringByteLen (0, (len+1) * sizeof (OLECHAR));
  811.     
  812.     // Copy the string
  813.     size_t n;
  814.     for (n=0; n < len; ++n)
  815. bstr [n] = psz [n];
  816.     bstr [n] = 0;
  817.     return bstr;
  818.     }
  819. /**************************************************************************
  820. *
  821. * SysAllocStringLen - Create a string of the given length and initialize it from the passed string.
  822. *
  823. * Public API for creating a BSTR of the given length. After allocation, 
  824. * 'nLen' characters are copied from 'psz' and a NULL character is appended.
  825. * If 'psz' includes NULL characters they will be copied also.
  826. *
  827. * RETURNS: A pointer to the new string or NULL if memory can't be allocated.
  828. */
  829. BSTR SysAllocStringLen 
  830.     (
  831.     const OLECHAR*  psz,  /* String to initialize new string from */
  832.     unsigned long  nLen /* Length of new string */
  833.     )
  834.     {
  835.     // Get a string
  836.     BSTR bstr = SysAllocStringByteLen (0, nLen * sizeof (OLECHAR));
  837.     
  838.     // Copy the string, if supplied...
  839.     if (psz)
  840. {
  841. for (size_t n=0; n < nLen; ++n)
  842.     bstr [n] = psz [n];
  843. }
  844.     bstr [nLen] = 0;
  845.     return bstr;
  846.     }
  847. /**************************************************************************
  848. *
  849. * SysAllocStringByteLen - Create a string of the given length and initialize it from the passed string.
  850. *
  851. * Public API for creating a BSTR containing 8-bit data, of the given length. 
  852. * The input arg 'psz' may be NULL in which case the resulting BSTR has 
  853. * uninitialized data. The argument 'bytes' indicates the number of bytes 
  854. * to copy from 'psz'. Two NULL characters, or a single NULL OLECHAR, are 
  855. * placed afterwards, allocating a total of (bytes + 2) bytes.
  856. *
  857. * RETURNS: A pointer to the new string or NULL if memory can't be allocated.
  858. */
  859. BSTR SysAllocStringByteLen 
  860.     (
  861.     const char*  psz,  /* String to initialize new string from */
  862.     unsigned long  nBytes /* number of bytes in new string */
  863.     )
  864.     {
  865.     // Allocate the string
  866.     void* pMem = comSysAlloc (sizeof (DWORD) + nBytes + sizeof (OLECHAR));
  867.     if (! pMem)
  868. return 0;
  869.     * ((DWORD*) pMem) = nBytes;
  870.     BSTR bstr = (BSTR) (((DWORD*) pMem) + 1);
  871.     if (psz)
  872. {
  873. memcpy (bstr, psz, nBytes);
  874. bstr [nBytes / sizeof (OLECHAR)] = 0;
  875. }
  876.     return bstr;
  877.     }
  878. /**************************************************************************
  879. *
  880. * SysFreeString - Releases the memory allocated to a BSTR.
  881. *
  882. * Public API for freeing BSTRs. The input 'bstr' may be NULL.
  883. *
  884. * RETURNS: S_OK.
  885. */
  886. HRESULT SysFreeString 
  887.     (
  888.     BSTR  bstr /* String to release */
  889.     )
  890.     {
  891.     if (bstr)
  892. comSysFree (((DWORD*)bstr) - 1);
  893.     return S_OK;
  894.     }
  895. /**************************************************************************
  896. *
  897. * SysStringByteLen - Calculates the number of bytes in a BSTR.
  898. *
  899. * Public API for finding the number of bytes in a BSTR (not the number of 
  900. * wide-characters).
  901. *
  902. * RETURNS: Number of bytes in a BSTR, or 0 if the BSTR is NULL.
  903. */
  904. DWORD SysStringByteLen 
  905.     (
  906.     BSTR  bstr /* String to calculate size of */
  907.     )
  908.     {
  909.     if (bstr == NULL)
  910.         return 0;
  911.     return * (((DWORD*)bstr) - 1);
  912.     }
  913. /**************************************************************************
  914. *
  915. * SysStringLen - Calculate length of BSTR
  916. *
  917. * Public API for finding length of a BSTR. Note that this may differ from 
  918. * the value returned by comWideStrLen() or wcslen() if the originating 
  919. * string contained embedded NULLs.
  920. *
  921. * RETURNS: Number of OLECHAR in the string.
  922. */
  923. DWORD SysStringLen 
  924.     (
  925.     BSTR  bstr /* String to calculate length of */
  926.     )
  927.     {
  928.     return SysStringByteLen (bstr) / 2;
  929.     }
  930. /**************************************************************************
  931. *
  932. * comStreamCreate - creates a memory-based IStream from raw memory
  933. *
  934. * This function creates an in-memory stream, as an <IStream>
  935. * implementation, based on the contents of the initial
  936. * memory-block. The stream allocates a new block to hold the contents,
  937. * and any changes occur inside the newly-allocated block, not inside
  938. * the original block. Its contents can be accessed by rewinding the
  939. * stream, finding its length (using SEEK_END) and then Read()ing the
  940. * entire stream.
  941. *
  942. * On entry, the arguments 'pMem' and 'len' should describe a block of
  943. * memory which is to be copied into the new stream object. The
  944. * argument 'ppStream' should point to an 'IStream*' variable which
  945. * will be set to point to the resulting stream object upon successful
  946. * completion of the function.
  947. *
  948. * RETURNS:
  949. * is
  950. * i S_OK
  951. * On Success
  952. * i E_OUTOFMEMORY if it is unable to allocate sufficient memory.
  953. * ie
  954. */
  955. HRESULT comStreamCreate
  956.     (
  957.     const void* pMem, /* address of initial memory */
  958.     unsigned long len, /* length of initial memory */
  959.     IStream** ppStream /* address of output variable */
  960.     )
  961.     {
  962.     TRACE_CALL;
  963.     // Create a memory-stream object (will have 1 ref if successful)
  964.     ISimpleStream* pStrm;
  965.     HRESULT hr = VxRWMemStream::CreateInstance (0,
  966.         IID_ISimpleStream,
  967. (void**) &pStrm);
  968.     if (FAILED (hr))
  969. return hr;
  970.     // Write data into stream, then rewind it...
  971.     pStrm->insert (pMem, len);
  972.     pStrm->locationSet (0);
  973.     // Hand out a single reference to its IStream interface
  974.     hr = pStrm->QueryInterface (IID_IStream, (void**) ppStream);
  975.     
  976.     // If QI was successful, this will leave the caller with the
  977.     // only ref, if not it will destroy the object...
  978.     pStrm->Release ();
  979.     return hr;
  980.     }
  981. /**************************************************************************
  982. *
  983. * comWideToAscii - convert a wide-string to a narrow (ascii) string
  984. *
  985. * This function simply converts a string consisting of 2-byte
  986. * characters to its equivalent ASCII string. No character-set
  987. * conversions are performed, the character values are simply narrowed
  988. * to 8 bits. On entry, the arguments 'result' and 'maxLen' describe
  989. * the output buffer where the resulting 8-bit string will be placed,
  990. * and 'wstr' points to a NULL-terminated wide-character string to be
  991. * converted.
  992. *
  993. * RETURNS: the number of characters converted.
  994. *
  995. */
  996. int comWideToAscii
  997.     (
  998.     char* result, /* resulting ascii string */
  999.     const OLECHAR* wstr, /* input wide-string */
  1000.     int maxLen /* max length to convert */
  1001.     )
  1002.     {
  1003.     TRACE_CALL;
  1004.     return vxcom_wcstombs (result, wstr, maxLen);
  1005.     }
  1006. /**************************************************************************
  1007. *
  1008. * comAsciiToWide - convert a narrow (ascii) string to a wide-string
  1009. *
  1010. * This function simply converts a string consisting of single-byte
  1011. * ASCII characters to its equivalent wide-string. No character-set
  1012. * conversions are performed, the character values are simply widened
  1013. * to 16 bits. On entry, the arguments 'result' and 'maxLen' describe
  1014. * the output buffer where the resulting double-byte string will be
  1015. * placed, and 'str' points to a NULL-terminated string to be converted.
  1016. *
  1017. * RETURNS: the number of characters converted.
  1018. *
  1019. */
  1020. int comAsciiToWide
  1021.     (
  1022.     OLECHAR* result, /* resulting wide string */
  1023.     const char* str, /* input string */
  1024.     int maxLen /* max length to convert */
  1025.     )
  1026.     {
  1027.     TRACE_CALL;
  1028.     return vxcom_mbstowcs (result, str, maxLen);
  1029.     }
  1030. /**************************************************************************
  1031. *
  1032. * comWideStrLen - find the length of a wide-string
  1033. *
  1034. * This function returns the length of the NULL-terminated
  1035. * wide-character string at 'wsz'.
  1036. *
  1037. * RETURNS: the number of characters in the string.
  1038. *
  1039. */
  1040. size_t comWideStrLen
  1041.     (
  1042.     const OLECHAR* wsz /* wide string */
  1043.     )
  1044.     {
  1045.     TRACE_CALL;
  1046.     return vxcom_wcslen (wsz);
  1047.     }
  1048. /**************************************************************************
  1049. *
  1050. * comWideStrCopy - make a copy of a wide-string
  1051. *
  1052. * This function copies the NULL-terminated wide-character string at
  1053. * 'wszSrc' to the location pointed to by 'wszDst' which must contain
  1054. * enough space to hold the resulting string.
  1055. *
  1056. * RETURNS: the address of the copy of the wide-string
  1057. *
  1058. */
  1059. OLECHAR* comWideStrCopy
  1060.     (
  1061.     OLECHAR* wszDst, /* destination */
  1062.     const OLECHAR* wszSrc /* source */
  1063.     )
  1064.     {
  1065.     TRACE_CALL;
  1066.     return vxcom_wcscpy (wszDst, wszSrc);
  1067.     }
  1068. /**************************************************************************
  1069. *
  1070. * comT2OLEHelper - Helper function for T2OLE macro.
  1071. *
  1072. * This function is used internaly by the T2OLE macro to convert the
  1073. * ASCII string into a wide string.
  1074. *
  1075. * RETURNS: The address of the wide string.
  1076. *
  1077. *.NOMANUAL
  1078. */
  1079. OLECHAR * comT2OLEHelper
  1080.     (
  1081.     void * pvWSZ, /* pointer to wide string */
  1082.     const char * psz /* pointer to ASCII string */
  1083.     )
  1084.     {
  1085.     OLECHAR* pwsz = (OLECHAR*) pvWSZ;
  1086.     COM_ASSERT(pvWSZ);
  1087.     comAsciiToWide (pwsz, psz, strlen (psz) + 1);
  1088.     return pwsz;
  1089.     }
  1090. /**************************************************************************
  1091. *
  1092. * comOLE2THelper - Helper function for OLE2T macro.
  1093. *
  1094. * This function is used internaly by the OLE2T macro to convert the
  1095. * wide string into an ASCII string.
  1096. *
  1097. * RETURNS: The address of the ASCII string.
  1098. *
  1099. *.NOMANUAL
  1100. */
  1101. char * comOLE2THelper
  1102.     (
  1103.     void * pvSZ, /* pointer to ASCII string */
  1104.     const OLECHAR * pwsz /* pointer to wide string. */
  1105.     )
  1106.     {
  1107.     char* psz = (char*) pvSZ;
  1108.     COM_ASSERT(pvSZ);
  1109.     comWideToAscii (psz, pwsz, vxcom_wcslen (pwsz) + 1);
  1110.     return psz;
  1111.     }
  1112. /* CComBSTR methods -- most are inline, but some are defined here... */
  1113. CComBSTR& CComBSTR::operator= (const CComBSTR& src)
  1114.     {
  1115.     TRACE_CALL;
  1116.     if (m_str != src.m_str)
  1117. {
  1118. if (m_str)
  1119.     ::SysFreeString (m_str);
  1120. m_str = src.Copy ();
  1121. }
  1122.     return *this;
  1123.     }
  1124. CComBSTR& CComBSTR::operator= (LPCOLESTR pwsz)
  1125.     {
  1126.     TRACE_CALL;
  1127.     ::SysFreeString (m_str);
  1128.     m_str = ::SysAllocString (pwsz);
  1129.     return *this;
  1130.     }
  1131. void CComBSTR::Append (LPCOLESTR pwsz, int nLen)
  1132.     {
  1133.     TRACE_CALL;
  1134.     int myLen = Length ();
  1135.     BSTR bs = ::SysAllocStringLen (0, myLen + nLen);
  1136.     memcpy (bs, m_str, myLen * sizeof (OLECHAR));
  1137.     memcpy (bs + myLen, pwsz, nLen * sizeof (OLECHAR));
  1138.     bs [myLen + nLen] = 0;
  1139.     ::SysFreeString (m_str);
  1140.     m_str = bs;
  1141.     }
  1142. /* VARIANT-related APIs. */
  1143. /**************************************************************************
  1144. *
  1145. * VariantInit - Initialize a VARIANT.
  1146. *
  1147. * Initialize a VARIANT, regardless of its current contents, to be VT_EMPTY.
  1148. *
  1149. * RETURNS: void
  1150. *
  1151. */
  1152. void VariantInit (VARIANT* v)
  1153.     {
  1154.     if (v == NULL) return;
  1155.     memset (v, 0, sizeof (VARIANT));
  1156.     v->vt = VT_EMPTY;
  1157.     }
  1158. /**************************************************************************
  1159. *
  1160. * VariantClear - clear the contents of a VARIANT.
  1161. *
  1162. * Clear the contents of a VARIANT back to VT_EMPTY, but taking account of 
  1163. * the current contents value. So, if the VARIANT is currently representing 
  1164. * a IUnknown pointer, that pointer will be released in this function. 
  1165. * Also, BSTRs and SAFEARRAY are freed.
  1166. *
  1167. * RETURNS:
  1168. * is
  1169. * i S_OK
  1170. * On Success.
  1171. * i E_INVALIDARG
  1172. * If v is null or otherwise invalid.
  1173. * i DISP_E_BARVARTYPE
  1174. * The VARIANT is not one of the following allowed types: VT_EMPTY, VT_NULL, 
  1175. * VT_I2, VT_I4, VT_R4, VT_R8, VT_CY, VT_DATE, VT_BSTR, VT_ERROR, VT_BOOL, 
  1176. * VT_UNKNOWN, VT_UI1.
  1177. * ie
  1178. */
  1179. HRESULT VariantClear (VARIANT* v)
  1180.     {
  1181.     HRESULT hr = S_OK;
  1182.     // check for NULL variant
  1183.     if (v == NULL)
  1184.         return E_INVALIDARG;
  1185.     // check for types of VARIANTs we can handle
  1186.     // and mask out ARRAY bit.
  1187.     switch (V_VT(v) & 0xDFFF)
  1188.         { 
  1189.         case VT_EMPTY:
  1190.         case VT_NULL:
  1191.         case VT_I2:
  1192.         case VT_I4:
  1193.         case VT_R4:
  1194.         case VT_R8:
  1195.         case VT_CY:
  1196.         case VT_DATE:
  1197.         case VT_BSTR:
  1198.         case VT_ERROR:
  1199.         case VT_BOOL:
  1200.         case VT_UNKNOWN:
  1201.         case VT_UI1:
  1202.             break;
  1203.         default:
  1204.             return DISP_E_BADVARTYPE;
  1205.         }
  1206.     if (V_ISARRAY (v))
  1207.         {
  1208.         hr = SafeArrayDestroy (V_ARRAY(v));
  1209.         if (SUCCEEDED (hr))
  1210.             {
  1211.             VariantInit (v);
  1212.             }
  1213.         }
  1214.     else
  1215.         {
  1216.         switch (V_VT(v))
  1217.             {
  1218.             case VT_BSTR:
  1219.                 hr = SysFreeString (V_BSTR(v));
  1220.                 break;
  1221.             case VT_UNKNOWN:
  1222. if (V_UNKNOWN(v))
  1223.     V_UNKNOWN(v)->Release ();
  1224.                 break;
  1225.             }
  1226.         VariantInit (v);
  1227.         }
  1228.     return hr;
  1229.     }
  1230. /**************************************************************************
  1231. *
  1232. * VariantCopy - Copy a VARIANT. 
  1233. *
  1234. * Frees the destination variant and makes a copy of the source variant.
  1235. * If s is a BSTR a copy of the BSTR is made.
  1236. *
  1237. * Copying SAFEARRAYs isn't supported so E_INVALIDARG is returned if this 
  1238. * is attempted.
  1239. *
  1240. * RETURNS:
  1241. * is
  1242. * i S_OK
  1243. * On success
  1244. * i E_INVALIDARG
  1245. * If source and destination are the same.
  1246. * i E_POINTER
  1247. * One of the VARIANTs is NULL or invalid.
  1248. * i E_OUTOFMEMORY
  1249. * If there isn't enough memory to allocate the new VARIANT.
  1250. * ie
  1251. */
  1252. HRESULT VariantCopy 
  1253.     (
  1254.     VARIANT *           d,  /* Pointer to the VARIANT to receive the copy */
  1255.     VARIANT *           s   /* Pointer to the VARIANT to be copied */
  1256.     )
  1257.     {
  1258.     HRESULT hr = S_OK;
  1259.     if (s == NULL)
  1260. {
  1261. return E_POINTER;
  1262. }
  1263.     if (d == NULL)
  1264. {
  1265. return E_POINTER;
  1266. }
  1267.     if (V_ISARRAY (s))
  1268.         {
  1269.         hr = VariantClear (d);
  1270.         if (FAILED (hr)) return hr;
  1271.         if (FAILED (hr)) 
  1272.             {
  1273.             return hr;
  1274.             }
  1275.      /* SPR#67806. set VT in dest. */
  1276.      V_VT(d) = V_VT(s);
  1277.      return SafeArrayCopy (V_ARRAY(s), &(V_ARRAY(d)));
  1278.         }
  1279.     if (d != s)
  1280.         {
  1281.      hr = VariantClear (d);
  1282.      /* SPR#67806. set VT in dest. */
  1283.      V_VT(d) = V_VT(s);
  1284.      if (SUCCEEDED (hr))
  1285.          {
  1286.             memcpy (d, s, sizeof(VARIANT));
  1287.             switch (V_VT (s))
  1288.                 {
  1289.                 case VT_BSTR:
  1290.                     V_BSTR(d) =  SysAllocString (V_BSTR(s));       
  1291.                     /* Check to see if the Alloc failed */
  1292.                     if ((V_BSTR (s) != NULL) && (V_BSTR (d) == NULL))
  1293.                         {
  1294.                         hr = E_OUTOFMEMORY;
  1295.                         }
  1296.                     break;
  1297.                 case VT_UNKNOWN:
  1298.                     if (V_UNKNOWN(s))
  1299.                         {
  1300.                         hr = V_UNKNOWN(s)->QueryInterface(IID_IUnknown, 
  1301.                                                         (void **)&V_UNKNOWN(d));
  1302.                         }
  1303.                     break;
  1304.                     
  1305.                 }
  1306.             }
  1307.         }
  1308.      else
  1309.         {
  1310.         hr = E_INVALIDARG;
  1311.         }
  1312.     return hr;
  1313.     }
  1314. /**************************************************************************
  1315. *
  1316. * GetVariantValue - Get certain VARIANT values as doubles.
  1317. *
  1318. * This function converts certain VARIANT values into doubles.
  1319. *
  1320. * RETURNS: The value of the VARIANT as a double or zero.
  1321. *.NOMANUAL
  1322. */
  1323. static double GetVariantValue
  1324.     (
  1325.     VARIANT *   v
  1326.     )
  1327.     {
  1328.     switch (V_VT(v))
  1329.         {
  1330.         case VT_BOOL:   return (double) V_BOOL(v);
  1331.         case VT_UI1:    return (double) V_UI1(v);
  1332.         case VT_I2:     return (double) V_I2(v);
  1333.         case VT_I4:     return (double) V_I4(v);
  1334.         case VT_R4:     return (double) V_R4(v);
  1335. case VT_R8:     return (double) V_R8(v);
  1336. case VT_BSTR:
  1337.     {
  1338.     double result;
  1339.     char * str = new char [comWideStrLen (V_BSTR (v)) + 1];
  1340.     if (str == 0) return 0;
  1341.     comWideToAscii (str, V_BSTR(v), comWideStrLen (V_BSTR (v)) + 1);
  1342.     result = atof (str);
  1343.     delete [] str;
  1344.     return result;
  1345.     }
  1346.         }
  1347.     
  1348.     return 0;
  1349.     }
  1350. /**************************************************************************
  1351. *
  1352. * VariantChangeType - Converts a variant from one type to another.
  1353. *
  1354. * This function converts one VARIANT of a specified type to another
  1355. * VARIANT type. s and d must point to valid VARIANTs. 
  1356. *
  1357. * Only conversion between the following types is supported: VT_BOOL, 
  1358. * VT_UI1, VT_I2, VT_I4, VT_R4, VT_R8, VT_BSTR.
  1359. * The wFlags parameter is ignored.
  1360. *
  1361. * RETURNS:
  1362. * is
  1363. * i S_OK
  1364. * On Success
  1365. * i E_INVALIDARG
  1366. * If source or destination are not valid VARIANTS.
  1367. * i DISP_E_BADVARTYPE
  1368. * The Variant isn't on of the following types: VT_BOOL, VT_UI1, VT_I2,
  1369. * VT_I4, VT_R4, VT_R8, VT_BSTR.
  1370. * ie
  1371. */
  1372. HRESULT VariantChangeType 
  1373.     (
  1374.     VARIANT *   d,      /* VARIANT to receive changed VARIANT */
  1375.     VARIANT *   s,      /* VARIANT that holds existing data */
  1376.     USHORT      wFlags, /* Ignored */
  1377.     VARTYPE     vt      /* VARIANT type to change to */
  1378.     )
  1379.     {
  1380.     HRESULT hr = S_OK;
  1381.     VARIANT tmp;
  1382.     /* check for NULL VARIANTs */
  1383.     if ((d == NULL) || (s == NULL))
  1384.         return E_INVALIDARG;
  1385.     /* Can only convert from some VT types */
  1386.     switch (V_VT(s))
  1387. {
  1388.         case VT_BOOL:
  1389.         case VT_UI1:
  1390.         case VT_I2:
  1391.         case VT_I4:
  1392.         case VT_R4:
  1393.         case VT_R8:
  1394.         case VT_BSTR:
  1395.             break;
  1396.         default:
  1397.             return DISP_E_BADVARTYPE;
  1398. }
  1399.     /* SPR#67805. To allow inline coersion use a tmp VARIANT to store source */
  1400.     /* VARIANT so if it is inline it doesn't get errased. */
  1401.     VariantInit (&tmp);
  1402.     VariantCopy (&tmp, s);
  1403.     hr = VariantClear (d);
  1404.     if (SUCCEEDED (hr))
  1405.         {
  1406.         switch (vt)
  1407.             {
  1408.             case VT_BOOL:
  1409.                 V_VT(d) = VT_BOOL;
  1410.                 if (GetVariantValue (&tmp) == 0)
  1411.                     {
  1412.                     V_BOOL (d) = VARIANT_FALSE;
  1413.                     }
  1414.                 else
  1415.                     {
  1416.                     V_BOOL (d) = VARIANT_TRUE;
  1417.                     }
  1418.                 break;
  1419.             case VT_UI1:
  1420.                 V_VT(d) = VT_UI1;
  1421.                 V_UI1(d) = (BYTE)GetVariantValue (&tmp);
  1422.                 break;
  1423.             case VT_I2:
  1424.                 V_VT (d) = VT_I2;
  1425.                 V_I2 (d) = (SHORT)GetVariantValue (&tmp);
  1426.                 break;
  1427.             case VT_I4:
  1428.                 V_VT (d) = VT_I4;
  1429.                 V_I4 (d) = (LONG)GetVariantValue (&tmp);
  1430.                 break;
  1431.             case VT_R4:
  1432.                 V_VT (d) = VT_R4;
  1433.                 V_R4 (d) = GetVariantValue(&tmp);
  1434.                 break;
  1435.             case VT_R8:
  1436.                 V_VT (d) = VT_R8;
  1437.                 V_R8 (d) = GetVariantValue (&tmp);
  1438.                 break;
  1439.     case VT_BSTR:
  1440.      V_VT (d) = VT_BSTR;
  1441.      switch (V_VT (&tmp))
  1442.          {
  1443.          case VT_BSTR:
  1444.      // straight copy needed here.
  1445.      V_BSTR (d) = ::SysAllocString (V_BSTR (&tmp));
  1446.      break;
  1447.          case VT_BOOL:
  1448.      // convert to True/False string
  1449.      if (GetVariantValue (&tmp) == 0)
  1450.     {
  1451.     const OLECHAR falseString [] = { 'F',
  1452.      'a',
  1453.      'l',
  1454.      's',
  1455.      'e',
  1456.       0 };
  1457.          V_BSTR (d) = ::SysAllocString (falseString);
  1458.     }
  1459.      else
  1460.     {
  1461.     const OLECHAR trueString [] = { 'T',
  1462.     'r',
  1463.     'u',
  1464.     'e',
  1465.      0 };
  1466.          V_BSTR (d) = ::SysAllocString (trueString);
  1467.     }
  1468.      break;
  1469.          default:
  1470.      {
  1471.      // Allocate tmp buffer this way so as not to stress
  1472.      // the stack too much.
  1473.      char * tmpBuffer = new char [128];
  1474. if (0 == tmpBuffer)
  1475.     return E_OUTOFMEMORY;
  1476.      sprintf (tmpBuffer, "%f", GetVariantValue (&tmp));
  1477. OLECHAR * wStr = new OLECHAR [strlen (tmpBuffer) + 1];
  1478. if (0 == wStr)
  1479.     {
  1480.     delete []tmpBuffer;
  1481.     return E_OUTOFMEMORY;
  1482.     }
  1483. comAsciiToWide (wStr, tmpBuffer, strlen (tmpBuffer) + 1);
  1484.      V_BSTR (d) = ::SysAllocString (wStr);
  1485. delete []wStr;
  1486.      delete []tmpBuffer;
  1487.      }
  1488.          }
  1489.      break;
  1490.             default:
  1491.                 hr = E_INVALIDARG;
  1492.                 break;
  1493.             }
  1494.         }
  1495.     VariantClear (&tmp);
  1496.     return hr;
  1497. }
  1498. /* SAFEARRAY-related APIs. */
  1499. /**************************************************************************
  1500. *
  1501. * elementSize - Get's the size of the element in bytes.
  1502. * Returns the size of a VARIANT data type in bytes.
  1503. *
  1504. * RETURNS: The size of the VARIANT data type or zero for unknown types.
  1505. *.NOMANUAL
  1506. *
  1507. */
  1508. static ULONG elementSize (VARTYPE sf)
  1509.     {
  1510.     switch (sf)
  1511.         {
  1512.         case VT_ERROR:  return sizeof (SCODE);
  1513.         case VT_UI1:    return sizeof (BYTE);
  1514.         case VT_I2:     return sizeof (SHORT);
  1515.         case VT_I4:     return sizeof (LONG);
  1516.         case VT_BSTR:   return sizeof (BSTR);
  1517.         case VT_R4:     return sizeof (float);
  1518.         case VT_R8:     return sizeof (double);
  1519.         case VT_CY:     return sizeof (CY);
  1520.         case VT_DATE:   return sizeof (DATE);
  1521.         case VT_BOOL:   return sizeof (VARIANT_BOOL);
  1522.         case VT_UNKNOWN:return sizeof (IUnknown *);
  1523.         case VT_VARIANT:return sizeof (VARIANT);
  1524.         default:
  1525.             return 0;
  1526.         }
  1527.     }
  1528. /**************************************************************************
  1529. *
  1530. * SafeArrayCreate - Creates a new SAFEARRAY.
  1531. * Creates a new array descriptor, allocates and initializes the data for 
  1532. * the array, and returns a pointer to the new array descriptor. 
  1533. *
  1534. * The array will always be created with the features FADF_HAVEVARTYPE | 
  1535. * FADF_FIXEDSIZE | FADF_AUTO and the appropriate BSTR, VARIANT or IUNKNOWN
  1536. * bit set.
  1537. *
  1538. * RETURNS: The array descriptor, or NULL if the array could not be created. 
  1539. *
  1540. */
  1541. SAFEARRAY * SafeArrayCreate
  1542.     ( 
  1543.     VARTYPE             vt,         /* The base type of the array. Neither  */
  1544.                                     /* the VT_ARRAY or the VT_BYREF flag    */
  1545.                                     /* can be set.                          */
  1546.                                     /* VT_EMPTY and VT_NULL are not valid   */
  1547.                                     /* base types for the array. All other  */
  1548.                                     /* types are legal.                     */
  1549.     UINT                cDims,      /* Number of dimensions in the array.   */
  1550.     SAFEARRAYBOUND *    rgsabound   /* Vector of bounds to allocate         */
  1551.     )
  1552.     {
  1553.     MEM_SAFEARRAY *     pArrayDesc = NULL;
  1554.     if (rgsabound == NULL)
  1555.         return NULL;
  1556.     if (cDims < 1)
  1557.         return NULL;
  1558.     /* Check for supported types */
  1559.     switch (vt)
  1560.         {
  1561.         case VT_ERROR:
  1562.         case VT_UI1:
  1563.         case VT_I2:
  1564.         case VT_I4:
  1565.         case VT_R4:
  1566.         case VT_R8:
  1567.         case VT_CY: 
  1568.         case VT_DATE:
  1569.         case VT_BOOL:
  1570.         case VT_UNKNOWN:
  1571.         case VT_VARIANT:
  1572.         case VT_BSTR:
  1573.             break;
  1574.         default:
  1575.             return NULL;
  1576.         }
  1577.     /* This will be sizeof (SAFEARRAYBOUND) bigger than it needs to be */
  1578.     /* because WIDL defines a dummy SAFEARRAYBOUND record so that the  */
  1579.     /* defined name can be used.                                       */
  1580.     pArrayDesc = reinterpret_cast<MEM_SAFEARRAY *>
  1581.                 (COM_MEM_ALLOC (sizeof (MEM_SAFEARRAY) 
  1582.                                 + sizeof (SAFEARRAYBOUND) * cDims));
  1583.     if (pArrayDesc == NULL)
  1584.         {
  1585.         /* No memory */
  1586.         return NULL;
  1587.         }
  1588.     /* Can get away with just zeroing the first part of the structure. */
  1589.     memset (pArrayDesc, 
  1590.             '', 
  1591.             sizeof (MEM_SAFEARRAY));
  1592.     /* Allocate mutex */
  1593.     pArrayDesc->pMutex = new VxMutex ();
  1594.     if (pArrayDesc->pMutex == NULL)
  1595.         {
  1596.         COM_MEM_FREE (pArrayDesc);
  1597.         return NULL;
  1598.         }
  1599.     /* Allocate data first since if it can't be done there isn't */
  1600.     /* any point in proceeding further                           */
  1601.     pArrayDesc->arrayData.cbElements = elementSize (vt);
  1602.     USHORT  index;
  1603.     pArrayDesc->dataCount = 1;
  1604.     for (index = 0; index < cDims; index++)
  1605.         {
  1606.         pArrayDesc->dataCount *= rgsabound [index].cElements;
  1607.         }
  1608.     pArrayDesc->arrayData.pvData = COM_MEM_ALLOC (pArrayDesc->dataCount * 
  1609.                                         pArrayDesc->arrayData.cbElements);
  1610.     if (pArrayDesc->arrayData.pvData == NULL)
  1611.         {
  1612.         /* We have a memory failure so delete the memory for the descriptor */
  1613.         /* and return an error.                                             */
  1614.         COM_MEM_FREE (pArrayDesc);
  1615.         return NULL;
  1616.         }
  1617.     // zero all allocated memory
  1618.     memset (pArrayDesc->arrayData.pvData, 
  1619.             '', 
  1620.             pArrayDesc->dataCount * pArrayDesc->arrayData.cbElements);
  1621.     /* Copy the rgsbound data into the correct place in the structure   */
  1622.     memcpy (pArrayDesc->arrayData.rgsabound, 
  1623.             rgsabound, 
  1624.             sizeof (SAFEARRAYBOUND) * cDims);
  1625.     /* Fill in various fields with appropriate values */
  1626.     pArrayDesc->vt = vt;
  1627.     pArrayDesc->arrayData.cDims = cDims;
  1628.     switch (vt)
  1629.         {
  1630.         case VT_VARIANT:
  1631.             {
  1632.             pArrayDesc->arrayData.fFeatures = FADF_VARIANT;
  1633.             /* VariantInit all members */
  1634.             VARIANT * pVar = (VARIANT *)(pArrayDesc->arrayData.pvData);
  1635.             for (index = 0; index < pArrayDesc->dataCount; index++)
  1636.                 {
  1637.                 VariantInit (pVar + index);
  1638.                 }
  1639.             }
  1640.             break;
  1641.         case VT_BSTR:
  1642.             pArrayDesc->arrayData.fFeatures = FADF_BSTR;
  1643.             break;
  1644.         case VT_UNKNOWN:
  1645.             pArrayDesc->arrayData.fFeatures = FADF_UNKNOWN;
  1646.             break;
  1647.         default:
  1648.             pArrayDesc->arrayData.fFeatures = 0;
  1649.         }
  1650.     pArrayDesc->arrayData.fFeatures |= FADF_HAVEVARTYPE 
  1651.                                        | FADF_FIXEDSIZE 
  1652.                                        | FADF_AUTO;
  1653.     pArrayDesc->arrayData.cLocks = 0;
  1654.     pArrayDesc->signature = SAFEARRAY_SIG;
  1655.     return &(pArrayDesc->arrayData);
  1656.     }
  1657. /*
  1658. * ArrayElement - list class to hold reference to a SA so that the mutex
  1659. *                can be unlocked in case of failure during SA destroy.
  1660. */
  1661. class ArrayElement
  1662.     {
  1663.     public:
  1664.     ArrayElement () { m_psa = NULL; }
  1665.     void setPsa (MEM_SAFEARRAY * psa) { m_psa = psa; }
  1666.     void unlock () { m_psa->pMutex->unlock (); }
  1667.     private:
  1668.     MEM_SAFEARRAY *     m_psa;
  1669.     };
  1670. /* List to hold above elements */
  1671. typedef VxGenericListElement<ArrayElement> ListElem;
  1672. typedef VxGenericList<ListElem,int,VxMutex> 
  1673.             ARRAY_LIST;
  1674. /**************************************************************************
  1675. *
  1676. * CheckArray - Check a SAFEARRAY for outstanding locks.
  1677. *
  1678. * This recurses through a SAFEARRAY of VARIANTs of SAFEARRAYs
  1679. * to check if there are any locks outstanding.
  1680. *
  1681. * RETURNS: S_OK if no locks exist and error code otherwise.
  1682. *.NOMANUAL
  1683. */
  1684. static HRESULT CheckArray
  1685.     (
  1686.     MEM_SAFEARRAY * pArrayDesc, /* Array descriptor */
  1687.     ARRAY_LIST & as /* list of array elements */
  1688.      /* that have been checked */
  1689.     )
  1690.     {
  1691.     ULONG    index;
  1692.     /* Check for a valid signature etc... */
  1693.     if (pArrayDesc->signature != SAFEARRAY_SIG)
  1694.         {
  1695.         return E_INVALIDARG;
  1696.         }
  1697.     /* Lock the mutex so that nothing can do anything bad underneath us */
  1698.     pArrayDesc->pMutex->lock();
  1699.     /* Save the descriptor so it can be unlocked later */
  1700.     as.pushHead (new ListElem);
  1701.     as.getHead ()->setPsa (pArrayDesc);
  1702.     if (pArrayDesc->arrayData.cLocks != 0)
  1703.         {
  1704.         return DISP_E_ARRAYISLOCKED;
  1705.         }
  1706.     /* Since we setup the array to have a VT when we create it we       */
  1707.     /* can use it in the deallocation.                                  */
  1708.     if (pArrayDesc->vt == VT_VARIANT)
  1709.         {
  1710.         VARIANT *   var = reinterpret_cast<VARIANT *>
  1711.                             (pArrayDesc->arrayData.pvData);
  1712.         for (index = 0; index < pArrayDesc->dataCount; index++)
  1713.             {
  1714.             /* Check if this variant contains an array */
  1715.             if (V_VT (&(var [index])) & VT_ARRAY)
  1716.                 {
  1717.                 MEM_SAFEARRAY * ptr = SA2MSA(V_ARRAY(&(var [index])));
  1718.                 HRESULT hr = CheckArray (ptr, as);
  1719.                 if (FAILED (hr))
  1720.                     {
  1721.                     return hr;
  1722.                     }
  1723.                 }
  1724.             }
  1725.         }
  1726.     return S_OK;
  1727.     }
  1728. /**************************************************************************
  1729. * DestroyArray - Deletes all SAFEARRAYs in a tree.
  1730. *
  1731. * Recurses through a SAFEARRAY (and any VARIANTS containing SAFEARRAYs)
  1732. * and deletes them.
  1733. *
  1734. * RETURNS: N/A
  1735. *.NOMANUAL
  1736. */
  1737. void DestroyArray
  1738.     (
  1739.     MEM_SAFEARRAY * pArrayDesc /* Array descriptor */
  1740.     )
  1741.     {
  1742.     ULONG    index;
  1743.     switch (pArrayDesc->vt)
  1744.         {
  1745.         case VT_VARIANT:
  1746.             {
  1747.             VARIANT *   var = reinterpret_cast<VARIANT *>
  1748.                                 (pArrayDesc->arrayData.pvData);
  1749.             for (index = 0; index < pArrayDesc->dataCount; index++)
  1750.                 {
  1751.                 /* Check if this variant contains an array */
  1752.                 if (V_VT (&(var [index])) & VT_ARRAY)
  1753.                     {
  1754.                     DestroyArray (SA2MSA(V_ARRAY(&(var [index]))));
  1755.                     }
  1756.                 else
  1757.                     {
  1758.                     VariantClear (&(var [index]));
  1759.                     }
  1760.                 }
  1761.             }
  1762.             break;
  1763.         case VT_BSTR:
  1764.             {
  1765.             BSTR *  pBstr = reinterpret_cast<BSTR *>
  1766.                                 (pArrayDesc->arrayData.pvData);
  1767.             for (index = 0; index < pArrayDesc->dataCount; index++)
  1768.                 {
  1769.                 if (pBstr [index] != NULL)
  1770.                     {
  1771.                     ::SysFreeString (pBstr [index]);
  1772.                     }
  1773.                 }
  1774.              }
  1775.             break;
  1776.         case VT_UNKNOWN:
  1777.             {
  1778.             IUnknown **  ppUnk = reinterpret_cast<IUnknown **>
  1779.                                 (pArrayDesc->arrayData.pvData);
  1780.             for (index = 0; index < pArrayDesc->dataCount; index++)
  1781.                 {
  1782.                 if (ppUnk [index] != NULL)
  1783.                     {
  1784.                     ppUnk [index]->Release ();
  1785.                     }
  1786.                 }
  1787.              }
  1788.              break;
  1789.         }
  1790.     pArrayDesc->signature = 0;
  1791.     pArrayDesc->pMutex->unlock ();
  1792.     delete pArrayDesc->pMutex;
  1793.     COM_MEM_FREE (pArrayDesc->arrayData.pvData);
  1794.     COM_MEM_FREE (pArrayDesc);
  1795.     }
  1796. /**************************************************************************
  1797. *
  1798. * SafeArrayDestroy - Destroys an existing array descriptor.
  1799. * Destroys an existing array descriptor and all of the 
  1800. * data in the array. If complex types are stored in the
  1801. * array the appropriate destruction will be performed.
  1802. *
  1803. * RETURNS:
  1804. * is
  1805. * i S_OK
  1806. * On success
  1807. * i DISP_E_ARRAYISLOCKED
  1808. * If the SAFEARRAY is locked
  1809. * i E_INVALIDARG 
  1810. * If one of the arguments is invalid.
  1811. * ie
  1812. */
  1813. HRESULT SafeArrayDestroy
  1814.     ( 
  1815.     SAFEARRAY *         psa     /* Pointer to an array descriptor created */
  1816.                                 /* by SafeArrayCreate */
  1817.     )
  1818.     {
  1819.     MEM_SAFEARRAY *     pArrayDesc;
  1820.     ARRAY_LIST          as;     /* This is only required in the case where */
  1821.                                 /* we have to unlock the mutexs if the     */
  1822.                                 /* fails. Mutexs are unlocked as part of   */
  1823.                                 /* the recursive delete otherwise.         */
  1824.     HRESULT             hr;
  1825.     /* Check descriptor is valid */
  1826.     if (psa == NULL)
  1827.         {
  1828.         return E_INVALIDARG;
  1829.         }
  1830.     pArrayDesc = SA2MSA(psa);
  1831.     hr = CheckArray (pArrayDesc, as);
  1832.     if (FAILED (hr))
  1833.         {
  1834.         /* release all locks */
  1835.         ArrayElement * ptr;
  1836.         while (!as.isEmpty ())
  1837.             {
  1838.             ptr = as.popHead ();
  1839.             ptr->unlock ();
  1840.             delete ptr;
  1841.             }
  1842.         return hr;
  1843.         }
  1844.     DestroyArray (pArrayDesc);
  1845.     as.destroyList ();
  1846.     return S_OK;
  1847.     }
  1848. /**************************************************************************
  1849. *
  1850. * SafeArrayLock - Increment the lock count of a SAFEARRAY.
  1851. *
  1852. * This function increments the lock count of a SAFEARRAY. 
  1853. *
  1854. * RETURNS:
  1855. * is
  1856. * i S_OK
  1857. * On success
  1858. * i E_INVALIDARG
  1859. * If the SAFEARRAY is invalid.
  1860. * ie
  1861. */
  1862. HRESULT SafeArrayLock 
  1863.     (
  1864.     SAFEARRAY *     psa     /* Pointer to an array descriptor created by */
  1865.                             /* SafeArrayCreate.                          */
  1866.     )
  1867.     {
  1868.     MEM_SAFEARRAY * pArrayDesc;
  1869.     if (psa == NULL)
  1870.         {
  1871.         return E_INVALIDARG;
  1872.         }
  1873.     pArrayDesc = SA2MSA(psa);
  1874.     /* Quick sanity check, if this passes but the mutex is invalid */
  1875.     /* we'll get a VxDCOM Assert.                                  */
  1876.     if (pArrayDesc->signature != SAFEARRAY_SIG)
  1877.         {
  1878.         return E_INVALIDARG;
  1879.         }
  1880.     pArrayDesc->pMutex->lock ();
  1881.     /* Check sig again just incase we're being woken up after SA has been */
  1882.     /* deleted. */
  1883.     if (pArrayDesc->signature != SAFEARRAY_SIG)
  1884.         {
  1885.         return E_INVALIDARG;
  1886.         }
  1887.     /* This is all OK so increment the lock */
  1888.     pArrayDesc->arrayData.cLocks++;
  1889.     pArrayDesc->pMutex->unlock ();
  1890.     return S_OK;
  1891.     }
  1892. /**************************************************************************
  1893. *
  1894. * SafeArrayUnlock - Decrement the lock count of a SAFEARRAY.
  1895. *
  1896. * This function decrements the lock count of a SAFEARRAY. 
  1897. *
  1898. * RETURNS:
  1899. * is
  1900. * i S_OK
  1901. * On success
  1902. * i E_INVALIDARG 
  1903. * If the SAFEARARAY is invalid.
  1904. * i  E_UNEXPECTED
  1905. * If and attempt is made to decrement the lock count when it is zero.
  1906. * ie
  1907. */
  1908. HRESULT SafeArrayUnlock 
  1909.     (
  1910.     SAFEARRAY *     psa     /* Pointer to an array descriptor created by */
  1911.                             /* SafeArrayCreate.                          */
  1912.     )
  1913.     {
  1914.     MEM_SAFEARRAY * pArrayDesc;
  1915.     HRESULT         hr = S_OK;
  1916.     if (psa == NULL)
  1917.         {
  1918.         return E_INVALIDARG;
  1919.         }
  1920.     pArrayDesc = SA2MSA(psa);
  1921.     /* Quick sanity check, if this passes but the mutex is invalid */
  1922.     /* we'll get a VxDCOM Assert.                                  */
  1923.     if (pArrayDesc->signature != SAFEARRAY_SIG)
  1924.         {
  1925.         return E_INVALIDARG;
  1926.         }
  1927.     pArrayDesc->pMutex->lock ();
  1928.     /* Check sig again just incase we're being woken up after SA has been */
  1929.     /* deleted. */
  1930.     if (pArrayDesc->signature != SAFEARRAY_SIG)
  1931.         {
  1932.         pArrayDesc->pMutex->unlock ();
  1933.         return E_INVALIDARG;
  1934.         }
  1935.     /* This is all OK so increment the lock */
  1936.     if (pArrayDesc->arrayData.cLocks)
  1937.         {
  1938.         pArrayDesc->arrayData.cLocks--;
  1939.         }
  1940.     else
  1941.         {
  1942.         hr = E_UNEXPECTED;
  1943.         }
  1944.     pArrayDesc->pMutex->unlock ();
  1945.     return hr;
  1946.     }
  1947. /**************************************************************************
  1948. * ArrayPos - Calculates the address of an array element.
  1949. * This calculates the position of an element in the array based on the
  1950. * following formula:
  1951. *
  1952. * p = i [0] + (d [0] * i [1]) + (d [0] * d [1] * i [2]) + ...
  1953. *
  1954. * RETURNS: S_OK on success, DISP_E_BADINDEX on failure.
  1955. *.NOMANUAL
  1956. */
  1957. HRESULT ArrayPos
  1958.     (
  1959.     SAFEARRAY * psa, /* Array descriptor */
  1960.     long * rgIndices, /* Index into array */
  1961.     void ** pv /* pointer to array dlement */
  1962.     )
  1963.     {
  1964.     LONG    inner;
  1965.     LONG    outer;
  1966.     LONG    sum = rgIndices [0] - psa->rgsabound [0].lLbound;
  1967.     *pv = NULL;
  1968.     /* Check that the index is in range since this is a Safearray */
  1969.     if ((rgIndices [0] < psa->rgsabound [0].lLbound) ||
  1970.         ((rgIndices [0] - psa->rgsabound [0].lLbound) 
  1971.             > (LONG)psa->rgsabound [0].cElements))
  1972.         {
  1973.         return DISP_E_BADINDEX;
  1974.         }
  1975.     for (outer = 1; outer < psa->cDims; outer++)
  1976.         {
  1977.         LONG    mul = 1;
  1978.         /* Check that the index is in range since this is a Safearray */
  1979.         if ((rgIndices [outer] < psa->rgsabound [outer].lLbound) ||
  1980.             ((rgIndices [outer] - psa->rgsabound [outer].lLbound) 
  1981.                 > (LONG)psa->rgsabound [outer].cElements))
  1982.             {
  1983.             return DISP_E_BADINDEX;
  1984.             }
  1985.         /* Do the d [0] + d [1] + ... bit */
  1986.         for (inner = 0; inner < outer; inner++)
  1987.             {
  1988.             mul *= psa->rgsabound [inner].cElements;
  1989.             }
  1990.         /* Multiply by the current index */
  1991.         mul *= (rgIndices [outer] - psa->rgsabound [outer].lLbound);
  1992.         /* Add to the cumulative offset */
  1993.         sum += mul;
  1994.         }
  1995.     /* Multiply the offset by the element size to get to the right position */
  1996.     /* without having to typecast anything.                                 */
  1997.     sum *= psa->cbElements;
  1998.     /* Set the data position. */
  1999.     *pv = reinterpret_cast<void *>(reinterpret_cast<BYTE *>(psa->pvData) + sum);
  2000.     return S_OK;
  2001.     }
  2002. /**************************************************************************
  2003. *
  2004. * SafeArrayPutElement - Stores a copy of the data at a given location.
  2005. *
  2006. * This function assigns a single element to the array. This function 
  2007. * calls SafeArrayLock and SafeArrayUnlock before and after assigning 
  2008. * the element. If the data element is a string, object, or variant, 
  2009. * the function copies it correctly. If the existing element is a string, 
  2010. * object, or variant, it is cleared correctly.
  2011. *
  2012. * RETURNS:
  2013. * is
  2014. * i S_OK
  2015. * Success. 
  2016. * i DISP_E_BADINDEX
  2017. * The specified index was invalid. 
  2018. * i E_INVALIDARG
  2019. * One of the arguments is invalid. 
  2020. * i E_OUTOFMEMORY
  2021. * Memory could not be allocated for the element. 
  2022. * ie
  2023. */
  2024. HRESULT SafeArrayPutElement
  2025.     (
  2026.     SAFEARRAY *     psa,        /* Pointer to an array descriptor created by */
  2027.                                 /* SafeArrayCreate.                          */
  2028.     long *          rgIndicies, /* Pointer to a vector of indices for each   */
  2029.                                 /* dimension of the array.                   */
  2030.     void *          pv          /* Pointer to the data to assign.            */
  2031.     )
  2032.     {
  2033.     void *          ptr;
  2034.     HRESULT         hr = S_OK;
  2035.     hr = SafeArrayLock (psa);
  2036.     if (FAILED (hr))
  2037.         {
  2038.         return hr;
  2039.         }
  2040.     /* get a pointer to the appropriate area of memory */
  2041.     hr = ArrayPos (psa, rgIndicies, &ptr);
  2042.     if (SUCCEEDED (hr))
  2043.         {
  2044.         switch (SA2MSA(psa)->vt)
  2045.             {
  2046.             case VT_ERROR:
  2047.             case VT_UI1:
  2048.             case VT_I2:
  2049.             case VT_I4:
  2050.             case VT_R4:
  2051.             case VT_R8:
  2052.             case VT_CY: 
  2053.             case VT_DATE:
  2054.             case VT_BOOL:
  2055.                 memcpy (ptr, pv, psa->cbElements);
  2056.                 break;
  2057.             case VT_UNKNOWN:
  2058.                 {
  2059.                 IUnknown ** iPtr = reinterpret_cast<IUnknown **>(ptr);
  2060.                 if (*iPtr != NULL)
  2061.                     {
  2062.                     (*iPtr)->Release ();
  2063.                     *iPtr = NULL;
  2064.                     }
  2065.                 if (reinterpret_cast<IUnknown *>(pv) != NULL)
  2066.                     {
  2067.                     hr = (reinterpret_cast<IUnknown *>(pv))->
  2068.                         QueryInterface(IID_IUnknown, 
  2069.                                        (void **)iPtr);
  2070.                     }
  2071.                 }
  2072.                 break;
  2073.             case VT_BSTR:
  2074.                 {
  2075.                 BSTR *      bPtr = reinterpret_cast<BSTR *>(ptr);
  2076.                 if (*bPtr != NULL)
  2077.                     {
  2078.                     hr = ::SysFreeString (*bPtr);
  2079.                     *bPtr = NULL;
  2080.                     }
  2081.                 if (SUCCEEDED (hr) && (pv != NULL))
  2082.                     {
  2083.                     *bPtr = ::SysAllocString ((BSTR)pv);
  2084.                     }
  2085.                 }
  2086.                 break;
  2087.             case VT_VARIANT:
  2088.                 hr = VariantClear (reinterpret_cast<VARIANT *>(ptr));
  2089.                 if (SUCCEEDED (hr))
  2090.                     {
  2091.                     hr = VariantCopy (reinterpret_cast<VARIANT *>(ptr), 
  2092.                                       reinterpret_cast<VARIANT *>(pv));
  2093.                     }
  2094.                 break;
  2095.             }
  2096.         }
  2097.     HRESULT hr2 = SafeArrayUnlock (psa);
  2098.     if (FAILED (hr2))
  2099.         {
  2100.         return hr2;
  2101.         }
  2102.     return hr;
  2103.     }
  2104. /**************************************************************************
  2105. *
  2106. * SafeArrayGetElement - Retrieves a single element of the array. 
  2107. *
  2108. * Retrieves a single element of the array. This function calls 
  2109. * SafeArrayLock and SafeArrayUnlock automatically, before and 
  2110. * after retrieving the element. The caller must provide a storage 
  2111. * area of the correct size to receive the data. If the data element 
  2112. * is a string, object, or variant, the function copies the element 
  2113. * in the correct way. 
  2114. *
  2115. * RETURNS:
  2116. * is
  2117. * i S_OK
  2118. * Success. 
  2119. * i DISP_E_BADINDEX
  2120. * The specified index was invalid. 
  2121. * i E_INVALIDARG
  2122. * One of the arguments is invalid. 
  2123. * i E_OUTOFMEMORY
  2124. * Memory could not be allocated for the element. 
  2125. * ie
  2126. */
  2127. HRESULT SafeArrayGetElement
  2128.     (
  2129.     SAFEARRAY *     psa,        /* Pointer to an array descriptor created by */
  2130.                                 /* SafeArrayCreate.                          */
  2131.     long *          rgIndicies, /* Pointer to a vector of indices for each   */
  2132.                                 /* dimension of the array.                   */
  2133.     void *          pv          /* Pointer to the returned data.             */
  2134.     )
  2135.     {
  2136.     HRESULT     hr = S_OK;
  2137.     void *      ptr;
  2138.     if (pv == NULL)
  2139.         {
  2140.         return E_INVALIDARG;
  2141.         }
  2142.     hr = SafeArrayLock (psa);
  2143.     if (FAILED (hr))
  2144.         {
  2145.         return hr;
  2146.         }
  2147.     /* get a pointer to the appropriate area of memory */
  2148.     hr = ArrayPos (psa, rgIndicies, &ptr);
  2149.     if (SUCCEEDED (hr))
  2150.         {        
  2151.         switch (SA2MSA(psa)->vt)
  2152.             {
  2153.             case VT_ERROR:
  2154.             case VT_UI1:
  2155.             case VT_I2:
  2156.             case VT_I4:
  2157.             case VT_R4:
  2158.             case VT_R8:
  2159.             case VT_CY: 
  2160.             case VT_DATE:
  2161.             case VT_BOOL:
  2162.                 memcpy (pv, ptr, psa->cbElements);
  2163.                 break;
  2164.             case VT_UNKNOWN:
  2165.                 if (*reinterpret_cast<IUnknown **>(ptr))
  2166.                     {
  2167.                     hr = (*reinterpret_cast<IUnknown **>(ptr))->
  2168.                             QueryInterface(IID_IUnknown, 
  2169.                                            reinterpret_cast<void **>(pv));
  2170.                     }
  2171.                 else
  2172.                     {
  2173.                     *reinterpret_cast<IUnknown **>(pv) = NULL;
  2174.                     }
  2175.                 break;
  2176.             case VT_BSTR:
  2177.                     if (*reinterpret_cast<BSTR *>(ptr) != NULL)
  2178.                         {
  2179.                         *reinterpret_cast<BSTR *>(pv) = 
  2180.                             ::SysAllocString (*reinterpret_cast<BSTR *>(ptr));
  2181.                         }
  2182.                     else
  2183.                         {
  2184.                         *reinterpret_cast<BSTR *>(pv) = NULL;
  2185.                         }
  2186.                 break;
  2187.             case VT_VARIANT:
  2188.                 VariantInit (reinterpret_cast<VARIANT *>(pv));
  2189.                 if (SUCCEEDED (hr))
  2190.                     {
  2191.                     hr = VariantCopy (reinterpret_cast<VARIANT *>(pv),
  2192.                                       reinterpret_cast<VARIANT *>(ptr));
  2193.                     }
  2194.                 break;
  2195.             }
  2196.         
  2197.         }
  2198.     HRESULT hr2 = SafeArrayUnlock (psa);
  2199.     if (FAILED (hr2))
  2200.         {
  2201.         return hr2;
  2202.         }
  2203.     
  2204.     return hr;
  2205.     
  2206.     }
  2207. /**************************************************************************
  2208. *
  2209. * SafeArrayAccessData - Locks a SAFEARRAY.
  2210. * This function increments the lock count of an array, and retrieves a 
  2211. * pointer to the array data.
  2212. *
  2213. * The data array returned is arranged using the following formula:
  2214. *
  2215. * p = (i [0] + (d [0] * i [1]) + (d [0] * d [1] * i [2]) ...) * size of element
  2216. *
  2217. * Where:
  2218. *    i [n]  - holds the indices 
  2219. *    d [n]  - holds the dimensions 
  2220. *    p      - a pointer to the storage location 
  2221. *
  2222. * RETURNS:
  2223. * is
  2224. * i S_OK
  2225. * Success. 
  2226. * i E_INVALIDARG
  2227. * One of the arguments is invalid. 
  2228. * ie
  2229. */
  2230. HRESULT SafeArrayAccessData
  2231.     ( 
  2232.     SAFEARRAY *     psa,        /* Pointer to an array descriptor */
  2233.     void **         ppvData     /* Pointer to a pointer to the array data */
  2234.     )
  2235.     {
  2236.     HRESULT hr = SafeArrayLock (psa);
  2237.     if (FAILED(hr))
  2238.         {
  2239.         return hr;
  2240.         }
  2241.     *ppvData = psa->pvData;
  2242.     return S_OK;
  2243.     }
  2244. /**************************************************************************
  2245. *
  2246. * SafeArrayUnaccessData - This function decrements the lock count of an array.
  2247. *
  2248. * This function decrements the lock count of an array which was locked 
  2249. * using SafeArrayAccessData.
  2250. *
  2251. * RETURNS:
  2252. * is
  2253. * i S_OK
  2254. * Success. 
  2255. * i E_INVALIDARG
  2256. * One of the arguments is invalid. 
  2257. * ie
  2258. */
  2259. HRESULT SafeArrayUnaccessData
  2260.     ( 
  2261.     SAFEARRAY *         psa    /* Pointer to an array descriptor */
  2262.     )
  2263.     {
  2264.     return SafeArrayUnlock (psa);
  2265.     }
  2266. /**************************************************************************
  2267. *
  2268. * SafeArrayCopy() - Creates a copy of an existing safe array.
  2269. *
  2270. * This function creates a copy of an existing SAFEARRAY created with 
  2271. * SafeArrayCreate. If the SAFEARRAY contains interface pointers the reference
  2272. * counts are incremeneted. If the SAFEARRAY contains BSTRS copies of the BSTRS
  2273. * are made.
  2274. *
  2275. * RETURNS:
  2276. * is
  2277. * i S_OK
  2278. * Success. 
  2279. * i E_INVALIDARG
  2280. * One of the arguments is invalid. 
  2281. * i E_OUTOFMEMORY
  2282. * There isn't enought memory to complete the copy.
  2283. * ie
  2284. */
  2285. HRESULT SafeArrayCopy
  2286.     (
  2287.     SAFEARRAY * psa,  /* Pointer to SAFEARRAY */
  2288.     SAFEARRAY ** ppsaOut  /* Pointer to destination */
  2289.     )
  2290.     {
  2291.     void * psv;
  2292.     void * pdv;
  2293.     HRESULT hr = S_OK;
  2294.     hr = SafeArrayLock (psa);
  2295.     if (FAILED (hr))
  2296.         {
  2297.         return hr;
  2298.         }
  2299.     *ppsaOut = SafeArrayCreate (SA2MSA(psa)->vt, 
  2300.                                 psa->cDims, 
  2301.                                 psa->rgsabound);
  2302.     if (*ppsaOut == NULL) return hr;
  2303.     hr = SafeArrayAccessData (psa, &psv);
  2304.     if (FAILED (hr))
  2305.         {
  2306.         SafeArrayDestroy (*ppsaOut);
  2307.         return hr;
  2308.         }
  2309.     hr = SafeArrayAccessData (*ppsaOut, &pdv);
  2310.     if (FAILED (hr))
  2311.         {
  2312.         SafeArrayUnaccessData (psa);
  2313.         SafeArrayDestroy (*ppsaOut);
  2314.         return hr;
  2315.         }
  2316.     switch (SA2MSA(psa)->vt)
  2317.         {
  2318.         case VT_BSTR:
  2319.             {
  2320.             BSTR *  source = reinterpret_cast<BSTR *>(psv);
  2321.             BSTR *  dest = reinterpret_cast<BSTR *>(pdv);
  2322.             DWORD   index;
  2323.             for (index = 0; index < SA2MSA(psa)->dataCount; index++)
  2324.                 {
  2325.                 // only copy if a string is present, otherwise leave as NULL.
  2326.                 if (source[index])
  2327.                     {
  2328.                     dest[index] = ::SysAllocString(source[index]);
  2329.                     }
  2330.                 }
  2331.             }
  2332.             break;
  2333.         case VT_UNKNOWN:
  2334.             {
  2335.             IUnknown **     source = reinterpret_cast<IUnknown **>(psv);
  2336.             IUnknown **     dest = reinterpret_cast<IUnknown **>(pdv);
  2337.             DWORD           index;
  2338.             for (index = 0; index < SA2MSA(psa)->dataCount; index++)
  2339.                 {
  2340.                 // only copy if a string is present, otherwise leave as NULL.
  2341.                 if (source[index])
  2342.                     {
  2343.                     source[index]->QueryInterface(IID_IUnknown, 
  2344.                                                   (void **)&dest[index]);
  2345.                     }
  2346.                 }
  2347.             }
  2348.             break;
  2349.         case VT_VARIANT:
  2350.             {
  2351.             VARIANT *   source = reinterpret_cast<VARIANT *>(psv);
  2352.             VARIANT *   dest = reinterpret_cast<VARIANT *>(pdv);
  2353.             DWORD       index;
  2354.             for (index = 0; index < SA2MSA(psa)->dataCount; index++)
  2355.                 {
  2356.                 // only copy if a string is present, otherwise leave as NULL.
  2357.                 VariantCopy(&dest [index], &source [index]);
  2358.                 }
  2359.             }
  2360.             break;
  2361.         default:
  2362.             memcpy(pdv, 
  2363.                    psv, 
  2364.                    SA2MSA(psa)->dataCount * psa->cbElements);
  2365.             break;
  2366.         }
  2367.     SafeArrayUnaccessData (psa);
  2368.     SafeArrayUnlock (psa);
  2369.     hr = SafeArrayUnaccessData (*ppsaOut);
  2370.     return hr;
  2371.     }
  2372. /**************************************************************************
  2373. *
  2374. * SafeArrayGetLBound() - Gets the lower bound for any dimension of a SAFEARRAY.
  2375. *
  2376. * This functions gets the lower bound for any dimension in a SAFEARRAY.
  2377. *
  2378. * RETURNS:
  2379. * is
  2380. * i S_OK
  2381. * Success.
  2382. * i DISP_E_BADINDEX
  2383. * The specified index is out of bounds.
  2384. * i E_INVALIDARG
  2385. * One of the arguments is invalid.
  2386. * ie
  2387. */
  2388. HRESULT SafeArrayGetLBound
  2389.     (
  2390.     SAFEARRAY * psa,  /* Pointer to SAFEARRAY */
  2391.     unsigned int nDim,  /* Dimension of SAFEARRAY starting at 1 */
  2392.     long * plLbound  /* Pointer to result */
  2393.     )
  2394.     {
  2395.     if (plLbound == NULL)
  2396.      {
  2397. return E_INVALIDARG;
  2398.      }
  2399.     if (nDim < 1)
  2400.         {
  2401.         return DISP_E_BADINDEX;
  2402.         }
  2403.     HRESULT hr = SafeArrayLock (psa);
  2404.     if (FAILED (hr))
  2405.         {
  2406.         return hr;
  2407.         }
  2408.     if (nDim > psa->cDims)
  2409.         {
  2410.         SafeArrayUnlock (psa);
  2411.         return DISP_E_BADINDEX;
  2412.         }
  2413.     *plLbound = psa->rgsabound [nDim - 1].lLbound;
  2414.     return SafeArrayUnlock (psa);
  2415.     }
  2416. /**************************************************************************
  2417. *
  2418. * SafeArrayGetUBound() - Gets the upper bound for any dimension of a SAFEARRAY.
  2419. *
  2420. * This functions gets the upper bound for any dimension in a SAFEARRAY.
  2421. *
  2422. * RETURNS:
  2423. * is
  2424. * i S_OK
  2425. * Success.
  2426. * i DISP_E_BADINDEX
  2427. * The specified index is out of bounds.
  2428. * i E_INVALIDARG
  2429. * One of the arguments is invalid.
  2430. * ie
  2431. */
  2432. HRESULT SafeArrayGetUBound
  2433.     (
  2434.     SAFEARRAY * psa,  /* Pointer to a SAFEARRAY */
  2435.     unsigned int nDim,  /* Dimension of SAFEARRAY starting at 1 */
  2436.     long * plUbound /* Pointer to returned result */
  2437.     )
  2438.     {
  2439.     if (plUbound == NULL)
  2440.      {
  2441. return E_INVALIDARG;
  2442.      }
  2443.     if (nDim < 1)
  2444.         {
  2445.         return DISP_E_BADINDEX;
  2446.         }
  2447.     HRESULT hr = SafeArrayLock (psa);
  2448.     if (FAILED (hr))
  2449.         {
  2450.         return hr;
  2451.         }
  2452.     if (nDim > psa->cDims)
  2453.         {
  2454.         SafeArrayUnlock (psa);
  2455.         return DISP_E_BADINDEX;
  2456.         }
  2457.     *plUbound = psa->rgsabound [nDim - 1].lLbound + 
  2458.                 (long)(psa->rgsabound [nDim - 1].cElements) - 1; 
  2459.     return SafeArrayUnlock (psa);
  2460.     }
  2461.   
  2462. /**************************************************************************
  2463. *
  2464. * SafeArrayGetDim() - Gets the number of dimensions in the array.
  2465. *
  2466. * This functions gets the number of dimensions in the array.
  2467. *
  2468. * RETURNS: 0 if an invalid SAFEARRAY is given, otherwise the number 
  2469. * dimmensions in the array
  2470. */
  2471. UINT SafeArrayGetDim
  2472.     ( 
  2473.     SAFEARRAY * psa /* Pointer to a SAFEARRAY */
  2474.     )
  2475.     {
  2476.     UINT  result;
  2477.     if (FAILED (SafeArrayLock (psa)))
  2478.         {
  2479.         return 0;
  2480.         }
  2481.     result = psa->cDims;
  2482.     SafeArrayUnlock (psa);
  2483.     return result;
  2484.     }
  2485.   
  2486. /**************************************************************************
  2487. *
  2488. * SafeArrayGetElemsize() - Gets the size of an element in the SAFEARRAY.
  2489. *
  2490. * This functions gets the size of an element in the SAFEARRAY
  2491. *
  2492. * RETURNS: 0 if an invalid SAFEARRAY is given, otherwise the size of the
  2493. * element in the SAFEARRAY.
  2494. */
  2495. UINT SafeArrayGetElemsize
  2496.     (
  2497.     SAFEARRAY * psa /* Pointer to a SAFEARRAY */
  2498.     )
  2499.     {
  2500.     UINT  result;
  2501.     if (FAILED (SafeArrayLock (psa)))
  2502.         {
  2503.         return 0;
  2504.         }
  2505.     result = psa->cbElements;
  2506.     SafeArrayUnlock (psa);
  2507.     return result;
  2508.     }
  2509. /**************************************************************************
  2510. *
  2511. * SafeArrayGetVartype() - Gets the VARTYPE stored in the given SAFEARRAY.
  2512. *
  2513. * This functions gets the VARTYPE stored in the given SAFEARRAY.
  2514. *
  2515. * RETURNS:
  2516. * is
  2517. * i S_OK
  2518. * On success
  2519. * i E_INVALIDARG
  2520. * One of the arguments is invalid.
  2521. * ie
  2522. */
  2523. HRESULT SafeArrayGetVartype
  2524.     ( 
  2525.     SAFEARRAY * psa,  /* Pointer to a SAFEARRAY */
  2526.     VARTYPE * pvt   /* Pointer to the type returned */
  2527.     )
  2528.     {
  2529.     if (pvt == NULL)
  2530.      {
  2531. return E_INVALIDARG;
  2532.      }
  2533.     if (FAILED (SafeArrayLock (psa)))
  2534.         {
  2535.         return E_INVALIDARG;
  2536.         }
  2537.     *pvt = SA2MSA (psa)->vt;
  2538.     SafeArrayUnlock (psa);
  2539.     return S_OK;
  2540.     }
  2541. /* CComVariant */
  2542. CComVariant& CComVariant::operator=(BSTR bstrSrc)
  2543.     {
  2544.     InternalClear();
  2545.     vt = VT_BSTR;
  2546.     bstrVal = ::SysAllocString(bstrSrc);
  2547.     if (bstrVal == NULL && bstrSrc != NULL)
  2548.         {
  2549.         vt = VT_ERROR;
  2550.         scode = E_OUTOFMEMORY;
  2551. }
  2552.     return *this;
  2553.     }
  2554. CComVariant& CComVariant::operator=(LPCOLESTR lpszSrc)
  2555.     {
  2556.     InternalClear();
  2557.     vt = VT_BSTR;
  2558.     bstrVal = ::SysAllocString(lpszSrc);
  2559.     if (bstrVal == NULL && lpszSrc != NULL)
  2560. {
  2561.         vt = VT_ERROR;
  2562.         scode = E_OUTOFMEMORY;
  2563. }
  2564.     return *this;
  2565.     }
  2566. CComVariant& CComVariant::operator=(bool bSrc)
  2567.     {
  2568.     if (vt != VT_BOOL)
  2569. {
  2570.         InternalClear();
  2571.         vt = VT_BOOL;
  2572. }
  2573.     boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
  2574.     return *this;
  2575.     }
  2576. CComVariant& CComVariant::operator=(int nSrc)
  2577.     {
  2578.     if (vt != VT_I4)
  2579. {
  2580.         InternalClear();
  2581.         vt = VT_I4;
  2582. }
  2583.     lVal = nSrc;
  2584.     return *this;
  2585.     }
  2586. CComVariant& CComVariant::operator=(BYTE nSrc)
  2587.     {
  2588.     if (vt != VT_UI1)
  2589. {
  2590.         InternalClear();
  2591.         vt = VT_UI1;
  2592. }
  2593.     bVal = nSrc;
  2594.     return *this;
  2595.     }
  2596. CComVariant& CComVariant::operator=(short nSrc)
  2597.     {
  2598.     if (vt != VT_I2)
  2599. {
  2600.         InternalClear();
  2601.         vt = VT_I2;
  2602. }
  2603.     iVal = nSrc;
  2604.     return *this;
  2605.     }
  2606. CComVariant& CComVariant::operator=(long nSrc)
  2607.     {
  2608.     if (vt != VT_I4)
  2609. {
  2610.         InternalClear();
  2611.         vt = VT_I4;
  2612. }
  2613.     lVal = nSrc;
  2614.     return *this;
  2615.     }
  2616. CComVariant& CComVariant::operator=(float fltSrc)
  2617.     {
  2618.     if (vt != VT_R4)
  2619. {
  2620.         InternalClear();
  2621.         vt = VT_R4;
  2622. }
  2623.     fltVal = fltSrc;
  2624.     return *this;
  2625.     }
  2626. CComVariant& CComVariant::operator=(double dblSrc)
  2627.     {
  2628.     if (vt != VT_R8)
  2629. {
  2630.         InternalClear();
  2631.         vt = VT_R8;
  2632. }
  2633.     dblVal = dblSrc;
  2634.     return *this;
  2635.     }
  2636. CComVariant& CComVariant::operator=(CY cySrc)
  2637.     {
  2638.     if (vt != VT_CY)
  2639. {
  2640.         InternalClear();
  2641.         vt = VT_CY;
  2642. }
  2643.     cyVal = cySrc;
  2644.     return *this;
  2645.     }
  2646. CComVariant& CComVariant::operator=(IUnknown* pSrc)
  2647.     {
  2648.     InternalClear();
  2649.     vt = VT_UNKNOWN;
  2650.     punkVal = pSrc;
  2651.     // Need to AddRef as VariantClear will Release
  2652.     if (punkVal != NULL)
  2653.         punkVal->AddRef();
  2654.     return *this;
  2655.     }
  2656. bool CComVariant::operator==(const VARIANT& varSrc)
  2657.     {
  2658.     if (this == &varSrc)
  2659.         return true;
  2660.     // Variants not equal if types don't match
  2661.     if (vt != varSrc.vt)
  2662.         return false;
  2663.     // Check type specific values
  2664.     switch (vt)
  2665.         {
  2666.         case VT_EMPTY:
  2667.         case VT_NULL:
  2668.             return true;
  2669.         case VT_BOOL:
  2670.             return boolVal == varSrc.boolVal;
  2671.         case VT_UI1:
  2672.             return bVal == varSrc.bVal;
  2673.         case VT_I2:
  2674.             return iVal == varSrc.iVal;
  2675.         case VT_I4:
  2676.             return lVal == varSrc.lVal;
  2677.         case VT_R4:
  2678.             return fltVal == varSrc.fltVal;
  2679.         case VT_R8:
  2680.             return dblVal == varSrc.dblVal;
  2681.         case VT_BSTR:
  2682.             return (::SysStringByteLen(bstrVal) == 
  2683.                     ::SysStringByteLen(varSrc.bstrVal)) &&
  2684.                    (::memcmp(bstrVal, 
  2685.                              varSrc.bstrVal, 
  2686.                              ::SysStringByteLen(bstrVal)) == 0);
  2687.         case VT_ERROR:
  2688.             return scode == varSrc.scode;
  2689.         case VT_UNKNOWN:
  2690.             return punkVal == varSrc.punkVal;
  2691.         default:
  2692.             COM_ASSERT (false);
  2693.             // fall through
  2694. }
  2695.     return false;
  2696.     }
  2697. HRESULT CComVariant::Attach(VARIANT* pSrc)
  2698.     {
  2699.     // Clear out the variant
  2700.     HRESULT hr = Clear();
  2701.     if (!FAILED(hr))
  2702. {
  2703.         // Copy the contents and give control to CComVariant
  2704.         memcpy(this, pSrc, sizeof(VARIANT));
  2705.         VariantInit(pSrc);
  2706.         hr = S_OK;
  2707. }
  2708.     return hr;
  2709.     }
  2710. HRESULT CComVariant::Detach(VARIANT* pDest)
  2711.     {
  2712.     // Clear out the variant
  2713.     HRESULT hr = ::VariantClear(pDest);
  2714.     if (!FAILED(hr))
  2715. {
  2716.         // Copy the contents and remove control from CComVariant
  2717.         memcpy(pDest, this, sizeof(VARIANT));
  2718.         vt = VT_EMPTY;
  2719.         hr = S_OK;
  2720. }
  2721.     return hr;
  2722.     }
  2723. HRESULT CComVariant::ChangeType(VARTYPE vtNew, const VARIANT* pSrc)
  2724.     {
  2725.     VARIANT* pVar = const_cast<VARIANT*>(pSrc);
  2726.     // Convert in place if pSrc is NULL
  2727.     if (pVar == NULL)
  2728.         pVar = this;
  2729.     // Do nothing if doing in place convert and vts not different
  2730.     return ::VariantChangeType(this, pVar, 0, vtNew);
  2731.     }
  2732. HRESULT CComVariant::InternalClear()
  2733.     {
  2734.     HRESULT hr = Clear();
  2735.     COM_ASSERT (SUCCEEDED(hr));
  2736.     if (FAILED(hr))
  2737. {
  2738.         vt = VT_ERROR;
  2739.         scode = hr;
  2740. }
  2741.     return hr;
  2742.     }
  2743. void CComVariant::InternalCopy(const VARIANT* pSrc)
  2744.     {
  2745.     HRESULT hr = Copy(pSrc);
  2746.     if (FAILED(hr))
  2747. {
  2748.         vt = VT_ERROR;
  2749.         scode = hr;
  2750. }
  2751.     }
  2752.