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

VxWorks

开发平台:

C/C++

  1. /* NdrTypes.cpp - VxDCOM NDR marshaling types */
  2. /* Copyright (c) 1999 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 02p,10jan02,nel  Conditional define out old sytle double handling for ARM for
  7.                  Veloce.
  8. 02o,09jan02,nel  Fix duplicate double definition in ARM specific code.
  9. 02n,17dec01,nel  Add include symbol for diab.
  10. 02m,12oct01,nel  Add extra padding to other VARIANT types.
  11. 02l,01oct01,nel  SPR#69557. Add extra padding bytes to make VT_BOOL type work.
  12. 02k,02aug01,dbs  add [v1_enum] support
  13. 02j,24jul01,dbs  take fix for SPR#65311, unnecessary align() in struct
  14.                  marshal2
  15. 02i,19jul01,dbs  fix include path of vxdcomGlobals.h
  16. 02h,13jul01,dbs  fix up includes
  17. 02g,30mar01,nel  SPR#35873. Modify extra pading bytes on the end of a
  18.                  SAFEARRAY.
  19. 02f,08feb01,nel  SPR#63885. SAFEARRAYs added.   
  20. 02e,19sep00,nel  Make widlMarshal match dcomProxy def.
  21. 02d,24aug00,dbs  fix many OPC-related SPRs, copied over from T2 VxDCOM
  22. 02c,26jul00,dbs  add enum_t descriptor
  23. 02b,18jul00,dbs  add CV-array NDR type
  24. 02a,28feb00,dbs  fix (properly) pointer-unmarshaling bug
  25. 01z,28feb00,dbs  fix nasty bug when unmarshaling arrays of pointers
  26. 01y,18feb00,dbs  change signature of widlMarshal() to take const void*
  27. 01x,07feb00,dbs  simplify NdrType classes, enhance marshaling of arrays to
  28.                  support all kinds
  29. 01w,14oct99,dbs  apply fix for ARM double format
  30. 01v,23sep99,dbs  add final parts of VARIANT marshaling
  31. 01u,16sep99,dbs  marshaling enhancements, part 2
  32. 01t,14sep99,dbs  add VARIANT, pointer and string types - first stage
  33. 01s,25aug99,dbs  correct marshaling of interface ptrs
  34. 01r,19aug99,aim  changed assert to VXDCOM_ASSERT
  35. 01q,16aug99,dbs  add variant and string support
  36. 01p,13aug99,aim  include vxdcomGlobals
  37. 01o,12aug99,dbs  improve struct support
  38. 01n,05aug99,dbs  fix warnings
  39. 01m,30jul99,dbs  tighten up type-safety of NDR types
  40. 01l,29jul99,dbs  make cstruct pointer bindings same for mshl and unmshl
  41. 01k,17jun99,aim  changed assert to assert
  42. 01j,17jun99,dbs  change to COM_MEM_ALLOC
  43. 01i,25may99,dbs  dynamically allocate IStream for marshaling
  44.                  interfaces, remove NDRTYPES::alloc/free
  45. 01h,24may99,dbs  add BSTR marshaling policy variable
  46. 01g,24may99,dbs  fix interface-ptr marshaling
  47. 01f,20may99,dbs  fix BSTR marshaling functions for improved BSTR format
  48. 01e,20may99,dbs  improve documentation
  49. 01d,18may99,dbs  optimise unmarshaling by copying only pointers when possible
  50. 01c,17may99,dbs  remove dummy-msg object, add documentation
  51. 01b,14may99,dbs  fix alignment of array counts
  52. 01a,12may99,dbs  created
  53. */
  54. /*
  55.   DESCRIPTION: NdrTypes.cpp
  56.   NDR Type Descriptors
  57.   --------------------
  58.   
  59.   This module implements the 'type descriptor' system for NDR
  60.   marshaling, in conjunction with the NdrMarshalStream and
  61.   NdrUnmarshalStream classes.
  62.   The NDR stream classes are unidirectional streams that can either be
  63.   marshaled into, or can be unmarshaled from. The type-descriptor
  64.   system described here implements some classes which know about
  65.   marshaling one specific IDL or C++ type into one of those
  66.   streams. In fact, each type-descriptor know about marshaling either
  67.   one complex type (like GUID) or one or more simple types, all of
  68.   which are the same size, for example, 'short' and 'unsigned short'
  69.   are handled by the same type descriptor class.
  70.   All type descriptors are subclasses of the abstract base class
  71.   'NdrType' and the WIDL (un)marshaling functions widlMarshal() and
  72.   widlUnmarshal() require a pointer to the appropriate kind of stream,
  73.   and a pointer to an NdrType which describes the item to be
  74.   (un)marshaled. All user-level marshaling (i.e. that which appears in
  75.   the generated proxy/stub code) uses these 2 functions.
  76.   Each proxy or stub function must include a local variable of type
  77.   NDRTYPES. This object functions as a 'factory' for the type
  78.   descriptors, and implements a fast allocation strategy using
  79.   placement new. Whenever a variable needs to be marshaled, then one
  80.   of the methods of the NDRTYPES factory class is called, to generate
  81.   a type descriptor. The descriptors are 'nestable' in that recursive
  82.   data types can be described, such as structures or arrays. The set
  83.   of type descriptor classes covers arrays (both fixed-size and
  84.   conformant) and structures (again, fixed or conformant) even though
  85.   WIDL doesn't currently cope with these complex types.
  86.   Each type descriptor can be 'bound' to a particular instance
  87.   variable, by passing the variable's address into the factory
  88.   method. Only the top-level descriptor needs to be bound to the
  89.   variable, and it will propogate down to nested descriptors. The
  90.   value that needs to be bound to the descriptor is usually the
  91.   address of the variable to be (un)marshaled. Arrays and structures
  92.   require the descriptor to be bound to the start-address, e.g. for an
  93.   array of T, the descriptor would be:-
  94.   T* aT;
  95.   array_t (aT, ...);
  96.   and for a structure (conformant or normal) of type T, it would be
  97.   like this:-
  98.   struct T t;
  99.   struct_t (&t, ...);
  100.   
  101.   Generally, the factory methods (of the NDRTYPES class) require the
  102.   address of a variable to bind to. This precludes marshaling
  103.   immediate values, but this is not generally a problem. However,
  104.   there are exceptions, which must be coded carefully (and will be
  105.   handled by WIDL in future).
  106.   IDL Syntax and its meaning
  107.   --------------------------
  108.   DCE IDL allows many ways of achieving the same thing, and is
  109.   particularly confusing when it comes to args which are pointers or
  110.   arrays. There are three kinds of pointer-attributes, namely [ref],
  111.   [unique] and [ptr] (which is know as 'full' also). The [ref] pointer
  112.   type is effectively a pass-by-reference pointer, which can never be
  113.   NULL (like a C++ reference type) and so does not require any
  114.   marshaling. However, both [unique] and [ptr] pointers can be NULL
  115.   and so must be marshaled (the marshaled value is known as a
  116.   'referent' and is usually the value of the pointer itself, but
  117.   effectively only conveys the NULL-ness or otherwise of the
  118.   pointer). Top-level pointers (i.e. those in method arguments, at the
  119.   outermost level) default to [ref] unless a specific attribute is
  120.   given in the IDL. Lower level pointers (i.e. those inside structures
  121.   or arrays, or even the 2nd level of indirection in method args)
  122.   default to [unique] and so require marshaling. The pointer_t
  123.   descriptor represents these kinds of pointers, and so it appears
  124.   frequently.
  125.   Pointers, as well as having one the above three attributes, can also
  126.   be 'sized' -- i.e. can represent arrays as they can in C. For
  127.   example, if the IDL says:-
  128.   typedef struct
  129.     {
  130.     long a;
  131.     char b;
  132.     } FOO;
  133.     
  134.   HRESULT FooBar ([in] long nFoos, [in, size_is(nFoos)] FOO* foos);
  135.   then the variable 'foos' is a 'conformant array' whose length is
  136.   given (at runtime) in the arg 'nFoos'. DCE IDL also allows for
  137.   returning conformant arrays, but the syntax for arrays of simple
  138.   types, and arrays of complex types, is different.
  139.   To return an array of simple types, the IDL would be something like
  140.   this:-
  141.   HRESULT Quz ([in] long nBytes, [out, size_is(nBytes)] char* bytes);
  142.   
  143.   To return an array of fixed-size structures, like FOO defined above,
  144.   then the syntax is different, like so:-
  145.   
  146.   HRESULT Func ([in] long num, [out, size_is(,num)] FOO** ppFoos);
  147.   In this case, the first pointer (rightmost *) defaults to [ref], and
  148.   the 2nd or inner pointer defaults to [unique], so this declaration
  149.   should be read as:-
  150.   (ref-ptr to (unique-array of dimension 'num' of (FOO)))
  151.   
  152.   In this case, the proxy allocates memory to hold the array of FOOs
  153.   and stores the address of this block in the pointer pointed-to by
  154.   the argument 'ppFoos'. The strange syntax size_is(,num) indicates
  155.   that the size_is value binds to the second star, and so this means a
  156.   'pointer to an array of FOOs'. Calling the function in C would look
  157.   like this:-
  158.   FOO* foos;
  159.   Func (3, &foos);
  160.   COM_MEM_FREE (foos);
  161.   where Func() is actually calling the proxy, which makes the ORPC and
  162.   returns the array of 3 FOO structures directly into the caller's
  163.   address space.
  164.   The final cases cover returning conformant structures, that is a
  165.   structure whose final member is a conformant array. To return a
  166.   single conformant structure, the IDL will be something like:-
  167.   typedef struct
  168.     {
  169.     long                    nBytes;
  170.     [size_is(nBytes)] char  data[];
  171.     } BAR;
  172.   HRESULT BarBaz ([out] BAR** ppBar);
  173.   where ppBar is a ref-ptr to a unique-ptr to BAR. There is a subtle
  174.   difference between this case and the case where the out-arg is an
  175.   array of conformant-structures, like the BAR structure defined
  176.   above. If the signature were:-
  177.   HRESULT Func ([in] long num, [out, size_is(num)] BAR** ppBars);
  178.   then this would mean 'ref-array of unique-pointer to BAR'
  179.   and the size_is attribute applies to the top-level * declarator,
  180.   i.e. ppBar is itself an array.
  181.   
  182.   NDR Phases
  183.   ----------
  184.   There are 4 phases of marshaling in ORPC : firstly, marshaling all
  185.   the [in] args at the proxy; secondly, unmarshaling all the [in] args
  186.   at the stub; thirdly, marshaling all the [out] args and the return
  187.   value at the stub; and finally unmarshaling all the [out] args and
  188.   the return value at the proxy.
  189.   In each of these phases there are different requirements on the type
  190.   descriptors in order to optimise the unmarshaling process,
  191.   minimising dynamic memory allocations. Also, at the stub side, the
  192.   stub function must provide the actual arguments to the real
  193.   stub-function when it is invoked - this requires making a temporary
  194.   local for each argument (whether [in] or [out]) and unmarshaling
  195.   into (and then marshaling from) those variables.
  196.   It can be seen from the descriptions of the IDL syntax above that
  197.   the possibilities are numerous, and the right type of allocation
  198.   strategy must be performed for each variant of the syntax. This is
  199.   why the job should ideally be performed by an IDL compiler, and
  200.   in future WIDL will do just that.
  201.   This description will document the behaviour of the type-descriptor
  202.   classes in each of the above cases, and recommend how they should be
  203.   handled by the generated proxy/stub code.
  204.   
  205.   The 'conformant array' Type Descriptor
  206.   --------------------------------------
  207.   The factory method NDRTYPES::carray_t() returns a type descriptor
  208.   designed to cope with conformant arrays. Marshaling conformant
  209.   arrays is always the same, in both the PROXY_MSHL and STUB_MSHL
  210.   phases. However, unmarshaling is a different matter.
  211.   
  212.   At the STUB_UNMSHL phase, unmarshaling can be optimised by letting
  213.   the temporary variable in the stub-function point into the
  214.   unmarshaling stream's buffer. To achieve this, the type-descriptor
  215.   must be bound to the address of the pointer-variable, so it
  216.   manipulate the contents.
  217.   Unmarshaling at the PROXY_UNMSHL stage is the most complex. If the
  218.   array-element type is a simple type, then the descriptor should be
  219.   bound to the start-address of the array, and should just unmarshal
  220.   directly into the caller-provided space. If the array-element is a
  221.   fixed-size structure and the size_is(,num) IDL syntax is being used,
  222.   then the type-descriptor must allocate dynamic memory to hold the
  223.   unmarshaled data, which the caller must eventually free (by calling
  224.   the CoTaskMemFree() function). This functionality is encoded in
  225.   NdrConfArray::unmarshal(), which makes the distinction between
  226.   simple types and others.
  227.   However, if the [out] array is an array of pointers to conformant
  228.   structures (see the Func(long,BAR**) example above) then the
  229.   complexity increases. The array is marshaled differently (the array
  230.   of pointer-referents is marshaled first, then each of the conformant
  231.   structures follows, in order, and NULL referents may be present) and
  232.   hence unmarshaling is different.
  233.   Currently, the type descriptors do not support this case -- it must
  234.   be hand-coded (by human hands, or by WIDL concocting the right
  235.   sequence of elements) -- and so only cope with the 2 cases outlined
  236.   earlier.
  237.   Variable-Binding Rules
  238.   ----------------------
  239.   Most of the NDR type-descriptors bind to the address of a variable,
  240.   whether marshaling or unmarshaling. The only exception is the
  241.   'array' type (class NdrArray) which binds to the start of the array,
  242.   i.e. the address of the first element. Note that conformant arrays
  243.   don't -- they follow the usual rules and bind to the address of a
  244.   variable holding the pointer to the first element of the array.
  245.   Pointer Types
  246.   -------------
  247.   
  248.   MIDL/WIDL supports 3 kinds of pointer-attributes, namely [ref],
  249.   [unique] and [ptr] (known as 'full') pointers. The difference
  250.   between unique and full pointers is that unique pointers must
  251.   literally be unique, i.e. there must be no aliasing between any 2
  252.   pointers within the context of a marshaling operation.
  253.   The [ref] pointer type indicates 'pass by reference' semantics, thus
  254.   a ref-pointer can never be NULL, and so [ref] pointers are not
  255.   marshaled. However, [unique] pointers can be NULL, and so do have to
  256.   be marshaled. Thus the type-descriptors for the pointer type (and
  257.   associated array and string types) are only used when the IDL
  258.   indicates a [unique] (or full) pointer. The pointer_t() descriptor
  259.   is generated by WIDL when a simple [unique] pointer is required,
  260.   i.e. an unsized, non-string pointer. If a dimension is supplied, or
  261.   the [string] attribute is used, then WIDL will generate a call to
  262.   either the carray_t() or wstring_t() descriptor, respectively.
  263.   In all cases where a [unique] pointer is utilised, the binding for
  264.   the descriptor is the address of the pointer variable. Only if a
  265.   [ref] string or fixed-size array is used as a method-arg is there a
  266.   potential problem.
  267.   Also, WIDL only supports conformant arrays, and not varying, or
  268.   conformant varying arrays. In IDL terms, this means the size_is
  269.   attribute is recognised, but max_is, length_is, etc, are not.
  270.   
  271. */
  272. #include <stdlib.h>
  273. #include "private/comMisc.h"
  274. #include "NdrTypes.h"
  275. #include "MemoryStream.h"
  276. #include "orpcLib.h"
  277. #include "private/vxdcomGlobals.h"
  278. #include "TraceCall.h"
  279. /* Include symbol for diab */
  280. extern "C" int include_vxdcom_NdrTypes (void)
  281.     {
  282.     return 0;
  283.     }
  284. //////////////////////////////////////////////////////////////////////////
  285. //
  286. // ARM-specific code for (un)marshaling doubles...
  287. //
  288. #if defined (CPU_FAMILY) && (CPU_FAMILY == ARM) && 
  289.     defined (VXDCOM_PLATFORM_VXWORKS) && (VXDCOM_PLATFORM_VXWORKS != 5)
  290. #ifdef __GNUC__
  291. template class NdrSimple<double>;
  292. #endif
  293. union armDouble
  294.     {
  295.     double        doubleValue;
  296.     struct
  297.         {
  298.         long        msw;
  299.         long        lsw;
  300.         }        txValue;
  301.     };
  302. static HRESULT marshalDouble (NdrMarshalStream * pStrm, double * value)
  303.     {
  304.     pStrm->align (sizeof (double));
  305.     armDouble d;
  306.     d.doubleValue = *value;
  307.     pStrm->insert (sizeof (long), &d.txValue.lsw, true);
  308.     return pStrm->insert (sizeof (long), &d.txValue.msw, true);
  309.     }
  310. HRESULT NdrSimple<double>::marshal1 (NdrMarshalStream* pStrm)
  311.     {
  312.     return marshalDouble(pStrm, m_pValue);
  313.     }
  314. static HRESULT unmarshalDouble (NdrUnmarshalStream * pStrm, double * value)
  315.     {
  316.     pStrm->align (sizeof (double));
  317.     armDouble d;
  318.     pStrm->extract (sizeof (long), &d.txValue.lsw, true);
  319.     HRESULT hr = pStrm->extract (sizeof (long), &d.txValue.msw, true);
  320.     if (SUCCEEDED (hr))
  321.         *value = d.doubleValue;
  322.     return hr;
  323.     }
  324.     
  325. HRESULT NdrSimple<double>::unmarshal1 (NdrUnmarshalStream* pStrm)
  326.     {
  327.     return unmarshalDouble(pStrm, m_pValue);
  328.     }
  329. #else
  330. static HRESULT marshalDouble (NdrMarshalStream * pStrm, double * value)
  331.     {
  332.     pStrm->align (sizeof (double));
  333.     return pStrm->insert (sizeof (double), value, true);
  334.     }
  335. static HRESULT unmarshalDouble (NdrUnmarshalStream * pStrm, double * value)
  336.     {
  337.     pStrm->align (sizeof (double));
  338.     return pStrm->extract (sizeof (double), value, true);
  339.     }
  340. #endif
  341. //////////////////////////////////////////////////////////////////////////
  342. //
  343. // (un)marshaling methods for enum types.
  344. //
  345. size_t NdrEnum::alignment () const
  346.     {
  347.     return (m_bV1Enum ? sizeof (DWORD) : sizeof (short));
  348.     }
  349. HRESULT NdrEnum::marshal1 (NdrMarshalStream* pStrm)
  350.     {
  351.     HRESULT hr = S_OK;
  352.     
  353.     if (m_bV1Enum)
  354.         {
  355.         // New-style 32-bit enum...
  356.         DWORD val = *m_pValue;
  357.         pStrm->align (alignment ());
  358.         hr = pStrm->insert (sizeof (val), &val, true);
  359.         }
  360.     else
  361.         {
  362.         // Old-style 16-bit enum...
  363.         short val = *m_pValue;
  364.         pStrm->align (alignment ());
  365.         hr = pStrm->insert (sizeof (val), &val, true);
  366.         }
  367.     return hr;
  368.     }
  369.     
  370. HRESULT NdrEnum::unmarshal1 (NdrUnmarshalStream* pStrm)
  371.     {
  372.     HRESULT hr = pStrm->align (alignment ());
  373.     if (FAILED (hr))
  374.         return hr;
  375.     if (m_bV1Enum)
  376.         {
  377.         // New-style 32-bit enum...
  378.         DWORD val;
  379.         hr = pStrm->extract (sizeof (val), &val, true);
  380.         if (FAILED (hr))
  381.             return hr;
  382.         *m_pValue = (DUMMY) val;
  383.         }
  384.     else
  385.         {
  386.         // Old-style 16-bit enum...
  387.         short val;
  388.         hr = pStrm->extract (sizeof (val), &val, true);
  389.         if (FAILED (hr))
  390.             return hr;
  391.         *m_pValue = (DUMMY) val;
  392.         }
  393.     return hr;
  394.     }
  395. //////////////////////////////////////////////////////////////////////////
  396. //
  397. void* NdrType::operator new (size_t n, NdrTypeFactory* pf)
  398.     {
  399.     return pf->allocate (n);
  400.     }
  401. //////////////////////////////////////////////////////////////////////////
  402. //
  403. void NdrType::operator delete (void*)
  404.     {}
  405. //////////////////////////////////////////////////////////////////////////
  406. //
  407. NdrTypeFactory::NdrTypeFactory (int hint)
  408.     {
  409.     TRACE_CALL;
  410.     size_t nBytes = hint * TYPESIZE;
  411.     m_begin = new char [nBytes];
  412.     m_curr = m_begin;
  413.     m_end = m_begin + nBytes;
  414.     }
  415. //////////////////////////////////////////////////////////////////////////
  416. //
  417. NdrTypeFactory::~NdrTypeFactory ()
  418.     {
  419.     TRACE_CALL;
  420.     if (m_begin)
  421.         delete [] m_begin;
  422.     }
  423. //////////////////////////////////////////////////////////////////////////
  424. //
  425. void* NdrTypeFactory::allocate (size_t nb)
  426.     {
  427.     COM_ASSERT((m_end - m_curr) > (int) nb);
  428.     if ((m_end - m_curr) < (int) nb)
  429.         return 0;
  430.     
  431.     void* pv = m_curr;
  432.     m_curr += nb;
  433.     return pv;
  434.     }
  435. //////////////////////////////////////////////////////////////////////////
  436. //
  437. // NdrType base-class default implementations of the marshaling
  438. // functions. Derived classes should put their main marshaling code in
  439. // marshal1() (and correspondingly, their main unmarshaling code in
  440. // unmarshal1()), the default implementations of marshal() and
  441. // unmarshal() simply call 1 then 2. This potential for splitting the
  442. // marshaling into 2 stages allows the marshaling of [unique] pointers
  443. // inside structures and arrays to work correctly.
  444. //
  445. HRESULT NdrType::marshal2 (NdrMarshalStream*)
  446.     {
  447.     return S_OK;
  448.     }
  449. HRESULT NdrType::unmarshal2 (NdrUnmarshalStream*)
  450.     {
  451.     return S_OK;
  452.     }
  453. HRESULT NdrType::marshal (NdrMarshalStream* pStrm)
  454.     {
  455.     HRESULT hr = marshal1 (pStrm);
  456.     if (FAILED (hr))
  457.         return hr;
  458.     return marshal2 (pStrm);
  459.     }
  460. HRESULT NdrType::unmarshal (NdrUnmarshalStream* pStrm)
  461.     {
  462.     HRESULT hr = unmarshal1 (pStrm);
  463.     if (FAILED (hr))
  464.         return hr;
  465.     return unmarshal2 (pStrm);
  466.     }
  467. void NdrType::arraySizeSet (int n)
  468.     {
  469.     m_ndrtypes.arraySize = n;
  470.     }
  471. int NdrType::arraySizeGet ()
  472.     {
  473.     return m_ndrtypes.arraySize;
  474.     }
  475. //////////////////////////////////////////////////////////////////////////
  476. //
  477. size_t NdrStruct::size (NdrUnmarshalStream* pStrm)
  478.     {
  479.     TRACE_CALL;
  480.     
  481.     size_t        nSize = 0;
  482.     for (size_t n=0; n < m_nMembers; ++n)
  483.         nSize += m_pMemberInfo [n].pType->size (pStrm);
  484.     return nSize;
  485.     }
  486. //////////////////////////////////////////////////////////////////////////
  487. //
  488. // NdrStruct::alignment -- the alignment of a structure is the largest
  489. // alignment() value of any of its members...
  490. //
  491. size_t NdrStruct::alignment () const
  492.     {
  493.     TRACE_CALL;
  494.     
  495.     size_t        nAlign = 0;
  496.     for (size_t i=0; i < m_nMembers; ++i)
  497.         {
  498.         size_t n = m_pMemberInfo [i].pType->alignment ();
  499.         if (n > nAlign)
  500.             nAlign = n;
  501.         }
  502.     return nAlign;
  503.     }
  504. //////////////////////////////////////////////////////////////////////////
  505. //
  506. // NdrStruct::init -- record structure info, including optionally the
  507. // index of the structure-member which holds the [size_is] value for
  508. // dynamically-sized structure members. This index will be -1 if there
  509. // is no dynamically-sized member in the structure.
  510. //
  511. void NdrStruct::init (size_t n, const NdrMemberInfo members [], int nsize_is)
  512.     {
  513.     TRACE_CALL;
  514.     
  515.     m_nMembers = n;
  516.     m_pMemberInfo = new NdrMemberInfo [n];
  517.     for (size_t i=0; i < n; ++i)
  518.         m_pMemberInfo[i] = members[i];
  519.     m_nSizeIs = nsize_is;
  520.     m_pInstance = 0;
  521.     }
  522. //////////////////////////////////////////////////////////////////////////
  523. //
  524. NdrStruct::~NdrStruct ()
  525.     {
  526.     if (m_pMemberInfo)
  527.         delete [] m_pMemberInfo;
  528.     }
  529. //////////////////////////////////////////////////////////////////////////
  530. //
  531. // NdrStruct::bind -- bind to a new instance of the type we
  532. // represent. We defer the binding of individual structure members
  533. // until the last minute...
  534. //
  535. void NdrStruct::bind (void* pv)
  536.     {
  537.     TRACE_CALL;
  538.     
  539.     m_pInstance = pv;
  540.     }
  541. //////////////////////////////////////////////////////////////////////////
  542. //
  543. // NdrConfStruct::confElemResize -- calculate the actual value of the
  544. // 'size_is' attribute, given its index in the m_nSizeIs member, and
  545. // resize the appropriate structure-member to this value. This
  546. // method should *NOT* be called if this index is negative, i.e. there
  547. // is no size_is attribute...
  548. //
  549. size_t NdrConfStruct::confElemResize ()
  550.     {
  551.     COM_ASSERT (m_nSizeIs >= 0);
  552.     
  553.     char* addr = (char*) m_pInstance;
  554.     
  555.     // find the value of the 'conformance' variable
  556.     NdrMemberInfo* pConf = &m_pMemberInfo [m_nSizeIs];
  557.     pConf->pType->bind (addr + pConf->nOffset);
  558.     unsigned long nArrayCount = pConf->pType->value ();
  559.     // resize the varying-length element so it knows to marshal 
  560.     // the right number of items (if applicable)...
  561.     m_pMemberInfo [m_nMembers - 1].pType->resize (nArrayCount);
  562.     
  563.     return nArrayCount;
  564.     }
  565. //////////////////////////////////////////////////////////////////////////
  566. //
  567. // NdrStruct::marshal1 -- call marshal1() for all the members...
  568. //
  569. HRESULT NdrStruct::marshal1 (NdrMarshalStream* pStrm)
  570.     {
  571.     TRACE_CALL;
  572.     
  573.     // find the start of the current instance
  574.     char* addr = (char*) m_pInstance;
  575.     
  576.     // align
  577.     pStrm->align (alignment ());
  578.     // call marshal1() for each element 
  579.     for (size_t n=0; n < m_nMembers; ++n)
  580.         {
  581.         m_pMemberInfo [n].pType->bind (addr + m_pMemberInfo [n].nOffset);
  582.         HRESULT hr = m_pMemberInfo [n].pType->marshal1 (pStrm);
  583.         if (FAILED (hr))
  584.             return hr;
  585.         }
  586.     return S_OK;
  587.     }
  588. //////////////////////////////////////////////////////////////////////////
  589. //
  590. // NdrStruct::marshal2 -- call marshal2() for all the members. Any
  591. // members which have a valid 'size_is' indicator must be resized to
  592. // the value nominated in their member-descriptor. This information is
  593. // provided for all struct and cstruct members which have a [size_is]
  594. // attribute present...
  595. //
  596. HRESULT NdrStruct::marshal2 (NdrMarshalStream* pStrm)
  597.     {
  598.     TRACE_CALL;
  599.     
  600.     char* addr = (char*) m_pInstance;
  601.     
  602.     // call marshal2() for each element 
  603.     for (size_t n=0; n < m_nMembers; ++n)
  604.         {
  605.         NdrMemberInfo& member = m_pMemberInfo [n];
  606.         // Does it have a [size_is] attribute...
  607.         if (member.nSizeIs >= 0)
  608.             {
  609.             NdrMemberInfo& sizeMem = m_pMemberInfo [member.nSizeIs];
  610.             sizeMem.pType->bind (addr + sizeMem.nOffset);
  611.             size_t size_is = sizeMem.pType->value ();
  612.             member.pType->resize (size_is);
  613.             }
  614.         // Now marshal the actual member...
  615.         member.pType->bind (addr + member.nOffset);
  616.         HRESULT hr = member.pType->marshal2 (pStrm);
  617.         if (FAILED (hr))
  618.             return hr;
  619.         }
  620.     return S_OK;
  621.     }
  622. //////////////////////////////////////////////////////////////////////////
  623. //
  624. // NdrStruct::unmarshal1 -- unmarshal all the structure members one by
  625. // one from the stream. The repeated operation mirrors the marshaling
  626. // side... 
  627. //
  628. HRESULT NdrStruct::unmarshal1 (NdrUnmarshalStream* pStrm)
  629.     {
  630.     TRACE_CALL;
  631.     
  632.     S_DEBUG (LOG_DCOM, "U1:struct @ " << m_pInstance);
  633.     // find the start of the current instance
  634.     char* addr = (char*) m_pInstance;
  635.     
  636.     // align
  637.     pStrm->align (alignment ());
  638.     // call unmarshal1() for each element
  639.     for (size_t n=0; n < m_nMembers; ++n)
  640.         {
  641.         m_pMemberInfo [n].pType->bind (addr + m_pMemberInfo [n].nOffset);
  642.         HRESULT hr = m_pMemberInfo [n].pType->unmarshal1 (pStrm);
  643.         if (FAILED (hr))
  644.             return hr;
  645.         }
  646.     return S_OK;
  647.     }
  648. //////////////////////////////////////////////////////////////////////////
  649. //
  650. // NdrStruct::unmarshal2 -- call unmarshal2() for all the members...
  651. //
  652. HRESULT NdrStruct::unmarshal2 (NdrUnmarshalStream* pStrm)
  653.     {
  654.     TRACE_CALL;
  655.     
  656.     char* addr = (char*) m_pInstance;
  657.     
  658.     S_DEBUG (LOG_DCOM, "U2:struct @ " << m_pInstance);
  659.     // call unmarshal2() for each element
  660.     for (size_t n=0; n < m_nMembers; ++n)
  661.         {
  662.         m_pMemberInfo [n].pType->bind (addr + m_pMemberInfo [n].nOffset);
  663.         HRESULT hr = m_pMemberInfo [n].pType->unmarshal2 (pStrm);
  664.         if (FAILED (hr))
  665.             return hr;
  666.         }
  667.     return S_OK;
  668.     }
  669. //////////////////////////////////////////////////////////////////////////
  670. //
  671. // NdrConfStruct::marshal1 -- marshal all the structure members one by
  672. // one into the stream, preceded by the array length. On entry, this
  673. // descriptor is bound to the start of the structure...
  674. //
  675. HRESULT NdrConfStruct::marshal1 (NdrMarshalStream* pStrm)
  676.     {
  677.     TRACE_CALL;
  678.     // Always calculate dynamic size for conf-structs...
  679.     unsigned long nArrayCount = confElemResize ();
  680.     
  681.     // marshal array-count first, as 4-byte value (unsigned long)
  682.     pStrm->align (4);
  683.     HRESULT hr = pStrm->insert (4, &nArrayCount, true);
  684.     if (FAILED (hr))
  685.         return hr;
  686.     S_DEBUG (LOG_DCOM, "M1:cstruct:size_is=" << nArrayCount);
  687.     
  688.     // marshal structure member-wise
  689.     return NdrStruct::marshal1 (pStrm);
  690.     }
  691. //////////////////////////////////////////////////////////////////////////
  692. //
  693. // NdrConfStruct::unmarshal1 -- unmarshal all the structure members one
  694. // by one from the stream, preceded by the array-length of the last
  695. // member. The m_pInstance pointer is pointing to the start of space
  696. // allocated to hold the structure itself...
  697. //
  698. HRESULT NdrConfStruct::unmarshal1 (NdrUnmarshalStream* pStrm)
  699.     {
  700.     TRACE_CALL;
  701.     
  702.     S_DEBUG (LOG_DCOM, "U1:cstruct");
  703.     
  704.     // unmarshal structure member-wise
  705.     return NdrStruct::unmarshal1 (pStrm);
  706.     }
  707. //////////////////////////////////////////////////////////////////////////
  708. //
  709. // NdrConfStruct::size -- during unmarshaling, extract the required
  710. // size of this structure (accounting for the variable-length array)
  711. // from the unmarshaling stream, and modify the descriptor for that
  712. // array to hold the discovered size.
  713. //
  714. size_t NdrConfStruct::size (NdrUnmarshalStream* pStrm)
  715.     {
  716.     TRACE_CALL;
  717.     
  718.     // unmarshal array-count first, as 4-byte value (unsigned long)
  719.     unsigned long nArrayCount;
  720.     pStrm->align (4);
  721.     HRESULT hr = pStrm->extract (4, &nArrayCount, true);
  722.     if (FAILED (hr))
  723.         return hr;
  724.     S_DEBUG (LOG_DCOM, "SZ:cstruct:size_is=" << nArrayCount);
  725.     
  726.     // resize the varying-length element so it knows to unmarshal 
  727.     // the right number of items (if applicable)...
  728.     m_pMemberInfo [m_nMembers - 1].pType->resize (nArrayCount);
  729.     // Now add up the size of all elements...
  730.     size_t nSize = 0;
  731.     for (size_t n=0; n < m_nMembers; ++n)
  732.         nSize += m_pMemberInfo [n].pType->size (pStrm);
  733.     return nSize;
  734.     }
  735.  
  736. //////////////////////////////////////////////////////////////////////////
  737. //
  738. void NdrArray::init
  739.     (
  740.     const NdrTypeDesc&        elementType,
  741.     size_t                elemSize,
  742.     size_t                max,
  743.     size_t                offset,
  744.     size_t                len
  745.     )
  746.     {
  747.     TRACE_CALL;
  748.     
  749.     m_pElementType = elementType;
  750.     m_nElementSize = elemSize;
  751.     m_arraySize = len;
  752.     m_offset = offset;
  753.     m_max = max;
  754.     m_ptr = 0;
  755.     }
  756. //////////////////////////////////////////////////////////////////////////
  757. //
  758. size_t NdrArray::size (NdrUnmarshalStream*)
  759.     {
  760.     return m_arraySize * m_nElementSize;
  761.     }
  762. //////////////////////////////////////////////////////////////////////////
  763. //
  764. size_t NdrArray::alignment () const
  765.     {
  766.     return m_pElementType->alignment ();
  767.     }
  768. //////////////////////////////////////////////////////////////////////////
  769. //
  770. // NdrArray::bind -- bind to an actual array of whatever type we are
  771. // dealing with...
  772. //
  773. void NdrArray::bind (void* pv)
  774.     {
  775.     TRACE_CALL;
  776.     
  777.     // Bind to instance address...
  778.     m_ptr = pv;
  779.     }
  780. //////////////////////////////////////////////////////////////////////////
  781. //
  782. // NdrArray::marshal1 -- marshal the array into the stream...
  783. //
  784. HRESULT NdrArray::marshal1 (NdrMarshalStream* pStrm)
  785.     {
  786.     TRACE_CALL;
  787.     
  788.     // locate start of array in user memory
  789.     char* pmem = (char*) m_ptr;
  790.     // align
  791.     pStrm->align (alignment ());
  792.     
  793.     // call marshal1() for individual elements
  794.     for (size_t n=0; n < m_arraySize; ++n)
  795.         {
  796.         m_pElementType->bind (pmem);
  797.         HRESULT hr = m_pElementType->marshal1 (pStrm);
  798.         if (FAILED (hr))
  799.             return hr;
  800.         pmem += m_nElementSize;
  801.         }
  802.     return S_OK;
  803.     }
  804. //////////////////////////////////////////////////////////////////////////
  805. //
  806. // NdrArray::marshal2 -- call marshal2() for each element
  807. //
  808. HRESULT NdrArray::marshal2 (NdrMarshalStream* pStrm)
  809.     {
  810.     TRACE_CALL;
  811.     
  812.     // locate start of array in user memory
  813.     char* pmem = (char*) m_ptr;
  814.     // align
  815.     pStrm->align (alignment ());
  816.     
  817.     // call marshal2() for individual elements
  818.     for (size_t n=0; n < m_arraySize; ++n)
  819.         {
  820.         m_pElementType->bind (pmem);
  821.         HRESULT hr = m_pElementType->marshal2 (pStrm);
  822.         if (FAILED (hr))
  823.             return hr;
  824.         pmem += m_nElementSize;
  825.         }
  826.     return S_OK;
  827.     }
  828. //////////////////////////////////////////////////////////////////////////
  829. //
  830. // NdrArray::unmarshal1 -- unmarshal the fixed-size array from the
  831. // stream, assuming that the memory to hold the array already
  832. // exists...
  833. //
  834. HRESULT NdrArray::unmarshal1 (NdrUnmarshalStream* pStrm)
  835.     {
  836.     TRACE_CALL;
  837.     
  838.     // locate the start of the array
  839.     char* pmem = (char*) m_ptr;
  840.     S_DEBUG (LOG_DCOM, "U1:array");
  841.     
  842.     // align
  843.     pStrm->align (alignment ());
  844.     
  845.     // call unmarshal1() for elements one at a time
  846.     for (size_t n=0; n < m_arraySize; ++n)
  847.         {
  848.         m_pElementType->bind (pmem);
  849.         HRESULT hr = m_pElementType->unmarshal1 (pStrm);
  850.         if (FAILED (hr))
  851.             return hr;
  852.         pmem += m_nElementSize;
  853.         }
  854.     return S_OK;
  855.     }
  856. //////////////////////////////////////////////////////////////////////////
  857. //
  858. // NdrArray::unmarshal2 -- call unmarshal2() for each element...
  859. //
  860. HRESULT NdrArray::unmarshal2 (NdrUnmarshalStream* pStrm)
  861.     {
  862.     TRACE_CALL;
  863.     
  864.     // locate the start of the array
  865.     char* pmem = (char*) m_ptr;
  866.     S_DEBUG (LOG_DCOM, "U2:array");
  867.     
  868.     // align
  869.     pStrm->align (alignment ());
  870.     
  871.     // call unmarshal2() for elements one at a time
  872.     for (size_t n=0; n < m_arraySize; ++n)
  873.         {
  874.         m_pElementType->bind (pmem);
  875.         HRESULT hr = m_pElementType->unmarshal2 (pStrm);
  876.         if (FAILED (hr))
  877.             return hr;
  878.         pmem += m_nElementSize;
  879.         }
  880.     return S_OK;
  881.     }
  882. //////////////////////////////////////////////////////////////////////////
  883. //
  884. size_t NdrConfArray::size (NdrUnmarshalStream* pStrm)
  885.     {
  886.     // unmarshal array-count first, as 4-byte value (unsigned long)
  887.     unsigned long nElements;
  888.     pStrm->align (4);
  889.     HRESULT hr = pStrm->extract (4, &nElements, true);
  890.     if (FAILED (hr))
  891.         return hr;
  892.     
  893.     S_DEBUG (LOG_DCOM, "SZ:carray:size_is=" << nElements);
  894.     
  895.     // In NDR rules for arrays, 'conformance' value as found here does
  896.     // not have to be emitted to a variable - the argument that indicates
  897.     // the length will be marshaled separately. So, all we do is set
  898.     // the size of the array to be unmarshaled, and treat it as 'fixed
  899.     // length' from then on...
  900.     m_arraySize = nElements;
  901.     // Return total size of array...
  902.     return m_arraySize * m_nElementSize;
  903.     }
  904. //////////////////////////////////////////////////////////////////////////
  905. //
  906. // NdrConfArray::marshal1 -- marshal the array into the stream. On
  907. // entry, the descriptor is bound to the start of the array...
  908. //
  909. HRESULT NdrConfArray::marshal1 (NdrMarshalStream* pStrm)
  910.     {
  911.     TRACE_CALL;
  912.     
  913.     // marshal array-count first, as 4-byte value (unsigned long)
  914.     unsigned long nElements = m_arraySize;
  915.     pStrm->align (4);
  916.     HRESULT hr = pStrm->insert (4, &nElements, true);
  917.     if (FAILED (hr))
  918.         return hr;
  919.     // Defer to base-class...
  920.     return NdrArray::marshal1 (pStrm);
  921.     }
  922. //////////////////////////////////////////////////////////////////////////
  923. //
  924. // NdrConfArray::unmarshal1 -- unmarshal the array from the stream...
  925. //
  926. HRESULT NdrConfArray::unmarshal1 (NdrUnmarshalStream* pStrm)
  927.     {
  928.     TRACE_CALL;
  929.     
  930.     S_DEBUG (LOG_DCOM, "U1:carray");
  931.     
  932.     // treat as a normal array now...
  933.     return NdrArray::unmarshal1 (pStrm);
  934.     }
  935. //////////////////////////////////////////////////////////////////////////
  936. //
  937. // NdrConfVarArray::size -- returns size of memory needed to hold
  938. // unmarshaled array. It unmarshals the 'max' count, then the offset
  939. // (which should always be zero), then defers to the base class
  940. // (NdrConfArray) to unmarshal the actual transmitted size. This is
  941. // the value we return, since this is the amount of memory we would
  942. // need to allocate...
  943. //
  944. size_t NdrConfVarArray::size (NdrUnmarshalStream* pStrm)
  945.     {
  946.     // unmarshal array-max and offset first, as 4-byte values
  947.     // (unsigned long)...
  948.     
  949.     pStrm->align (4);
  950.     pStrm->extract (4, &m_max, true);
  951.     HRESULT hr = pStrm->extract (4, &m_offset, true);
  952.     if (FAILED (hr))
  953.         return hr;
  954.     // Return transmitted size of array...
  955.     return NdrConfArray::size (pStrm);
  956.     }
  957. //////////////////////////////////////////////////////////////////////////
  958. //
  959. // NdrConfVarArray::marshal1 -- marshal the array into the stream. On
  960. // entry, the descriptor is bound to the start of the array...
  961. //
  962. HRESULT NdrConfVarArray::marshal1 (NdrMarshalStream* pStrm)
  963.     {
  964.     TRACE_CALL;
  965.     
  966.     // marshal array-max, and zero-offset first, as 4-byte values
  967.     // (unsigned long)...
  968.     pStrm->align (4);
  969.     pStrm->insert (4, &m_max, true);
  970.     HRESULT hr = pStrm->insert (4, &m_offset, true);
  971.     if (FAILED (hr))
  972.         return hr;
  973.     // Defer to base-class to marshal the actual runtime size of the
  974.     // array, plus the array contents...
  975.     return NdrConfArray::marshal1 (pStrm);
  976.     }
  977. //////////////////////////////////////////////////////////////////////////
  978. //
  979. // NdrInterface::bind -- bind to an instance of an interface
  980. // pointer. The address in 'pv' is always the address of the
  981. // pointer-variable itself.
  982. void NdrInterface::bind (void* pv)
  983.     {
  984.     TRACE_CALL;
  985.     
  986.     m_pPointer = (IUnknown**) pv;
  987.     }
  988. //////////////////////////////////////////////////////////////////////////
  989. //
  990. // NdrInterface::marshal1 -- marshal the interface-pointer, it goes
  991. // into a MInterfacePointer conformant structure before being sent
  992. // over the wire...
  993. //
  994. HRESULT NdrInterface::marshal1 (NdrMarshalStream* pStrm)
  995.     {
  996.     TRACE_CALL;
  997.     // Get hold of the interface ptr...
  998.     IUnknown* punk = * (IUnknown**) m_pPointer;
  999.     // We need to marshal a 'pointer referent' first...
  1000.     pStrm->align (4);
  1001.     HRESULT hr = pStrm->insert (sizeof (long), &punk, true);
  1002.     return hr;
  1003.     }
  1004. HRESULT NdrInterface::marshal2 (NdrMarshalStream* pStrm)
  1005.     {
  1006.     HRESULT hr = S_OK;
  1007.     IUnknown* punk = * (IUnknown**) m_pPointer;
  1008.     // If non-NULL pointer, we must marshal pointer/OBJREF...
  1009.     if (punk)
  1010.         {
  1011.         // Use a 'memory stream' to marshal the interface into
  1012.         VxRWMemStream* pMemStrm = new VxRWMemStream;
  1013.         IStream* pIStream=0;
  1014.         // QI for IStream, this gets us one reference...
  1015.         hr = pMemStrm->QueryInterface (IID_IStream,
  1016.                                        (void**) &pIStream);
  1017.         if (FAILED (hr))
  1018.             return hr;
  1019.     
  1020.         // marshal the interface-ptr
  1021.         hr = CoMarshalInterface (pIStream, m_iid, punk, 0, 0, 0);
  1022.         if (SUCCEEDED (hr))
  1023.             {
  1024.             // okay we got it - now align the stream and put the
  1025.             // marshaling packet into there, in the shape of a
  1026.             // MInterfacePointer structure, i.e. conformance-value
  1027.             // (length), then ulCntData, then abData[] containing the
  1028.             // actual packet...
  1029.             ULONG ulCntData = pMemStrm->size ();
  1030.         
  1031.             pStrm->insert (sizeof (ulCntData), &ulCntData, true);
  1032.             pStrm->insert (sizeof (ulCntData), &ulCntData, true);
  1033.             hr = pStrm->insert (ulCntData, pMemStrm->begin (), false);
  1034.             }
  1035.         pMemStrm->Release ();
  1036.         }
  1037.     
  1038.     return hr;
  1039.     }
  1040. //////////////////////////////////////////////////////////////////////////
  1041. //
  1042. // NdrInterface::unmarshal -- see marshal() method for details of
  1043. // formatting of a marshaled interface pointer...
  1044. // A cosutom marsh routine is required so that unmarshal2 can be used by
  1045. // the SAFEARRAY routines.
  1046. //
  1047. HRESULT NdrInterface::unmarshal (NdrUnmarshalStream* pStrm)
  1048.     {
  1049.     HRESULT hr = unmarshal1 (pStrm);
  1050.     // Check to see if the ptr is NULL and stop if it is,
  1051.     if (hr == S_FALSE)
  1052.         {
  1053.         return S_OK;
  1054.         }
  1055.     
  1056.     if (FAILED (hr))
  1057.         return hr;
  1058.     return unmarshal2 (pStrm);
  1059.     }
  1060. //////////////////////////////////////////////////////////////////////////
  1061. //
  1062. // NdrInterface::unmarshal1 -- see marshal() method for details of
  1063. // formatting of a marshaled interface pointer...
  1064. //
  1065. HRESULT NdrInterface::unmarshal1 (NdrUnmarshalStream* pStrm)
  1066.     {
  1067.     TRACE_CALL;
  1068.     
  1069.     // align the buffer before we begin
  1070.     HRESULT hr = pStrm->align (4);
  1071.     // unmarshal the conformance-value (length), then the conf-array
  1072.     // member 'ulCntData' (which will be the same) and then the array
  1073.     // of bytes...
  1074.     
  1075.     // need to extract 'ptr referent' first...
  1076.     ULONG pp;
  1077.     hr = pStrm->extract (sizeof (pp), &pp, true);
  1078.     // If ptr is NULL, thats okay, but we have nothing else to do so
  1079.     // return a dummy code to unmarshal to indicate this.
  1080.     if (pp == 0)
  1081.         return S_FALSE;
  1082.     return hr;
  1083.     }
  1084.     
  1085. HRESULT NdrInterface::unmarshal2 (NdrUnmarshalStream* pStrm)
  1086.     {
  1087.     TRACE_CALL;
  1088.     HRESULT     hr;
  1089.     // Use a 'memory stream' to hold the marshaling packet, and make
  1090.     // sure we don't try to delete it from the stack!
  1091.     VxRWMemStream memStrm;
  1092.     memStrm.AddRef ();
  1093.     // Now extract the actual MInterfacePointer...
  1094.     ULONG length;
  1095.     hr = pStrm->extract (sizeof (length), &length, true);
  1096.     if (SUCCEEDED (hr))
  1097.         {
  1098.         ULONG ulCntData;
  1099.         hr = pStrm->extract (sizeof (ulCntData), &ulCntData, true);
  1100.         if (SUCCEEDED (hr))
  1101.             {
  1102.             COM_ASSERT(length == ulCntData);
  1103.             // get the bytes from the unmarshaling stream into the
  1104.             // memory-stream, ready for CoUnmarshalInterface()...
  1105.             
  1106.             memStrm.insert (pStrm->curr (), ulCntData);
  1107.             hr = pStrm->extract (memStrm.locationGet (), 0, false);
  1108.             if (SUCCEEDED (hr))
  1109.                 {
  1110.                 // unmarshal the interface
  1111.                 memStrm.locationSet (0);
  1112.                 hr = CoUnmarshalInterface (static_cast<IStream*> (&memStrm),
  1113.                                            m_iid,
  1114.                                            (void**) m_pPointer);
  1115.                 }
  1116.             }
  1117.         }
  1118.     return hr;
  1119.     }
  1120. //////////////////////////////////////////////////////////////////////////
  1121. //
  1122. // NdrBSTR::marshal1/2 -- according to the MS headers (and IDL) the wire
  1123. // format of a BSTR is FLAGGED_WORD_BLOB structure -- a flags-word,
  1124. // the array-length, then the array of wide-chars. However, looking at
  1125. // real marshaled packets on the network shows another structure where
  1126. // the characters 'User' precede the string! Which is right???
  1127. // Obviously, the info snooped off the network.
  1128. //
  1129. // The format is 'User' followed by the string as a CV-array of wide
  1130. // chars... 
  1131. //
  1132. HRESULT NdrBSTR::marshal1 (NdrMarshalStream* pStrm)
  1133.     {
  1134.     // align buffer correctly first
  1135.     HRESULT hr = pStrm->align (sizeof (long));
  1136.     if (FAILED (hr))
  1137.         return hr;
  1138.     
  1139.     // now insert the chars 'User' one at a time
  1140.     char userText [] = "User";
  1141.     
  1142.     return pStrm->insert (4, userText, false);
  1143.     }
  1144. HRESULT NdrBSTR::marshal2 (NdrMarshalStream* pStrm)
  1145.     {
  1146.     long a, b, c;
  1147.     
  1148.     BSTR bstr = *m_pBstr;
  1149.     if (bstr)
  1150.         {
  1151.         b = ::SysStringByteLen (bstr);
  1152.         a = c = (b/2);
  1153.         }
  1154.     else
  1155.         {
  1156.         a = c = 0;
  1157.         b = -1;
  1158.         }
  1159.     
  1160.     // align first
  1161.     HRESULT hr = pStrm->align (sizeof (long));
  1162.     if (FAILED (hr))
  1163.         return hr;
  1164.     
  1165.     // now insert the length words
  1166.     pStrm->insert (sizeof (long), &a, true);
  1167.     pStrm->insert (sizeof (long), &b, true);
  1168.     hr = pStrm->insert (sizeof (long), &c, true);
  1169.     if (FAILED (hr))
  1170.         return hr;
  1171.     // Now insert the text -- we assume it is wide-character data,
  1172.     // unless the user-configurable policy parameter has been set,
  1173.     // which means we should treat BSTRs as byte arrays...
  1174.     if (vxdcomBSTRPolicy == 0)
  1175.         {
  1176.         // treat BSTR as array of OLECHARs, marshaling each one
  1177.         // individually so byte-ordering is preserved...
  1178.         for (long n=0; n < a; ++n)
  1179.             hr = pStrm->insert (sizeof (short), &bstr[n], true);
  1180.         }
  1181.     else
  1182.         hr = pStrm->insert (b, bstr, false);
  1183.     return hr;
  1184.     }
  1185. //////////////////////////////////////////////////////////////////////////
  1186. //
  1187. // NdrBSTR::unmarshal1 -- simply reverses the above process...
  1188. //
  1189. HRESULT NdrBSTR::unmarshal1 (NdrUnmarshalStream* pStrm)
  1190.     {
  1191.     char user [8];
  1192.     /// align first
  1193.     HRESULT hr = pStrm->align (sizeof (long));
  1194.     if (FAILED (hr))
  1195.         return hr;
  1196.     
  1197.     for (int n=0; n < 4; ++n)
  1198.         pStrm->extract (sizeof (char), &user [n], false);
  1199.     user [4] = 0;
  1200.     if (strcmp (user, "User") != 0)
  1201.         return E_UNEXPECTED;
  1202.     return S_OK;
  1203.     }
  1204. HRESULT NdrBSTR::unmarshal2 (NdrUnmarshalStream* pStrm)
  1205.     {
  1206.     /// align first
  1207.     HRESULT hr = pStrm->align (sizeof (long));
  1208.     if (FAILED (hr))
  1209.         return hr;
  1210.     
  1211.     // now unmarshal length fields
  1212.     long a, b, c;
  1213.     pStrm->extract (sizeof (long), &a, true);
  1214.     pStrm->extract (sizeof (long), &b, true);
  1215.     hr = pStrm->extract (sizeof (long), &c, true);
  1216.     // 'a' should == 'c' and 'b' is twice 'a', unless the BSTR is
  1217.     // NULL, in which case 'a' and 'c' are zero and 'b' is -1 (or
  1218.     // 0xFFFFFFFF if you prefer)...
  1219.     BSTR bstr = 0;
  1220.     if (a)
  1221.         {
  1222.         COM_ASSERT(a == c);
  1223.         COM_ASSERT(b == 2*a);
  1224.         // Get a string - remember, we are working in terms of OLECHARs
  1225.         // unless the system was built with the 'marshal as chars' policy
  1226.         bstr = SysAllocStringLen (0, a);
  1227.         // Read the string - if we are treating BSTRs as array of
  1228.         // OLECHAR then we need to marshal each wide-char individually
  1229.         // to retain byte-ordering...
  1230.         if (vxdcomBSTRPolicy == 0)
  1231.             {
  1232.             for (long n=0; n < a; ++n)
  1233.                 hr = pStrm->extract (sizeof (short), &bstr [n], true);
  1234.             }
  1235.         else
  1236.             hr = pStrm->extract (b, bstr, false);
  1237.         
  1238.         // Terminate the string...
  1239.         bstr [a] = 0;
  1240.         }
  1241.     *m_pBstr = bstr;
  1242.     return hr;
  1243.     }
  1244. //////////////////////////////////////////////////////////////////////////
  1245. //
  1246. // Strings are marshaled as conformant varying arrays, with both the
  1247. // max and the length being strlen() + 1 effectively...
  1248. //
  1249.  
  1250. HRESULT NdrWString::marshal1 (NdrMarshalStream* pStrm)
  1251.     {
  1252.     pStrm->align (4);
  1253.     WCHAR* str = m_pString;
  1254.     m_len = vxcom_wcslen (str) + 1;
  1255.     m_max = m_len;
  1256.     m_offset = 0;
  1257.     pStrm->insert (sizeof (m_max), &m_max, true);
  1258.     pStrm->insert (sizeof (m_offset), &m_offset, true);
  1259.     HRESULT hr = pStrm->insert (sizeof (m_len), &m_len, true);
  1260.     if (FAILED (hr))
  1261.         return hr;
  1262.     for (ULONG i=0; i < m_len; ++i)
  1263.         hr = pStrm->insert (sizeof(WCHAR), &str [i], true);
  1264.     return hr;
  1265.     }
  1266. //////////////////////////////////////////////////////////////////////////
  1267. //
  1268. HRESULT NdrWString::unmarshal1 (NdrUnmarshalStream* pStrm)
  1269.     {
  1270.     HRESULT hr = S_OK;
  1271.     S_DEBUG (LOG_DCOM, "U1:wstring");
  1272.     
  1273.     WCHAR* wsz = m_pString + m_offset;
  1274.     for (ULONG i=0; i < m_len; ++i)
  1275.         hr = pStrm->extract (sizeof(WCHAR), &wsz [i], true);
  1276.     return hr;
  1277.     }
  1278. //////////////////////////////////////////////////////////////////////////
  1279. //
  1280. size_t NdrWString::size (NdrUnmarshalStream* pStrm)
  1281.     {
  1282.     pStrm->align (4);
  1283.     pStrm->extract (sizeof (m_max), &m_max, true);
  1284.     pStrm->extract (sizeof (m_offset), &m_offset, true);
  1285.     HRESULT hr = pStrm->extract (sizeof (m_len), &m_len, true);
  1286.     if (FAILED (hr))
  1287.         return 0;
  1288.     size_t nBytes = m_max * sizeof(WCHAR);
  1289.     S_DEBUG (LOG_DCOM, "SZ:wstring:len=" << nBytes);
  1290.     
  1291.     return nBytes;
  1292.     }
  1293.  
  1294. //////////////////////////////////////////////////////////////////////////
  1295. //
  1296. HRESULT NdrCString::marshal1 (NdrMarshalStream* pStrm)
  1297.     {
  1298.     pStrm->align (4);
  1299.     m_len = strlen (m_pString) + 1;
  1300.     m_max = m_len;
  1301.     m_offset = 0;
  1302.     pStrm->insert (sizeof (m_max), &m_max, true);
  1303.     pStrm->insert (sizeof (m_offset), &m_offset, true);
  1304.     pStrm->insert (sizeof (m_len), &m_len, true);
  1305.     return pStrm->insert (m_len, m_pString + m_offset, false);
  1306.     }
  1307. //////////////////////////////////////////////////////////////////////////
  1308. //
  1309. HRESULT NdrCString::unmarshal1 (NdrUnmarshalStream* pStrm)
  1310.     {
  1311.     return pStrm->extract (m_len, m_pString + m_offset, false);
  1312.     }
  1313. //////////////////////////////////////////////////////////////////////////
  1314. //
  1315. size_t NdrCString::size (NdrUnmarshalStream* pStrm)
  1316.     {
  1317.     pStrm->align (4);
  1318.     pStrm->extract (sizeof (m_max), &m_max, true);
  1319.     pStrm->extract (sizeof (m_offset), &m_offset, true);
  1320.     HRESULT hr = pStrm->extract (sizeof (m_len), &m_len, true);
  1321.     if (FAILED (hr))
  1322.         return 0;
  1323.     return m_max;
  1324.     }
  1325.  
  1326. //////////////////////////////////////////////////////////////////////////
  1327. //
  1328. // NdrPointer::resize -- no sense in resizing the pointer, but as it
  1329. // may be pointing to an array or something, we simply pass it on...
  1330. //
  1331. void NdrPointer::resize (size_t n)
  1332.     {
  1333.     m_pointeeType->resize (n);
  1334.     }
  1335. //////////////////////////////////////////////////////////////////////////
  1336. //
  1337. // NdrPointer::marshal1 -- first-stage of marshaling a pointer. If its
  1338. // a [unique] pointer, just deal with the pointer-referent, deferring
  1339. // the pointee until marshal2() time...
  1340. //
  1341. HRESULT NdrPointer::marshal1 (NdrMarshalStream* pStrm)
  1342.     {
  1343.     // Find actual pointer value from binding...
  1344.     void* referent = *m_pPtr;
  1345.     
  1346.     if (! m_refptr)
  1347.         {
  1348.         // Its a [unique] ptr...
  1349.         pStrm->align (4);
  1350.         HRESULT hr = pStrm->insert (sizeof (long), &referent, true);
  1351.         if (FAILED (hr))
  1352.             return hr;
  1353.         }
  1354.     return S_OK;
  1355.     }
  1356. HRESULT NdrPointer::marshal2 (NdrMarshalStream* pStrm)
  1357.     {
  1358.     // Find actual pointer value from binding...
  1359.     void* referent = *m_pPtr;
  1360.     // Nothing to do if its NULL...
  1361.     if (referent == 0)
  1362.         return S_OK;
  1363.     
  1364.     // Either a [unique] ptr with non-NULL referent, or a [ref]
  1365.     // pointer, so go ahead and marshal the pointee...
  1366.     m_pointeeType->bind (referent);
  1367.     return m_pointeeType->marshal (pStrm);
  1368.     }
  1369. //////////////////////////////////////////////////////////////////////////
  1370. //
  1371. // NdrPointer::unmarshal1/2 -- when unmarshaling pointers, we need to
  1372. // keep the pointer-value (actually, the 'referent' which is not a
  1373. // true pointer, just an indicator of NULL-ness or otherwise)
  1374. // somewhere safe. Formerly, it was kept in m_referent, but since this
  1375. // may be re-used inside, for example, an array of pointers, by many
  1376. // pointer instances, we now keep the referent in '*m_pPtr' between
  1377. // calls to unmarshal1() and unmarshal2()...
  1378. //
  1379. HRESULT NdrPointer::unmarshal1 (NdrUnmarshalStream* pStrm)
  1380.     {
  1381.     // Now decide how to dereference this pointer. If its a [ref]
  1382.     // pointer then, by definition, it must point to something (its a
  1383.     // pass-by-reference)...
  1384.     if (m_refptr)
  1385.         {
  1386.         // Its a [ref] pointer, so if we are unmarshaling in the stub, 
  1387.         // then we need to mark it with some arbitrary non-NULL
  1388.         // value. If its in the proxy-unmshl phase, it will have a
  1389.         // real (non-NULL) value, so we can leave it as-is...
  1390.         if (pStrm->phaseGet () == NdrPhase::STUB_UNMSHL)
  1391.             *m_pPtr = (void*) 0xDEADBEEF;
  1392.         S_DEBUG (LOG_DCOM, "U1:[ref]ptr:referent=" << (*m_pPtr));
  1393.         }
  1394.     else
  1395.         {
  1396.         // Its a [unique] pointer, so we need to allocate memory if
  1397.         // unmarshaling return-values in the proxy, 
  1398.         pStrm->align (4);
  1399.         void* referent;
  1400.         HRESULT hr = pStrm->extract (sizeof (long), &referent, true);
  1401.         if (FAILED (hr))
  1402.             return hr;
  1403.         // Save referent-value (although its not a true pointer in this
  1404.         // context, yet) in the pointer variable...
  1405.         *m_pPtr = referent;
  1406.         S_DEBUG (LOG_DCOM, "U1:[unique]ptr:referent=" << referent);
  1407.         }
  1408.     return S_OK;
  1409.     }
  1410. HRESULT NdrPointer::unmarshal2 (NdrUnmarshalStream* pStrm)
  1411.     {
  1412.     // On entry, the referent-value is either NULL, or some
  1413.     // meaningless, but non-NULL, value. If its NULL, there is no
  1414.     // pointee to unmarshal...
  1415.     void* referent = *m_pPtr;
  1416.     if (referent == 0)
  1417.         return S_OK;
  1418.     
  1419.     // Non-NULL referent, so we can unmarshal the pointee. First, we
  1420.     // ask the pointee for its size, this forces it to read the
  1421.     // unmarshaling stream if its a conformant type...
  1422.     
  1423.     size_t objSize = m_pointeeType->size (pStrm);
  1424.     // If its a [unique] pointer, we may need to allocate some memory
  1425.     // for the pointer to point to. However, if we're in the
  1426.     // stub-unmarshaling phase we can borrow the stream memory. Either
  1427.     // way, we need to get the referent pointing to some real memory
  1428.     
  1429.     if (pStrm->phaseGet () == NdrPhase::STUB_UNMSHL)
  1430.         {
  1431.             //referent = pStrm->curr ();
  1432.         referent = pStrm->stubAlloc (objSize);
  1433.         if (m_refptr)
  1434.             {S_DEBUG (LOG_DCOM, "U2:[ref]ptr:value=" << referent
  1435.                       << " size=" << objSize);}
  1436.         else
  1437.             {S_DEBUG (LOG_DCOM, "U2:[unique]ptr:value=" << referent
  1438.                       << " size=" << objSize);}
  1439.         }
  1440.     else
  1441.         {
  1442.         // If its a [ref] ptr, then it must (since we're in the proxy
  1443.         // unmarshal phase) be pointing at something real, so we
  1444.         // simply dereference it to get to the pointee. If its a
  1445.         // [unique] pointer, in the proxy-unmarshal phase, we need to
  1446.         // allocate memory to hold the pointee... 
  1447.         if (m_refptr)
  1448.             {
  1449.             S_DEBUG (LOG_DCOM, "U2:[ref]ptr:value=" << referent
  1450.                      << " size=" << objSize);
  1451.             }
  1452.         else
  1453.             {
  1454.             referent = CoTaskMemAlloc (objSize);
  1455.             if (! referent)
  1456.                 return E_OUTOFMEMORY;
  1457.             S_DEBUG (LOG_DCOM, "U2:[unique]ptr:value=" << referent
  1458.                      << " size=" << objSize);
  1459.             }
  1460.         }
  1461.     
  1462.     // Set the value of the pointer-variable...
  1463.     *m_pPtr = referent;
  1464.     // Now unmarshal the pointee, at last...
  1465.     m_pointeeType->bind (referent);
  1466.     return m_pointeeType->unmarshal (pStrm);
  1467.     }
  1468. NDRTYPES::NDRTYPES (int hint)
  1469.     {
  1470.     m_pFactory = new NdrTypeFactory (hint);
  1471.     }
  1472. NDRTYPES::~NDRTYPES ()
  1473.     {
  1474.     if (m_pFactory)
  1475.         delete m_pFactory;
  1476.     }
  1477. NdrTypeDesc NDRTYPES::byte_t ()
  1478.     {
  1479.     COM_ASSERT(m_pFactory);
  1480.     NdrSimple<byte>* td = new (m_pFactory) NdrSimple<byte> (*this);
  1481.     return td;
  1482.     }
  1483. NdrTypeDesc NDRTYPES::short_t ()
  1484.     {
  1485.     COM_ASSERT(m_pFactory);
  1486.     NdrSimple<short> *td = new (m_pFactory) NdrSimple<short> (*this);
  1487.     return td;
  1488.     }
  1489. NdrTypeDesc NDRTYPES::long_t ()
  1490.     {
  1491.     COM_ASSERT(m_pFactory);
  1492.     NdrSimple<long> *td = new (m_pFactory) NdrSimple<long> (*this);
  1493.     return td;
  1494.     }
  1495. NdrTypeDesc NDRTYPES::enum_t ()
  1496.     {
  1497.     COM_ASSERT(m_pFactory);
  1498.     NdrEnum *td = new (m_pFactory) NdrEnum (*this);
  1499.     td->init (false);
  1500.     return td;
  1501.     }
  1502. NdrTypeDesc NDRTYPES::v1enum_t ()
  1503.     {
  1504.     COM_ASSERT(m_pFactory);
  1505.     NdrEnum *td = new (m_pFactory) NdrEnum (*this);
  1506.     td->init (true);
  1507.     return td;
  1508.     }
  1509. NdrTypeDesc NDRTYPES::hyper_t ()
  1510.     {
  1511.     COM_ASSERT(m_pFactory);
  1512.     NdrSimple<hyper> *td = new (m_pFactory) NdrSimple<hyper> (*this);
  1513.     return td;
  1514.     }
  1515. NdrTypeDesc NDRTYPES::float_t ()
  1516.     {
  1517.     COM_ASSERT(m_pFactory);
  1518.     NdrSimple<float> *td = new (m_pFactory) NdrSimple<float> (*this);
  1519.     return td;
  1520.     }
  1521. NdrTypeDesc NDRTYPES::double_t ()
  1522.     {
  1523.     COM_ASSERT(m_pFactory);
  1524.     NdrSimple<double> *td = new (m_pFactory) NdrSimple<double> (*this);
  1525.     return td;
  1526.     }
  1527. NdrTypeDesc NDRTYPES::bstr_t ()
  1528.     {
  1529.     COM_ASSERT(m_pFactory);
  1530.     NdrBSTR *td = new (m_pFactory) NdrBSTR (*this);
  1531.     return td;
  1532.     }
  1533. NdrTypeDesc NDRTYPES::struct_t (int nelems, const NdrMemberInfo m[], int nSizeIs)
  1534.     {
  1535.     COM_ASSERT(m_pFactory);
  1536.     NdrStruct *td = new (m_pFactory) NdrStruct (*this);
  1537.     td->init (nelems, m, nSizeIs);
  1538.     return td;
  1539.     }
  1540. NdrTypeDesc NDRTYPES::cstruct_t (int nelems, const NdrMemberInfo m[], int nSizeIs)
  1541.     {
  1542.     COM_ASSERT(m_pFactory);
  1543.     NdrConfStruct *td = new (m_pFactory) NdrConfStruct (*this);
  1544.     td->init (nelems, m, nSizeIs);
  1545.     return td;
  1546.     }
  1547. NdrTypeDesc NDRTYPES::array_t (const NdrTypeDesc& eltype, size_t elsz, size_t nelems)
  1548.     {
  1549.     COM_ASSERT(m_pFactory);
  1550.     NdrArray *td = new (m_pFactory) NdrArray (*this);
  1551.     td->init (eltype, elsz, nelems, 0, nelems);
  1552.     return td;
  1553.     }
  1554. NdrTypeDesc NDRTYPES::carray_t (const NdrTypeDesc& eltype, size_t elsz, size_t nelems)
  1555.     {
  1556.     COM_ASSERT(m_pFactory);
  1557.     NdrConfArray *td = new (m_pFactory) NdrConfArray (*this);
  1558.     td->init (eltype, elsz, nelems, 0, nelems);
  1559.     return td;
  1560.     }
  1561. NdrTypeDesc NDRTYPES::cvarray_t (const NdrTypeDesc& eltype, size_t elsz, size_t nelems, size_t nmax)
  1562.     {
  1563.     COM_ASSERT(m_pFactory);
  1564.     NdrConfVarArray *td = new (m_pFactory) NdrConfVarArray (*this);
  1565.     td->NdrArray::init (eltype, elsz, nmax, 0, nelems);
  1566.     return td;
  1567.     }
  1568. NdrTypeDesc NDRTYPES::interfaceptr_t (const IID& riid)
  1569.     {
  1570.     COM_ASSERT(m_pFactory);
  1571.     NdrInterface *td = new (m_pFactory) NdrInterface (*this);
  1572.     td->init (riid);
  1573.     return td;
  1574.     }
  1575. NdrTypeDesc NDRTYPES::variant_t ()
  1576.     {
  1577.     COM_ASSERT(m_pFactory);
  1578.     NdrVariant *td = new (m_pFactory) NdrVariant (*this);
  1579.     return td;
  1580.     }
  1581. NdrTypeDesc NDRTYPES::wstring_t ()
  1582.     {
  1583.     COM_ASSERT(m_pFactory);
  1584.     NdrWString *td = new (m_pFactory) NdrWString (*this);
  1585.     return td;
  1586.     }
  1587. NdrTypeDesc NDRTYPES::cstring_t ()
  1588.     {
  1589.     COM_ASSERT(m_pFactory);
  1590.     NdrCString *td = new (m_pFactory) NdrCString (*this);
  1591.     return td;
  1592.     }
  1593. NdrTypeDesc NDRTYPES::pointer_t (const NdrTypeDesc& pt)
  1594.     {
  1595.     COM_ASSERT(m_pFactory);
  1596.     NdrPointer *td = new (m_pFactory) NdrPointer (*this, false);
  1597.     td->init (pt);
  1598.     return td;
  1599.     }
  1600. NdrTypeDesc NDRTYPES::refptr_t (const NdrTypeDesc& pt)
  1601.     {
  1602.     COM_ASSERT(m_pFactory);
  1603.     NdrPointer *td = new (m_pFactory) NdrPointer (*this, true);
  1604.     td->init (pt);
  1605.     return td;
  1606.     }
  1607. //////////////////////////////////////////////////////////////////////////
  1608. //
  1609. // widlMarshal -- simplified WIDL runtime marshaling routine, takes
  1610. // the stream, the address of the top-level variable to be marshaled,
  1611. // and the type-descriptor, and binds the descriptor to the variable
  1612. // before invoking its marshal() method...
  1613. //
  1614. HRESULT widlMarshal (void const* pv, NdrMarshalStream* pms, const NdrTypeDesc& t)
  1615.     {
  1616.     NdrTypeDesc& td = const_cast<NdrTypeDesc&> (t);
  1617.     td->bind (const_cast<void*> (pv));
  1618.     HRESULT hr = td->marshal1 (pms);
  1619.     if (FAILED (hr))
  1620.         return hr;
  1621.     return td->marshal2 (pms);
  1622.     }
  1623. HRESULT widlUnmarshal (void* pv, NdrUnmarshalStream* pus, const NdrTypeDesc& t)
  1624.     {
  1625.     NdrTypeDesc& td = const_cast<NdrTypeDesc&> (t);
  1626.     td->bind (pv);
  1627.     HRESULT hr = td->unmarshal1 (pus);
  1628.     if (FAILED (hr))
  1629.         return hr;
  1630.     return td->unmarshal2 (pus);
  1631.     }
  1632. //////////////////////////////////////////////////////////////////////////
  1633. //
  1634. // VARIANT marshaling support. The VARIANT structure, in true MS
  1635. // fashion, is wire-marshaled differently from its in-memory
  1636. // representation. To see the wire-representation, look at OAIDL.IDL,
  1637. // which contains the full details. Basically, the start of the
  1638. // wireVARIANT structure is as follows:-
  1639. //
  1640. //    DWORD  clSize;          /* wire buffer length in units of hyper */
  1641. //    DWORD  rpcReserved;     /* for future use */
  1642. //    USHORT vt;
  1643. //    USHORT wReserved1;
  1644. //    USHORT wReserved2;
  1645. //    USHORT wReserved3;
  1646. //
  1647. // ...followed by the usual union, with 'vt' as the discriminator,
  1648. // and a slightly restricted set of types within the union. In the
  1649. // first release, we will only cope with simple VARIANTs, and none of
  1650. // the pointer or BYREF vartypes. This means effectively the intrinsic
  1651. // types plus VT_UNKNOWN and VT_BSTR.
  1652. //
  1653. HRESULT NdrVariant::marshal1 (NdrMarshalStream* pStrm)
  1654.     {
  1655.     char user [] = "User";
  1656.     
  1657.     // Start with the header ("User" + padding)...
  1658.     pStrm->align (4);
  1659.     return pStrm->insert (4, user, false);
  1660.     }
  1661. HRESULT NdrVariant::marshal2 (NdrMarshalStream* pStrm)
  1662.     {
  1663.     // First, make sure its a VT we can cope with...
  1664.     switch (m_pVariant->vt & VT_TYPEMASK)
  1665.         {
  1666.         case VT_EMPTY:
  1667.         case VT_NULL:
  1668.         case VT_UI1:
  1669.         case VT_I2:
  1670.         case VT_I4:
  1671.         case VT_R4:
  1672.         case VT_R8:
  1673.         case VT_CY:
  1674.         case VT_DATE:
  1675.         case VT_BSTR:
  1676.         case VT_ERROR:
  1677.         case VT_BOOL:
  1678.         case VT_UNKNOWN:
  1679.             break;
  1680.         default:
  1681.             S_ERR (LOG_DCOM, "Unsupported VARTYPE:" << hex << m_pVariant->vt << endl);
  1682.             return DISP_E_BADVARTYPE;
  1683.         }
  1684.     // The total length of required buffer space must be calculated,
  1685.     // in units of hyper. The size of the header is constant, and its
  1686.     // only the union part that is variable. Without counting [unique]
  1687.     // pointers, the max extra size is sizeof(double) (i.e. 8 bytes)
  1688.     // except for the interface-ptr and BSTR cases. To simplify this
  1689.     // process, we create a 2nd marshaling stream and marshal the
  1690.     // entire structure into there first, (including the leading
  1691.     // DWORD, so we can get alignment right). We then use its size to
  1692.     // calculate the rounded-up packet size, and copy the whole lot
  1693.     // into the real stream...
  1694.     NdrMarshalStream s2 (pStrm->phaseGet (), pStrm-> drep ());
  1695.     
  1696.     DWORD rpcReserved=0;
  1697.     USHORT wReserved=0;
  1698.     // Stuff a dummy clSize value in, to allow for correct alignment
  1699.     // within the VARIANT packet...
  1700.     ULONG clSizeDummy=0;
  1701.     s2.insert (sizeof(ULONG), &clSizeDummy, true);
  1702.     
  1703.     // Now the post-clSize contents...
  1704.     s2.insert (sizeof(rpcReserved), &rpcReserved, true);
  1705.     s2.insert (sizeof(USHORT), &m_pVariant->vt, true);
  1706.     s2.insert (sizeof(USHORT), &wReserved, true);
  1707.     s2.insert (sizeof(USHORT), &wReserved, true);
  1708.     HRESULT hr = s2.insert (sizeof(USHORT), &wReserved, true);
  1709.     if (FAILED (hr))
  1710.         return hr;
  1711.     // Now the union part -- first the discriminator, then the
  1712.     // body. We don't marshal the discriminator (as there's no body)
  1713.     // if its VT_EMPTY or VT_NULL, nice one MS!
  1714.     
  1715.     // Marshal discriminator
  1716.     ULONG discrim;
  1717.     if (V_ISARRAY(m_pVariant))
  1718.         {
  1719.         discrim = VT_ARRAY;
  1720.         }
  1721.     else
  1722.         {
  1723.         discrim = m_pVariant->vt & VT_TYPEMASK;
  1724.         }
  1725.     s2.insert (sizeof (ULONG), &discrim, true);
  1726.     NDRTYPES ndrtypes;
  1727.     // Marshal union-body?
  1728.     if (V_ISARRAY(m_pVariant))
  1729.         {
  1730.         NdrSafearray ndrSafearray (ndrtypes);
  1731.         ndrSafearray.bind (m_pVariant);
  1732.         hr = ndrSafearray.marshal (&s2);
  1733.         }
  1734.     else
  1735.         {
  1736.         // This is a  simple type.
  1737.         switch (m_pVariant->vt & VT_TYPEMASK)
  1738.             {
  1739.             case VT_EMPTY:
  1740.             case VT_NULL:
  1741.                 break;
  1742.             
  1743.             case VT_UI1:
  1744.                 hr = s2.insert (sizeof (byte), &V_UI1(m_pVariant), false);
  1745. s2.addEndPadding (8);
  1746.                 break;
  1747.             
  1748.             case VT_I2:
  1749.                 hr = s2.insert (sizeof (short), &V_I2(m_pVariant), true);
  1750. s2.addEndPadding (8);
  1751.                 break;
  1752.             
  1753.             case VT_I4:
  1754.                 hr = s2.insert (sizeof (long), &V_I4(m_pVariant), true);
  1755.                 break;
  1756.             
  1757.             case VT_R4:
  1758.                 hr = s2.insert (sizeof (float), &V_R4(m_pVariant), true);
  1759.                 break;
  1760.             
  1761.             case VT_R8:
  1762.                 hr = marshalDouble (&s2, &V_R8(m_pVariant));
  1763.                 break;
  1764.             
  1765.             case VT_CY:
  1766.                 s2.align (sizeof (CY));
  1767.                 hr = s2.insert (sizeof (CY), &V_CY(m_pVariant) , true);
  1768.                 break;
  1769.             
  1770.             case VT_DATE:
  1771.                 s2.align (sizeof (DATE));
  1772.                 hr = s2.insert (sizeof (DATE), &V_DATE(m_pVariant), true);
  1773.                 break;
  1774.         
  1775.             case VT_ERROR:
  1776.                 hr = s2.insert (sizeof (SCODE), &V_ERROR(m_pVariant), true);
  1777.                 break;
  1778.         
  1779.             case VT_BOOL:
  1780.                 hr = s2.insert (sizeof (VARIANT_BOOL), &V_BOOL(m_pVariant), true);
  1781. s2.addEndPadding (8);
  1782.                 break;
  1783.         
  1784.             case VT_BSTR:
  1785.                 {
  1786.                 // We marshal the BSTR pointer referent, then the value itself...
  1787.                 s2.insert (sizeof(ULONG), &V_BSTR(m_pVariant), true);
  1788.                 if (V_BSTR(m_pVariant))
  1789.                     {
  1790.                     NdrBSTR ndrBSTR (ndrtypes);
  1791.                     ndrBSTR.bind (&V_BSTR(m_pVariant));
  1792.                     hr = ndrBSTR.marshal2 (&s2);
  1793.                     }
  1794. s2.addEndPadding (8);
  1795.                 }
  1796.                 break;
  1797.         
  1798.             case VT_UNKNOWN:
  1799.                 {
  1800.                 // Need to add the length of the marshaled interface pointer
  1801.                 // packet...
  1802.                 NdrInterface ndrItf (ndrtypes);
  1803.                 ndrItf.init (IID_IUnknown);
  1804.                 ndrItf.bind (&V_UNKNOWN(m_pVariant));
  1805.                 hr = ndrItf.marshal (&s2);
  1806.                 }
  1807.                 break;
  1808.             default:
  1809.                 hr = DISP_E_BADVARTYPE;
  1810.             }
  1811.         }
  1812.     // Check marshaling results...
  1813.     if (FAILED (hr))
  1814.         return hr;
  1815.     
  1816.     // Calculate the size including the leading 'clSize' word, which
  1817.     // will be a multiple of sizeof(hyper) since we aligned the stream
  1818.     // already...
  1819.     ULONG clSize = (s2.size () + sizeof(hyper) - 1) / sizeof(hyper);
  1820.     // Now insert the actual clSize value into the main stream...
  1821.     pStrm->align (sizeof (hyper));
  1822.     pStrm->insert (sizeof (ULONG), &clSize, true);
  1823.      // Transfer any padding that have been added.
  1824.     pStrm->addEndPadding (s2.getEndPadding ());
  1825.     // Now copy s2 (except for its first 4 bytes) to the main stream...
  1826.     return pStrm->insert (s2.size () - sizeof(ULONG),
  1827.                           s2.begin () + sizeof(ULONG),
  1828.                           false);
  1829.     }
  1830. //////////////////////////////////////////////////////////////////////////
  1831. //
  1832. // NdrVariant::size -- determine the actual wire-size, and return the
  1833. // required memory size (which is sizeof(VARIANT) since we don't
  1834. // support indirected types yet). This advances the stream position
  1835. // over all the run-in data, leaving only the actual data in the
  1836. // stream. Thus, when it gets unmarshaled, it can be over-written in
  1837. // place, like all other data types...
  1838. //
  1839. size_t NdrVariant::size (NdrUnmarshalStream* pStrm)
  1840.     {
  1841.     S_DEBUG (LOG_DCOM, "SZ:variant");
  1842.     return sizeof (VARIANT);
  1843.     }
  1844. //////////////////////////////////////////////////////////////////////////
  1845. //
  1846. // NdrVariant::unmarshal1 -- unmarshal the "User" string, and check it
  1847. // is correct...
  1848. //
  1849. HRESULT NdrVariant::unmarshal1 (NdrUnmarshalStream* pStrm)
  1850.     {
  1851.     HRESULT hr = pStrm->align (4);
  1852.     if (FAILED (hr))
  1853.         return hr;
  1854.     char user[5];
  1855.     // "User" string
  1856.     hr = pStrm->extract (4, user, false);
  1857.     user[4]=0;
  1858.     S_DEBUG (LOG_DCOM, "U1:variant");
  1859.     if (strcmp (user, "User") != 0)
  1860.         return E_UNEXPECTED;
  1861.     
  1862.     return hr;
  1863.     }
  1864. //////////////////////////////////////////////////////////////////////////
  1865. //
  1866. // NdrVariant::unmarshal2 -- complete the unmarshaling of the union.
  1867. //
  1868. HRESULT NdrVariant::unmarshal2 (NdrUnmarshalStream* pStrm)
  1869.     {
  1870.     // Align properly
  1871.     HRESULT hr = pStrm->align (sizeof (hyper));
  1872.     if (FAILED (hr))
  1873.         return hr;
  1874.     // clSize
  1875.     ULONG clSize;
  1876.     pStrm->extract (sizeof (clSize), &clSize, true);
  1877.     DWORD tmp;
  1878.     // rpcReserved
  1879.     hr = pStrm->extract (sizeof(DWORD), &tmp, true);
  1880.     // VT and reserved fields
  1881.     pStrm->extract (sizeof(USHORT), &m_pVariant->vt, true);
  1882.     pStrm->extract (sizeof(USHORT), &m_pVariant->wReserved1, true);
  1883.     pStrm->extract (sizeof(USHORT), &m_pVariant->wReserved2, true);
  1884.     hr = pStrm->extract (sizeof(USHORT), &m_pVariant->wReserved3, true);
  1885.     if (FAILED (hr))
  1886.         return hr;
  1887.     // Union discriminator
  1888.     ULONG discrim;
  1889.     pStrm->extract (sizeof(ULONG), &discrim, true);
  1890.     
  1891.     S_DEBUG (LOG_DCOM, "U2:variant @ " << m_pVariant << " vt=" << m_pVariant->vt);
  1892.     NDRTYPES    ndrtypes;
  1893.     if (discrim & VT_ARRAY)
  1894.         {
  1895.         NdrSafearray ndrSafearray (ndrtypes);
  1896.         ndrSafearray.bind (m_pVariant);
  1897.         hr = ndrSafearray.unmarshal (pStrm);
  1898.         }
  1899.     else
  1900.         {
  1901.         COM_ASSERT (discrim == m_pVariant->vt);
  1902.     
  1903.         // Now the union part...
  1904.         switch (m_pVariant->vt & VT_TYPEMASK)
  1905.             {
  1906.             case VT_EMPTY:
  1907.             case VT_NULL:
  1908.                 break;
  1909.         
  1910.             case VT_UI1:
  1911.                 hr = pStrm->extract (sizeof (byte), &V_UI1(m_pVariant), false);
  1912.                 break;
  1913.         
  1914.             case VT_I2:
  1915.                 hr = pStrm->extract (sizeof (short), &V_I2(m_pVariant), true);
  1916.                 break;
  1917.         
  1918.             case VT_I4:
  1919.                 hr = pStrm->extract (sizeof (long), &V_I4(m_pVariant), true);
  1920.                 break;
  1921.             
  1922.             case VT_R4:
  1923.                 hr = pStrm->extract (sizeof (float), &V_R4(m_pVariant), true);
  1924.                 break;
  1925.             
  1926.             case VT_R8:
  1927.                 hr = unmarshalDouble (pStrm, &V_R8(m_pVariant));
  1928.                 break;
  1929.             
  1930.             case VT_CY:
  1931.                 pStrm->align (sizeof (CY));
  1932.                 hr = pStrm->extract (sizeof (CY), &V_CY(m_pVariant), true);
  1933.                 break;
  1934.             
  1935.             case VT_DATE:
  1936.                 pStrm->align (sizeof (DATE));
  1937.                 hr = pStrm->extract (sizeof (DATE), &V_DATE(m_pVariant), true);
  1938.                 break;
  1939.             
  1940.             case VT_ERROR:
  1941.                 hr = pStrm->extract (sizeof (SCODE), &V_ERROR(m_pVariant), true);
  1942.                 break;
  1943.             
  1944.             case VT_BOOL:
  1945.                 hr = pStrm->extract (sizeof (VARIANT_BOOL), &V_BOOL(m_pVariant), true);
  1946.                 break;
  1947.             
  1948.             case VT_BSTR:
  1949.                 {
  1950.                 // Reverse the marshaling process - first, get the
  1951.                 // pointer-referent, if its non-NULL, then unmarshal2() the
  1952.                 // remainder of the BSTR, as its "User" string won't be
  1953.                 // present due to it being inside a VARIANT...
  1954.                 ULONG ref;
  1955.                 hr = pStrm->extract (sizeof(ULONG), &ref, true);
  1956.                 if (SUCCEEDED (hr) && ref)
  1957.                     {
  1958.                     NdrBSTR ndrBSTR (ndrtypes);
  1959.                     ndrBSTR.bind (&V_BSTR(m_pVariant));
  1960.                     hr = ndrBSTR.unmarshal2 (pStrm);
  1961.                     }
  1962.                 }
  1963.                 break;
  1964.         
  1965.             case VT_UNKNOWN:
  1966.                 {
  1967.                 // Need to add the length of the marshaled interface pointer
  1968.                 // packet...
  1969.                 NdrInterface ndrItf (ndrtypes);
  1970.                 ndrItf.init (IID_IUnknown);
  1971.                 ndrItf.bind (&V_UNKNOWN(m_pVariant));
  1972.                 hr = ndrItf.unmarshal (pStrm);
  1973.                 }
  1974.                 break;
  1975.             default:
  1976.                 S_ERR (LOG_DCOM, "Unsupported VARTYPE: 0x" << hex << m_pVariant->vt << endl);
  1977.                 hr = DISP_E_BADVARTYPE;
  1978.             }
  1979.         }
  1980.     return hr;
  1981.     }
  1982. //////////////////////////////////////////////////////////////////////////////
  1983. //
  1984. // NdrSafearray::NdrSafearray - Constructor for NdrSafearray class.
  1985. //
  1986. NdrSafearray::NdrSafearray (NDRTYPES& n) : NdrType (n), 
  1987.                                            m_pVariant (0), 
  1988.                                            m_phase (PHASE1), 
  1989.                                            m_pTag (0)
  1990.     {
  1991.     }
  1992. //////////////////////////////////////////////////////////////////////////////
  1993. //
  1994. // NdrSafearray::NdrSafearray - Destructor for NdrSafearray class.
  1995. //
  1996. NdrSafearray::~NdrSafearray ()
  1997.     {
  1998.     }
  1999. //////////////////////////////////////////////////////////////////////////////
  2000. //
  2001. // NdrSafearray::bind - bind containing variant to NdrSafearray.
  2002. //
  2003. void NdrSafearray :: bind (void * pv) 
  2004.     { 
  2005.     m_pVariant = reinterpret_cast<VARIANT *>(pv);
  2006.     }
  2007. //////////////////////////////////////////////////////////////////////////
  2008. //
  2009. // NdrSafearray::marshal1 -- marshal the SAFEARRAY header
  2010. //
  2011. HRESULT NdrSafearray::marshal1 (NdrMarshalStream* pStrm)
  2012.     {
  2013.     // marshall parray
  2014.     return pStrm->insert (sizeof (SAFEARRAY *), &V_ARRAY(m_pVariant), true);
  2015.     }
  2016. //////////////////////////////////////////////////////////////////////////
  2017. //
  2018. // NdrSafearray::marshal2 -- marshal the SAFEARRAY body
  2019. //
  2020. HRESULT NdrSafearray::marshal2 (NdrMarshalStream* pStrm)
  2021.     {
  2022.     USHORT  tmpS;
  2023.     ULONG   tmpL;
  2024.     HRESULT hr = S_OK;
  2025.     // structure tag
  2026.     pStrm->insert (sizeof (SAFEARRAY *), &V_ARRAY(m_pVariant), true);
  2027.     // cDims
  2028.     tmpL = V_ARRAY(m_pVariant)->cDims;
  2029.     pStrm->insert (sizeof (ULONG), &tmpL, true);
  2030.     tmpS = V_ARRAY(m_pVariant)->cDims;
  2031.     pStrm->insert (sizeof (USHORT), &tmpS, true);
  2032.     // Features
  2033.     pStrm->insert (sizeof (USHORT), &V_ARRAY(m_pVariant)->fFeatures, true);
  2034.     // cbElements
  2035.     pStrm->insert (sizeof (ULONG), &V_ARRAY(m_pVariant)->cbElements, true);
  2036.     // cLocks
  2037.     tmpS = V_ARRAY(m_pVariant)->cLocks;
  2038.     pStrm->insert (sizeof (USHORT), &tmpS, true);
  2039.     // VT
  2040.     tmpS = V_VT(m_pVariant) & VT_TYPEMASK;
  2041.     pStrm->insert (sizeof (USHORT), &tmpS, true);
  2042.     // storage type, e.g. VT_R8 maps to VT_I8
  2043.     switch (V_VT(m_pVariant) & VT_TYPEMASK)
  2044.         {
  2045.         case VT_UI1:        tmpL = VT_I1; break;
  2046.         case VT_I2:         tmpL = VT_I2; break;
  2047.         case VT_I4:         tmpL = VT_I4; break;
  2048.         case VT_R4:         tmpL = VT_I4; break;
  2049.         case VT_R8:         tmpL = VT_I8; break;
  2050.         case VT_CY:         tmpL = VT_I8; break;
  2051.         case VT_DATE:       tmpL = VT_I8; break;
  2052.         case VT_BSTR:       tmpL = VT_BSTR; break;
  2053.         case VT_ERROR:      tmpL = VT_I4; break;
  2054.         case VT_BOOL:       tmpL = VT_I2; break;
  2055.         case VT_UNKNOWN:    tmpL = VT_UNKNOWN; break;
  2056.         default:
  2057.             COM_ASSERT (0);
  2058.             break;
  2059.         }
  2060.     pStrm->insert (sizeof (ULONG), &tmpL, true);
  2061.     // total count of elements
  2062.     pStrm->insert (sizeof (ULONG), &SA2MSA(V_ARRAY(m_pVariant))->dataCount, true);
  2063.     // rgsabound tag
  2064.     tmpL = reinterpret_cast<ULONG>
  2065.             (reinterpret_cast<BYTE *>(V_ARRAY(m_pVariant)) 
  2066.                     + sizeof (SAFEARRAY) - 1);
  2067.     pStrm->insert (sizeof (ULONG), &tmpL, true);
  2068.     ULONG index;
  2069.     // rgsabound
  2070.     for (index = 0; index < V_ARRAY(m_pVariant)->cDims; index++)
  2071.         {
  2072.         pStrm->insert (sizeof (ULONG), 
  2073.                    &V_ARRAY(m_pVariant)->rgsabound [index].cElements, true);
  2074.         hr = pStrm->insert (sizeof (LONG), 
  2075.                    &V_ARRAY(m_pVariant)->rgsabound [index].lLbound, true);
  2076.         }
  2077.     if (FAILED (hr))
  2078.         {
  2079.         return hr;
  2080.         }
  2081.     // total count of elements (again!)
  2082.     pStrm->insert (sizeof (ULONG), &SA2MSA(V_ARRAY(m_pVariant))->dataCount, true);
  2083.     // fill in data
  2084.     long * ix = new long [V_ARRAY(m_pVariant)->cDims];
  2085.     if (ix == NULL)
  2086.         {
  2087.         return E_OUTOFMEMORY;
  2088.         }
  2089.     switch (V_VT(m_pVariant) & VT_TYPEMASK)
  2090.         {
  2091.         case VT_BSTR:
  2092.         case VT_UNKNOWN:
  2093.             m_phase = PHASE1;
  2094.             hr = actionArray (V_ARRAY(m_pVariant)->cDims - 1, 
  2095.                               pStrm, 
  2096.                               NULL, 
  2097.                               ix);
  2098.             if (SUCCEEDED (hr))
  2099.                 {
  2100.                 m_phase = PHASE2;
  2101.                 hr = actionArray (V_ARRAY(m_pVariant)->cDims - 1, 
  2102.                                   pStrm, 
  2103.                                   NULL, 
  2104.                                   ix);
  2105.                 }
  2106.             break;
  2107.         default:
  2108.             hr = actionArray (V_ARRAY(m_pVariant)->cDims - 1, 
  2109.                               pStrm, 
  2110.                               NULL, 
  2111.                               ix);
  2112.             break;
  2113.         }
  2114.     delete [] ix;
  2115.     // Extra padding and alignment 
  2116.     pStrm->addEndPadding (8);
  2117.     pStrm->align(8);
  2118.     return hr;
  2119.     }
  2120. //////////////////////////////////////////////////////////////////////////
  2121. //
  2122. // NdrSafearray::unmarshal1 -- unmarshal the SAFEARRAY header
  2123. //
  2124. HRESULT NdrSafearray::unmarshal1 (NdrUnmarshalStream* pStrm)
  2125.     {
  2126.     void *              ptr;
  2127.     // Safearray marshalled as a pointer to a structure so get rid of
  2128.     // ptr.
  2129.     return pStrm->extract (sizeof (void *), &ptr, true);
  2130.     }
  2131. //////////////////////////////////////////////////////////////////////////
  2132. //
  2133. // NdrSafearray::unmarshal2 -- complete the unmarshaling of the SAFEARRAY.
  2134. //
  2135. HRESULT NdrSafearray::unmarshal2 (NdrUnmarshalStream* pStrm)
  2136.     {
  2137.     HRESULT             hr = S_OK;
  2138.     void *              ptr;
  2139.     USHORT              dims;
  2140.     USHORT              features;
  2141.     ULONG               cbElements;
  2142.     USHORT              locks;
  2143.     ULONG               cElements;
  2144.     SAFEARRAYBOUND *    sab;
  2145.     USHORT              index;
  2146.     ULONG               tmpL;
  2147.     USHORT              tmpS;
  2148.     hr = pStrm->extract (sizeof (void *), &ptr, true);
  2149.     // cDims
  2150.     hr = pStrm->extract (sizeof (USHORT), &dims, true);
  2151.     hr = pStrm->extract (sizeof (ULONG), &tmpL, true);
  2152.     // cFeatures
  2153.     hr = pStrm->extract (sizeof (USHORT), &features, true);
  2154.     // cbElements
  2155.     hr = pStrm->extract (sizeof (ULONG), &cbElements, true);
  2156.     // cLocks
  2157.     hr = pStrm->extract (sizeof (USHORT), &locks, true);
  2158.     // cbElements again as short and long
  2159.     hr = pStrm->extract (sizeof (USHORT), &tmpS, true);
  2160.     hr = pStrm->extract (sizeof (ULONG), &tmpL, true);
  2161.     // total count of elements
  2162.     hr = pStrm->extract (sizeof (ULONG), &cElements, true);
  2163.     // now follows the rgsa structure
  2164.     hr = pStrm->extract (sizeof (void *), &ptr, true);
  2165.     if (FAILED (hr)) return hr;
  2166.     sab = new SAFEARRAYBOUND [dims];
  2167.     if (sab == NULL)
  2168.         {
  2169.         return E_OUTOFMEMORY;
  2170.         }
  2171.     for (index = 0; index < dims; index++)
  2172.         {
  2173.         hr = pStrm->extract (sizeof (ULONG), &(sab [index].cElements), true);
  2174.         if (FAILED (hr))
  2175.             {
  2176.             delete sab;
  2177.             return hr;
  2178.             }
  2179.         hr = pStrm->extract (sizeof (LONG), &(sab [index].lLbound), true);
  2180.         if (FAILED (hr))
  2181.             {
  2182.             delete sab;
  2183.             return hr;
  2184.             }
  2185.         }
  2186.     // we now have enough info to contruct the safearray.
  2187.     V_ARRAY(m_pVariant) = SafeArrayCreate (V_VT(m_pVariant) & VT_TYPEMASK,
  2188.                                            dims,
  2189.                                            sab);
  2190.     // a copy of the SAFEARRAYBOUNDS has been made in SAFEARRAY
  2191.     delete [] sab;
  2192.     if (V_ARRAY(m_pVariant) == NULL)
  2193.         {
  2194.         // couldn't create safearray
  2195.         return E_OUTOFMEMORY;
  2196.         }
  2197.     hr = pStrm->extract (sizeof (ULONG), &cbElements, true);
  2198.     long *      ix = new long [V_ARRAY(m_pVariant)->cDims];
  2199.     if (ix == NULL)
  2200.         {
  2201.         SafeArrayDestroy (V_ARRAY(m_pVariant));
  2202.         return E_OUTOFMEMORY;
  2203.         }
  2204.     switch (V_VT(m_pVariant) & VT_TYPEMASK)
  2205.         {
  2206.         case VT_BSTR:
  2207.         case VT_UNKNOWN:
  2208.             {
  2209.             // We use a second SAFEARRAY to store pointer tags on
  2210.             // the first pass so they can be retrieved on the second 
  2211.             // pass to check for NULL pointers.
  2212.             m_pTag = SafeArrayCreate (VT_I4, 
  2213.                                       V_ARRAY(m_pVariant)->cDims, 
  2214.                                       V_ARRAY(m_pVariant)->rgsabound);
  2215.             if (m_pTag == NULL)
  2216.                 {
  2217.                 delete [] ix;
  2218.                 SafeArrayDestroy (V_ARRAY(m_pVariant));
  2219.                 return E_OUTOFMEMORY;
  2220.                 }
  2221.             m_phase = PHASE1;
  2222.             hr = actionArray (V_ARRAY(m_pVariant)->cDims - 1, NULL, pStrm, ix);
  2223.             if (SUCCEEDED (hr))
  2224.                 {
  2225.                 m_phase = PHASE2;
  2226.                 hr = actionArray (V_ARRAY(m_pVariant)->cDims - 1, 
  2227.                                   NULL, 
  2228.                                   pStrm, 
  2229.                                   ix);
  2230.                 }
  2231.             // get rid of tag SAFEARRAY.
  2232.             SafeArrayDestroy (m_pTag);
  2233.             }
  2234.             break;
  2235.         default:
  2236.             hr = actionArray (V_ARRAY(m_pVariant)->cDims - 1, NULL, pStrm, ix);
  2237.             break;
  2238.         }
  2239.     delete [] ix;
  2240.     
  2241.     return hr;
  2242.     }
  2243. /////////////////////////////////////////////////////////////////////////////
  2244. //
  2245. // NdrSafearray::unmarshalBody - unmarshal a single instance of 
  2246. HRESULT NdrSafearray::unmarshalBody (NdrUnmarshalStream * pStrm, long * ix)
  2247.     {
  2248.     HRESULT     hr = S_OK;
  2249.     switch (V_VT(m_pVariant) & VT_TYPEMASK)
  2250.         {
  2251.         case VT_R8:
  2252.         case VT_CY:
  2253.         case VT_DATE:
  2254.             {
  2255.             double  value;
  2256.             hr = unmarshalDouble (pStrm, &value);
  2257.             if (SUCCEEDED (hr))
  2258.                 {
  2259.                 hr = SafeArrayPutElement (V_ARRAY(m_pVariant), ix, &value);
  2260.                 }
  2261.             }
  2262.             break;
  2263.         case VT_ERROR:
  2264.         case VT_BOOL:
  2265.         case VT_I2:
  2266.         case VT_I4:
  2267.         case VT_R4:
  2268.         case VT_UI1:
  2269.             {
  2270.             BYTE *  data = new BYTE [V_ARRAY(m_pVariant)->cbElements];
  2271.             if (data == NULL)
  2272.                 {
  2273.                 return E_OUTOFMEMORY;
  2274.                 }
  2275.             hr = pStrm->extract (V_ARRAY(m_pVariant)->cbElements, data, true);
  2276.             if (SUCCEEDED(hr))
  2277.                 {
  2278.                 hr = SafeArrayPutElement (V_ARRAY(m_pVariant), ix, data);
  2279.                 }
  2280.             delete [] data;
  2281.             }
  2282.             break;
  2283.         
  2284.         case VT_UNKNOWN:
  2285.         case VT_BSTR:
  2286.             switch (m_phase)
  2287.                 {
  2288.                 case PHASE1:
  2289.                     {
  2290.                     // unmarshall the tag
  2291.                     ULONG ref;
  2292.                     hr = pStrm->extract (sizeof(ULONG), &ref, true);
  2293.                     if (SUCCEEDED(hr))
  2294.                         {
  2295.                         // Store ref so it can be used in phase 2.
  2296.                         hr = SafeArrayPutElement (m_pTag, ix, &ref);
  2297.                         }
  2298.                     }
  2299.                     break;
  2300.                 case PHASE2:
  2301.                     {
  2302.                     ULONG       ref;
  2303.                     hr = SafeArrayGetElement (m_pTag, ix, &ref);
  2304.                     // We only need to unmarshall data for pointers 
  2305.                     // that are non-NULL.
  2306.                     if (SUCCEEDED (hr) && ref)
  2307.                         {
  2308.                         NDRTYPES    ndrtypes;
  2309.                         switch (V_VT(m_pVariant) & VT_TYPEMASK)
  2310.                             {
  2311.                             case VT_BSTR:
  2312.                                 {
  2313.                                 BSTR        bstr;
  2314.                                 NdrBSTR     ndrBSTR (ndrtypes);
  2315.                                 ndrBSTR.bind (&bstr);
  2316.                                 hr = ndrBSTR.unmarshal2 (pStrm);
  2317.                                 if (SUCCEEDED (hr))
  2318.                                     {
  2319.                                     hr = SafeArrayPutElement (V_ARRAY(m_pVariant),
  2320.                                                               ix, 
  2321.                                                               bstr);
  2322.                                     }
  2323.                                 }
  2324.                                 break;
  2325.                             case VT_UNKNOWN:
  2326.                                 {
  2327.                                 NdrInterface ndrItf (ndrtypes);
  2328.                                 IUnknown *   pItf;
  2329.                                 ndrItf.init (IID_IUnknown);
  2330.                                 ndrItf.bind (&pItf);
  2331.                                 hr = ndrItf.unmarshal2 (pStrm);
  2332.                                 if (SUCCEEDED (hr))
  2333.                                     {
  2334.                                     hr = SafeArrayPutElement (V_ARRAY(m_pVariant),
  2335.                                                               ix, 
  2336.                                                               pItf);
  2337.                                     }
  2338.                                 pItf->Release ();
  2339.                                 }
  2340.                                 break;
  2341.                             }
  2342.                         }
  2343.                     }
  2344.                     break;
  2345.                 }
  2346.             break;
  2347.         default:
  2348.             return E_INVALIDARG;
  2349.         }
  2350.     return hr;
  2351.     }
  2352. HRESULT NdrSafearray::marshalBody (NdrMarshalStream * pStrm, long * ix)
  2353.     {
  2354.     HRESULT     hr = S_OK;
  2355.     switch (V_VT(m_pVariant) & VT_TYPEMASK)
  2356.         {
  2357.         case VT_R8:
  2358.         case VT_CY:
  2359.         case VT_DATE:
  2360.             {
  2361.             double                  value;
  2362.             hr = SafeArrayGetElement (V_ARRAY (m_pVariant), ix, &value);
  2363.             if (SUCCEEDED (hr))
  2364.                 {
  2365.                 hr = marshalDouble (pStrm, &value);
  2366.                 }
  2367.             }
  2368.             break;
  2369.         case VT_I2:
  2370.         case VT_I4:
  2371.         case VT_R4:
  2372.         case VT_ERROR:
  2373.         case VT_BOOL:
  2374.         case VT_UI1:
  2375.             {
  2376.             BYTE *  data = new BYTE [V_ARRAY(m_pVariant)->cbElements];
  2377.             if (data == NULL)
  2378.                 {
  2379.                 return E_OUTOFMEMORY;
  2380.                 }
  2381.             hr = SafeArrayGetElement (V_ARRAY (m_pVariant), ix, data);
  2382.             if (FAILED (hr))
  2383.                 {
  2384.                 delete data;
  2385.                 return hr;
  2386.                 }
  2387.             hr = pStrm->insert (V_ARRAY(m_pVariant)->cbElements, data, true);
  2388.             delete [] data;
  2389.             }
  2390.             break;
  2391.         
  2392.         case VT_UNKNOWN:
  2393.         case VT_BSTR:
  2394.             {
  2395.             switch (m_phase)
  2396.                 {
  2397.                 case PHASE1:
  2398.                     {
  2399.                     ULONG       ref;
  2400.                     VARTYPE     oldVt = SA2MSA(V_ARRAY(m_pVariant))->vt;
  2401.                     // get the tag as a pointer by changing the type of the 
  2402.                     // SAFEARRAY to I4 (same size as a pointer) and thus
  2403.                     // prevent a copy of the BSTR being returned.
  2404.                     SA2MSA(V_ARRAY(m_pVariant))->vt = VT_I4;
  2405.                     hr = SafeArrayGetElement(V_ARRAY(m_pVariant), ix, &ref);
  2406.                     SA2MSA(V_ARRAY(m_pVariant))->vt = oldVt;
  2407.                     if (FAILED(hr))
  2408.                         {
  2409.                         return hr;
  2410.                         }
  2411.                     // marshall the tag
  2412.                     hr = pStrm->insert (sizeof(ULONG), &ref, true);
  2413.                     }
  2414.                     break;
  2415.                 case PHASE2:
  2416.                     {
  2417.                     ULONG       ref;
  2418.                     VARTYPE     oldVt = SA2MSA(V_ARRAY(m_pVariant))->vt;
  2419.                     // get the tag as a pointer by changing the type of the 
  2420.                     // SAFEARRAY to I4 (same size as a pointer) and thus
  2421.                     // prevent a copy of the BSTR being returned.
  2422.                     SA2MSA(V_ARRAY(m_pVariant))->vt = VT_I4;
  2423.                     hr = SafeArrayGetElement(V_ARRAY(m_pVariant), ix, &ref);
  2424.                     SA2MSA(V_ARRAY(m_pVariant))->vt = oldVt;
  2425.                     if (FAILED(hr))
  2426.                         {
  2427.                         return hr;
  2428.                         }
  2429.                     // only marshal data for non-NULL types.
  2430.                     if (ref)
  2431.                         {
  2432.                         NDRTYPES ndrtypes;
  2433.                         switch (V_VT(m_pVariant) & VT_TYPEMASK)
  2434.                             {
  2435.                             case VT_BSTR:
  2436.                                 {
  2437.                                 BSTR    bstr;
  2438.                                 hr = SafeArrayGetElement (V_ARRAY(m_pVariant),
  2439.                                                           ix,
  2440.                                                           &bstr);
  2441.                                 if (FAILED(hr))
  2442.                                     {
  2443.                                     return hr;
  2444.                                     }
  2445.                                 NdrBSTR ndrBSTR (ndrtypes);
  2446.                                 ndrBSTR.bind (&bstr);
  2447.                                 hr = ndrBSTR.marshal2 (pStrm);
  2448.                                 }
  2449.                                 break;
  2450.                             case VT_UNKNOWN:
  2451.                                 {
  2452.                                 IUnknown * pItf;
  2453.                                 hr = SafeArrayGetElement (V_ARRAY(m_pVariant),
  2454.                                                           ix,
  2455.                                                           &pItf);
  2456.                                 if (FAILED(hr))
  2457.                                     {
  2458.                                     return hr;
  2459.                                     }
  2460.                                 NdrInterface ndrInterface (ndrtypes);
  2461.                                 ndrInterface.bind (&pItf);
  2462.                                 hr = ndrInterface.marshal2 (pStrm);
  2463.                                 }
  2464.                                 break;
  2465.                             default:
  2466.                                 COM_ASSERT(0);
  2467.                                 break;
  2468.                             }
  2469.                         }
  2470.                     }
  2471.                     break;
  2472.                 default:
  2473.                     COM_ASSERT(0);
  2474.                 }
  2475.             }
  2476.             break;
  2477.         default:
  2478.             return E_INVALIDARG;
  2479.         }
  2480.     return hr;
  2481.     }
  2482. HRESULT NdrSafearray::actionArray 
  2483.     (
  2484.     int                     dim, 
  2485.     NdrMarshalStream *      pMaStrm,
  2486.     NdrUnmarshalStream *    pUnStrm,
  2487.     long *                  ix
  2488.     )
  2489.     {
  2490.     HRESULT hr = S_OK;
  2491.     long index;
  2492.     for (index = 0; 
  2493.             index < (long)V_ARRAY(m_pVariant)->rgsabound [dim].cElements; 
  2494.                 index++)
  2495.         {
  2496.         ix [dim] = index + V_ARRAY(m_pVariant)->rgsabound [dim].lLbound;
  2497.         if (dim == 0)
  2498.             {
  2499.             if (pMaStrm)
  2500.                 {
  2501.                 // we have been given a marshaling pointer so me must be 
  2502.                 // marshling the data.
  2503.                 hr = marshalBody (pMaStrm, ix);
  2504.                 }
  2505.             else
  2506.                 {
  2507.                 hr = unmarshalBody (pUnStrm, ix);
  2508.                 }
  2509.             if (FAILED(hr))
  2510.                 {
  2511.                 return hr;
  2512.                 }
  2513.             }
  2514.         else
  2515.             {
  2516.             hr = actionArray (dim - 1, pMaStrm, pUnStrm, ix);
  2517.             if (FAILED (hr))
  2518.                 {
  2519.                 return hr;
  2520.                 }
  2521.             }
  2522.         }
  2523.     return hr;
  2524.     }