473,480 Members | 1,530 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Convert byte array to byte pointer

12 New Member
Hi,

I have a C++ CLR class method that takes System::Byte *b as parameter argument. I want the CSharp caller pass a byte * to this function.
But in the CSharp prorgram, I only managed to create a byte array (byte[]).

Can anyone tell me how to convert byte array to byte pointer in CSharp?

Please show me an simple example about how to do it.

Thank you for your help
Edit/Delete Message
Jan 22 '09 #1
18 42894
PRR
750 Recognized Expert Contributor
@MrVS
You need to use unsafe keyword before using pointers... unsafe
sample code
Expand|Select|Wrap|Line Numbers
  1. public string ConvertToString(byte[] arr)
  2. {
  3.     unsafe
  4.     {
  5.         string returnStr;
  6.         fixed(byte* fixedPtr = arr)
  7.         {
  8.             returnStr = new string((sbyte*)fixedPtr);
  9.         }
  10.     }
  11.  
  12.     return (returnStr);
  13. }
  14.  
  15.  
  16.  
Jan 22 '09 #2
MrVS
12 New Member
@DeepBlue
I can't convert it to string, the "arr" in my code is a serializable object, setup as Class type in C#. I used the following codes to convert this Class type object into serializable byte array:

Expand|Select|Wrap|Line Numbers
  1.         public byte[] MQGMO_ToByteArray(MQGMOs obj)
  2.         {
  3.             if (obj == null)
  4.                 return null;
  5.             BinaryFormatter bf = new BinaryFormatter();
  6.             MemoryStream ms = new MemoryStream();
  7.             bf.Serialize(ms, obj);
  8.             return ms.ToArray();
  9.         }
  10.  
Thanks for your answer.
Jan 22 '09 #3
vekipeki
229 Recognized Expert New Member
[EDIT:] Ooops, I just realized you were talking about C++/CLR. In that case, you are not calling a unmanaged dll.

Anyway, this part covers unmanaged interop.

You have to tell .Net that you want to marshal the unmanaged array to a managed byte[] object.

For example, if you have this signature in C++:
Expand|Select|Wrap|Line Numbers
  1. void DoSomething(byte* data, long size);
  2.  
You would marshal it as UnmanagedType.LPArray:

Expand|Select|Wrap|Line Numbers
  1. [DllImport ("SomeDll.dll")]
  2. public static extern void DoSomething(
  3.   [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
  4.   byte[] data,
  5.   long size);
  6.  
Note that managed array is an object which must have a known length. This is why the SizeParamIndex must be supplied (1 in the example above, indicating that parameter 1 (size) contains the size information.

Check Default Marshaling for Arrays for detailed info. Also google for "P/Invoke"; if you are using some known unmanaged/Win32 APIs, you can find lots of DllImports at pinvoke.net: the interop wiki!.
Jan 22 '09 #4
vekipeki
229 Recognized Expert New Member
I am not sure that BinaryFormatter.Serialize() method will give you what you want. Have you tried checking the length of your MemoryStream after serialization? You can use Marshal.Copy Method (System.Runtime.InteropServices) instead.
Jan 22 '09 #5
MrVS
12 New Member
@vekipeki
Is there a big difference between Unmanaged dll and Unmanaged Interop?
Since I am not using Unmanaged dll, but the example you shown me still *import* dll the marshal it. Is this example still applicable to my current situation?

Thanks
Jan 22 '09 #6
MrVS
12 New Member
@vekipeki
the COPY method looks like for int type only.
Jan 23 '09 #7
MrVS
12 New Member
Hi,

Perhaps a simple project is more clear about this idea.
But I still can't get it working.

Here is my C# program:

Expand|Select|Wrap|Line Numbers
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections;
  4. using System.ComponentModel;
  5. using System.Data;
  6. using System.Text;
  7. using System.Reflection;
  8. using System.Runtime.InteropServices;
  9. using System.IO;
  10. using test_ptr;
  11.  
  12. namespace DebugEntry
  13. {
  14.  
  15.     class DebugEntry
  16.     {
  17.         static void Main(string[] args)
  18.         {
  19.             using (Managed managed = new Managed())
  20.             {
  21.                 byte[] test_byte = new byte[6] { 1, 2, 3, 4, 5, 6 };
  22.                 unsafe
  23.                 {
  24.                     fixed (byte* t_byte = test_byte)
  25.                     {
  26.                         Console.WriteLine(t_byte->ToString());
  27.                         Console.WriteLine(t_byte[1].ToString());
  28.                         int ret = managed.MQCBX(8, 9, &test_byte, sizeof(byte*));
  29.                        // int ret = managed.MQCBX(8, 9, &t_byte, sizeof(byte*));
  30.                     }
  31.                 }
  32.             }
  33.  
  34.             System.Console.WriteLine("Press ENTER to end the console..");
  35.             Console.ReadLine();
  36.         }
  37.  
  38.     }
  39. }
My C++ CLI file
Expand|Select|Wrap|Line Numbers
  1. test_ptr.h:
  2.  
  3. // test_ptr.h
  4.  
  5. #pragma once
  6.  
  7. #include <iostream>
  8.  
  9. using namespace System;
  10.  
  11. namespace test_ptr {
  12.  
  13.     public ref class Managed
  14.     {
  15.         public:
  16.             int MQCBX(int hConn, int op, System::Byte **cbd, int cbd_size);
  17.  
  18.             Managed() {}
  19.  
  20.             ~Managed() { } // Dispose()
  21.             !Managed() { } // finalizer
  22.     };
  23. }
  24.  
  25. int inline test_ptr::Managed::MQCBX(int hConn,int op,System::Byte **cbd, int cbd_size)
  26. {
  27.     System::Byte *buffer = new System::Byte[sizeof(System::Byte)];
  28.     memcpy(buffer, cbd, cbd_size);
  29.     //memcpy(p_cbd, &(cbd), sizeof(cbd));
  30.  
  31.     return 1;
  32. }
How can I change the cpp code and the c# code so that I can pass the byte pointer to c++ funciton(MQCBX)?


Very appreciate for your help.
Thanks
Jan 23 '09 #8
vekipeki
229 Recognized Expert New Member
Please use the CODE tags when posting, it makes your code easier to read.

Since you are using memcpy to copy the contents of your array to a different memory place, it is enough to pass a pointer to test_byte. Your t_byte is a fixed pointer to a byte (byte*), so that is what your method should accept.

Second thing, this line:
Expand|Select|Wrap|Line Numbers
  1. System::Byte *buffer = new System::Byte[sizeof(System::Byte)];
doesn't make much sense because it creates an array of constant length (sizeof(Byte) is always the same). You should rather create an array of the same size as test_byte.

So, in C# you should be using something like:
Expand|Select|Wrap|Line Numbers
  1. int ret = managed.MQCBX(8, 9, t_byte, test_byte.Length);
and your C++ function should be changed to something like:
Expand|Select|Wrap|Line Numbers
  1. int inline test_ptr::Managed::MQCBX
  2.    (int hConn, int op, 
  3.     System::Byte *cbd, int cbd_size)
  4. {
  5.    System::Byte *buffer = new System::Byte[cbd_size];
  6.    memcpy(buffer, cbd, cbd_size);
  7.    return 1;
  8. }
Note however that if you are using Managed C++, there is no need for this. You can use managed data types in Visual C++ 2005. All you need to do is change your function to:

Expand|Select|Wrap|Line Numbers
  1. int inline test_ptr::Managed::MQCBX
  2.    (int hConn, int op,
  3.     array<System::Byte>^ cbd)
  4. {
  5.    // no need for memcpy, we are using managed array's Clone() method
  6.    array<System::Byte>^  buffer = (array<System::Byte>^)cbd->Clone();
  7.    return 1;
  8. }
Then, in C# you can avoid using unsafe code completely:
Expand|Select|Wrap|Line Numbers
  1. using (Managed managed = new Managed())
  2. {
  3.   byte[] test_byte = new byte[] { 1, 2, 3, 4, 5, 6 };
  4.   int ret = managed.MQCBX(8, 9, test_byte);
  5. }
  6.  
If you are using Managed C++, then you have .Net classes sitting there anyway, so why not use them to make your life easier? If you want to go for native C++, then it makes sense to use unsafe code in C#.
Jan 23 '09 #9
MrVS
12 New Member
Thanks for the help. Your fix works.
When I step into the MQCBX function in C++, and pull the variable name cbd the Watch list, I found there is funny character on each of the array index.
eg.
In the C++ Watch list:
cbd
-- [0] 1 ' '
-- [1] 2 'a'
-- [2] 3 'c'
etc

In the C# Watch list,
the cbd buffer is clearly printed as:
cbd
-- [0] 1
-- [1] 2
-- [2] 3
etc

I don't know whether this is the cbd buffer/pointer becomes garbage when it calls the C++ MQCBX function.

What is wrong with it?

Here is the complete code:
in C#:
Expand|Select|Wrap|Line Numbers
  1. using System.IO;
  2. using byte_test;
  3.  
  4. namespace DebugEntry
  5. {
  6.  
  7.     class DebugEntry
  8.     {
  9.         static void Main(string[] args)
  10.         {
  11.             using (Managed managed = new Managed())
  12.             {
  13.                byte[] test_byte = new byte[] { 1, 2, 3, 4, 5, 6 };
  14.                int ret = managed.MQCBX(8, 9, test_byte);
  15.             }
  16.  
  17.         }
  18.     }
  19. }
  20. [/quote]
  21.  
  22. In C++ CLI:
  23. [quote]
  24. pragma once
  25.  
  26. using namespace System;
  27.  
  28. namespace byte_test {
  29.  
  30.     public ref class Managed
  31.     {
  32.         public:
  33.             int MQCBX(int hConn, int op,array<System::Byte>^ cbd);
  34.  
  35.             Managed() {}
  36.  
  37.             ~Managed() { } // Dispose()
  38.             !Managed() { } // finalizer
  39.     };
  40. }
  41.  
  42.  
  43. int inline byte_test::Managed::MQCBX(int hConn, int op,array<System::Byte>^ cbd)
  44. {
  45.         array<System::Byte>^  buffer = {array<System::Byte>^)cbd->Clone();
  46.         return 1;
  47. }
  48.  
  49.  
edit by mod: [code] tags, not [quote] tags. Makes it easier to read your code.
--insertAlias (mod)

Thanks
Jan 23 '09 #10
vekipeki
229 Recognized Expert New Member
What do you mean by "funny character"? Are they really ' ', 'a', 'c' as you wrote, or some different characters? C++ Watch window might show you the Ascii representation (char) for each byte, but if the value is correct, that's ok.

If this code outputs "123456", then it works:
Expand|Select|Wrap|Line Numbers
  1. for (int i = 0; i<buffer->Length; i++)
  2.      System::Console::Write(buffer[i]);
Jan 23 '09 #11
MrVS
12 New Member
@vekipeki
OK, it works, it prints 123456.
The *funny character* at the end of each index array is non-printable character.
Not quite understand why they are there after passed into C++.

Thank you very much for the help again.
REALLY REALLY appreciate for your help.
Jan 23 '09 #12
MrVS
12 New Member
Do you know how to copy the "array<System::Byte>^ cbd" into a
"System::Byte *" ?
eg.
Either this:
Expand|Select|Wrap|Line Numbers
  1.   System::Byte *buffer = (System::Byte *)(array<System::Byte>^)cbd->Clone();
  2.  
OR:
Expand|Select|Wrap|Line Numbers
  1.    array<System::Byte>^ buffer = (array<System::Byte>^)cbd->Clone();
  2.    p_mqcbd = new MQCBD[buffer->Length+1];
  3.     for (int i = 0; i<buffer->Length; i++)
  4.         strcpy(p_mqcbd[i], buffer[i]);
  5.  
is wrong.

Thanks
Jan 25 '09 #13
vekipeki
229 Recognized Expert New Member
Use pin_ptr to pin a pointer to your managed array, then do something with that pointer.

Expand|Select|Wrap|Line Numbers
  1. int inline byte_test::Managed::MQCBX(int hConn,int op, array<System::Byte>^ cbd)
  2. {
  3.     array<System::Byte>^  buffer = (array<System::Byte>^)cbd->Clone();
  4.  
  5.     {
  6.         // you must _pin_ the pointer to prevent GC from
  7.         // collecting
  8.         pin_ptr<unsigned char> pin_buffer = &buffer[0];
  9.         unsigned char* p = pin_buffer;
  10.  
  11.         // call some native function with 'p' as parameter
  12.         // NativeFunction(p);
  13.  
  14.         // when 'p' goes out of scope, it is _unpinned_, 
  15.         // so it can be collected again
  16.     }
  17.  
  18.     return 1;
  19. };
Note that 'p' should only be a local variable, because you don't want your object to be fixed for a long time.

Also note the difference between System::Byte, which is a managed class, and unsigned char, which is a native C++ type.
Jan 26 '09 #14
MrVS
12 New Member
Hi,

I just found out the caller of the MQCBX function passed in a serialized object "cbd* from the CSharp program.
eg. in C#
Expand|Select|Wrap|Line Numbers
  1. private byte[] MQCBD_ToByteArray(MQCBDs obj)
  2.         {
  3.             if (obj == null)
  4.                 return null;
  5.             BinaryFormatter bf = new BinaryFormatter();
  6.             MemoryStream ms = new MemoryStream();
  7.             try
  8.             {
  9.                 bf.Serialize(ms, obj);
  10.             }
  11.             catch (Exception Exp)
  12.             {
  13.                 // report the error
  14.                 System.Console.WriteLine("MQQueue::Get ended with " + Exp.Message);
  15.             }             
  16.             return ms.ToArray();
  17.         }
  18.  
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 hellp.
Jan 27 '09 #15
MrVS
12 New Member
@MrVS
The MQCBDs object is defined as a class in CSharp:
Expand|Select|Wrap|Line Numbers
  1. [Serializable,StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
  2.     public class MQCBDs
  3.     {
  4.         public const string MQCBD_STRUC_ID = "CBD ";
  5.         public const int MQCBD_VERSION_1 = 1;
  6.         public const int MQCBD_CURRENT_VERSION = 1;
  7.         public const int MQCBDO_NONE = 0x00000000;
  8.         public const int MQCBDO_START_CALL = 0x00000001;
  9.         public const int MQCBDO_STOP_CALL = 0x00000004;
  10.         public const int MQCBDO_REGISTER_CALL = 0x00000100;
  11.         public const int MQCBDO_DEREGISTER_CALL = 0x00000200;
  12.         public const int MQCBDO_FAIL_IF_QUIESCING = 0x00002000;
  13.         public const int MQCBT_MESSAGE_CONSUMER = 0x00000001;
  14.         public const int MQCBT_EVENT_HANDLER = 0x00000002;
  15.         public const int MQCBD_FULL_MSG_LENGTH = -1;
  16.  
  17.         //    MQCHAR4    StrucId;           /* Structure identifier */
  18.         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
  19.         public byte[] StrucId;
  20.         //    MQLONG     Version;           /* Structure version number */
  21.         public int Version;
  22.         //    MQLONG     CallbackType;      /* Callback function type */
  23.         public int CallbackType;
  24.         //    MQLONG     Options;           /* Options controlling message
  25.         public int Options;
  26.         //                                     consumption */
  27.         //    MQPTR      CallbackArea;      /* User data passed to the function */
  28.         public byte[] CallbackArea;
  29.         //    MQPTR      CallbackFunction;  /* FP: Callback function pointer */
  30.         //public mqCallBacks CallbackFunction;
  31.         //    MQCHAR128  CallbackName;      /* Callback name */
  32.         //       [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
  33.         //     public string CallbackName;
  34.         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
  35.         public byte[] CallbackName;
  36.  
  37.         //    MQLONG     MaxMsgLength;      /* Maximum message length */
  38.         public int MaxMsgLength;
  39.  
  40.         public MQCBDs()
  41.         {
  42.             StrucId = utilities.getBytes(MQCBD_STRUC_ID);
  43.             //StrucId = getBytes(MQCBD_STRUC_ID);
  44.             Version = MQCBD_VERSION_1;
  45.             CallbackType = MQCBT_MESSAGE_CONSUMER;
  46.             Options = MQCBDO_NONE;
  47.             CallbackArea = null;
  48.             //CallbackFunction = null;
  49.             CallbackName = new byte[128];
  50.             Array.Clear(CallbackName, 0, CallbackName.Length);
  51.             MaxMsgLength = MQCBD_FULL_MSG_LENGTH;
  52.         }
  53.     }
  54.  
My goal is pass this MQCBDs object from CSharp to VC++(CLI).

Thanks
Jan 27 '09 #16
vekipeki
229 Recognized Expert New Member
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.
Jan 27 '09 #17
MrVS
12 New Member
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.
Jan 27 '09 #18
vekipeki
229 Recognized Expert New Member
@MrVS
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++:

Expand|Select|Wrap|Line Numbers
  1. public static byte[] SerializeExact( object anything )
  2. {
  3.   int structsize = Marshal.SizeOf( anything );
  4.   IntPtr buffer = Marshal.AllocHGlobal( structsize );
  5.   Marshal.StructureToPtr( anything, buffer, false );
  6.   byte[] streamdatas = new byte[ structsize ];
  7.   Marshal.Copy( buffer, streamdatas, 0, structsize );
  8.   Marshal.FreeHGlobal( buffer );
  9.   return streamdatas;
  10. }
  11.  
and the matching Deserialize:

Expand|Select|Wrap|Line Numbers
  1. public static object RawDeserialize( byte[] rawdatas, Type anytype )
  2. {
  3.   int rawsize = Marshal.SizeOf( anytype );
  4.   if( rawsize > rawdatas.Length ) return null;
  5.   IntPtr buffer = Marshal.AllocHGlobal( rawsize );
  6.   Marshal.Copy( rawdatas, 0, buffer, rawsize );
  7.   object retobj = Marshal.PtrToStructure( buffer, anytype );
  8.   Marshal.FreeHGlobal( buffer );
  9.   return retobj;
  10. }
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.
Jan 27 '09 #19

Sign in to post your reply or Sign up for a free account.

Similar topics

5
3158
by: overbored | last post by:
I can do this: int asdf; int* zxcv = asdf; but not this: int asdf; int** zxcv = asdf;
2
21770
by: Jim H | last post by:
I am getting binary data form a database binary(8). I am copying it to a byte array byte. I need to covert this to a number, ulong, so I can write it to a string in hex format. Any idea on how...
1
1389
by: War Eagle | last post by:
I have int SomeNumber (which is less than 256) which I want to convert to 1 byte array so I might send it over TCP. Can someone help me out with writing this line of code? TIA, War Eagle
16
14068
by: Ekim | last post by:
hello, I'm allocating a byte-Array in C# with byte byteArray = new byte; Now I want to pass this byte-Array to a managed C++-function by reference, so that I'm able to change the content of the...
1
5702
by: Angel Filev | last post by:
Hi everyone, I am trying to store a file as a binary array in an "image" field in SQL Server 2000 database. It works OK except for the ".PDF" files, which I believe get corrupted in the process...
53
4463
by: Tomás | last post by:
Some programmers treat arrays just like pointers (and some even think that they're exactly equivalent). I'm going to demonstrate the differences. Firstly, let's assume that we're working on a...
19
27558
by: Frank | last post by:
Hello, I have a byte array (byte) and want to search for 3 bytes next to each other containing 0x10, 0x12 and 0x16. Is there some method for that? Thanks Frank
3
16639
by: Peted | last post by:
In the default state ie somemethod(Byte array); is the byte array passed by method or by reference ? or do you have to use the ref keyword to be able to mod the contents of the orig array...
10
24603
by: Chunekit Pong | last post by:
I have a BYTE array - BYTE const* pbBinary I would like to know how many bytes in that byte array but if I do - sizeof(* pbBinary); - then I got 1 but if I do - sizeof( pbBinary); - then I...
0
6908
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7044
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
7084
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
6929
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
5337
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
4779
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
4481
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
2995
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
1
563
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.