I'm trying to integrate Video4Linux in my managed application. Indeed I've declared all required structures and relative ioctl. In this question I present two ioctl: SetFormat and GetFormat; while the former is working well (like the other dozen I actually use), the latter is returning me bad memory behavior.
The GetFormat ioctl is actually performing, but as soon the application is accessing to the ioctl parameter (either debugger or my application itself), it always crashes with following stack:
System.NullReferenceException: ...
at System.String.mempy4(...) in <filename unknown>:0
at System.String.memcpy(...) in <filename unknown>:0
at Derm.Platform.Video4Linux.ControlGetFormat(...) in <...>
...
I had some investigation on p/invoking ioctl, and again, I cannot understand why my application is crashing. I suspect it's becuase structure memory layout, but I cannot explain why SetFormat is working while GetFormat don't (since they use the very same parameter).
I have to P/Invoke a ioctl routine that receive/return the structure v4l2_format:
struct v4l2_format {
enum v4l2_buf_type type;
union {
struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
struct v4l2_pix_format_mplane pix_mp; /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
__u8 raw_data[200]; /* user-defined */
} fmt;
};
struct v4l2_pix_format {
__u32 width;
__u32 height;
__u32 pixelformat;
enum v4l2_field field;
__u32 bytesperline; /* for padding, zero if unused */
__u32 sizeimage;
enum v4l2_colorspace colorspace;
__u32 priv; /* private data, depends on pixelformat */
};
I've traduced the structure v4l2_format using the following form
[StructLayout(LayoutKind.Explicit, Pack = 4, CharSet = CharSet.Ansi)]
public struct Format
{
public Format(BufferType bufferType)
{
Type = bufferType;
Pixmap = new PixmapFormat();
RawData = new byte[RawDataLength];
}
public Format(BufferType bufferType, PixmapFormat pixmapFormat)
{
Type = bufferType;
Pixmap = pixmapFormat;
RawData = new byte[RawDataLength];
}
[FieldOffset(0)]
public BufferType Type;
[FieldOffset(4)]
public PixmapFormat Pixmap;
[FieldOffset(4)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst=RawDataLength)]
public byte[] RawData;
public const int RawDataLength = 200;
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct PixmapFormat
{
public PixmapFormat(uint width, uint height, PixelFormatCode pixelFormat)
{
Width = width;
Height = height;
PixelFormat = pixelFormat;
Field = Video4Linux.BufferField.Any;
BytesPerLine = 0;
SizeImage = 0;
Colorspace = Video4Linux.PixelColorspace.None;
Private = 0;
}
public UInt32 Width;
public UInt32 Height;
public PixelFormatCode PixelFormat;
public BufferField Field;
public UInt32 BytesPerLine;
public UInt32 SizeImage;
public PixelColorspace Colorspace;
public UInt32 Private;
}
And finally, here is the methods calling ioctl:
public static void ControlGetFormat(IntPtr fd, BufferType pixmapType, out PixmapFormat pixmapFormat)
{
if (fd == IntPtr.Zero)
throw new ArgumentException("invalid file descriptor", "fd");
Format format = new Format(pixmapType);
int result = IoCtrlGetFormat(fd, GetFormat.ControlCode, ref format);
if (result < 0)
ThrowExceptionOnError();
pixmapFormat = format.Pixmap;
}
private static readonly IoCtrlRequest GetFormat = new IoCtrlRequest(IoCtrlDirection.Read | IoCtrlDirection.Write, 'V', 4, typeof(Format));
[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
private static extern int IoCtrlGetFormat(IntPtr fd, Int32 code, ref Format argument);
public static void ControlSetFormat(IntPtr fd, BufferType pixmapType, ref PixmapFormat pixmapFormat)
{
if (fd == IntPtr.Zero)
throw new ArgumentException("invalid file descriptor", "fd");
PixmapFormat pixmapFormatCopy = pixmapFormat;
Format format = new Format(pixmapType, pixmapFormatCopy);
int result = IoCtrlSetFormat(fd, SetFormat.ControlCode, ref format);
if (result < 0)
ThrowExceptionOnError();
pixmapFormat = format.Pixmap;
}
private static readonly IoCtrlRequest SetFormat = new IoCtrlRequest(IoCtrlDirection.Read | IoCtrlDirection.Write, 'V', 5, typeof(Format));
[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
private static extern int IoCtrlSetFormat(IntPtr fd, Int32 code, ref Format argument);
The problem has been solved by forcing the structure size to the actual one (204, in my case), and remove the array field RawData (as suggested by David Heffernan).
Indeed:
[StructLayout(LayoutKind.Explicit, Pack = 4, CharSet = CharSet.Ansi, Size = 204)]
public struct Format
{
public Format(BufferType bufferType)
{
Type = bufferType;
Pixmap = new PixmapFormat();
}
public Format(BufferType bufferType, PixmapFormat pixmapFormat)
{
Type = bufferType;
Pixmap = pixmapFormat;
}
[FieldOffset(0)]
public BufferType Type;
[FieldOffset(4)]
public PixmapFormat Pixmap;
}
Of course, Marshal.SizeOf(typeof(Format)) == 204.
Related
I am attempting to bring over a function from vmmdll.h to vmmsharp.cs. In this case, I am trying to bring over Map_GetPool.
You can see here my implementation to C#:
//Please view the images:
Bringing function over
internal static uint VMMDLL_POOLMAP_FLAG_ALL = 0;
internal static uint VMMDLL_POOLMAP_FLAG_BIG = 1;
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal unsafe struct VMMDLL_MAP_POOLENTRYTAG
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] internal char[] szTag;
//szTag struct
/*internal uint dwTag;
internal uint _Filler;
internal uint cEntry;
internal uint iTag2Map;*/
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal unsafe struct VMMDLL_MAP_POOLENTRY
{
internal ulong va;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] internal char[] szTag;
//szTag struct
/*internal uint dwTag;
internal byte _ReservedZero;
internal byte fAlloc;
internal byte tpPool;
internal byte tpSS;*/
internal uint cb;
internal uint _Filler;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal unsafe struct VMMDLL_MAP_POOL
{
internal uint dwVersion;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] internal uint[] _Reserved1;
internal uint cbTotal;
internal uint* piTag2Map;
internal VMMDLL_MAP_POOLENTRYTAG* pTag;
internal uint cTag;
internal uint cMap;
internal VMMDLL_MAP_POOLENTRY[] pMap;
}
[DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetPoolEx")]
internal static extern unsafe bool VMMDLL_Map_GetPoolEx(
byte* pNetMap,
ref uint pcbNetMap);
Implementing it into c#
//My map pool
public unsafe struct MAP_POOL
{
public uint dwVersion;
public uint[] _Reserved1;
//public unsafe fixed uint _Reserved1[6];
public uint cbTotal;
public uint[] piTag2Map;
public MAP_POOLENTRYTAG* pTag;
public uint cTag;
public uint cMap;
public MAP_POOLENTRY[] pMap;
}
//szTag[5] -> POOLENTRY 4th tpPool MAP_POOL_TYPE 5th tpSS MAP_POOL_TYPE_SUBSEGMENT
public enum MAP_POOL_TYPE
{
MAP_POOL_TYPE_Unknown = 0,
MAP_POOL_TYPE_NonPagedPool = 1,
MAP_POOL_TYPE_NonPagedPoolNx = 2,
MAP_POOL_TYPE_PagedPool = 3
}
public enum MAP_POOL_TYPE_SUBSEGMENT
{
VMM_MAP_POOL_TYPE_SUBSEGMENT_UNKNOWN = 0,
VMM_MAP_POOL_TYPE_SUBSEGMENT_NA = 1,
VMM_MAP_POOL_TYPE_SUBSEGMENT_BIG = 2,
VMM_MAP_POOL_TYPE_SUBSEGMENT_LARGE = 3,
VMM_MAP_POOL_TYPE_SUBSEGMENT_VS = 4,
VMM_MAP_POOL_TYPE_SUBSEGMENT_LFH = 5
}
public unsafe struct MAP_POOLENTRYTAG
{
//union
public char[] szTag;
/*
* struct {
DWORD dwTag;
DWORD _Filler;
DWORD cEntry;
DWORD iTag2Map;
};
*/
}
public unsafe struct MAP_POOLENTRY
{
public ulong va;
public char[] szTag;
//public unsafe fixed char szTag[5];
public uint cb;
public uint _Filler;
}
Function
public static unsafe MAP_POOLENTRY[] Map_GetPoolEx()
{
bool result;
uint cb = 0;
int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_POOL));
int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_POOLENTRY));
result = vmmi.VMMDLL_Map_GetPoolEx(null, ref cb);
if (!result || (cb == 0)) { return new MAP_POOLENTRY[0]; }
fixed (byte* pb = new byte[cb])
{
result = vmmi.VMMDLL_Map_GetPoolEx(pb, ref cb);
if (!result) { return new MAP_POOLENTRY[0]; }
vmmi.VMMDLL_MAP_POOL pm = Marshal.PtrToStructure<vmmi.VMMDLL_MAP_POOL>((System.IntPtr)pb);
if (pm.dwVersion != vmmi.VMMDLL_MAP_PHYSMEM_VERSION) { return new MAP_POOLENTRY[0]; }
MAP_POOLENTRY[] m = new MAP_POOLENTRY[pm.cMap];
for (int i = 0; i < pm.cMap; i++)
{
vmmi.VMMDLL_MAP_POOLENTRY n = Marshal.PtrToStructure<vmmi.VMMDLL_MAP_POOLENTRY>((System.IntPtr)(pb + cbMAP + i * cbENTRY));
MAP_POOLENTRY e;
e.va = n.va;
e.cb = n.cb;
e.szTag = n.szTag;
//m[i] = e;
}
return m;
}
}
As you can see, the pointer PVMMDLL -> VMMDLL* throws an error stating it can't do that.
For the function, for some reason, e is undefined even though it is indeed defined. Also, is my overall setup correct?
Thanks, I appreciate any help.
Here are the links again to the implementations if needed (This doesn't have my implementation in it, but it has other implementations for similar functions):
vmmdll: https://github.com/ufrisk/MemProcFS/blob/master/vmm/vmmdll.h#L1506
vmmsharp: https://github.com/ufrisk/MemProcFS/blob/master/vmmsharp/vmmsharp.cs
I'm trying to get Informations about DVDs by ioctl in C#
the C Structure Looks like this and is working in a mixed CLR C++ Library
typedef enum {
DvdChallengeKey = 0x01,
DvdBusKey1,
DvdBusKey2,
DvdTitleKey,
DvdAsf,
DvdSetRpcKey = 0x6,
DvdGetRpcKey = 0x8,
DvdDiskKey = 0x80,
DvdInvalidateAGID = 0x3f
} DVD_KEY_TYPE;
typedef struct DVD_COPY_PROTECT_KEY
{
ULONG KeyLength;
DVD_SESSION_ID SessionId;
DVD_KEY_TYPE KeyType;
ULONG KeyFlags;
union
{
struct
{
ULONG FileHandle;
ULONG Reserved; // used for NT alignment
};
LARGE_INTEGER TitleOffset;
} Parameters;
UCHAR KeyData[0];
} DVD_COPY_PROTECT_KEY, * PDVD_COPY_PROTECT_KEY;
My C# equivalent Looks
public enum DVD_KEY_TYPE
{
DvdChallengeKey = 0x01,
DvdBusKey1,
DvdBusKey2,
DvdTitleKey,
DvdAsf,
DvdSetRpcKey = 0x6,
DvdGetRpcKey = 0x8,
DvdDiskKey = 0x80,
DvdInvalidateAGID = 0x3f
}
[StructLayout(LayoutKind.Sequential)]
public struct DVD_COPY_PROTECT_KEY
{
public uint KeyLength;
public int SessionId;
public DVD_KEY_TYPE KeyType;
public uint KeyFlags;
[MarshalAs(UnmanagedType.Struct)]
public DVD_COPY_PROTECT_KEY_Parameters Parameters;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
private byte[] KeyData;
public DVD_COPY_PROTECT_KEY(DVD_KEY_TYPE keyType, int sessionId)
{
SessionId = sessionId;
KeyType = keyType;
KeyFlags = 0;
KeyData = new byte[10];
KeyLength = 32;//GetKeyLength(this);
Parameters = new DVD_COPY_PROTECT_KEY_Parameters();
var t = Marshal.SizeOf(Parameters);
var t1 = Marshal.SizeOf(Parameters.Inner);
var t2 = Marshal.SizeOf(Parameters.TitleOffset);
var challenge = GetChallenge();
/* Get challenge from host */
for (int i = 0; i < 10; ++i)
{
KeyData[9 - i] = challenge[i];
}
}
public static byte[] GetChallenge()
{
byte[] p_challenge = new byte[10];
/* Setup a challenge, any values should work */
for (int i = 0; i < 10; ++i)
{
p_challenge[i] = (byte)i;
}
return p_challenge;
}
public static uint GetKeyLength(DVD_COPY_PROTECT_KEY dcpk)
{
int size = Marshal.SizeOf(dcpk);
switch (dcpk.KeyType)
{
case DVD_KEY_TYPE.DvdChallengeKey:
return (uint)(12 + size); //36
case DVD_KEY_TYPE.DvdBusKey1:
return (uint)(8 + size); //32
case DVD_KEY_TYPE.DvdBusKey2:
return (uint)(8 + size);
default:
return 0;
}
}
}
[StructLayout(LayoutKind.Explicit)]
public struct DVD_COPY_PROTECT_KEY_Parameters
{
[FieldOffset(0)]
public DVD_COPY_PROTECT_KEY_Parameters_Inner Inner;
[FieldOffset(0)]
public int TitleOffset;
}
[StructLayout(LayoutKind.Sequential)]
public struct DVD_COPY_PROTECT_KEY_Parameters_Inner
{
public IntPtr FileHandle;
public uint Reserved;
}
If i call DeviceIoControl i get an Exception PInvokeStackImbalance, if i use classes instead i get ErrorCode 87 from Marshal.GetLastWin32Error();
Someone any Idea?
Update
My DeviceIoControl
[System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
public extern static int DeviceIoControl(IntPtr hDevice, uint IoControlCode, ref DVD_COPY_PROTECT_KEY dcpk, uint InBufferSize, ref DVD_COPY_PROTECT_KEY dcpk2, uint OutBufferSize, ref uint BytesReturned, IntPtr Overlapped);
I have add ref keywords now i get with structs no Exception but ErrorCode 87
My Code can be found here
Days ago I made this question: Passing a complex Struct (with inner array of struct) from C# to C++
Fortunately it as been answered and the code seems to work.
Now I need to do the oposite case, I mean, I need to get the struct from the C++ dll to my C# code.
I was researching in this site, trying the use of the IntPtr type, but didnt work. Then as my struct in C# was defined correctly I tried to use an out reference.
As a sumary, gonna repost the structs defined in both languages
typedef struct _ImParam
{
UINT Format;
UINT Resolution;
UINT ColorDepth;
} IM_PARAM;
typedef struct _sValues
{
UINT Xpos;
UINT Ypos;
UINT Width;
UINT Height;
BOOL Milli;
} S_VALUES;
typedef struct _sProperties
{
BOOL Enable;
S_VALUES Properties;
} S_PROPERTIES;
typedef struct _DevParam
{
BOOL Enable;
UINT Font;
char Symbol;
IM_PARAM Image1;
IM_PARAM Image2;
S_PROPERTIES Properties[10];
UINT FeedMode;
} DevParam;
// more code, comments, etc. etc.
// The function I want to use
BOOL GetParameters( DWORD ID, DevParam *dParam );
This is how I build the structs in C#
[StructLayout(LayoutKind.Sequential)]
public struct ImParam
{
public uint Format;
public uint Resolution;
public uint ColorDepth;
public ImParam(uint n)
{
Format = n;
Resolution = 300;
ColorDepth = 256;
}
};
[StructLayout(LayoutKind.Sequential)]
public struct sValues
{
public uint Xpos;
public uint Ypos;
public uint Width;
public uint Height;
public bool Milli;
public sValues(uint n)
{
Xpos = n;
Ypos = n;
Width = n;
Height = n;
Milli = false;
}
};
[StructLayout(LayoutKind.Sequential)]
public struct sProperties
{
public bool Enable;
public sValues Properties;
public sProperties(int n)
{
Enable = false;
Properties = new sValues(n);
}
};
[StructLayout(LayoutKind.Sequential)]
public struct DevParam
{
public bool Enable;
public uint Font;
public char Symbol;
public ImParam Image1;
public ImParam Image2;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public sProperties[] Properties;
public uint FeedMode;
public DeviceParameters(int n)
{
Enable = true;
Font = 0;
Symbol = '?';
Image1 = new ImParam(3);
Image2 = new ImParam(3);
Properties = new sProperties[10];
for(int i = 0; i < 10; i++)
Properties[i] = new sProperties(n);
FeedMode = 1;
}
};
// This is the method imported from the C++ dll
[DllImport(path, EntryPoint = "?GetParameters##YGHKPAU_DevParam###Z")]
public static extern bool GetParameters(int ID, out DevParam dParam);
And here's the call
// Already got ID from somewhere else
DevParam DP;
bool res = Class1.GetParameters(ID, out DP);
Console.WriteLine("Result: " + res);
The code seems to work, since I'm getting a "true" as result. The problem is it's getting wrong values in the structs members, placing the default ones (always 0 the numbers, always false the booleans), even if I use the SetParam(..) method before (and I know that one works because when I change the image format scanner decreases scanning speed).
What am I missing?
Note: I dont have source code of the .dll
Edited:
Been trying with these modifications:
// At the dll wrapper class
[DllImport(path, EntryPoint = "?GetParameters##YGHKPAU_DevParam###Z")]
public static extern bool GetParameters(int ID, ref IntPtr dParam);
// At main
int size = Marshal.SizeOf(typeof(DevParam));
IntPtr Ptr = Marshal.AllocHGlobal(size);
bool res = Class1.GetParameters(ID, ref Ptr);
Console.WriteLine("Result: " + res);
var test = Marshal.PtrToStructure(Ptr, typeof(DevParam));
// No idea what I'll do here
Marshal.FreeHGlobal(Ptr);
If I try to print "test", it should give an adress, since it's a pointer, but it's null. Neither know how can I extract the data from the struct.
Any ideas?
Solved!
// At the dll wrapper class
[DllImport(path, EntryPoint = "?GetParameters##YGHKPAU_DevParam###Z")]
public static extern bool GetParameters(int ID, IntPtr dParam);
// At main
int size = Marshal.SizeOf(typeof(DevParam));
IntPtr Ptr = Marshal.AllocHGlobal(size);
bool res = Class1.GetParameters(ID, Ptr);
DevParam test = (DevParam)Marshal.PtrToStructure(Ptr, typeof(DevParam));
// For testing purpoises, previously changed the default values with another method
Console.WriteLine(test.Enable);
Marshal.FreeHGlobal(Ptr);
Had to remove the ref keyword.
I try to programmatically enumerate the DHCP filters on my Windows 2012 R2 DHCP server. Using P/Invoke, the code looks like:
public const uint ERROR_SUCCESS = 0;
public const uint ERROR_MORE_DATA = 234;
public const uint ERROR_NO_MORE_ITEMS = 259;
public const int MAX_PATTERN_LENGTH = 255;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DHCP_ADDR_PATTERN {
public bool MatchHWType;
public byte HWType;
public bool IsWildCard;
public byte Length;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_PATTERN_LENGTH)]
public byte[] Pattern;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DHCP_FILTER_ENUM_INFO {
public uint NumElements;
public IntPtr pEnumRecords;
}
public enum DHCP_FILTER_LIST_TYPE : uint {
Deny = 0x1,
Allow = 0x2
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DHCP_FILTER_RECORD {
public DHCP_ADDR_PATTERN AddrPatt;
public string Comment;
}
[DllImport("dhcpsapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint DhcpEnumFilterV4(string ServerIpAddress,
ref DHCP_ADDR_PATTERN ResumeHandle, uint PreferredMaximum,
DHCP_FILTER_LIST_TYPE ListType, out IntPtr EnumFilterInfo,
out uint ElementsRead, out uint ElementsTotal);
public static IEnumerable<DHCP_FILTER_RECORD> DhcpEnumFilterV4(
string serverIpAddress, DHCP_FILTER_LIST_TYPE listType,
uint preferredMaximum = 1024) {
uint cntRead = 0;
uint cntTotal = 0;
uint error = ERROR_SUCCESS;
var hResume = new DHCP_ADDR_PATTERN();
var data = IntPtr.Zero;
var size = Marshal.SizeOf(typeof(DHCP_FILTER_RECORD));
do {
error = DhcpEnumFilterV4(serverIpAddress, ref hResume,
preferredMaximum, listType, out data, out cntRead,
out cntTotal);
//
// PROBLEM OCCURS HERE: 'error' is always 259
//
if ((error == ERROR_SUCCESS) || (error == ERROR_MORE_DATA)) {
var array = data.ToStructure<DHCP_FILTER_ENUM_INFO>();
for (uint i = 0; i < array.NumElements; ++i) {
var ptr = new IntPtr((long) array.pEnumRecords + i * size);
var obj = (DHCP_FILTER_RECORD) Marshal.PtrToStructure(ptr, typeof(DHCP_FILTER_RECORD));
yield return obj;
}
DhcpRpcFreeMemory(array.pEnumRecords);
DhcpRpcFreeMemory(data);
data = IntPtr.Zero;
} else if (error != ERROR_NO_MORE_ITEMS) {
Debug.Assert(data == IntPtr.Zero);
throw new Win32Exception((int) error);
}
} while (error == ERROR_MORE_DATA);
}
[DllImport("dhcpsapi.dll", SetLastError = true)]
public static extern void DhcpRpcFreeMemory(IntPtr BufferPointer);
The documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/dd897526(v=vs.85).aspx) of the whole DHCP APIs is imho a bit sketchy, so I am not completely sure whether I am doing the right thing.
The problem is: I never get any results, DhcpEnumFilterV4 always returns ERROR_NO_MORE_ITEMS. Any suggestions?
I just stumbled over an important user comment regarding DHCP_FILTER_LIST_TYPE in MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/dd897586(v=vs.85).aspx). It seems that the definition of the enumeration in MSDN is wrong. The following
typedef enum {
Deny = 0x1, // This is wrong!
Allow = 0x2 // This is wrong!
} DHCP_FILTER_LIST_TYPE;
should be
typedef enum {
Deny = 0x0, // This is correct!
Allow = 0x1 // This is correct!
} DHCP_FILTER_LIST_TYPE;
Using the updated constants, my code works.
Consider the following code as an example of copying memory between a struct [] and a byte []. The method of memory copy is irrelevant to the core question. It's there to demonstrate two pointers to managed arrays.
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory (IntPtr dest, IntPtr src, uint count);
public struct MyStruct { public float Value; public TimeSpan Value; }
var bufferSize = 1000000;
var size = Marshal.SizeOf(typeof(MyStruct));
var bufferSource = new MyStruct [bufferSize];
var bufferTarget = new byte [bufferSize * size];
for (int i = 0; i < bufferSource.Length; i++)
{
bufferSource [j] = new MyStruct() { Value = i; };
}
var handleSource = GCHandle.Alloc(bufferSource, GCHandleType.Pinned);
var handleTarget = GCHandle.Alloc(bufferTarget, GCHandleType.Pinned);
var pointerSource = handleSource.AddrOfPinnedObject();
var pointerTarget = handleTarget.AddrOfPinnedObject();
handleSource.Free();
handleTarget.Free();
CopyMemory(pointerTarget, pointerSource, (uint) (bufferSize * size));
The IntPtr pointerTarget did not originate as a MyStruct []. Is there a way to cast this allocated and initialized memory to a MyStruct []? I do not want to allocate a new array to be able to do this.
It's easier to redefine the p/invoke signature, in this case like this:
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
private static extern void CopyMemory([In, Out] byte[] pdst, Mystruct[] psrc, int cb);
define the struct layout for p/invoke:
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct { public float Value; public TimeSpan Value;}
Then you can just use it like this:
CopyMemory(bufferTarget, bufferSource, bufferTarget.Length);