C# Marshalling for C Struct and Function - c#

I have the following C Header/Code Example:
Header file
struct category_info {
int id;
const char *name;
const char *description;
};
DLLEXPORT
void* xyz_categories_info(struct category_info **info, size_t *info_count);
Example C Snippet
struct category_info *catinfo;
size_t catcount;
size_t i;
int max_name_len = 0;
void *catmem = xyz_categories_info(&catinfo, &catcount)
Which I would like to convert to c#...
My First GUESS (and its a guess) is:
[StructLayout(LayoutKind.Sequential)]
public struct category_info
{
int id;
[MarshalAs(UnmanagedType.LPStr)]
StringBuilder name;
[MarshalAs(UnmanagedType.LPStr)]
StringBuilder description;
};
[DllImport("mydll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr xyz_categories_info([Out]category_info cat, [Out]int catSize);
But it just doesn't look right..
Any suggestions.. Once the above is declared correctly in C#.. How should it be accessed in C#
category_info catinfo;
catmem = xyz_categories_info(out catinfo, out catcount);
??????
Any help greatly appreciated.
Thanks
================================================================================
Update 2
The memory allocated in xyz_categories_info is freed using this C call:
void xyz_categories_info_free(void *p);
Below is an example of it being used in C.... Hope this explains it a bit more..
category_buffer = xyz_categories_info(&category_info, &category_count);
if( !category_buffer )
{
// Failed Log a message and exit.
exit(1);
}
for(j=0; j<category_count; j++)
{
if( category_info[j].id == 0 )
continue;
printf("id: %d name: '%s' description: '%s'\n",
category_info[j].id,
category_info[j].name,
category_info[j].description
);
}
xyz_categories_info_free(category_buffer);

This code is compiled, but not tested. If you know C, you will understand what happens here, this is just the same C code translated to C#.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
public struct category_info
{
public int id;
public IntPtr name;
public IntPtr description;
};
class Program
{
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr xyz_categories_info(ref IntPtr cat, ref int catSize);
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void xyz_categories_info_free(IntPtr cat);
static void Main(string[] args)
{
IntPtr categories = IntPtr.Zero;
IntPtr category_buffer = IntPtr.Zero;
int category_count = 0;
category_info info = new category_info();
IntPtr current;
try
{
category_buffer = xyz_categories_info(ref categories, ref category_count);
if (category_buffer == IntPtr.Zero)
{
return;
}
if (category_count == 0)
{
return;
}
for (int j = 0; j < category_count; j++)
{
if (IntPtr.Size == 4)
{
current = new IntPtr(categories.ToInt32() + j * Marshal.SizeOf(info));
}
else
{
current = new IntPtr(categories.ToInt64() + j * Marshal.SizeOf(info));
}
info = (category_info)Marshal.PtrToStructure(current, typeof(category_info));
if (info.id == 0)
{
continue;
}
Console.WriteLine(info.id);
Console.WriteLine(Marshal.PtrToStringAnsi(info.name));
Console.WriteLine(Marshal.PtrToStringAnsi(info.description));
}
}
finally
{
if (category_buffer != IntPtr.Zero)
{
xyz_categories_info_free(category_buffer);
}
}
}
}
}

This is correct for importing DLL's functions
[DllImport("mydll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr xyz_categories_info([Out]category_info cat, [Out]int catSize);
But not sure about the OUT
Your C code of that
struct category_info {
int id;
const char *name;
const char *description;
};
I bilive should be C# Class
public class category_info
{
public const string name {get; set};
public const string description {get; set};
public int id {get; set;}
public category_info(int id, const string name, const string description){
this.name = name;
this.description = description;
this.id = id;
}
}
As to using it and using the code i'm not sure what your trying todo
size_t catcount;
size_t i;
int max_name_len = 0;
void *catmem = xyz_categories_info(&catinfo, &catcount)
This in C# I'm not sure about as size_t would have to be an class in C# but then that class has to match exactly what the DLL class is or there will be a type mismatch this is the problem with loading cross lang DLLS
What is that DLL supposed to be doing? maybe we can help

Related

How to deal with "no set size" arrays in pinvoke structs?

How would you write this type of struct in c#?
struct _JOBOBJECT_BASIC_PROCESS_ID_LIST {
DWORD NumberOfAssignedProcesses;
DWORD NumberOfProcessIdsInList;
ULONG_PTR ProcessIdList[1];
}
sins there is no set size for the ProcessIdList array, what do you do? Do you just write it like this:
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
int NumberOfAssignedProcesses;
int NumberOfProcessIdsInList;
IntPtr ProcessIdList; //Must point to a allocated array, thanks jdweng for letting me know.
}
or do you just assign a size which is big enough, e.g.:
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
int NumberOfAssignedProcesses;
int NumberOfProcessIdsInList;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_PATH)]
UIntPtr[] ProcessIdList; //Works just fine, but is limited to the SizeConst.
}
This sort of structure is usually declared (there are others like this one in WLan APIs for example) :
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
public int NumberOfAssignedProcesses;
public int NumberOfProcessIdsInList;
public IntPtr[] ProcessIdList;
public JOBOBJECT_BASIC_PROCESS_ID_LIST(IntPtr pList)
{
int nIntSize = Marshal.SizeOf<int>(); // 4
NumberOfAssignedProcesses = Marshal.ReadInt32(pList, 0);
NumberOfProcessIdsInList = Marshal.ReadInt32(pList, nIntSize);
ProcessIdList = new IntPtr[NumberOfProcessIdsInList];
for (int i = 0; i < NumberOfProcessIdsInList; i++)
{
IntPtr pItemList = IntPtr.Zero;
if (Marshal.SizeOf<IntPtr>() == 4)
pItemList = new IntPtr(pList.ToInt32() + (i * Marshal.SizeOf<IntPtr>()) + (nIntSize * 2));
else
pItemList = new IntPtr(pList.ToInt64() + (i * Marshal.SizeOf<IntPtr>()) + (nIntSize * 2));
IntPtr nPID = new IntPtr();
nPID = Marshal.ReadIntPtr(pItemList, 0);
ProcessIdList[i] = nPID;
}
}
}
A test with 5 Notepad launched and assigned to a job with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE,
then QueryInformationJobObject to enumerate the PIDs by using this structure =>
private IntPtr hJob = IntPtr.Zero;
bool bRet = false;
hJob = CreateJobObject(IntPtr.Zero, "Test Job Object");
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jbeli = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
jbeli.BasicLimitInformation.LimitFlags |= (JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_BREAKAWAY_OK);
int nLength = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
IntPtr pJobInfo = Marshal.AllocHGlobal(nLength);
Marshal.StructureToPtr(jbeli, pJobInfo, false);
SetInformationJobObject(hJob, JOBOBJECTINFOCLASS.JobObjectExtendedLimitInformation, pJobInfo, (uint)nLength);
Marshal.FreeHGlobal(pJobInfo);
int nNbProcesses = 5;
for (int i = 0; i < nNbProcesses; i++)
{
using (Process exeProcess = new Process())
{
exeProcess.StartInfo.FileName = "notepad";
exeProcess.Start();
exeProcess.WaitForInputIdle();
IntPtr hProcess = exeProcess.Handle;
bRet = AssignProcessToJobObject(hJob, hProcess);
}
}
JOBOBJECT_BASIC_PROCESS_ID_LIST jobpil = new JOBOBJECT_BASIC_PROCESS_ID_LIST();
jobpil.NumberOfAssignedProcesses = nNbProcesses;
int nSize = Marshal.SizeOf<JOBOBJECT_BASIC_PROCESS_ID_LIST>() + (nNbProcesses - 1) * Marshal.SizeOf<IntPtr>();
IntPtr pJobpil = Marshal.AllocHGlobal(nSize);
Marshal.StructureToPtr(jobpil, pJobpil, false);
int nReturnLength = 0;
bRet = QueryInformationJobObject(hJob, JOBOBJECTINFOCLASS.JobObjectBasicProcessIdList, pJobpil, nSize, out nReturnLength);
if (bRet)
{
var processidlist = new JOBOBJECT_BASIC_PROCESS_ID_LIST(pJobpil);
foreach (var pid in processidlist.ProcessIdList)
{
Console.WriteLine("PID: {0}", pid.ToString());
}
}
else
{
int nErr = Marshal.GetLastWin32Error();
Win32Exception win32Exception = new Win32Exception(nErr);
this.Activate();
MessageBox.Show("Error: " + win32Exception.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Marshal.FreeHGlobal(pJobpil);
// CloseHandle can be added in Form1_FormClosed :
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
CloseHandle(hJob);
}
Declarations =>
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string lpName);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SetInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInfoClass, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool QueryInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, [Out, MarshalAs(UnmanagedType.SysUInt)] IntPtr lpJobObjectInformation, int cbJobObjectInformationLength, out int lpReturnLength);
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public ulong PerProcessUserTimeLimit;
public ulong PerJobUserTimeLimit;
public int LimitFlags;
public IntPtr MinimumWorkingSetSize;
public IntPtr MaximumWorkingSetSize;
public int ActiveProcessLimit;
public IntPtr Affinity;
public int PriorityClass;
public int SchedulingClass;
}
[StructLayout(LayoutKind.Sequential)]
struct IO_COUNTERS
{
public ulong ReadOperationCount;
public ulong WriteOperationCount;
public ulong OtherOperationCount;
public ulong ReadTransferCount;
public ulong WriteTransferCount;
public ulong OtherTransferCount;
}
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
public IO_COUNTERS IoInfo;
public IntPtr ProcessMemoryLimit;
public IntPtr JobMemoryLimit;
public IntPtr PeakProcessMemoryUsed;
public IntPtr PeakJobMemoryUsed;
}
//
// Basic Limits
//
public const int JOB_OBJECT_LIMIT_WORKINGSET = 0x00000001;
public const int JOB_OBJECT_LIMIT_PROCESS_TIME = 0x00000002;
public const int JOB_OBJECT_LIMIT_JOB_TIME = 0x00000004;
public const int JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 0x00000008;
public const int JOB_OBJECT_LIMIT_AFFINITY = 0x00000010;
public const int JOB_OBJECT_LIMIT_PRIORITY_CLASS = 0x00000020;
public const int JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME = 0x00000040;
public const int JOB_OBJECT_LIMIT_SCHEDULING_CLASS = 0x00000080;
//
// Extended Limits
//
public const int JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x00000100;
public const int JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200;
public const int JOB_OBJECT_LIMIT_JOB_MEMORY_HIGH = JOB_OBJECT_LIMIT_JOB_MEMORY;
public const int JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x00000400;
public const int JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800;
public const int JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000;
public const int JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000;
public const int JOB_OBJECT_LIMIT_SUBSET_AFFINITY = 0x00004000;
public const int JOB_OBJECT_LIMIT_JOB_MEMORY_LOW = 0x00008000;
public enum JOBOBJECTINFOCLASS
{
JobObjectBasicAccountingInformation = 1,
JobObjectBasicLimitInformation,
JobObjectBasicProcessIdList,
JobObjectBasicUIRestrictions,
JobObjectSecurityLimitInformation, // deprecated
JobObjectEndOfJobTimeInformation,
JobObjectAssociateCompletionPortInformation,
JobObjectBasicAndIoAccountingInformation,
JobObjectExtendedLimitInformation,
JobObjectJobSetInformation,
JobObjectGroupInformation,
JobObjectNotificationLimitInformation,
JobObjectLimitViolationInformation,
JobObjectGroupInformationEx,
JobObjectCpuRateControlInformation,
JobObjectCompletionFilter,
JobObjectCompletionCounter,
JobObjectReserved1Information = 18,
JobObjectReserved2Information,
JobObjectReserved3Information,
JobObjectReserved4Information,
JobObjectReserved5Information,
JobObjectReserved6Information,
JobObjectReserved7Information,
JobObjectReserved8Information,
JobObjectReserved9Information,
JobObjectReserved10Information,
JobObjectReserved11Information,
JobObjectReserved12Information,
JobObjectReserved13Information,
JobObjectReserved14Information = 31,
JobObjectNetRateControlInformation,
JobObjectNotificationLimitInformation2,
JobObjectLimitViolationInformation2,
JobObjectCreateSilo,
JobObjectSiloBasicInformation,
JobObjectReserved15Information = 37,
JobObjectReserved16Information,
JobObjectReserved17Information,
JobObjectReserved18Information,
JobObjectReserved19Information = 41,
JobObjectReserved20Information,
MaxJobObjectInfoClass
}
I think any of the ways you mentioned should work.
In addition, there is a matching feature in c#: Define an array with the fixed keyword:
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
int NumberOfAssignedProcesses;
int NumberOfProcessIdsInList;
fixed IntPtr ProcessIdList[1];
}
See documentation:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/unsafe-code-pointers/fixed-size-buffers
Also no bounds check, so you should be able to read behind the end of the struckt easily:
Note
Except for memory created by using stackalloc, the C# compiler and the common language runtime (CLR) do not perform any security buffer overrun checks. As with all unsafe code, use caution.

Marshalling array of structures from c++ to c# in WinCE

I'm trying to Marshal the following structures from c++ to c# on a Windows CE program and compact framework 2.0. I'm having a lot of difficulties with the marshalling of strings.
I have this c++ code:
#define Console_Parameters_MAX 50
struct AllParameters {
Parameter Parameters[Console_Parameters_MAX];
} ;
struct Parameter {
int Index;
int Id;
char Value[20];
};
extern "C" {
BOOL GetAllConsoleParameters(AllParameters *pItem);
}
and this are the corresponding c# code:
[StructLayout(LayoutKind.Sequential)]
public struct AllParameters {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
public Parameter[] Parameters
}
[StructLayout(LayoutKind.Sequential)]
public struct Parameter {
public int Index;
public int Id;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public byte[] Value;
}
[DllImport("exemple.dll", SetLastError = true)]
public static extern bool GetAllConsoleParameters([MarshalAs(UnmanagedType.Struct)] ref AllParameters pItem);
and this is how I invoke it:
AllParameters item = new AllParameters();
if (AppAPI.GetAllConsoleParameters(ref item)) {
var array = item.Parameters;
}
When I call the GetAllConsoleParameters I get exception NotSupportedException. I've tried many configurations but with no success.
Can anyone advise on how to achieve it?
Thanks in advance
This works for me on a Windows Desktop. You might have to change the calling convention to Cdecl in the C DLL and the C# DllImport attribute, because I read here that Cdecl is standard on Windows CE: https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention(v=vs.110).aspx
C code:
extern "C" {
__declspec(dllexport) BOOL __stdcall GetAllConsoleParameters(AllParameters *pItem)
{
pItem->Parameters[0].Index = 0;
pItem->Parameters[0].Id = 42;
CopyMemory(&pItem->Parameters[0].Value[0], "Hello World", 12);
pItem->Parameters[1].Index = 1;
pItem->Parameters[1].Id = 43;
CopyMemory(&pItem->Parameters[1].Value[0], "Hello World 43", 15);
return TRUE;
}
}
C# code:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct Parameter
{
int Index;
int Id;
//char Value[20];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
string Value;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct AllParameters
{
//Parameter Parameters[Console_Parameters_MAX];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
Parameter[] Parameters;
};
class Program
{
[DllImport("MarshalC.dll", CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetAllConsoleParameters(ref AllParameters pItem);
static void Main(string[] args)
{
var size = Marshal.SizeOf<AllParameters>();
AllParameters all = new AllParameters();
bool result = GetAllConsoleParameters(ref all);
}
}
I would do it like this
[StructLayout(LayoutKind.Sequential)]
public struct AllParameters {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
public Parameter[] Parameters;
}
[StructLayout(LayoutKind.Sequential)]
public struct Parameter {
public int Index;
public int Id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte[] Value;
}
[DllImport("exemple.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern bool GetAllConsoleParameters(ref IntPtr pItem);
static void Main(string[] args)
{
AllParameters allParameters = new AllParameters();
allParameters.Parameters = new Parameter[50];
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(allParameters));
int z = Marshal.SizeOf(allParameters);
if (GetAllConsoleParameters(ref ptr))
{
Marshal.PtrToStructure(ptr, allParameters);
Parameter[] parameters = allParameters.Parameters;
}
}
following my solution, c++ code:
/* - not used
#define Console_Parameters_MAX 50
struct AllParameters {
Parameter Parameters[Console_Parameters_MAX];
} ;
*/
struct Parameter {
int Index;
int Id;
char Value[20];
};
extern "C" {
BOOL GetAllConsoleParameters(Parameter pItem[], int size);
}
and corresponding c# code:
/* - not used
[StructLayout(LayoutKind.Sequential)]
public struct AllParameters {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
public Parameter[] Parameters
}
*/
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct Parameter {
public int Index;
public int Id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte[] Value;
}
[DllImport("exemple.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool GetAllConsoleParameters([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), Out] ConsoleParameter[] myStruct, int size);
and code invoke:
ConsoleParameter[] item = new ConsoleParameter[50];
if (AppAPI.GetAllConsoleParameters(item, 50)) {
var array = item;
}
thanks a lot for help

C# DllImport : AccessViolationException when calling a vkCreateInstance

I'm trying to create a Vulkan wrapper in C#, but I have some problems when I call a function. I rewrote the vulkan.h header as follows :
public static class Vk {
[StructLayout(LayoutKind.Sequential)] public class Instance { }
public enum Result {
...
}
public enum StructureType {
...
}
[StructLayout(LayoutKind.Sequential)] public class ApplicationInfo {
public StructureType sType;
public IntPtr pNext;
public string pApplicationName;
public uint applicationVersion;
public string pEngineName;
public uint engineVersion;
public uint apiVersion;
}
[StructLayout(LayoutKind.Sequential)] public class InstanceCreateInfo {
public StructureType sType;
public IntPtr pNext;
public uint flags_VkInstanceCreateFlags;
public ApplicationInfo pApplicationInfo;
public uint enabledLayerCount;
public string[] ppEnabledLayerNames;
public uint enabledExtensionCount;
public string[] ppEnabledExtensionNames;
}
[DllImport("vulkan-1.dll", EntryPoint = "vkCreateInstance")]
public extern static Result CreateInstance(
InstanceCreateInfo pCreateInfo,
IntPtr AllocationCallbacks_pAllocator,
out IntPtr pInstance_Instance);
}
The original declaration in C of this function is
VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance);
Now when I call my function, I'm doing like this :
Vk.InstanceCreateInfo instance_create_info = new Vk.InstanceCreateInfo();
...
IntPtr hinstance;
Vk.Result result = Vk.CreateInstance(instance_create_info, IntPtr.Zero, out hinstance); <-- error AccessViolationException
I don't understand where is my problem, because it seems to be a valid solution : StackOverflow : AccessViolationException when calling vkEnumeratePhysicalDevices via pInvoke from c#.
I tried by initializing my IntPtr hinstance with
Marshal.AllocHGlobal(Marshal.SizeOf<Vk.Instance>());
I also tried to "convert" my instance_create_info to another IntPtr with Marshal.StructureToPtr(...); and I tried to pass instance_create_info and instance by the ref keyword. Obviously, nothing worked.
Any idea ?
EDIT :
The native function is used as follows :
//Definition
typedef struct VkApplicationInfo {
VkStructureType sType;
const void* pNext;
const char* pApplicationName;
uint32_t applicationVersion;
const char* pEngineName;
uint32_t engineVersion;
uint32_t apiVersion;
} VkApplicationInfo;`
typedef struct VkInstanceCreateInfo {
VkStructureType sType;
const void* pNext;
VkInstanceCreateFlags flags;
const VkApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
} VkInstanceCreateInfo;
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
VK_DEFINE_HANDLE(VkInstance)
//Code
VkApplicationInfo application_info{};
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
application_info.apiVersion = VK_API_VERSION;
application_info.applicationVersion = VK_MAKE_VERSION( 1, 0, 0 );
application_info.pApplicationName = "";
application_info.engineVersion = VK_MAKE_VERSION( 1, 0, 0 );
application_info.pEngineName = "";
VkInstanceCreateInfo instance_create_info{};
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instance_create_info.pApplicationInfo = &application_info;
instance_create_info.enabledLayerCount = 0
instance_create_info.ppEnabledLayerNames = nullptr
instance_create_info.enabledExtensionCount = 0
instance_create_info.ppEnabledExtensionNames = nullptr
VkInstance _instance = nullptr;
assert( !vkCreateInstance( &instance_create_info, nullptr, &_instance ) );
it seems that you are trying to do something similar this guy made a wrapper for the c#. Can be useful for you. Go to Source/SharpVulkan/Generated/Functions.
public static unsafe Instance CreateInstance(ref InstanceCreateInfo createInfo, AllocationCallbacks* allocator = null)
{
Instance instance;
fixed (InstanceCreateInfo* __createInfo__ = &createInfo)
{
vkCreateInstance(__createInfo__, allocator, &instance).CheckError();
}
return instance;
}
[DllImport("vulkan-1.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern unsafe Result vkCreateInstance(InstanceCreateInfo* createInfo, AllocationCallbacks* allocator, Instance* instance);
internal static unsafe void EnumerateInstanceExtensionProperties(byte* layerName, ref uint propertyCount, ExtensionProperties* properties)
{
fixed (uint* __propertyCount__ = &propertyCount)
{
vkEnumerateInstanceExtensionProperties(layerName, __propertyCount__, properties).CheckError();
}
}
Hope it is helpfull :)
remove out keyword for third argument or declare it as corresponding struct.

DhcpEnumFilterV4 (P/Invoke) always reports ERROR_NO_MORE_ITEMS

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.

Using pinvoke to pass embedded array of C structs inside struct array to c#

I am attempting to use an array of structures to pass data to/fro my C# ui and my C dll.
Further complicating matters is that the structure contains another array of structures.
I have figured out how to the simpler stuff using pinvoke, but how do I declare
the embedded structures, and how do I pass them?
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class csForm {
public int endDate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public char[] formId;
}
[DllImport("myDll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void fillForm([In, Out] csForm data, 5);
// c code
typedef struct s_ptxRow {
int ptxNumber;
char primitive[128];
int primitiveParams[128];
} ptxRow;
typedef struct s_workSpace{
char formId[128];
int endDate;
ptxRow PtxRow[128];
} cForm;
extern "C" __declspec(dllexport) fillForm(cForm csForm[], interface csFormCount)
{
for (int i = 0, j = 0; i < csFormCount; ++i)
{
j = int / 2;
csForm[i].endDate = i;
strcpy(csForm[i].formId, "formId here");
csForm[i].PtxRow[j].ptxNumber = i;
csForm[i].PtxRow[j].primitiveParams[i] = i;
strcpy(csForm[i].PtxRow[j].primitive, "someText");
}
}
You were going in the right direction. You just needed to declare the ptxRow structure in C# and then add an array of it to csForm. You even don't need to allocate any arrays beforehand - apparently P/Invoke does it for you since it knows their sizes. The entire sample code is included because there were minute errors in some declarations.
Note: When I tried to use classes in C# I got strange results (e.g. incorrect member and pointer values in the C++ code) which led to various errors. Switching to structs made the problem go away. I think this has something to do with reference and value types, but would appreciate input from more knowledgeable people. I'm testing with .NET 3.5 if it matters.
#include <string.h>
typedef struct s_ptxRow {
int ptxNumber;
char primitive[128];
int primitiveParams[128];
} ptxRow;
typedef struct s_workSpace {
char formId[128];
int endDate;
ptxRow PtxRow[128];
} cForm;
extern "C" __declspec(dllexport) void fillForm(cForm csForm[], int csFormCount)
{
for (int i = 0, j = 0; i < csFormCount; ++i)
{
j = i / 2;
csForm[i].endDate = i;
strcpy(csForm[i].formId, "formId here");
csForm[i].PtxRow[j].ptxNumber = i;
csForm[i].PtxRow[j].primitiveParams[i] = i;
strcpy(csForm[i].PtxRow[j].primitive, "someText");
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace PInvokeStructsCS
{
class Program
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct PtxRow
{
public int ptxNumber;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public char[] primitive;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public int[] primitiveParams;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct csForm
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public char[] formId;
public int endDate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public PtxRow[] ptxRow;
}
[DllImport("PInvokeStructsC.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void fillForm([In, Out]csForm[] data, int count);
static void Main(string[] args)
{
csForm[] forms = new csForm[2];
try
{
fillForm(forms, 2);
}
catch (Exception e)
{
Console.Out.WriteLine(e.Message);
return;
}
}
}
}

Categories