📄 ndrtypes.cpp
字号:
/* NdrTypes.cpp - VxDCOM NDR marshaling types *//* Copyright (c) 1999 Wind River Systems, Inc. *//*modification history--------------------02p,10jan02,nel Conditional define out old sytle double handling for ARM for Veloce.02o,09jan02,nel Fix duplicate double definition in ARM specific code.02n,17dec01,nel Add include symbol for diab.02m,12oct01,nel Add extra padding to other VARIANT types.02l,01oct01,nel SPR#69557. Add extra padding bytes to make VT_BOOL type work.02k,02aug01,dbs add [v1_enum] support02j,24jul01,dbs take fix for SPR#65311, unnecessary align() in struct marshal202i,19jul01,dbs fix include path of vxdcomGlobals.h02h,13jul01,dbs fix up includes02g,30mar01,nel SPR#35873. Modify extra pading bytes on the end of a SAFEARRAY.02f,08feb01,nel SPR#63885. SAFEARRAYs added. 02e,19sep00,nel Make widlMarshal match dcomProxy def.02d,24aug00,dbs fix many OPC-related SPRs, copied over from T2 VxDCOM02c,26jul00,dbs add enum_t descriptor02b,18jul00,dbs add CV-array NDR type02a,28feb00,dbs fix (properly) pointer-unmarshaling bug01z,28feb00,dbs fix nasty bug when unmarshaling arrays of pointers01y,18feb00,dbs change signature of widlMarshal() to take const void*01x,07feb00,dbs simplify NdrType classes, enhance marshaling of arrays to support all kinds01w,14oct99,dbs apply fix for ARM double format01v,23sep99,dbs add final parts of VARIANT marshaling01u,16sep99,dbs marshaling enhancements, part 201t,14sep99,dbs add VARIANT, pointer and string types - first stage01s,25aug99,dbs correct marshaling of interface ptrs01r,19aug99,aim changed assert to VXDCOM_ASSERT01q,16aug99,dbs add variant and string support01p,13aug99,aim include vxdcomGlobals01o,12aug99,dbs improve struct support01n,05aug99,dbs fix warnings01m,30jul99,dbs tighten up type-safety of NDR types01l,29jul99,dbs make cstruct pointer bindings same for mshl and unmshl01k,17jun99,aim changed assert to assert01j,17jun99,dbs change to COM_MEM_ALLOC01i,25may99,dbs dynamically allocate IStream for marshaling interfaces, remove NDRTYPES::alloc/free01h,24may99,dbs add BSTR marshaling policy variable01g,24may99,dbs fix interface-ptr marshaling01f,20may99,dbs fix BSTR marshaling functions for improved BSTR format01e,20may99,dbs improve documentation01d,18may99,dbs optimise unmarshaling by copying only pointers when possible01c,17may99,dbs remove dummy-msg object, add documentation01b,14may99,dbs fix alignment of array counts01a,12may99,dbs created*//* DESCRIPTION: NdrTypes.cpp NDR Type Descriptors -------------------- This module implements the 'type descriptor' system for NDR marshaling, in conjunction with the NdrMarshalStream and NdrUnmarshalStream classes. The NDR stream classes are unidirectional streams that can either be marshaled into, or can be unmarshaled from. The type-descriptor system described here implements some classes which know about marshaling one specific IDL or C++ type into one of those streams. In fact, each type-descriptor know about marshaling either one complex type (like GUID) or one or more simple types, all of which are the same size, for example, 'short' and 'unsigned short' are handled by the same type descriptor class. All type descriptors are subclasses of the abstract base class 'NdrType' and the WIDL (un)marshaling functions widlMarshal() and widlUnmarshal() require a pointer to the appropriate kind of stream, and a pointer to an NdrType which describes the item to be (un)marshaled. All user-level marshaling (i.e. that which appears in the generated proxy/stub code) uses these 2 functions. Each proxy or stub function must include a local variable of type NDRTYPES. This object functions as a 'factory' for the type descriptors, and implements a fast allocation strategy using placement new. Whenever a variable needs to be marshaled, then one of the methods of the NDRTYPES factory class is called, to generate a type descriptor. The descriptors are 'nestable' in that recursive data types can be described, such as structures or arrays. The set of type descriptor classes covers arrays (both fixed-size and conformant) and structures (again, fixed or conformant) even though WIDL doesn't currently cope with these complex types. Each type descriptor can be 'bound' to a particular instance variable, by passing the variable's address into the factory method. Only the top-level descriptor needs to be bound to the variable, and it will propogate down to nested descriptors. The value that needs to be bound to the descriptor is usually the address of the variable to be (un)marshaled. Arrays and structures require the descriptor to be bound to the start-address, e.g. for an array of T, the descriptor would be:- T* aT; array_t (aT, ...); and for a structure (conformant or normal) of type T, it would be like this:- struct T t; struct_t (&t, ...); Generally, the factory methods (of the NDRTYPES class) require the address of a variable to bind to. This precludes marshaling immediate values, but this is not generally a problem. However, there are exceptions, which must be coded carefully (and will be handled by WIDL in future). IDL Syntax and its meaning -------------------------- DCE IDL allows many ways of achieving the same thing, and is particularly confusing when it comes to args which are pointers or arrays. There are three kinds of pointer-attributes, namely [ref], [unique] and [ptr] (which is know as 'full' also). The [ref] pointer type is effectively a pass-by-reference pointer, which can never be NULL (like a C++ reference type) and so does not require any marshaling. However, both [unique] and [ptr] pointers can be NULL and so must be marshaled (the marshaled value is known as a 'referent' and is usually the value of the pointer itself, but effectively only conveys the NULL-ness or otherwise of the pointer). Top-level pointers (i.e. those in method arguments, at the outermost level) default to [ref] unless a specific attribute is given in the IDL. Lower level pointers (i.e. those inside structures or arrays, or even the 2nd level of indirection in method args) default to [unique] and so require marshaling. The pointer_t descriptor represents these kinds of pointers, and so it appears frequently. Pointers, as well as having one the above three attributes, can also be 'sized' -- i.e. can represent arrays as they can in C. For example, if the IDL says:- typedef struct { long a; char b; } FOO; HRESULT FooBar ([in] long nFoos, [in, size_is(nFoos)] FOO* foos); then the variable 'foos' is a 'conformant array' whose length is given (at runtime) in the arg 'nFoos'. DCE IDL also allows for returning conformant arrays, but the syntax for arrays of simple types, and arrays of complex types, is different. To return an array of simple types, the IDL would be something like this:- HRESULT Quz ([in] long nBytes, [out, size_is(nBytes)] char* bytes); To return an array of fixed-size structures, like FOO defined above, then the syntax is different, like so:- HRESULT Func ([in] long num, [out, size_is(,num)] FOO** ppFoos); In this case, the first pointer (rightmost *) defaults to [ref], and the 2nd or inner pointer defaults to [unique], so this declaration should be read as:- (ref-ptr to (unique-array of dimension 'num' of (FOO))) In this case, the proxy allocates memory to hold the array of FOOs and stores the address of this block in the pointer pointed-to by the argument 'ppFoos'. The strange syntax size_is(,num) indicates that the size_is value binds to the second star, and so this means a 'pointer to an array of FOOs'. Calling the function in C would look like this:- FOO* foos; Func (3, &foos); COM_MEM_FREE (foos); where Func() is actually calling the proxy, which makes the ORPC and returns the array of 3 FOO structures directly into the caller's address space. The final cases cover returning conformant structures, that is a structure whose final member is a conformant array. To return a single conformant structure, the IDL will be something like:- typedef struct { long nBytes; [size_is(nBytes)] char data[]; } BAR; HRESULT BarBaz ([out] BAR** ppBar); where ppBar is a ref-ptr to a unique-ptr to BAR. There is a subtle difference between this case and the case where the out-arg is an array of conformant-structures, like the BAR structure defined above. If the signature were:- HRESULT Func ([in] long num, [out, size_is(num)] BAR** ppBars); then this would mean 'ref-array of unique-pointer to BAR' and the size_is attribute applies to the top-level * declarator, i.e. ppBar is itself an array. NDR Phases ---------- There are 4 phases of marshaling in ORPC : firstly, marshaling all the [in] args at the proxy; secondly, unmarshaling all the [in] args at the stub; thirdly, marshaling all the [out] args and the return value at the stub; and finally unmarshaling all the [out] args and the return value at the proxy. In each of these phases there are different requirements on the type descriptors in order to optimise the unmarshaling process, minimising dynamic memory allocations. Also, at the stub side, the stub function must provide the actual arguments to the real stub-function when it is invoked - this requires making a temporary local for each argument (whether [in] or [out]) and unmarshaling into (and then marshaling from) those variables. It can be seen from the descriptions of the IDL syntax above that the possibilities are numerous, and the right type of allocation strategy must be performed for each variant of the syntax. This is why the job should ideally be performed by an IDL compiler, and in future WIDL will do just that. This description will document the behaviour of the type-descriptor classes in each of the above cases, and recommend how they should be handled by the generated proxy/stub code. The 'conformant array' Type Descriptor -------------------------------------- The factory method NDRTYPES::carray_t() returns a type descriptor designed to cope with conformant arrays. Marshaling conformant arrays is always the same, in both the PROXY_MSHL and STUB_MSHL phases. However, unmarshaling is a different matter. At the STUB_UNMSHL phase, unmarshaling can be optimised by letting the temporary variable in the stub-function point into the unmarshaling stream's buffer. To achieve this, the type-descriptor must be bound to the address of the pointer-variable, so it manipulate the contents. Unmarshaling at the PROXY_UNMSHL stage is the most complex. If the array-element type is a simple type, then the descriptor should be bound to the start-address of the array, and should just unmarshal directly into the caller-provided space. If the array-element is a fixed-size structure and the size_is(,num) IDL syntax is being used, then the type-descriptor must allocate dynamic memory to hold the unmarshaled data, which the caller must eventually free (by calling the CoTaskMemFree() function). This functionality is encoded in NdrConfArray::unmarshal(), which makes the distinction between simple types and others. However, if the [out] array is an array of pointers to conformant structures (see the Func(long,BAR**) example above) then the complexity increases. The array is marshaled differently (the array of pointer-referents is marshaled first, then each of the conformant structures follows, in order, and NULL referents may be present) and hence unmarshaling is different. Currently, the type descriptors do not support this case -- it must be hand-coded (by human hands, or by WIDL concocting the right sequence of elements) -- and so only cope with the 2 cases outlined earlier. Variable-Binding Rules ---------------------- Most of the NDR type-descriptors bind to the address of a variable, whether marshaling or unmarshaling. The only exception is the 'array' type (class NdrArray) which binds to the start of the array, i.e. the address of the first element. Note that conformant arrays don't -- they follow the usual rules and bind to the address of a variable holding the pointer to the first element of the array. Pointer Types ------------- MIDL/WIDL supports 3 kinds of pointer-attributes, namely [ref], [unique] and [ptr] (known as 'full') pointers. The difference between unique and full pointers is that unique pointers must literally be unique, i.e. there must be no aliasing between any 2 pointers within the context of a marshaling operation. The [ref] pointer type indicates 'pass by reference' semantics, thus a ref-pointer can never be NULL, and so [ref] pointers are not marshaled. However, [unique] pointers can be NULL, and so do have to be marshaled. Thus the type-descriptors for the pointer type (and associated array and string types) are only used when the IDL indicates a [unique] (or full) pointer. The pointer_t() descriptor is generated by WIDL when a simple [unique] pointer is required, i.e. an unsized, non-string pointer. If a dimension is supplied, or the [string] attribute is used, then WIDL will generate a call to either the carray_t() or wstring_t() descriptor, respectively. In all cases where a [unique] pointer is utilised, the binding for the descriptor is the address of the pointer variable. Only if a [ref] string or fixed-size array is used as a method-arg is there a potential problem. Also, WIDL only supports conformant arrays, and not varying, or conformant varying arrays. In IDL terms, this means the size_is attribute is recognised, but max_is, length_is, etc, are not. */#include <stdlib.h>#include "private/comMisc.h"#include "NdrTypes.h"#include "MemoryStream.h"#include "orpcLib.h"#include "private/vxdcomGlobals.h"#include "TraceCall.h"/* Include symbol for diab */extern "C" int include_vxdcom_NdrTypes (void) { return 0; }////////////////////////////////////////////////////////////////////////////// ARM-specific code for (un)marshaling doubles...//#if defined (CPU_FAMILY) && (CPU_FAMILY == ARM) && \ defined (VXDCOM_PLATFORM_VXWORKS) && (VXDCOM_PLATFORM_VXWORKS != 5)#ifdef __GNUC__template class NdrSimple<double>;#endifunion armDouble { double doubleValue; struct { long msw; long lsw; } txValue; };static HRESULT marshalDouble (NdrMarshalStream * pStrm, double * value) { pStrm->align (sizeof (double)); armDouble d; d.doubleValue = *value; pStrm->insert (sizeof (long), &d.txValue.lsw, true); return pStrm->insert (sizeof (long), &d.txValue.msw, true); }HRESULT NdrSimple<double>::marshal1 (NdrMarshalStream* pStrm) { return marshalDouble(pStrm, m_pValue); }static HRESULT unmarshalDouble (NdrUnmarshalStream * pStrm, double * value) { pStrm->align (sizeof (double)); armDouble d; pStrm->extract (sizeof (long), &d.txValue.lsw, true); HRESULT hr = pStrm->extract (sizeof (long), &d.txValue.msw, true); if (SUCCEEDED (hr)) *value = d.doubleValue; return hr; } HRESULT NdrSimple<double>::unmarshal1 (NdrUnmarshalStream* pStrm) { return unmarshalDouble(pStrm, m_pValue); }#elsestatic HRESULT marshalDouble (NdrMarshalStream * pStrm, double * value) { pStrm->align (sizeof (double)); return pStrm->insert (sizeof (double), value, true); }static HRESULT unmarshalDouble (NdrUnmarshalStream * pStrm, double * value) { pStrm->align (sizeof (double)); return pStrm->extract (sizeof (double), value, true); }#endif////////////////////////////////////////////////////////////////////////////// (un)marshaling methods for enum types.//size_t NdrEnum::alignment () const { return (m_bV1Enum ? sizeof (DWORD) : sizeof (short)); }HRESULT NdrEnum::marshal1 (NdrMarshalStream* pStrm) { HRESULT hr = S_OK; if (m_bV1Enum) { // New-style 32-bit enum... DWORD val = *m_pValue; pStrm->align (alignment ()); hr = pStrm->insert (sizeof (val), &val, true); } else { // Old-style 16-bit enum... short val = *m_pValue; pStrm->align (alignment ()); hr = pStrm->insert (sizeof (val), &val, true); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -