i'm trying to convert code from c++ to c#.. but i'm stuck.
Can somebody let me know where i'm wrong?
C++ code is:
void CALLBACK Test(void *buffer, DWORD length)
{
BYTE *b=(BYTE*)buffer, temp[20000];
DWORD p=0;
while (p<length)
{
DWORD c=min(length-p, sizeof(temp));
memcpy(temp, b+p, c);
c=SendData(dummy, temp, c);
if (c==-1) break;
p+=c;
}
}
where is SendData(int, byte[], int)
And current c# code
void Test(IntPtr buffer, int length)
{
byte[] temp = new byte[20000];
byte[] b = new byte[length];
Marshal.Copy(buffer, b, 0, length);
long p=0;
while (p<length)
{
long c=Math.Min(length-p, 20000);
Array.Copy(temp, b+p, c);
c=SendData(dummy, temp, (int)c);
if (c==-1) break;
p+=c;
}
}
I'm not sure did I did it correctly, but I can see I cannot apply operator + to b+s because it's long and byte[].
Thanks
I think you want to use the 5-arg version of Array.Copy, which lets you pass offsets into both the start and destination arrays. This is the more "C#" way of doing things as opposed to pointer arithmetic.
In C++ you may add a DWORD (an int, really) to a pointer and the compiler knows to offset the address of the pointer by the specified amount. C# doesn't let you do that, normally. (There is a way to do pointer arithmetic in C#, but don't.) So, in the C# version, you need another way to copy at offset p relative to the start of b. One of the overloads of Array.Copy will let you do that. Something like:
Array.Copy(temp, 0, b, p, c);
You may want to look at: How to split a byte array, because that is in effect what you are trying to accomplish with the b+pportion.
Related
I'm receiving byte-arrays containing float variables (32 bit).
In my C# application I'd like to turn byte[] byteArray into a float using bitwise shifting (because it's a lot faster than BitConverter).
Turning a byte-array into a short works like this:
short shortVal = (short)((short)inputBuffer [i++] << 8 | inputBuffer [i++]);
How do I do this for float-variables?
Let's gut the BCL and use its intestines for our purposes:
unsafe public static float ToSingle (byte[] value, int startIndex)
{
int val = ToInt32(value, startIndex);
return *(float*)&val;
}
You can implement ToInt32 using bit shifting.
If you don't need endianness behavior a single unsafe access can give you the float (assuming it's aligned).
Alternatively, you can use a union struct to convert an int to a float.
To get away from C# conventional methods and obtain fast performance, you'll most likely have to implement "unsafe" behavior. You could do something like the C style memory copy.
unsafe public static void MemoryCopy (void* memFrom, void* memTo, int size) {
byte* pFrom = (byte*)memFrom;
byte* pTo = (byte*)memTo;
while (size-- >= 0)
*pTo++ = *pFrom++;
}
This assumes that the float's endianness is the same going into the byte[] as it on the other end.
To use this you'll have to first fix the byte array since the runtime can move it anytime it wants during garbage collection. Something like this:
float f;
unsafe {
fixed (byte* ptr = byteArray) {
MemoryCopy (ptr, &f, sizeof(float));
}
}
I am new to c++ and as for now I have quite a heavy task on my work, I have a gui made in wpf and I need to send parameters from the gui to the c++ the (which as for now I already handled)
My problem is that on the c++ layer I get the info as a BYTE* I need to reinterprete the values to their "original" state (the first translation from ont\float to byte array is being made on the C# level using the static BitConvertor class) as for now I used this little method -
void GetNextValue(byte* bytes, deque<BYTE> *buffer)
{
bytes[3] = buffer->front();
buffer->pop_front();
bytes[2] = buffer->front();
buffer->pop_front();
bytes[1] = buffer->front();
buffer->pop_front();
bytes[0] = buffer->front();
buffer->pop_front();
}
But for an integer value of 1 I get a really high number, on the other hand going directly for the int value in the whole buffer will yield the correct answer...(i.e. int x = pBuffer[4]), any help or suggestions will be gladly accepted..
BTW-
I used
_rxBuffer.insert( _rxBuffer.end(), pBuffer, pBuffer + nLength);
To convert the BYTE* of data to -
deque<BYTE> _rxBuffer;
If you have an array of byte[4] you can just convert it to integer by this:
byte bytes[4];
int value = *(int*)bytes;
But beware, depending on endianess of your platform you may or may need not swap bytes order (try to replace 3<>0 and 2<>1 in bytes).
I receive IntPtr value from C++ library method and i need to get byte[] array from this received IntPtr. When I try do this:
byte[] myArray = new byte[Marshal.SizeOf(myReceivedIntPtr)];
Marshal.Copy(myReceivedIntPtr, myArray, 0, Marshal.SizeOf(myReceivedIntPtr));
I receive an exception: AccessViolationException.
What I missed?
EDIT:
Here is Method name and params in header of C++ library:
int MSR_DecodeTrack(char *AscBuff, unsigned char *BinBuff, unsigned char bpc, unsigned char parity, unsigned char ss, unsigned char es);
And I call it from C# this way:
UInt32 result;
IntPtr myReceivedIntPtr;
IntPtr BinBuff;
byte BPC1 = 7, Parity1 = 1, SS1 = 0x05, ES1 = 0x1F;
result = MSR_DecodeTrack(ref myReceivedIntPtr, ref BinBuff, BPC1, Parity1, SS1, ES1);
And here is else code:
byte[] myArray = new byte[Marshal.SizeOf(myReceivedIntPtr)];
Marshal.Copy(myReceivedIntPtr, myArray, 0, Marshal.SizeOf(myReceivedIntPtr));
I'm pretty sure Marshal.SizeOf(myReceivedIntPtr) will return the size of the IntPtr object, not the size of the unmanaged array. You will need to get the size of the unmanaged array from the c++ library.
I haven't had to do this in a while so I'm a bit rusty but from looking at the c++ headers I think it is expecting a pointer to a buffer. You are giving it a pointer to a pointer (intptr is a pointer and passing it by ref means you are passing the c++ code a pointer to that pointer). Firstly, don't use ref. Secondly, I suspect you are supposed to be passing it an already sized buffer - is there any documentation describing what you are supposed to pass to the function? What is the return code from the function? You are checking it for success aren't you? ;)
The method named MSR_DecodeTrack should also return the length of each array it allocates.
As far as I know, when you allocate an array in C/C++ environment, you get a pointer to the zero element of that array, nothing more. For that reason, you should also somehow return the length of the allocated array back to the caller. It can be done by an additional "ref" parameter.
HTH.
I have an unmanaged C++ function which is calling a managed C# method in a DLL. The purpose of the C# method is to take an array of bytes (allocated by the C++ caller), populate the array, and return it. I can get the array INTO the C# method, but the populated data are lost when they get back to the C++ function. Right now, this is my test code to debug the process:
C# DLL Method:
// Take an array of bytes and modify it
public ushort GetBytesFromBlaster([MarshalAs(UnmanagedType.LPArray)] byte[] dataBytes)
{
dataBytes[0] = (byte)'a';
dataBytes[1] = (byte)'b';
dataBytes[2] = (byte)'c';
return 3;
}
C++ function which calls the DLL:
// bytes[] has been already allocated by its caller
short int SimGetBytesP2P(unsigned char bytes[])
{
unsigned short int numBytes = 0;
bytes[0] = 'x';
bytes[1] = 'y';
bytes[2] = 'z';
// bytes[] are {'x', 'y', 'z'} here
guiPtr->GetBytesFromBlaster(bytes, &numBytes);
// bytes[] SHOULD be {'a', 'b', 'c'} here, but they are still {'x', 'y', 'z'}
return(numBytes);
}
I believe it has something to do with C# turning the C++ pointer into a new managed array, but modifying the original one. I have tried several variations using the "ref" modifyer, etc., but no luck. Also, these data are NOT null-terminated strings; the date bytes are raw 1-byte values, not null-terminated.
Can anyone please shed some light on this? Thanks!
Stuart
You could do the marshaling yourself. Have the C# function accept a parameter by value of type IntPtr. Also a second parameter indicating array length. No special marshaling attributes are needed or wanted.
Then, use Marshal.Copy and copy the array from the unmanaged pointer to a managed byte[] array that you allocated. Do your thing, and then when you're done, use Marshal.Copy to copy it back to the C++ unmanaged array.
These particular overloads should get you started:
http://msdn.microsoft.com/en-us/library/ms146625.aspx
http://msdn.microsoft.com/en-us/library/ms146631.aspx
For example:
public ushort GetBytesFromBlaster(IntPtr dataBytes, int arraySize)
{
byte[] managed = new byte[arraySize];
Marshal.Copy(dataBytes, managed, 0, arraySize);
managed[0] = (byte)'a';
managed[1] = (byte)'b';
managed[2] = (byte)'c';
Marshal.Copy(managed, 0, dataBytes, arraySize);
return 3;
}
Alternatively you could implement a custom marshaller as described in http://msdn.microsoft.com/en-us/library/w22x2hw6.aspx if the default one isn't doing what you need it to. But that looks like more work.
I believe that you just need to add a SizeConst attribute:
public ushort GetBytesFromBlaster(
[MarshalAs(UnmanagedType.LPArray, SizeConst=3)]
byte[] dataBytes
)
and the default marshaller should do the rest for you.
How can I convert an int to a byte* at a certain index in a byte*?
Ideally I would like to have something like:
unsafe{
byte* igm=stackalloc byte[8];
igm[4]=4283;
}
It would set the first part of the bit to igm[4] and the rest into igm[5].
Edit: I realize there may be a lot of possible ways to handle this, i am looking for the most efficient way if possible.
try this:
unsafe
{
byte* igm = stackalloc byte[8];
*(int*)(igm + 4) = 4283;
}
Once you realize that you can use simple pointer arithmetic to index anywhere in your byte array, things get a LOT easier.
The type system in C# will prevent you from doing that, as you might have noticed. However, you can cast your pointers to be the appropiate types:
unsafe
{
byte* igm = stackalloc byte[8];
int* intPtr = (int*)igm;
intPtr[1] = 4283;
}
You need to break your int to sizeof(int) count of bytes and then manually set this parts to your byte* at specified indexes.
This will be safer as you'll know WHAT and WHERE you place your data.