Convert byte array to byte pointer

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • MrVS
    New Member
    • Jan 2009
    • 12

    #16
    Originally posted by MrVS
    Hi,

    I just found out the caller of the MQCBX function passed in a serialized object "cbd* from the CSharp program.
    eg. in C#
    Code:
    private byte[] MQCBD_ToByteArray(MQCBDs obj)
            {
                if (obj == null)
                    return null;
                BinaryFormatter bf = new BinaryFormatter();
                MemoryStream ms = new MemoryStream();
                try
                {
                    bf.Serialize(ms, obj);
                }
                catch (Exception Exp)
                {
                    // report the error
                    System.Console.WriteLine("MQQueue::Get ended with " + Exp.Message);
                }             
                return ms.ToArray();
            }
    The problem now is how can I deserialize the "cbd" object in VC++ (CLI)?
    In CSharp, do I really need to serialize the "cbd" object into byte-array before passing it to the VC++ function and deserialize it there?



    Thanks for the help.
    The MQCBDs object is defined as a class in CSharp:
    Code:
    [Serializable,StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        public class MQCBDs
        {
            public const string MQCBD_STRUC_ID = "CBD ";
            public const int MQCBD_VERSION_1 = 1;
            public const int MQCBD_CURRENT_VERSION = 1;
            public const int MQCBDO_NONE = 0x00000000;
            public const int MQCBDO_START_CALL = 0x00000001;
            public const int MQCBDO_STOP_CALL = 0x00000004;
            public const int MQCBDO_REGISTER_CALL = 0x00000100;
            public const int MQCBDO_DEREGISTER_CALL = 0x00000200;
            public const int MQCBDO_FAIL_IF_QUIESCING = 0x00002000;
            public const int MQCBT_MESSAGE_CONSUMER = 0x00000001;
            public const int MQCBT_EVENT_HANDLER = 0x00000002;
            public const int MQCBD_FULL_MSG_LENGTH = -1;
    
            //    MQCHAR4    StrucId;           /* Structure identifier */
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] StrucId;
            //    MQLONG     Version;           /* Structure version number */
            public int Version;
            //    MQLONG     CallbackType;      /* Callback function type */
            public int CallbackType;
            //    MQLONG     Options;           /* Options controlling message
            public int Options;
            //                                     consumption */
            //    MQPTR      CallbackArea;      /* User data passed to the function */
            public byte[] CallbackArea;
            //    MQPTR      CallbackFunction;  /* FP: Callback function pointer */
            //public mqCallBacks CallbackFunction;
            //    MQCHAR128  CallbackName;      /* Callback name */
            //       [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
            //     public string CallbackName;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
            public byte[] CallbackName;
    
            //    MQLONG     MaxMsgLength;      /* Maximum message length */
            public int MaxMsgLength;
    
            public MQCBDs()
            {
                StrucId = utilities.getBytes(MQCBD_STRUC_ID);
                //StrucId = getBytes(MQCBD_STRUC_ID);
                Version = MQCBD_VERSION_1;
                CallbackType = MQCBT_MESSAGE_CONSUMER;
                Options = MQCBDO_NONE;
                CallbackArea = null;
                //CallbackFunction = null;
                CallbackName = new byte[128];
                Array.Clear(CallbackName, 0, CallbackName.Length);
                MaxMsgLength = MQCBD_FULL_MSG_LENGTH;
            }
        }
    My goal is pass this MQCBDs object from CSharp to VC++(CLI).

    Thanks

    Comment

    • vekipeki
      Recognized Expert New Member
      • Nov 2007
      • 229

      #17
      Are you writing both programs, or is one of them already written and cannot be changed?

      Because there is no problem in passing a managed object between C# and C+/CLI -- they both accept managed code. There is no need to do any conversion.

      Avoid using .NET internal binary serialization when passing objects between applications written in different languages. If you need to get a native object, use marshaling. But here, you can simply pass a managed object.

      The easiest way would be to define your MQCBDs class in C++/CLI (byte_test namespace). Then your can import it to C# (using byte_test;), and you have your same managed class in both applications.

      Comment

      • MrVS
        New Member
        • Jan 2009
        • 12

        #18
        If I can do it by passing C# class object to C++ CLI, I want to see how complicated it is. Because my programmers want to write as much as they can in C# including the MQCBDs class, then pass the MQCBDs object into C++ CLI for a lower level operation. There are just too many similar MQXXX classes/objects they have created in C#, they dont' want to convert all of them into C++ class.

        Is there any example I can follow to pass C# class type object into C++ CLI?

        Thanks.

        Comment

        • vekipeki
          Recognized Expert New Member
          • Nov 2007
          • 229

          #19
          Originally posted by MrVS
          There are just too many similar MQXXX classes/objects they have created in C#, they dont' want to convert all of them into C++ class.
          But won't you be needing all those classes in C++ anyway? What good does it do it just pass a serialized object, if you don't have a class in C++ to deserialize it?

          If you want to have a native struct in plain C++ (again, not CLI, because in CLI there is no need for this - it is a managed language), then you can use Marshal.Copy (http://msdn.microsoft.com/en-us/library/ms146631.aspx, I mentioned it a couple of post ago). If you add MarshalAs attributes do define the way fields are marshaled to the native side, then Marshal.Copy will create a byte array, which can be directly cast to a native struct in C++:

          Code:
          public static byte[] SerializeExact( object anything )
          {
            int structsize = Marshal.SizeOf( anything );
            IntPtr buffer = Marshal.AllocHGlobal( structsize );
            Marshal.StructureToPtr( anything, buffer, false );
            byte[] streamdatas = new byte[ structsize ];
            Marshal.Copy( buffer, streamdatas, 0, structsize );
            Marshal.FreeHGlobal( buffer );
            return streamdatas;
          }
          and the matching Deserialize:

          Code:
          public static object RawDeserialize( byte[] rawdatas, Type anytype )
          {
            int rawsize = Marshal.SizeOf( anytype );
            if( rawsize > rawdatas.Length ) return null;
            IntPtr buffer = Marshal.AllocHGlobal( rawsize );
            Marshal.Copy( rawdatas, 0, buffer, rawsize );
            object retobj = Marshal.PtrToStructure( buffer, anytype );
            Marshal.FreeHGlobal( buffer );
            return retobj;
          }
          Of course, to get the struct back in C++, you need to define it in C++ anyway, so I am not quite sure I understand why you need to do it this way.

          Comment

          Working...