I do have the follwing struct in a C# wrapper for some unmanaged code. I try to hand over some data using pointers, which is fine for the ushort* and byte* part, but does not work for the fixed int.
[StructLayout(LayoutKind.Sequential)]
unsafe public struct IMAGE
{
public fixed int nSize[2];
public ushort* pDepthIm;
public byte* pColorIm;
}
To fill this struct with some information, I use:
unsafe public void LoadImage(ushort[] depthImage, byte[] rgbImage, int[] size)
{
unsafe
{
fixed (int* pSize = size)
fixed (ushort* pDepth = depthImage)
fixed (byte* pRGB = rgbImage)
{
_im.nSize = pSize;
_im.pColorIm = pRGB;
_im.pDepthIm = pDepth;
...
}
}
}
At _im.nSize = pSize; the compiler shows an error, stating:
You cannot use fixed size buffers contained in unfixed expressions.
Try using the fixed statement.
I already noticed that the int is initialized in a different way (not with the Pointer-*, but as fixed int), but I can't figure out how to hand over the value. When hovering over the variable, it is shown as int*...
Update: I came across the MSDN error reference for the mentioned message. I'm now sure it has to do with the fixed statement in the IMAGE struct, but I still have no idea how to fix it.
You can't assign a pointer to an array. You have to use memcpy.
memcpy(_im.nSize, size, sizeof(_im.nSize));
As a matter of fact you can't assign anything to an array. You can modify array's value, but not reassign it.
I would also check for the array length, pass it as a parameter or check it's .length if the languge allows it.
If found a way to access the fixed int[2] like this:
public unsafe void LoadImage(ushort[] depthImage, byte[] rgbImage, int[] size)
{
unsafe
{
fixed (int* pSize = _im.nSize)
fixed (ushort* pDepth = depthImage)
fixed (byte* pRGB = rgbImage)
fixed (S_IMAGE* pim = &_im)
{
pSize[0] = size[0];
pSize[1] = size[1];
_im.pColorIm = pRGB;
_im.pDepthIm = pDepth;
}
}
}
Im not sure if this is a good way or if this is how it is meant to be, but at least it works as expected...
Related
Using the NetworkInfo2SecurityParameter function I am trying to copy the fixed-size buffer unkRandom from from LdnNetworkInfo struct held in NetworkInfo struct to the SecurityParameter struct's buffer.
Basically I am making a method to convert these two types, and I want to copy these two arrays to another. This code features all structs relevant.
The error is happening at the Buffer.MemoryCopy() function. The error is "You cannot use fixed size buffers contained in unfixed expressions. Try using the 'fixed' statement"
unsafe void NetworkInfo2SecurityParameter(NetworkInfo info, out SecurityParameter output)
{
output = new SecurityParameter();
output.sessionId = info.networkId.sessionId;
Buffer.MemoryCopy(output.unkRandom, info.ldn.unkRandom, 16, 16);
}
struct SecurityParameter {
public unsafe fixed byte unkRandom[16];// = new byte[16];
public SessionId sessionId;
};
struct NetworkInfo : /sf::/LargeData {
public NetworkId networkId;
public CommonNetworkInfo common;
public LdnNetworkInfo ldn;
};
struct LdnNetworkInfo {
public unsafe fixed byte unkRandom[16];// = new byte[16];
public ushort securityMode;
public byte stationAcceptPolicy;
public unsafe fixed byte _unk1[3];// = new byte[3];
public byte nodeCountMax;
public byte nodeCount;
//TODO non primitive array,,
private unsafe fixed byte _nodes[sizeof(NodeInfo)*NodeCountMax]; //Needs to be fixed array, and needs to be casted to NodeInfo span, so thats why its size is this
public unsafe fixed Span<NodeInfo> nodes => MemoryMarshal.Cast<byte, NodeInfo>(MemoryMarshal.CreateSpan(ref _nodes[0], 128));
public ushort _unk2;
public ushort advertiseDataSize;
public unsafe fixed byte advertiseData[AdvertiseDataSizeMax];// = new byte[AdvertiseDataSizeMax];
public unsafe fixed byte _unk3[148];// = new byte[148];
};
struct is assignable, like any primitive. Undoubtedly faster than Buffer.MemoryCopy() would be:
public unsafe struct FixedSizeBufferWrapper
{
public unsafe fixed byte unkRandom[16];
}
unsafe
{
fixed (byte* firstStruct = somewhere.securityParameter, otherStruct = somewhereElse.ldnNetworkInfo )
{
//one assignment blits all contents
*((FixedSizeBufferWrapper*)firstStruct.unkRandom) =
*((FixedSizeBufferWrapper*)otherStruct.unkRandom);
}
}
We cast buffers in each of your original structs to the wrapper pointer type and dereference each pointer SO THAT we can assign one to the other; assigning fixed buffers directly is not possible.
We have to cast outside the fixed statement because (at least in my version of C#) we aren't allowed to cast inside fixed(...) and we cannot assign anything other than a primitive type (usually byte[]) as the buffer type. The wrapper struct exists purely for this casting / assignment.
Fixed it with this approach: I created a new variable called ret, which I did copy the data to, and then I assigned ret to output.
unsafe void NetworkInfo2SecurityParameter(NetworkInfo info, out SecurityParameter output)
{
var ret = new SecurityParameter();
output.sessionId = info.networkId.sessionId;
Buffer.MemoryCopy(ret.unkRandom, info.ldn.unkRandom, 16, 16);
output = ret;
}
In C# book is written that I'm unable to access unallocated memory. They said that is possible in unsafe context. My question is how this can be done?
I tried something like this:
static void Main(string[] args)
{
unsafe
{
int c;
Console.WriteLine(c);
}
}
With allow unsafe option in project properties. And this code is unable to compile.
The unsafe keyword does not completely alter the language or compilation model, you still need to initialize any variables before using them. If you want to access "unallocated memory", you need to get a pointer to that memory. Here is an example:
unsafe void AccessMemory()
{
const int address = 10000;
byte[] array = new byte[0];
fixed (byte* zero = array)
{
byte* p = zero + address;
}
}
Here we get a pointer to the empty array, which gives the zero pointer. Then we offset that pointer by some amount (address), which results in a pointer to that memory address.
I'm using an external C library that comes with a C# wrapper file containing a struct like (among many other things):
[StructLayout(LayoutKind.Sequential, Pack = 8)]
unsafe public struct Data
{
public fixed double Values[3];
};
I can get the values by adding an additional method to that struct:
public double[] CopyFixedDoubleArray()
{
double[] result = new double[3];
fixed (double* pDst = result)
{
fixed (double* pSrc = Values)
{
double* pd = pDst;
double* ps = pSrc;
for (int i = 0; i < result.Length; i++)
{
*pd = *ps;
pd++; ps++;
}
}
}
return result;
}
But this is not what I want because I don't want to touch the wrapper file (to avoid having to keep the external file in our SCM repository). Whatever I try to do to get the values from outside that struct results in the following error:
Fixed size buffers can only be accessed through locals or fields
What I've tried:
double a = data.Values[2];
double a; unsafe { a = data.Values[2]; }
double a; fixed (double* p = data.Values) { a = p[2]; }
fixed (double a = data.Values[2]) { /* use a */ }
Is there any way to get around this?
Suddenly the word 'extension method' crossed my mind. And yes, I have it working:
public static double[] CopyFixedDoubleArray(this Data data)
{
unsafe
{
return new[] { data.Values[0], data.Values[1], data.Values[2] };
}
}
Rather than patch your code up, have you considered shoving this over to the marshaller? That's its entire purpose: to assist with native interop while letting you write pure managed code.
You'd have to declare your struct like this:
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct Data
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public double[] Values;
};
When this structure is filled by the marshaller (through either a direct function call through a pointer, or from mapping the struct on top of a byte buffer) it will allocate the proper array and copy its contents over. This makes your entire function obsolete, but if you really wanted to you could simply use Array.Copy (or the Linq equivalent).
Notice there's no more unsafe modifier. You can run this in a partially trusted environment with no issues!
I have some struct like this
struct MyStruct
{
public int field1;
public int field2;
public int field3;
}
and I have pointer to array of this struct.
So, I need to get array from this pointer.
I'm tried to using Marshal.PtrToStructure, but i had memory reading error.
This is my methode:
public MyStruct[] GetArrayOfStruct(IntPtr pointerToStruct, int length)
{
var sizeInBytes = Marshal.SizeOf(typeof(TCnt));
MyStruct[] output = new MyStruct[length];
for (int i = 0; i < length; i++)
{
IntPtr p = new IntPtr((pointerToStruct.ToInt32() + i * sizeInBytes));
output[i] = (MyStruct)System.Runtime.InteropServices.Marshal.PtrToStructure(p, typeof(MyStruct));
}
return output;
}
So, what am i doing wrong ?
This function worked for me, assuming that the size of the struct is fixed:
public static void MarshalUnmananagedArray2Struct<T>(IntPtr unmanagedArray, int length, out T[] mangagedArray)
{
var size = Marshal.SizeOf(typeof(T));
mangagedArray = new T[length];
for (int i = 0; i < length; i++)
{
IntPtr ins = new IntPtr(unmanagedArray.ToInt64() + i * size);
mangagedArray[i] = Marshal.PtrToStructure<T>(ins);
}
}
Two problems. You use TCnt instead of MyStruct in the Marshal.SizeOf() call. Your IntPtr arithmetic cannot work on a 64-bit machine, you must use IntPtr.ToInt64() or cast to (long).
Just getting the wrong IntPtr or length is certainly a possibility too of course. Use Debug + Windows + Memory + Memory 1 and put "pointerToStruct" in the Address box for basic verification.
Structs in C and C# are not the same thing. One of the differences is that in C# you have to explicitly demand that your struct should be sequentially laid out. If you didn't write
[StructLayout(LayoutKind.Sequential)] or [StructLayout(LayoutKind.Explicit)] attribute to your structure I don't believe that you can manage it in this way. Microsoft states that PtrToStructure is to be used to convert structures from unmanaged to managed memory
You should test if adding this attributes to your struct helps, If it doesn't yet help try allocating memory with Marshal.AllocHGlobal(IntPtr) and use Marshal.Copy to init your structure and then try using PtrToStructure. If this works then you can't use PtrToStructure with managed memory
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.