/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Copyright (c) 1993-1999 Microsoft Corporation Module Name: stndr.hxx Abstract: Contains routines for the generation of the new NDR format strings for structure types, and the new NDR marshalling and unmarshalling calls. Notes: History: DKays Oct-1993 Created. ----------------------------------------------------------------------------*/ #include "becls.hxx" #pragma hdrstop void CG_STRUCT::GenNdrFormat( CCB * pCCB ) /*++ Routine Description : Generates the format string description for a simple, conformant, or conformant varying structure. Arguments : pCCB - pointer to the code control block. --*/ { FORMAT_STRING * pFormatString; CG_NDR * pOldCGNodeContext; CG_NDR * pConformantArray; if ( GetFormatStringOffset() != -1 ) return; // // Check if this structure is "complex". // if ( IsComplexStruct() ) { GenNdrFormatComplex( pCCB ); return; } // // Check if the structure is "hard". // if ( IsHardStruct() ) { GenNdrFormatHard( pCCB ); return; } Unroll(); // // Temporarily set the format string offset to 0 in case this structure // has pointers to it's own type. // SetFormatStringOffset( 0 ); SetInitialOffset( 0 ); CG_FIELD *pOldRegionField = NULL; #if defined(NDR64_ON_DCE_HACK) if ( NULL != dynamic_cast( this ) ) { pOldRegionField = pCCB->StartRegion(); } else #endif pOldCGNodeContext = pCCB->SetCGNodeContext( this ); pFormatString = pCCB->GetFormatString(); // // Search the fields of the structure for embedded structures and generate // the format string for these. // CG_ITERATOR Iterator; CG_FIELD * pField; CG_NDR * pMember; GetMembers( Iterator ); while ( ITERATOR_GETNEXT( Iterator, pField ) ) { CG_NDR * pOldPlaceholder; pOldPlaceholder = pCCB->SetLastPlaceholderClass( pField ); pMember = (CG_NDR *) pField->GetChild(); // // If there is a structure or array member then generate // it's format string. We don't have to check for a union, because // that will make the struct CG_COMPLEX_STRUCT. // if ( pMember->IsStruct() || pMember->IsArray() ) pMember->GenNdrFormat( pCCB ); pCCB->SetLastPlaceholderClass( pOldPlaceholder ); } // // If this is a conformant (varying) struct then generate the array's // description. // if ( GetCGID() == ID_CG_CONF_STRUCT || GetCGID() == ID_CG_CONF_VAR_STRUCT ) { CG_NDR * pOldPlaceholder; pOldPlaceholder = pCCB->SetLastPlaceholderClass( (CG_NDR *) ((CG_CONFORMANT_STRUCT *)this)->GetConformantField() ); // Get the conformant array CG class. pConformantArray = (CG_NDR *) ((CG_CONFORMANT_STRUCT *)this)->GetConformantArray(); // Generate the format string for the array. pConformantArray->GenNdrFormat( pCCB ); pCCB->SetLastPlaceholderClass( pOldPlaceholder ); } // // If there are pointers in the structure then before you can start // generating the format string for the structure, you must generate // the format string for all of the pointees. // if ( HasPointer() ) { GenNdrStructurePointees( pCCB ); } SetFormatStringOffset( pFormatString->GetCurrentOffset() ); SetInitialOffset( pFormatString->GetCurrentOffset() ); switch ( GetCGID() ) { case ID_CG_STRUCT : pFormatString->PushFormatChar( HasPointer() ? FC_PSTRUCT : FC_STRUCT ); break; case ID_CG_CONF_STRUCT : pFormatString->PushFormatChar( HasPointer() ? FC_CPSTRUCT : FC_CSTRUCT ); break; case ID_CG_CONF_VAR_STRUCT : pFormatString->PushFormatChar( FC_CVSTRUCT ); break; } // Set the alignment. pFormatString->PushByte( GetWireAlignment() - 1 ); // Set the structure memory size. pFormatString->PushShort( (short)GetMemorySize() ); // // If this is a conformant array then push the offset to the conformant // array's description. // if ( GetCGID() == ID_CG_CONF_STRUCT || GetCGID() == ID_CG_CONF_VAR_STRUCT ) { // Set the offset to the array description. pFormatString->PushShortOffset( pConformantArray->GetFormatStringOffset() - pFormatString->GetCurrentOffset() ); } // Generate the pointer layout if needed. if ( HasPointer() ) { GenNdrStructurePointerLayout( pCCB, FALSE, FALSE ); } // Now generate the layout. GenNdrStructureLayout( pCCB ); // // Now we have to fix up the offset for any recursive pointer to this // structure. // GenNdrPointerFixUp( pCCB, this ); #if defined(NDR64_ON_DCE_HACK) if ( NULL != dynamic_cast( this ) ) { pCCB->EndRegion(pOldRegionField); } else #endif pCCB->SetCGNodeContext( pOldCGNodeContext ); SetFormatStringEndOffset( pFormatString->GetCurrentOffset() ); pFormatString->OptimizeFragment( this ); SetInitialOffset( GetFormatStringOffset() ); FixupEmbeddedComplex( pCCB ); if ( GetDuplicatingComplex() ) GetDuplicatingComplex()->FixupEmbeddedComplex( pCCB ); } void CG_STRUCT::GenNdrFormatHard( CCB * pCCB ) /*++ Routine Description : Generates the format string description for a packed structure. The description has the same format as for a complex struct. Arguments : pCCB - pointer to the code control block. --*/ { FORMAT_STRING * pFormatString; CG_NDR * pOldCGNodeContext; CG_NDR * pUnion; CG_FIELD * pFinalField; long CopySize; long MemoryIncrement; if ( GetFormatStringOffset() != -1 ) return; // // Temporarily set the format string offset to 0 in case this structure // has pointers to it's own type. // SetFormatStringOffset( 0 ); SetInitialOffset( 0 ); pOldCGNodeContext = pCCB->SetCGNodeContext( this ); pFormatString = pCCB->GetFormatString(); // // Search the fields of the structure for embedded structures and generate // the format string for these. // CG_ITERATOR Iterator; CG_FIELD * pField; CG_NDR * pMember; CG_NDR * pOldPlaceholder; GetMembers( Iterator ); pOldPlaceholder = pCCB->GetLastPlaceholderClass(); while ( ITERATOR_GETNEXT( Iterator, pField ) ) { pMember = (CG_NDR *) pField->GetChild(); // // If there is an embedded structure, array, or union then generate // it's format string. // if ( pMember->IsStruct() || pMember->IsArray() || pMember->IsUnion() ) { pCCB->SetLastPlaceholderClass( pField ); pMember->GenNdrFormat( pCCB ); } } pCCB->SetLastPlaceholderClass( pOldPlaceholder ); SetFormatStringOffset( pFormatString->GetCurrentOffset() ); SetInitialOffset( pFormatString->GetCurrentOffset() ); pFinalField = GetFinalField(); // // See if we have a union. // if ( pFinalField->GetChild()->IsUnion() ) pUnion = (CG_NDR *) pFinalField->GetChild(); else pUnion = 0; // // Determine the copy size and memory increment for the copy. // if ( pUnion ) { CG_STRUCT * pStruct; pStruct = this; CopySize = 0; for ( ;; ) { pStruct->GetMembers( Iterator ); while ( ITERATOR_GETNEXT( Iterator, pField ) ) ; CopySize += pField->GetWireOffset(); pMember = (CG_NDR *) pField->GetChild(); if ( pMember->IsStruct() ) { pStruct = (CG_STRUCT *) pMember; continue; } else break; } MemoryIncrement = GetMemorySize() - pUnion->GetMemorySize(); } else { CopySize = GetWireSize(); MemoryIncrement = GetMemorySize(); } // // Format string generation. // pFormatString->PushFormatChar( FC_HARD_STRUCT ); // The alignment. pFormatString->PushByte( GetWireAlignment() - 1 ); // The structure's memory size. pFormatString->PushShort( (short)GetMemorySize() ); // Reserved for future use. pFormatString->PushLong( 0 ); // // Offset to enum in struct. // if ( GetNumberOfEnum16s() == 1 ) pFormatString->PushShort( GetEnum16Offset() ); else pFormatString->PushShort( (short) -1 ); // // Copy size and memory increment. // pFormatString->PushShort( CopySize ); pFormatString->PushShort( MemoryIncrement ); // // Offset to union's format string description. // if ( pUnion ) { pOldPlaceholder = pCCB->GetLastPlaceholderClass(); pCCB->SetLastPlaceholderClass( pFinalField ); pFormatString->PushShort( (short) (pUnion->GetFormatStringOffset() - pFormatString->GetCurrentOffset()) ); pCCB->SetLastPlaceholderClass( pOldPlaceholder ); } else pFormatString->PushShort( (short) 0 ); // Now generate the layout. GenNdrStructureLayout( pCCB ); // // Now we have to fix up the offset for any recursive pointer to this // structure. // GenNdrPointerFixUp( pCCB, this ); pCCB->SetCGNodeContext( pOldCGNodeContext ); SetFormatStringEndOffset( pFormatString->GetCurrentOffset() ); pFormatString->OptimizeFragment( this ); SetInitialOffset( GetFormatStringOffset() ); FixupEmbeddedComplex( pCCB ); } void CG_STRUCT::GenNdrFormatComplex( CCB * pCCB ) /*++ Routine Description : Generates the format string description for a packed structure. The description has the same format as for a complex struct. Arguments : pCCB - pointer to the code control block. --*/ { CG_CLASS * pConfField; CG_COMPLEX_STRUCT * pComplex; if ( (GetCGID() == ID_CG_CONF_STRUCT) || (GetCGID() == ID_CG_CONF_VAR_STRUCT) ) pConfField = ((CG_CONFORMANT_STRUCT *)this)->GetConformantField(); else pConfField = 0; // // Do the old duplication trick. // pComplex = new CG_COMPLEX_STRUCT( this, pConfField ); SetDuplicatingComplex( pComplex ); // // Now temporarily set our format string offset to 0 to handle recursive // definitions. // SetFormatStringOffset( 0 ); SetInitialOffset( 0 ); // // This call will set our format string offset correctly. // pComplex->GenNdrFormat( pCCB ); // Don't delete since the expression evaluator might need this. // delete( pComplex ); } bool IsEnum16UnionAlignBug( CG_STRUCT *pStruct ) { // Comment from old hack wacked on stub. // The NT 3.50 stubs had a problem with union alignment that affects // structs with 16b enum and a union as the only other thing. // The old, incorrect alignment was 2 (code 1), the correct alignment is 4 (code 3). // All the compilers since NT 3.51, i.e. MIDL 2.0.102 generate correct code, // however we needed to introduce the wrong alignment into newly compiled stubs // to get interoperability with the released dhcp client and server binaries. if ( 4 != pStruct->GetWireAlignment()) return false; CG_ITERATOR StructElements; pStruct->GetMembers( StructElements ); ITERATOR_INIT( StructElements ); size_t Elements = ITERATOR_GETCOUNT( StructElements ); if ( 2 != Elements ) return false; ITERATOR_INIT( StructElements ); CG_FIELD *pField1 = NULL; ITERATOR_GETNEXT( StructElements, pField1 ); MIDL_ASSERT( NULL != pField1); // Is the first field a enum16? CG_ENUM *pEnum = dynamic_cast( pField1->GetChild() ); if ( ( NULL == pEnum ) || pEnum->IsEnumLong() ) return false; // Is the second field a union CG_FIELD *pField2 = NULL; ITERATOR_GETNEXT( StructElements, pField2 ); MIDL_ASSERT( NULL != pField2 ); if ( ! pField2->GetChild()->IsUnion()) return false; // Ok. We have a 2 field structure were the first field is an enum16 and the second field is // and union. return true; } void CG_COMPLEX_STRUCT::GenNdrFormat( CCB * pCCB ) /*++ Routine Description : Generates the format string description for a complex structure. Arguments : pCCB - pointer to the code control block. --*/ { FORMAT_STRING * pFormatString; CG_NDR * pOldCGNodeContext; CG_NDR * pConformantArray; long PointerLayoutOffset; if ( GetFormatStringOffset() != -1 ) return; pFormatString = pCCB->GetFormatString(); // // Temporarily set the format string offset to 0 in case this structure // has pointers to it's own type. // SetFormatStringOffset( 0 ); SetInitialOffset( 0 ); pOldCGNodeContext = pCCB->SetCGNodeContext( this ); // // Search the fields of the structure for imbeded structures, arrays, and // and unions and generate the format string for these. // CG_ITERATOR Iterator; CG_FIELD * pField; CG_NDR * pMember; GetMembers( Iterator ); while ( ITERATOR_GETNEXT( Iterator, pField ) ) { pMember = (CG_NDR *) pField->GetChild(); // // If the field is anything other than a base type or a // non-interface pointer then generate it's description. // if ( ! pMember->IsSimpleType() && ! ( pMember->IsPointer() && !pMember->IsInterfacePointer() ) && (pMember->GetCGID() != ID_CG_IGN_PTR) || pMember->GetRangeAttribute() ) { CG_NDR * pOldPlaceholder; pOldPlaceholder = pCCB->SetLastPlaceholderClass( pField ); pMember->GenNdrFormat( pCCB ); pCCB->SetLastPlaceholderClass( pOldPlaceholder ); } } // Generate pointee format strings. GenNdrStructurePointees( pCCB ); // Generate conformant array description. if ( ( pConformantArray = (CG_NDR *) GetConformantArray() ) != 0 ) { CG_NDR * pOldPlaceholder; pOldPlaceholder = pCCB->SetLastPlaceholderClass( (CG_NDR *) GetConformantField() ); pConformantArray->GenNdrFormat( pCCB ); pCCB->SetLastPlaceholderClass( pOldPlaceholder ); } // Now set the struct's format string offset. SetFormatStringOffset( pFormatString->GetCurrentOffset() ); SetInitialOffset( pFormatString->GetCurrentOffset() ); // // Set the duplicated struct's format string offset if we were duplicated. // if ( GetDuplicatedStruct() ) { GetDuplicatedStruct()->SetFormatStringOffset( GetFormatStringOffset() ); GetDuplicatedStruct()->SetInitialOffset( GetFormatStringOffset() ); } pFormatString->PushFormatChar( FC_BOGUS_STRUCT ); WarnAboutEmbeddedComplexStruct(); // // Set the wire alignment. // if ( pCommand->WireCompat( WIRE_COMPAT_ENUM16UNIONALIGN ) && IsEnum16UnionAlignBug(this) ) { // Comment from old hack wacked on stub. // The NT 3.50 stubs had a problem with union alignment that affects // structs with 16b enum and a union as the only other thing. // The old, incorrect alignment was 2 (code 1), the correct alignment is 4 (code 3). // All the compilers since NT 3.51, i.e. MIDL 2.0.102 generate correct code, // however we needed to introduce the wrong alignment into newly compiled stubs // to get interoperability with the released dhcp client and server binaries. pFormatString->AddComment( pFormatString->GetCurrentOffset(), "/* 3 */ /* enum16unionalign Bug Compatibility */" ); pFormatString->PushByte( 1 ); } else pFormatString->PushByte( GetWireAlignment() - 1 ); // Set the structure memory size. pFormatString->PushShort( (short)GetMemorySize() ); // Array description. if ( pConformantArray ) pFormatString->PushShortOffset( pConformantArray->GetFormatStringOffset() - pFormatString->GetCurrentOffset() ); else pFormatString->PushShort( (short) 0 ); // // Remember where the offset_to_pointer_layout<> field will go and push // some space for it. // PointerLayoutOffset = pFormatString->GetCurrentOffset(); pFormatString->PushShortOffset( 0 ); // Now generate the structure's layout. GenNdrStructureLayout( pCCB ); // // Now see if we have any plain pointer fields and if so generate a // pointer layout. We can't use the HasAtLeastOnePointer() method // because this tells us TRUE if we have any embedded arrays, structs, // or unions which have pointers. For complex structs we're only // interested in actual pointer fields. // GetMembers( Iterator ); // // Fill in the offset_to_pointer_layout<2> field and generate a // pointer_layout<> if we have any pointer fields. Interface pointers // do not reside in the pointer layout. // while ( ITERATOR_GETNEXT( Iterator, pField ) ) if ( pField->GetChild()->IsPointer() && !pField->IsInterfacePointer() ) { // This is an internal offset within the struct descriptor, namely // to the pointer layout field, not the offset to a type. // Surprisingly, this code may produce an offset to an array etc. // Hence, we push an offset to be backward compatible. pFormatString->PushShortOffset( pFormatString->GetCurrentOffset() - PointerLayoutOffset, PointerLayoutOffset ); GenNdrStructurePointerLayout( pCCB ); break; } pFormatString->Align(); // // Now we have to fix up the offset for any recursive pointer to this // structure. // GenNdrPointerFixUp( pCCB, GetDuplicatedStruct() ? GetDuplicatedStruct() : this ); pCCB->SetCGNodeContext( pOldCGNodeContext ); SetFormatStringEndOffset( pFormatString->GetCurrentOffset() ); pFormatString->OptimizeFragment( this ); SetInitialOffset( GetFormatStringOffset() ); if ( GetDuplicatedStruct() ) GetDuplicatedStruct()->SetFormatStringOffset( GetFormatStringOffset() ); FixupEmbeddedComplex( pCCB ); if ( GetDuplicatedStruct() ) GetDuplicatedStruct()->FixupEmbeddedComplex( pCCB ); // There is no call to the string optimizer here. If we wanted to put it in, // the code should check if the optimization is possible or not by checking the // result of GenNdrEmbeddedPointers via GenNdrStructurePointerLayout call. } void CG_COMPLEX_STRUCT::GenNdrStructurePointerLayout( CCB * pCCB ) /*++ Routine Description : Generates the format string pointer layout section for a complex structure. Arguments : pCCB - pointer to the code control block. --*/ { CG_ITERATOR Iterator; CG_FIELD * pField; CG_NDR * pMember; GetMembers( Iterator ); while( ITERATOR_GETNEXT( Iterator, pField ) ) { CG_NDR * pOldPlaceholder; pOldPlaceholder = pCCB->SetLastPlaceholderClass( pField ); pMember = (CG_NDR *) pField->GetChild(); if ( pMember->IsPointer() && !pMember->IsInterfacePointer()) { CG_POINTER * pPointer; pPointer = (CG_POINTER *) pMember; // The pointer description. pPointer->GenNdrFormatEmbedded( pCCB ); } pCCB->SetLastPlaceholderClass( pOldPlaceholder ); } // while } //--------------------------------------------------------------------------- // Methods shared by all or most structure classes. //--------------------------------------------------------------------------- void CG_STRUCT::GenNdrStructurePointerLayout( CCB * pCCB, BOOL fNoPP, BOOL fNoType ) /*++ Routine Description : Generates the format string pointer layout section for a structure. This is the default routine for this used by the structure classes. Only CG_COMPLEX_STRUCT redefines this virtual method. Arguments : pCCB - pointer to the code control block. fNoPP - TRUE if no FC_PP or FC_END should be emitted fNoType - TRUE only the bare offset and description should be emitted for each pointer --*/ { CG_ITERATOR Iterator; FORMAT_STRING * pFormatString; CG_FIELD * pField; CG_NDR * pMember; long ImbedingMemSize; long ImbedingBufSize; pFormatString = pCCB->GetFormatString(); // Get/Save the current imbeding sizes. ImbedingMemSize = pCCB->GetImbedingMemSize(); ImbedingBufSize = pCCB->GetImbedingBufSize(); if ( ! fNoPP ) { pFormatString->PushFormatChar( FC_PP ); pFormatString->PushFormatChar( FC_PAD ); } GetMembers( Iterator ); while( ITERATOR_GETNEXT( Iterator, pField ) ) { CG_NDR * pOldPlaceholder; pOldPlaceholder = pCCB->SetLastPlaceholderClass( pField ); pMember = (CG_NDR *) pField->GetChild(); if ( pMember->IsPointer() && !pMember->IsInterfacePointer() ) { CG_POINTER * pPointer; pPointer = (CG_POINTER *) pMember; // Push the instance type. if ( ! fNoType ) { pFormatString->PushFormatChar( FC_NO_REPEAT ); pFormatString->PushFormatChar( FC_PAD ); } pFormatString->PushShort( (short) (ImbedingMemSize + pField->GetMemOffset())); pFormatString->PushShort( (short) (ImbedingBufSize + pField->GetWireOffset())); // The actual pointer description. pPointer->GenNdrFormatEmbedded( pCCB ); } // // Generate pointer descriptions for all embedded arrays and structs. // We don't have to check for unions because that will make the struct // complex. // if ( pMember->IsArray() ) { CG_NDR * pNdr = (CG_NDR *) pMember->GetChild(); // // For arrays we set the imbeded memory size equal to the // size of the whole imbededing structure. // pCCB->SetImbedingMemSize( ImbedingMemSize + GetMemorySize() ); pCCB->SetImbedingBufSize( ImbedingBufSize + GetWireSize() ); if ( (pNdr->IsPointer() && !pNdr->IsInterfacePointer() ) || ( pNdr->IsStruct() && ((CG_COMP *)pNdr)->HasPointer() ) ) ((CG_ARRAY *)pMember)->GenNdrFormatArrayPointerLayout( pCCB, TRUE ); } if ( pMember->IsStruct() ) if ( ((CG_STRUCT *)pMember)->HasPointer() ) { // // For embedded structs we add the embedded struct's offset to // the value of the current embeddeding size. // pCCB->SetImbedingMemSize( ImbedingMemSize + pField->GetMemOffset() ); pCCB->SetImbedingBufSize( ImbedingBufSize + pField->GetWireOffset() ); ((CG_STRUCT *)pMember)->GenNdrStructurePointerLayout( pCCB, TRUE, fNoType ); } pCCB->SetLastPlaceholderClass( pOldPlaceholder ); } // while if ( ! fNoPP ) pFormatString->PushFormatChar( FC_END ); // Re-set the old imbeding sizes. pCCB->SetImbedingMemSize( ImbedingMemSize ); pCCB->SetImbedingBufSize( ImbedingBufSize ); // There is no call to the string optimizer here. If we wanted to put it in, // the code should check if the optimization is possible or not by checking the // result of GenNdrEmbeddedPointers via GenNdrStructurePointerLayout call. } CG_FIELD * CG_STRUCT::GetPreviousField( CG_FIELD * pMarkerField ) /*++ Routine description: Finds the field immediately preceding the given field. Argument: pMarkerField - the given field Returns: The preceding field or NULL if the given field is the first one. --*/ { CG_ITERATOR Iterator; CG_FIELD *pField, *pPreviousField = 0; GetMembers( Iterator ); while( ITERATOR_GETNEXT( Iterator, pField ) ) { if ( pField == pMarkerField ) return( pPreviousField ); pPreviousField = pField; } return( 0 ); } void CG_STRUCT::GenStructureMemPad( CCB * pCCB, unsigned long MemPad ) /*++ Routine Description : Generates the format string for memory padding in a structure layout. Arguments : pCCB - pointer to the code control block. MemPad - Amount of required padding. --*/ { FORMAT_STRING * pFormatString = pCCB->GetFormatString(); MIDL_ASSERT( MemPad < 0xFFFF ); // structures must be less then 64k switch( MemPad) { case 0: return; // No padding needed case 1: pFormatString->PushFormatChar( FC_STRUCTPAD1 ); return; case 2: pFormatString->PushFormatChar( FC_STRUCTPAD2 ); return; case 3: pFormatString->PushFormatChar( FC_STRUCTPAD3 ); return; case 4: pFormatString->PushFormatChar( FC_STRUCTPAD4 ); return; case 5: pFormatString->PushFormatChar( FC_STRUCTPAD5 ); return; case 6: pFormatString->PushFormatChar( FC_STRUCTPAD6 ); return; case 7: pFormatString->PushFormatChar( FC_STRUCTPAD7 ); return; default: // NDR60 Feature // Pad an arbitrary amount // FC_STRUCTPADN 0 pFormatString->Align(); pFormatString->PushFormatChar( FC_STRUCTPADN ); pFormatString->PushFormatChar( FC_ZERO ); pFormatString->PushShort( (short)MemPad ); pCommand->GetNdrVersionControl().SetHasStructPadN(); } } void CG_STRUCT::GenNdrStructureLayout( CCB * pCCB ) /*++ Routine Description : Generates the format string layout section for a structure. Arguments : pCCB - pointer to the code control block. --*/ { FORMAT_STRING * pFormatString = pCCB->GetFormatString(); CG_NDR * pOldPlaceholder = pCCB->GetLastPlaceholderClass(); CG_ITERATOR Iterator; GetMembers( Iterator ); CG_FIELD * pField; CG_FIELD * pPrevField = NULL; unsigned long BufferOffset = 0; bool fSawUnknownRepAs = false; while( ITERATOR_GETNEXT( Iterator, pField ) ) { if ( fSawUnknownRepAs && !pField->HasEmbeddedUnknownRepAs() ) { switch ( pField->GetMemoryAlignment() ) { case 2: pFormatString->PushFormatChar( FC_ALIGNM2 ); break; case 4: pFormatString->PushFormatChar( FC_ALIGNM4 ); break; case 8: pFormatString->PushFormatChar( FC_ALIGNM8 ); break; } } else if ( !fSawUnknownRepAs && !pField->HasEmbeddedUnknownRepAs() ) { unsigned long MemPad = pField->GetMemOffset() - BufferOffset; GenStructureMemPad( pCCB, MemPad ); BufferOffset += MemPad; } pCCB->SetLastPlaceholderClass( pField ); CG_NDR *pMember = (CG_NDR *) pField->GetChild(); while ( pMember->GetCGID() == ID_CG_TYPEDEF ) { pMember = ( CG_NDR* )pMember->GetChild(); } // The ending conformat array is not included in the // size of the structure. // Note that this must be the last field. if ( pMember->GetCGID() == ID_CG_CONF_ARRAY || pMember->GetCGID() == ID_CG_CONF_VAR_ARRAY || pMember->GetCGID() == ID_CG_CONF_STRING_ARRAY ) { break; } // Generate an embedded complex for embedded things. if ( pMember->IsStruct() || pMember->IsUnion() || pMember->IsArray() || pMember->IsXmitRepOrUserMarshal() || pMember->GetRangeAttribute() || pMember->IsInterfacePointer() ) { pFormatString->PushFormatChar( FC_EMBEDDED_COMPLEX ); if ( pField->HasEmbeddedUnknownRepAs() ) { pCCB->GetRepAsPadExprDict()->Register( pFormatString->GetCurrentOffset(), GetType(), pField->GetType()->GetSymName(), pPrevField ? pPrevField->GetType() : 0 ); pFormatString->PushByteWithPadMacro(); fSawUnknownRepAs = true; } else { pFormatString->PushByte( 0 ); //Padding is generated independently } if ( pMember->GetFormatStringOffset() == -1 || pMember->GetFormatStringOffset() == 0 ) { RegisterComplexEmbeddedForFixup( pMember, pFormatString->GetCurrentOffset() - GetInitialOffset() ); } pFormatString->PushShortOffset( pMember->GetFormatStringOffset() - pFormatString->GetCurrentOffset() ); } else if (pMember->IsPointer() || ( pMember->GetCGID() == ID_CG_IGN_PTR ) ) { if ( pMember->IsPointer() ) { if ( GetCGID() == ID_CG_COMPLEX_STRUCT ) pFormatString->PushFormatChar( FC_POINTER ); else { pFormatString->PushFormatChar( FC_LONG ); #if !defined(NDR64_ON_DCE_HACK ) MIDL_ASSERT( ! pCommand->Is64BitEnv() ); #endif } } else pFormatString->PushFormatChar( FC_IGNORE ); } #if defined( NDR64_ON_DCE_HACK ) else if ( NULL != dynamic_cast( pMember ) ) { pFormatString->PushFormatChar( FC_BUFFER_ALIGN ); pFormatString->PushByte( pMember->GetWireAlignment() - 1); } #endif else { // // Must be a CG_BASETYPE if we get here. // FORMAT_CHARACTER FormatChar = ((CG_BASETYPE *)pMember)->GetFormatChar(); pFormatString->PushFormatChar( FormatChar ); } BufferOffset += pField->GetMemorySize(); pPrevField = pField; } // Account for padding at the end of the structure. MIDL_ASSERT( GetMemorySize() >= BufferOffset ); unsigned long EndingPad = GetMemorySize() - BufferOffset; // End padding is only allow on complex struct. MIDL_ASSERT( EndingPad ? ( (GetCGID() == ID_CG_COMPLEX_STRUCT) || IsComplexStruct() || IsHardStruct() ) : true ); GenStructureMemPad( pCCB, EndingPad ); // // If the format string is on a short boundary right now then push // a format character so that the format string will be properly aligned // following the FC_END. // if ( ! (pFormatString->GetCurrentOffset() % 2) ) pFormatString->PushFormatChar( FC_PAD ); pFormatString->PushFormatChar( FC_END ); pCCB->SetLastPlaceholderClass( pOldPlaceholder ); } void CG_STRUCT::GenNdrStructurePointees( CCB * pCCB ) { CG_ITERATOR Iterator; FORMAT_STRING * pFormatString; CG_FIELD * pField; CG_NDR * pMember; pFormatString = pCCB->GetFormatString(); GetMembers( Iterator ); // // We only have to check for pointer fields here, because if the structure // has a struct or array field which has pointers, this will be handled // when we generate their format strings. // while( ITERATOR_GETNEXT( Iterator, pField ) ) { pMember = (CG_NDR *) pField->GetChild(); if ( pMember->IsPointer() && !pMember->IsInterfacePointer() ) { CG_NDR * pOldPlaceholder; pOldPlaceholder = pCCB->SetLastPlaceholderClass( pField ); // // Skip over an unattributed pointer to a simple type or string. // if ( ( ((CG_POINTER *)pMember)->IsPointerToBaseType() ) || ( pMember->GetCGID() == ID_CG_STRING_PTR ) ) { pCCB->SetLastPlaceholderClass( pOldPlaceholder ); continue; } ((CG_POINTER *)pMember)->GenNdrFormatPointee( pCCB ); pCCB->SetLastPlaceholderClass( pOldPlaceholder ); } } } BOOL CG_STRUCT::ShouldFreeOffline() { return ( (GetCGID() == ID_CG_COMPLEX_STRUCT) || (GetCGID() == ID_CG_CONF_VAR_STRUCT) || HasPointer() || IsComplexStruct() || IsHardStruct() ); } void CG_STRUCT::GenFreeInline( CCB* ) { } void CG_NDR::GenNdrPointerFixUp( CCB * pCCB, CG_STRUCT * pStruct ) { CG_ITERATOR Iterator; CG_NDR * pMember; CG_NDR * pNdr; long Offset; if ( ! IsStruct() && ! IsArray() && ! IsUnion() ) return; if ( IsInFixUp() ) return; SetFixUpLock( TRUE ); GetMembers( Iterator ); while ( ITERATOR_GETNEXT( Iterator, pMember ) ) { if ( IsStruct() ) { pNdr = (CG_NDR *) pMember->GetChild(); } else if ( IsUnion() ) { // member of union is a case, then case->field->ndr if ( pMember->GetChild() && pMember->GetChild()->GetChild() ) pNdr = (CG_NDR *) pMember->GetChild()->GetChild(); else continue; } else // IsArray() { pNdr = pMember; // // See if the array's element is the structure we're looking for. // if ( pNdr == pStruct ) { Offset = ((CG_ARRAY *)this)->GetElementDescriptionOffset() + 2; pCCB->GetFormatString()->PushShortOffset( pStruct->GetFormatStringOffset() - Offset, Offset ); } } if (pNdr->GetCGID() == ID_CG_TYPEDEF ) pNdr = (CG_NDR *)pNdr->GetChild(); if ( (pNdr->GetCGID() == ID_CG_PTR) || (pNdr->GetCGID() == ID_CG_SIZE_PTR) || (pNdr->GetCGID() == ID_CG_SIZE_LENGTH_PTR) ) { CG_POINTER * pPointer = (CG_POINTER *) pNdr; // // Check if we're ready for this guy yet. // if ( pPointer->GetFormatStringOffset() == -1 ) continue; // Get the pointee. switch ( pPointer->GetCGID() ) { case ID_CG_PTR : pNdr = (CG_NDR *) pPointer->GetChild(); break; case ID_CG_SIZE_PTR : pNdr = ((CG_SIZE_POINTER *)pPointer)->GetPointee(); break; case ID_CG_SIZE_LENGTH_PTR : pNdr = ((CG_SIZE_LENGTH_POINTER *)pPointer)->GetPointee(); break; } // // If the pointer's pointee is the struct we're checking for, // then patch up the pointer's offset_to_description<2> field. // if ( pNdr == pStruct ) { long PointerOffset; // // Get the offset in the format string where the // offset_to_description<2> field of the pointer is. // PointerOffset = pPointer->GetFormatStringOffset() + 2; /* printf( " **MIDL_fixup: Non-Reg Actually fixing %s at %d with %d (%d)\n", pNdr->GetSymName(), PointerOffset, pNdr->GetFormatStringOffset() - PointerOffset, pNdr->GetFormatStringOffset() ); */ pCCB->GetFormatString()->PushShortOffset( pStruct->GetFormatStringOffset() - PointerOffset, PointerOffset ); continue; } } // // This can happen sometimes because of structs which are promoted // to complex because of padding. // if ( pNdr == this ) continue; // // Continue the chase if necessary. // if ( pNdr->IsStruct() || pNdr->IsUnion() || pNdr->IsArray() ) pNdr->GenNdrPointerFixUp( pCCB, pStruct ); } SetFixUpLock( FALSE ); } void CG_NDR::RegisterComplexEmbeddedForFixup( CG_NDR * pEmbeddedComplex, long RelativeOffset ) { if ( GetInitialOffset() == -1 ) printf( " Internal compiler problem with recursive embeddings\n" ); MIDL_ASSERT( GetInitialOffset() != -1 ); if ( pEmbeddedComplexFixupRegistry == NULL ) { pEmbeddedComplexFixupRegistry = new TREGISTRY; } // printf( "MIDL_fixup: RegisterComplex %s\n", pEmbeddedComplex->GetSymName()); EMB_COMPLEX_FIXUP * pFixup = new EMB_COMPLEX_FIXUP; pFixup->pEmbeddedNdr = pEmbeddedComplex; pFixup->RelativeOffset = RelativeOffset; pEmbeddedComplexFixupRegistry->Register( (node_skl *)pFixup ); } void CG_NDR::FixupEmbeddedComplex( CCB * pCCB ) { if ( IsInComplexFixup() ) return; SetComplexFixupLock( TRUE ); // Go down first CG_ITERATOR Iterator; CG_NDR * pField; GetMembers( Iterator ); while ( ITERATOR_GETNEXT( Iterator, pField ) ) pField->FixupEmbeddedComplex( pCCB ); // Now fix up this level description. if ( GetEmbeddedComplexFixupRegistry() ) { ITERATOR FixupList; EMB_COMPLEX_FIXUP * pFixup; long FixAtOffset; FORMAT_STRING * pFormatString = pCCB->GetFormatString(); GetListOfEmbeddedComplex( FixupList ); while ( ITERATOR_GETNEXT( FixupList, pFixup ) ) { FixAtOffset = GetFormatStringOffset() + pFixup->RelativeOffset; pFormatString->PushShortOffset( pFixup->pEmbeddedNdr->GetFormatStringOffset() - FixAtOffset, FixAtOffset ); /* printf( " MIDL_fixup: Reg-Cmplx Actually fixing at %d with %d\n", FixAtOffset, pFixup->pEmbeddedNdr->GetFormatStringOffset() - FixAtOffset ); */ } } // Due to duplication, the list may be at the duplicating node. if ( IsStruct() ) { CG_COMPLEX_STRUCT * pDuping = ((CG_STRUCT *)this)->GetDuplicatingComplex(); if ( pDuping ) pDuping->FixupEmbeddedComplex( pCCB ); } SetComplexFixupLock( FALSE ); } // All these different ways of fixing recursive pointers need to be cleaned up. // The RecPointer registry seems to be the best solution in that it fixes // the pointers once per compilation while complex embed fixup calls walk the // tree several times recursively. // Also, the reason the below registry is different from previously introduced // EmbeddedComplex fixup registry is that the emb cplx fixup registry uses // a relative pointer when fixing up while the bug we are trying to address now // affects standalone pointers where absolute offset is appropriate. // The basic scheme with "struct _S**" field shows up in VARIANT and LPSAFEARRAY. // Rkk, May, 1999. void CCB::RegisterRecPointerForFixup( CG_NDR * pNdr, long AbsoluteOffset ) { if ( pRecPointerFixupRegistry == NULL ) { pRecPointerFixupRegistry = new TREGISTRY; } POINTER_FIXUP * pFixup = new POINTER_FIXUP; // printf( "MIDL_fixup: Registering for %s at %d\n", pNdr->GetSymName(), AbsoluteOffset); pFixup->pNdr = pNdr; pFixup->AbsoluteOffset = AbsoluteOffset; pFixup->fFixed = false; pRecPointerFixupRegistry->Register( (node_skl *)pFixup ); } void CCB::FixupRecPointers() { if ( GetRecPointerFixupRegistry() ) { ITERATOR FixupList; POINTER_FIXUP * pFixup; long FixAtOffset; FORMAT_STRING * pFormatString = GetFormatString(); GetListOfRecPointerFixups( FixupList ); while ( ITERATOR_GETNEXT( FixupList, pFixup ) ) { FixAtOffset = pFixup->AbsoluteOffset; if ( ! pFixup->fFixed ) { long Recorded = pFormatString->GetFormatShort(FixAtOffset) + FixAtOffset; long NdrOffset = pFixup->pNdr->GetFormatStringOffset(); if ( 0 == Recorded && 0 != NdrOffset || -1 == Recorded && -1 != NdrOffset ) { /* printf( " MIDL_fixup: Actually fixing %s at %d with %d (%d)\n", pFixup->pNdr->GetSymName(), FixAtOffset, NdrOffset - FixAtOffset, NdrOffset ); */ pFormatString->PushShortOffset( NdrOffset - FixAtOffset, FixAtOffset ); pFixup->fFixed = true; } /* else if ( 0 != Recorded && -1 != Recorded ) { printf( " MIDL_fixup: %s at %d was already fixed to %d (%d)\n", pFixup->pNdr->GetSymName(), FixAtOffset, NdrOffset - FixAtOffset, NdrOffset ); pFixup->fFixed = true; } else { printf( " MIDL_fixup: %s at %d has not been fixed to %d (%d)\n", pFixup->pNdr->GetSymName(), FixAtOffset, NdrOffset - FixAtOffset, NdrOffset ); } */ } // if ! fixed } // while } } long CG_STRUCT::FixedBufferSize( CCB * pCCB ) { CG_ITERATOR Iterator; CG_FIELD * pField; CG_NDR * pNdr; CG_NDR * pOldPlaceholder; long TotalBufferSize; long BufSize; // // Check for recursion. // if ( IsInFixedBufferSize() ) return -1; if ( (GetCGID() == ID_CG_CONF_STRUCT) || (GetCGID() == ID_CG_CONF_VAR_STRUCT) || (GetCGID() == ID_CG_COMPLEX_STRUCT) || IsComplexStruct() ) return -1; if ( IsHardStruct() ) { if ( GetNumberOfUnions() == 0 ) return MAX_WIRE_ALIGNMENT + GetWireSize(); else return -1; } SetInFixedBufferSize( TRUE ); MIDL_ASSERT( GetCGID() == ID_CG_STRUCT ); pOldPlaceholder = pCCB->SetLastPlaceholderClass( this ); GetMembers( Iterator ); TotalBufferSize = MAX_WIRE_ALIGNMENT + GetWireSize(); while ( ITERATOR_GETNEXT( Iterator, pField ) ) { pNdr = (CG_NDR *) pField->GetChild(); // skip these nodes to get to the transmitted element type. if ( pNdr->IsXmitRepOrUserMarshal() ) pNdr = (CG_NDR *)pNdr->GetChild(); if ( pNdr->IsStruct() || pNdr->IsArray() || pNdr->IsPointer() ) { BufSize = pNdr->FixedBufferSize( pCCB ); if ( BufSize == -1 ) { SetInFixedBufferSize( FALSE ); return -1; } // // First subtract the basic size of this thing from the struct's // size and then add back the value it returned. // TotalBufferSize -= pNdr->GetWireSize(); TotalBufferSize += BufSize; } } pCCB->SetLastPlaceholderClass( pOldPlaceholder ); SetInFixedBufferSize( FALSE ); // Success! return TotalBufferSize; }