DynamicAssembly, FieldBuilder and fixed size buffers

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • =?Utf-8?B?TWFyZWs=?=

    DynamicAssembly, FieldBuilder and fixed size buffers

    Hi
    I am trying to dynamically create the following structure using
    AssemblyBuilder , TypeBuilder and DefineField:

    [StructLayout(La youtKind.Sequen tial, Pack = 8)]
    public struct SimpleType2
    {
    public double dScalar1;
    public fixed double dArray[5];
    public int iScalar1;
    }

    I've got pretty much everything working except the fixed keyword on the
    dArray[5] member. I tried to add this using a custom attribute, but as soon
    as I did that, the field was not added to the created type. Is this the
    right approach? Could it be that I need to mark the code as unsafe or
    something?

    Any help would be much appreciated.

    Best regards

    Marek
  • Jialiang Ge [MSFT]

    #2
    RE: DynamicAssembly , FieldBuilder and fixed size buffers

    Hello Marek,

    I'd suggest you use the utility "ILReader" from:

    plus the .net Reflector from


    The two tools can help us write codes to dynamically create
    assembly/module/type. With the help of the tools, I wrote the following
    code for your SimpleType2 type:
    (Note: because Newsgroup system may wrap the long sentences and make it
    hard for you to read my codes, I attach the .cs file to this message for
    your convenience. You can download the .cs code file with outlook express
    or windows mail)

    public class Test
    {
    static TypeBuilder fixedBufTypeBui lder;

    public static void Main()
    {
    AppDomain.Curre ntDomain.TypeRe solve += new
    ResolveEventHan dler(CurrentDom ain_TypeResolve );

    #region AttributeBuilde rs
    // UnsafeValueType Attribute
    ConstructorInfo unsafeValueType Ctor =
    typeof(UnsafeVa lueTypeAttribut e).GetConstruct or(new Type[] { });
    CustomAttribute Builder unsafeAttrBuild er = new
    CustomAttribute Builder(unsafeV alueTypeCtor, new object[] { });

    // UnverifiableCod eAttribute
    ConstructorInfo unverifiableCto r =
    typeof(Unverifi ableCodeAttribu te).GetConstruc tor(new Type[] { });
    CustomAttribute Builder unverifiableAtt rBuilder = new
    CustomAttribute Builder(unverif iableCtor, new object[] { });

    // CompilerGenerat edAttribute
    ConstructorInfo compilerGenCtor =
    typeof(Compiler GeneratedAttrib ute).GetConstru ctor(new Type[] { });
    CustomAttribute Builder compilerGenAttr Builder = new
    CustomAttribute Builder(compile rGenCtor, new object[] { });

    // FixedBufferAttr ibute
    ConstructorInfo fixedBufCtor =
    typeof(FixedBuf ferAttribute).G etConstructor(n ew Type[] { typeof(Type),
    typeof(int) });
    CustomAttribute Builder fixedBufAttrBui lder = new
    CustomAttribute Builder(fixedBu fCtor, new object[] { typeof(double), 5 });
    #endregion

    AssemblyName asmname = new AssemblyName("m ytest");
    AssemblyBuilder asmbuild =
    AppDomain.Curre ntDomain.Define DynamicAssembly (asmname,
    AssemblyBuilder Access.RunAndSa ve);
    ModuleBuilder moduleBuilder =
    asmbuild.Define DynamicModule(" mytest", "mytest.dll ");
    moduleBuilder.S etCustomAttribu te(unverifiable AttrBuilder);

    TypeBuilder typeBuilder = moduleBuilder.D efineType("Simp leType2",
    TypeAttributes. Public | TypeAttributes. SequentialLayou t,
    typeof(ValueTyp e), PackingSize.Siz e8);

    #region <dArray>e__Fixe dBuffer0
    fixedBufTypeBui lder =
    typeBuilder.Def ineNestedType(" <dArray>e__Fixe dBuffer0",
    TypeAttributes. NestedPublic | TypeAttributes. SequentialLayou t,
    typeof(ValueTyp e), 40);
    fixedBufTypeBui lder.SetCustomA ttribute(compil erGenAttrBuilde r);
    fixedBufTypeBui lder.SetCustomA ttribute(unsafe AttrBuilder);
    fixedBufTypeBui lder.DefineFiel d("FixedElement Field",
    typeof(double), FieldAttributes .Public);
    #endregion

    typeBuilder.Def ineField("dScal ar1", typeof(double),
    FieldAttributes .Public);
    FieldBuilder fixedBufFieldBu ilder =
    typeBuilder.Def ineField("dArra y", fixedBufTypeBui lder,
    FieldAttributes .Public);
    fixedBufFieldBu ilder.SetCustom Attribute(fixed BufAttrBuilder) ;
    typeBuilder.Def ineField("iScal ar1", typeof(int),
    FieldAttributes .Public);

    typeBuilder.Cre ateType();

    asmbuild.Save(" mytest");
    }

    private static Assembly CurrentDomain_T ypeResolve(obje ct sender,
    ResolveEventArg s args)
    {
    if (args.Name == "<dArray>e__Fix edBuffer0")
    {
    return fixedBufTypeBui lder.CreateType ().Assembly;
    }
    return null;
    }
    }

    In the code above, the line
    AppDomain.Curre ntDomain.TypeRe solve += new
    ResolveEventHan dler(CurrentDom ain_TypeResolve );
    Is used for the nested struct type. See:

    ckID=98299

    Below is my detailed steps when I write the code above (I think this may
    help you if you encounter such cases again in future)
    Step1. Compose a simple assembly with our target code:
    [StructLayout(La youtKind.Sequen tial, Pack = 8)]
    public unsafe struct SimpleType2
    {
    public double dScalar1;
    public fixed double dArray[5];
    public int iScalar1;
    }

    Step2. Compile the assembly, use .NET Reflector to open the output dll, and
    use ILReader to parse the dll.
    Step3. Translate the output of ILReader to our AssemblyBuilder ,
    TypeBuilder, DefineField codes
    Step4. Run our AssemblyBuilder , TypeBuilder, DefineField codes and get the
    resulting assembly dll.
    Step5. Use .Net Reflector to open the dll, and compare its result with the
    that of the dll in step2.

    If you have any other concerns or questions, feel free to let me know.

    Regards,
    Jialiang Ge (jialge@online. microsoft.com, remove 'online.')
    Microsoft Online Community Support

    Delighting our customers is our #1 priority. We welcome your comments and
    suggestions about how we can improve the support we provide to you. Please
    feel free to let my manager know what you think of the level of service
    provided. You can send feedback directly to my manager at:
    msdnmg@microsof t.com.

    =============== =============== =============== =====
    Get notification to my posts through email? Please refer to
    Gain technical skills through documentation and training, earn certifications and connect with the community

    ications.

    Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
    where an initial response from the community or a Microsoft Support
    Engineer within 1 business day is acceptable. Please note that each follow
    up response may take approximately 2 business days as the support
    professional working with you may need further investigation to reach the
    most efficient resolution. The offering is not appropriate for situations
    that require urgent, real-time or phone-based interactions or complex
    project analysis and dump analysis issues. Issues of this nature are best
    handled working with a dedicated Microsoft Support Engineer by contacting
    Microsoft Customer Support Services (CSS) at
    http://msdn.microsoft.com/subscripti...t/default.aspx.
    =============== =============== =============== =====
    This posting is provided "AS IS" with no warranties, and confers no rights.

    Comment

    • =?Utf-8?B?TWFyZWs=?=

      #3
      RE: DynamicAssembly , FieldBuilder and fixed size buffers

      Hi Jialiang
      Fantastic - that has done the trick. Believe it or not this code is now
      calling into a FORTRAN dll with a structure, which is exactly what I wanted
      to do. As with all these things though, one answer generates another
      question:

      I would like to display the fixed array field correctly inside the property
      grid and I notice the debugger has no problem working out what the field is,
      whereas the property grid does. I guess I need some sort of TypeConverter?
      Is there a standard way of achieving what I need?

      Many thanks again.

      Best regards

      Marek

      "Jialiang Ge [MSFT]" wrote:
      Hello Marek,
      >
      I'd suggest you use the utility "ILReader" from:

      plus the .net Reflector from

      >
      The two tools can help us write codes to dynamically create
      assembly/module/type. With the help of the tools, I wrote the following
      code for your SimpleType2 type:
      (Note: because Newsgroup system may wrap the long sentences and make it
      hard for you to read my codes, I attach the .cs file to this message for
      your convenience. You can download the .cs code file with outlook express
      or windows mail)
      >
      public class Test
      {
      static TypeBuilder fixedBufTypeBui lder;
      >
      public static void Main()
      {
      AppDomain.Curre ntDomain.TypeRe solve += new
      ResolveEventHan dler(CurrentDom ain_TypeResolve );
      >
      #region AttributeBuilde rs
      // UnsafeValueType Attribute
      ConstructorInfo unsafeValueType Ctor =
      typeof(UnsafeVa lueTypeAttribut e).GetConstruct or(new Type[] { });
      CustomAttribute Builder unsafeAttrBuild er = new
      CustomAttribute Builder(unsafeV alueTypeCtor, new object[] { });
      >
      // UnverifiableCod eAttribute
      ConstructorInfo unverifiableCto r =
      typeof(Unverifi ableCodeAttribu te).GetConstruc tor(new Type[] { });
      CustomAttribute Builder unverifiableAtt rBuilder = new
      CustomAttribute Builder(unverif iableCtor, new object[] { });
      >
      // CompilerGenerat edAttribute
      ConstructorInfo compilerGenCtor =
      typeof(Compiler GeneratedAttrib ute).GetConstru ctor(new Type[] { });
      CustomAttribute Builder compilerGenAttr Builder = new
      CustomAttribute Builder(compile rGenCtor, new object[] { });
      >
      // FixedBufferAttr ibute
      ConstructorInfo fixedBufCtor =
      typeof(FixedBuf ferAttribute).G etConstructor(n ew Type[] { typeof(Type),
      typeof(int) });
      CustomAttribute Builder fixedBufAttrBui lder = new
      CustomAttribute Builder(fixedBu fCtor, new object[] { typeof(double), 5 });
      #endregion
      >
      AssemblyName asmname = new AssemblyName("m ytest");
      AssemblyBuilder asmbuild =
      AppDomain.Curre ntDomain.Define DynamicAssembly (asmname,
      AssemblyBuilder Access.RunAndSa ve);
      ModuleBuilder moduleBuilder =
      asmbuild.Define DynamicModule(" mytest", "mytest.dll ");
      moduleBuilder.S etCustomAttribu te(unverifiable AttrBuilder);
      >
      TypeBuilder typeBuilder = moduleBuilder.D efineType("Simp leType2",
      TypeAttributes. Public | TypeAttributes. SequentialLayou t,
      typeof(ValueTyp e), PackingSize.Siz e8);
      >
      #region <dArray>e__Fixe dBuffer0
      fixedBufTypeBui lder =
      typeBuilder.Def ineNestedType(" <dArray>e__Fixe dBuffer0",
      TypeAttributes. NestedPublic | TypeAttributes. SequentialLayou t,
      typeof(ValueTyp e), 40);
      fixedBufTypeBui lder.SetCustomA ttribute(compil erGenAttrBuilde r);
      fixedBufTypeBui lder.SetCustomA ttribute(unsafe AttrBuilder);
      fixedBufTypeBui lder.DefineFiel d("FixedElement Field",
      typeof(double), FieldAttributes .Public);
      #endregion
      >
      typeBuilder.Def ineField("dScal ar1", typeof(double),
      FieldAttributes .Public);
      FieldBuilder fixedBufFieldBu ilder =
      typeBuilder.Def ineField("dArra y", fixedBufTypeBui lder,
      FieldAttributes .Public);
      fixedBufFieldBu ilder.SetCustom Attribute(fixed BufAttrBuilder) ;
      typeBuilder.Def ineField("iScal ar1", typeof(int),
      FieldAttributes .Public);
      >
      typeBuilder.Cre ateType();
      >
      asmbuild.Save(" mytest");
      }
      >
      private static Assembly CurrentDomain_T ypeResolve(obje ct sender,
      ResolveEventArg s args)
      {
      if (args.Name == "<dArray>e__Fix edBuffer0")
      {
      return fixedBufTypeBui lder.CreateType ().Assembly;
      }
      return null;
      }
      }
      >
      In the code above, the line
      AppDomain.Curre ntDomain.TypeRe solve += new
      ResolveEventHan dler(CurrentDom ain_TypeResolve );
      Is used for the nested struct type. See:

      ckID=98299
      >
      Below is my detailed steps when I write the code above (I think this may
      help you if you encounter such cases again in future)
      Step1. Compose a simple assembly with our target code:
      [StructLayout(La youtKind.Sequen tial, Pack = 8)]
      public unsafe struct SimpleType2
      {
      public double dScalar1;
      public fixed double dArray[5];
      public int iScalar1;
      }
      >
      Step2. Compile the assembly, use .NET Reflector to open the output dll, and
      use ILReader to parse the dll.
      Step3. Translate the output of ILReader to our AssemblyBuilder ,
      TypeBuilder, DefineField codes
      Step4. Run our AssemblyBuilder , TypeBuilder, DefineField codes and get the
      resulting assembly dll.
      Step5. Use .Net Reflector to open the dll, and compare its result with the
      that of the dll in step2.
      >
      If you have any other concerns or questions, feel free to let me know.
      >
      Regards,
      Jialiang Ge (jialge@online. microsoft.com, remove 'online.')
      Microsoft Online Community Support
      >
      Delighting our customers is our #1 priority. We welcome your comments and
      suggestions about how we can improve the support we provide to you. Please
      feel free to let my manager know what you think of the level of service
      provided. You can send feedback directly to my manager at:
      msdnmg@microsof t.com.
      >
      =============== =============== =============== =====
      Get notification to my posts through email? Please refer to
      Gain technical skills through documentation and training, earn certifications and connect with the community

      ications.
      >
      Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
      where an initial response from the community or a Microsoft Support
      Engineer within 1 business day is acceptable. Please note that each follow
      up response may take approximately 2 business days as the support
      professional working with you may need further investigation to reach the
      most efficient resolution. The offering is not appropriate for situations
      that require urgent, real-time or phone-based interactions or complex
      project analysis and dump analysis issues. Issues of this nature are best
      handled working with a dedicated Microsoft Support Engineer by contacting
      Microsoft Customer Support Services (CSS) at
      http://msdn.microsoft.com/subscripti...t/default.aspx.
      =============== =============== =============== =====
      This posting is provided "AS IS" with no warranties, and confers no rights

      Comment

      • Jialiang Ge [MSFT]

        #4
        RE: DynamicAssembly , FieldBuilder and fixed size buffers

        Hi Marek,

        Would you let me know what the "property grid" is? Do you mean the Property
        window in Visual Studio IDE? How do you display the fixed field in it
        currently?

        Regards,
        Jialiang Ge (jialge@online. microsoft.com, remove 'online.')
        Microsoft Online Community Support

        =============== =============== =============== ====
        Delighting our customers is our #1 priority. We welcome your comments and
        suggestions about how we can improve the support we provide to you. Please
        feel free to let my manager know what you think of the level of service
        provided. You can send feedback directly to my manager at:
        msdnmg@microsof t.com.

        This posting is provided "AS IS" with no warranties, and confers no rights.
        =============== =============== =============== ====

        Comment

        • =?Utf-8?B?TWFyZWs=?=

          #5
          RE: DynamicAssembly , FieldBuilder and fixed size buffers

          Hi Jialiang
          The property grid is essentially the standard .NET (Windows Forms) property
          grid control which I would like the users to use to populate this fixed array
          structure before calling into the FORTRAN DLL.

          I have tried to extract the the data from the object using code such as this:

          object data =
          parameterValues[0].GetType().Invo keMember("dArra y", BindingFlags.Ge tField,
          null, parameterValues[0], null);

          List<doublevalu es = new List<double>();
          double start =
          (double)instanc e.GetType().Get Field("FixedEle mentField").Get Value(instance) ;

          fixed (double* pValue = (double*)(&star t))
          {
          for (int i = 0; i < 5; i++)
          values.Add(*(pV alue + i));
          }

          But this is not giving me the values I am expecting. The first one is
          correct, after that it all seems to go wrong!

          If I could get the above to work, I might be able to attach a TypeConverter
          to the field(?) so that it displays correctly in the .NET property grid.

          Best regards

          Marek


          "Jialiang Ge [MSFT]" wrote:
          Hi Marek,
          >
          Would you let me know what the "property grid" is? Do you mean the Property
          window in Visual Studio IDE? How do you display the fixed field in it
          currently?
          >
          Regards,
          Jialiang Ge (jialge@online. microsoft.com, remove 'online.')
          Microsoft Online Community Support
          >
          =============== =============== =============== ====
          Delighting our customers is our #1 priority. We welcome your comments and
          suggestions about how we can improve the support we provide to you. Please
          feel free to let my manager know what you think of the level of service
          provided. You can send feedback directly to my manager at:
          msdnmg@microsof t.com.
          >
          This posting is provided "AS IS" with no warranties, and confers no rights.
          =============== =============== =============== ====
          >
          >

          Comment

          • Jialiang Ge [MSFT]

            #6
            RE: DynamicAssembly , FieldBuilder and fixed size buffers

            Hello Marek,

            The following solution may work, but I understand it's a very bad and
            tricky one. I post it here simply to let you know that I am still
            researching the issue and will find a better one soon.

            object data = myVal.GetType() .InvokeMember(" dArray",
            BindingFlags.Ge tField, null, myVal, null);
            List<doublevalu es = new List<double>();
            double start =
            (double)data.Ge tType().GetFiel d("FixedElement Field").GetValu e(data);
            double* startAddr = &start;

            // I find the array's values start from (startAddr + 3) in your
            struct SimpleType2
            // and the value at (startAddr + 2) is dScalar1
            for (int i = 3; i < 3 + 5; i++)
            values.Add(*(st artAddr + i));

            Regards,
            Jialiang Ge (jialge@online. microsoft.com, remove 'online.')
            Microsoft Online Community Support

            =============== =============== =============== ====
            Delighting our customers is our #1 priority. We welcome your comments and
            suggestions about how we can improve the support we provide to you. Please
            feel free to let my manager know what you think of the level of service
            provided. You can send feedback directly to my manager at:
            msdnmg@microsof t.com.

            This posting is provided "AS IS" with no warranties, and confers no rights.
            =============== =============== =============== ====

            Comment

            • Jialiang Ge [MSFT]

              #7
              RE: DynamicAssembly , FieldBuilder and fixed size buffers

              Hello Marek,

              Based on my further researches, I find we can use the method:
              Marshal.OffsetO f to get the correct field offset of the unmanaged form in
              the managed struct/class. I write the following sample code which works
              well on my side. Please try it and let me know if it helps in your .NET and
              FORTRAN DLL interoperabilit y scenario.

              unsafe
              {
              SimpleType2 myVal;
              myVal.dScalar1 = 3.0;
              myVal.dArray[0] = 1.1;
              myVal.dArray[1] = 1.2;
              myVal.dArray[2] = 1.3;
              myVal.dArray[3] = 1.4;
              myVal.dArray[4] = 1.5;
              myVal.iScalar1 = 4;

              byte* pStruct = (byte*)&myVal;
              IntPtr dArrayPtr = Marshal.OffsetO f(myVal.GetType (), "dArray");
              pStruct += (int)dArrayPtr;
              double* pValue = (double*) pStruct;
              List<doublevalu es = new List<double>();
              for (int i = 0; i < 5; i++)
              values.Add(*(pV alue + i));
              }

              If you have any other concerns or questions, feel free to let me know.

              Regards,
              Jialiang Ge
              Microsoft Online Community Support

              =============== =============== =============== ====
              Delighting our customers is our #1 priority. We welcome your comments and
              suggestions about how we can improve the support we provide to you. Please
              feel free to let my manager know what you think of the level of service
              provided. You can send feedback directly to my manager at:
              msdnmg@microsof t.com.

              This posting is provided "AS IS" with no warranties, and confers no rights.
              =============== =============== =============== ====

              Comment

              Working...