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
18 42894 PRR 750
Recognized Expert Contributor @MrVS
You need to use unsafe keyword before using pointers... unsafe
sample code -
public string ConvertToString(byte[] arr)
-
{
-
unsafe
-
{
-
string returnStr;
-
fixed(byte* fixedPtr = arr)
-
{
-
returnStr = new string((sbyte*)fixedPtr);
-
}
-
}
-
-
return (returnStr);
-
}
-
-
-
@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: - public byte[] MQGMO_ToByteArray(MQGMOs obj)
-
{
-
if (obj == null)
-
return null;
-
BinaryFormatter bf = new BinaryFormatter();
-
MemoryStream ms = new MemoryStream();
-
bf.Serialize(ms, obj);
-
return ms.ToArray();
-
}
-
Thanks for your answer.
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++: -
void DoSomething(byte* data, long size);
-
You would marshal it as UnmanagedType.LPArray: -
[DllImport ("SomeDll.dll")]
-
public static extern void DoSomething(
-
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
-
byte[] data,
-
long size);
-
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!.
@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
@vekipeki
the COPY method looks like for int type only.
Hi,
Perhaps a simple project is more clear about this idea.
But I still can't get it working.
Here is my C# program: - using System;
-
using System.Collections.Generic;
-
using System.Collections;
-
using System.ComponentModel;
-
using System.Data;
-
using System.Text;
-
using System.Reflection;
-
using System.Runtime.InteropServices;
-
using System.IO;
-
using test_ptr;
-
-
namespace DebugEntry
-
{
-
-
class DebugEntry
-
{
-
static void Main(string[] args)
-
{
-
using (Managed managed = new Managed())
-
{
-
byte[] test_byte = new byte[6] { 1, 2, 3, 4, 5, 6 };
-
unsafe
-
{
-
fixed (byte* t_byte = test_byte)
-
{
-
Console.WriteLine(t_byte->ToString());
-
Console.WriteLine(t_byte[1].ToString());
-
int ret = managed.MQCBX(8, 9, &test_byte, sizeof(byte*));
-
// int ret = managed.MQCBX(8, 9, &t_byte, sizeof(byte*));
-
}
-
}
-
}
-
-
System.Console.WriteLine("Press ENTER to end the console..");
-
Console.ReadLine();
-
}
-
-
}
-
}
My C++ CLI file - test_ptr.h:
-
-
// test_ptr.h
-
-
#pragma once
-
-
#include <iostream>
-
-
using namespace System;
-
-
namespace test_ptr {
-
-
public ref class Managed
-
{
-
public:
-
int MQCBX(int hConn, int op, System::Byte **cbd, int cbd_size);
-
-
Managed() {}
-
-
~Managed() { } // Dispose()
-
!Managed() { } // finalizer
-
};
-
}
-
-
int inline test_ptr::Managed::MQCBX(int hConn,int op,System::Byte **cbd, int cbd_size)
-
{
-
System::Byte *buffer = new System::Byte[sizeof(System::Byte)];
-
memcpy(buffer, cbd, cbd_size);
-
//memcpy(p_cbd, &(cbd), sizeof(cbd));
-
-
return 1;
-
}
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
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: - 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: - int ret = managed.MQCBX(8, 9, t_byte, test_byte.Length);
and your C++ function should be changed to something like: -
int inline test_ptr::Managed::MQCBX
-
(int hConn, int op,
-
System::Byte *cbd, int cbd_size)
-
{
-
System::Byte *buffer = new System::Byte[cbd_size];
-
memcpy(buffer, cbd, cbd_size);
-
return 1;
-
}
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: -
int inline test_ptr::Managed::MQCBX
-
(int hConn, int op,
-
array<System::Byte>^ cbd)
-
{
-
// no need for memcpy, we are using managed array's Clone() method
-
array<System::Byte>^ buffer = (array<System::Byte>^)cbd->Clone();
-
return 1;
-
}
Then, in C# you can avoid using unsafe code completely: - using (Managed managed = new Managed())
-
{
-
byte[] test_byte = new byte[] { 1, 2, 3, 4, 5, 6 };
-
int ret = managed.MQCBX(8, 9, test_byte);
-
}
-
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#.
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#: -
using System.IO;
-
using byte_test;
-
-
namespace DebugEntry
-
{
-
-
class DebugEntry
-
{
-
static void Main(string[] args)
-
{
-
using (Managed managed = new Managed())
-
{
-
byte[] test_byte = new byte[] { 1, 2, 3, 4, 5, 6 };
-
int ret = managed.MQCBX(8, 9, test_byte);
-
}
-
-
}
-
}
-
}
-
[/quote]
-
-
In C++ CLI:
-
[quote]
-
pragma once
-
-
using namespace System;
-
-
namespace byte_test {
-
-
public ref class Managed
-
{
-
public:
-
int MQCBX(int hConn, int op,array<System::Byte>^ cbd);
-
-
Managed() {}
-
-
~Managed() { } // Dispose()
-
!Managed() { } // finalizer
-
};
-
}
-
-
-
int inline byte_test::Managed::MQCBX(int hConn, int op,array<System::Byte>^ cbd)
-
{
-
array<System::Byte>^ buffer = {array<System::Byte>^)cbd->Clone();
-
return 1;
-
}
-
-
edit by mod: [code] tags, not [quote] tags. Makes it easier to read your code.
--insertAlias (mod)
Thanks
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: - for (int i = 0; i<buffer->Length; i++)
-
System::Console::Write(buffer[i]);
@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.
Do you know how to copy the "array<System::Byte>^ cbd" into a
"System::Byte *" ?
eg.
Either this: -
System::Byte *buffer = (System::Byte *)(array<System::Byte>^)cbd->Clone();
-
OR: -
array<System::Byte>^ buffer = (array<System::Byte>^)cbd->Clone();
-
p_mqcbd = new MQCBD[buffer->Length+1];
-
for (int i = 0; i<buffer->Length; i++)
-
strcpy(p_mqcbd[i], buffer[i]);
-
is wrong.
Thanks
vekipeki 229
Recognized Expert New Member
Use pin_ptr to pin a pointer to your managed array, then do something with that pointer. - int inline byte_test::Managed::MQCBX(int hConn,int op, array<System::Byte>^ cbd)
-
{
-
array<System::Byte>^ buffer = (array<System::Byte>^)cbd->Clone();
-
-
{
-
// you must _pin_ the pointer to prevent GC from
-
// collecting
-
pin_ptr<unsigned char> pin_buffer = &buffer[0];
-
unsigned char* p = pin_buffer;
-
-
// call some native function with 'p' as parameter
-
// NativeFunction(p);
-
-
// when 'p' goes out of scope, it is _unpinned_,
-
// so it can be collected again
-
}
-
-
return 1;
-
};
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.
Hi,
I just found out the caller of the MQCBX function passed in a serialized object "cbd* from the CSharp program.
eg. in C# -
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 hellp.
@MrVS
The MQCBDs object is defined as a class in CSharp: -
[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
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.
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.
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++: -
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: -
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.
Sign in to post your reply or Sign up for a free account.
Similar topics |
by: overbored |
last post by:
I can do this:
int asdf;
int* zxcv = asdf;
but not this:
int asdf;
int** zxcv = asdf;
|
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...
|
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
|
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...
|
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...
| |
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...
|
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
|
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...
|
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...
|
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...
|
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,...
| |
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...
|
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...
|
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,...
|
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...
|
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...
|
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...
| |
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
| |