C# PInvoke issue - c#

I have been trying to replicate the following C++ function in my C# application but I am getting an AccessViolationException at the time the method "ObjSearchObject2" is invoked. Pretty sure I am doing a lot of things wrong. The C++ function and the corresponding headers looks like this,
bool DocumentSearch(char *pFileId)
{
const int NUM_CONDITIONS = 1;
const int NUM_TYPE_DEFNS = 1;
ObjSearchObjectParm rSearchObject;
ObjSearchCondition rSearchCondition;
ObjObjectResults rSearchResults;
char *pTypeDefnIdArray[NUM_TYPE_DEFNS];
bool bReturnValue = false;
memset(&rSearchObject, 0, sizeof(ObjSearchObjectParm));
memset(&rSearchCondition, 0, sizeof(ObjSearchCondition));
memset(&rSearchResults, 0, sizeof(ObjObjectResults));
pTypeDefnIdArray[0] = "dotdA9";//Documents
rSearchObject.obj_defn_ids = pTypeDefnIdArray;
rSearchObject.obj_defn_count = NUM_TYPE_DEFNS;
rSearchObject.num_conditions = NUM_CONDITIONS;
rSearchObject.max_results = 5000;
rSearchObject.search_cond = &rSearchCondition;
rSearchCondition.field = "ancestor";
rSearchCondition.op = "is";
rSearchCondition.value = pFileId;
if (ObjSearchObject2(&rSearchObject, &rSearchResults))
{
printf("ERROR: ObjSearchObject2 returned: %s \n", ObjGetErrorMsg());
}
else
{
printf("INFO : Number of returned results = %d \n", rSearchResults.num_results);
if (rSearchResults.num_results > 0)
{
for (int iIndex = 0; iIndex < rSearchResults.num_results; iIndex++)
{
if (rSearchResults.object_handle[iIndex])
{
printf("INFO : Object Id returned: %s (name=%s, updated=%s, type=%s, state=%s) \n",
ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "id_object"),
ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "name"),
ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "date_update"),
ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "id_type_definition"),
ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "num_state")
);
ObjFreeObjectHdl(rSearchResults.object_handle[iIndex]);
}
}
bReturnValue = true;
}
}
return bReturnValue;
}
int ObjSearchObject2(ObjSearchObjectParm *, ObjObjectResults *);
char * ObjGetObjectAttr(ObjApiObjectHdl objectHdl, char *attr_name);
char * ObjGetErrorMsg();
void ObjFreeObjectHdl(ObjApiObjectHdl objectHdl);
typedef struct _ObjSearchObjectParm {
int obj_defn_count; // mandatory
char **obj_defn_ids; // mandatory
char *text_server_alias; // optional.
char *query_string; // optional text search string
ObjApiBoolean include_deleted; // defaults to OBJAPI_FALSE
int max_results; // default = 200
int num_conditions; // mandatory
ObjSearchCondition *search_cond; // mandatory
ObjApiBoolean include_content; // mandatory for COMPLEX searches, translated to Y/N in API
ObjApiBoolean include_metadata; // mandatory for COMPLEX searches, translated to Y/N in API
} ObjSearchObjectParm;
enum ObjApiSearchOp
{
OBJAPI_MATCH_ALL=1,
OBJAPI_MATCH_ANY=2
};
enum ObjApiBoolean
{
OBJAPI_FALSE,
OBJAPI_TRUE
};
typedef struct _ObjSearchCondition {
ObjApiSearchOp boolop; // only for complex searches
char *join_relation; // only for complex searches
int num_opening_brackets; // only for complex searches
int num_closing_brackets; // only for complex searches
char *field;
char *op;
char *value;
} ObjSearchCondition;
typedef void* ObjApiObjectHdl;
typedef struct _ObjObjectResults {
ObjApiObjectHdl *object_handle;
int num_results;
} ObjObjectResults;
My take on this is as follows, (UPDATE: Code updated)
public class ObjectiveNativeAPI
{
private const string dllPath = #"objapi.dll";
public enum ObjApiBoolean
{
OBJAPI_FALSE,
OBJAPI_TRUE
};
public enum ObjApiSearchOp
{
OBJAPI_MATCH_ALL = 1,
OBJAPI_MATCH_ANY = 2
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ObjSearchObjectParm
{
public int obj_defn_count;
public string[] obj_defn_ids;
public string text_server_alias;
public string query_string;
public ObjApiBoolean include_deleted;
public int max_results;
public int num_conditions;
public IntPtr search_cond;
public ObjApiBoolean include_content;
public ObjApiBoolean include_metadata;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ObjSearchCondition
{
public ObjApiSearchOp boolop;
public string join_relation;
public int num_opening_brackets;
public int num_closing_brackets;
public string field;
public string op;
public string value;
}
[StructLayout(LayoutKind.Sequential)]
public struct ObjObjectResults
{
public IntPtr object_handle;
public int num_results;
}
[DllImport(dllPath, EntryPoint = "ObjSearchObject2")]
public static extern int ObjSearchObject2(ref ObjSearchObjectParm objSearchObjectParm, ref ObjObjectResults objObjectResults);
[DllImport(dllPath, EntryPoint = "ObjGetObjectAttr")]
public static extern string ObjGetObjectAttr(IntPtr object_handle, string attr_name);
[DllImport(dllPath, EntryPoint = "ObjFreeObjectHdl")]
public static extern void ObjFreeObjectHdl(IntPtr object_handle);
}
public void Run()
{
ObjectiveNativeAPI.ObjSearchObjectParm rSearchObject = new ObjectiveNativeAPI.ObjSearchObjectParm();
ObjectiveNativeAPI.ObjSearchCondition rSearchCondition = new ObjectiveNativeAPI.ObjSearchCondition();
ObjectiveNativeAPI.ObjObjectResults rSearchResults = new ObjectiveNativeAPI.ObjObjectResults();
rSearchCondition.field = "ancestor";
rSearchCondition.op = "is";
rSearchCondition.value = txtCotainerId.Text;
rSearchObject.obj_defn_ids = new[] {"dotdA9"};
rSearchObject.obj_defn_count = 1;
rSearchObject.num_conditions = 1;
rSearchObject.max_results = 5000;
IntPtr search_cond = Marshal.AllocCoTaskMem(Marshal.SizeOf(rSearchCondition));
Marshal.StructureToPtr(rSearchCondition, search_cond, false);
rSearchObject.search_cond = search_cond;
int result = ObjectiveNativeAPI.ObjSearchObject2(ref rSearchObject, ref rSearchResults);
MessageBox.Show(string.Format("FunctionResult: {0}", result));
Marshal.FreeCoTaskMem(search_cond);
}
I am a bit lost on this. I have managed to translate some other segments of this project but this is causing me grief. Any help around this would be appreciated.

Related

How to p/invoke getpwnam() from libc in C#?

Let's start with documentation:
https://man7.org/linux/man-pages/man3/getpwnam.3.html
Having this, I made a following C# code:
using System;
using System.Runtime.InteropServices;
if (args.Length < 1) {
Console.Error.WriteLine("Provide user name.");
Environment.Exit(-1);
}
var name = args[0];
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
Syscall.getpwnam(name, out var passwd);
Console.WriteLine($"User = {name}, UID = {passwd.Uid}, GID = {passwd.Gid}");
passwd = GetPasswd(name);
Console.WriteLine($"User = {name}, UID = {passwd.Uid}, GID = {passwd.Gid}");
}
else {
Console.WriteLine("It supposed to be run on Linux.");
}
static Passwd GetPasswd(string name) {
var bufsize = 16384;
var buf = new byte[bufsize];
var passwd = new Passwd();
Syscall.getpwnam_r(name, passwd, buf, (uint)bufsize, out var result);
return result;
}
public struct Passwd {
public string Name;
public string Password;
public uint Uid;
public uint Gid;
public string Gecos;
public string Directory;
public string Shell;
}
static class Syscall {
[DllImport("libc", SetLastError = true)]
public static extern void getpwnam(string name, out Passwd passwd);
[DllImport("libc", SetLastError = true)]
public static extern void getpwnam_r(string name, Passwd passwd, byte[] buf, uint bufsize, out Passwd result);
}
It doesn't work.
Here's what I get:
User = service, UID = 0, GID = 0
Segmentation fault (core dumped)
What am I doing wrong?
How should I call it to get the actual structure? I'm not interested in returned strings. All I care of are Uid and Gid values.
As linked documentation mentions - this function accepts one parameter - name, and returns pointer to structure with data. So signature should be:
[DllImport("libc", SetLastError = true)]
public static extern IntPtr getpwnam(string name);
And then:
// we have pointer here
var passwdPtr = Syscall.getpwnam(name);
// don't forget to check if pointer is not IntPtr.Zero.
// interpret data at pointer as structure
var passwd = Marshal.PtrToStructure<Passwd>(passwdPtr);
Console.WriteLine($"User = {passwd.Name}, UID = {passwd.Uid}, GID = {passwd.Gid}");

P/invoking the NtQueryVolumeInformationFile function returns 0xC0000003 error

The C# import code:
[DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true)]
public static extern long NtQueryVolumeInformationFile(IntPtr FileHandle, out IO_STATUS_BLOCK IoStatusBlock, IntPtr FsInformation, uint Length, FSINFOCLASS FsInformationClass);
The FSINFOCLASS enum:
public enum FSINFOCLASS
{
FileFsVolumeInformation,
FileFsLabelInformation,
FileFsSizeInformation,
FileFsDeviceInformation,
FileFsAttributeInformation,
FileFsControlInformation,
FileFsFullSizeInformation,
FileFsObjectIdInformation,
FileFsDriverPathInformation,
FileFsVolumeFlagsInformation,
FileFsSectorSizeInformation,
FileFsDataCopyInformation,
FileFsMetadataSizeInformation,
FileFsFullSizeInformationEx,
FileFsMaximumInformation
}
The way it is called:
var handlePtr = Win32.CreateFile(#"\\.\c:", Win32.GENERIC_READ, Win32.FILE_SHARE_READ | Win32.FILE_SHARE_WRITE | Win32.FILE_SHARE_DELETE, 0, Win32.OPEN_EXISTING, 0, 0);
if (handlePtr == IntPtr.Zero - 1)
return 0;
var iosb = new Win32.IO_STATUS_BLOCK();
var buffer = Marshal.AllocHGlobal(273);
var result = Win32.NtQueryVolumeInformationFile(handlePtr, out iosb, buffer, 273,
Win32.FSINFOCLASS.FileFsVolumeInformation);
// result=0xC0000003 , should be zero
The code runs with the administrative privilege.
The error code's description is: STATUS_INVALID_INFO_CLASS
But as far as I can tell, the info class enum is correct.
What am I missing?
Thanks to Jimi's comment, I assigned the value 1 to the enum member FileFsVolumeInformation and that fixed that error.
However it needed more fixes to fully work. The complete working code for the interop imports follows:
[DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true)]
public static extern long NtQueryVolumeInformationFile(IntPtr FileHandle, out IO_STATUS_BLOCK IoStatusBlock, IntPtr FsInformation,
uint Length, FSINFOCLASS FsInformationClass);
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct FILE_FS_VOLUME_INFORMATION
{
public long VolumeCreationTime;
public uint VolumeSerialNumber;
public uint VolumeLabelLength;
public bool SupportsObjects;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string VolumeLabel;
}
public enum FSINFOCLASS
{
FileFsVolumeInformation = 1,
FileFsLabelInformation,
FileFsSizeInformation,
FileFsDeviceInformation,
FileFsAttributeInformation,
FileFsControlInformation,
FileFsFullSizeInformation,
FileFsObjectIdInformation,
FileFsDriverPathInformation,
FileFsVolumeFlagsInformation,
FileFsSectorSizeInformation,
FileFsDataCopyInformation,
FileFsMetadataSizeInformation,
FileFsFullSizeInformationEx,
FileFsMaximumInformation
}
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct IO_STATUS_BLOCK
{
public uint status;
public IntPtr information;
}
public uint GetVolumeSerialNumber(string volumePath)
{
var handlePtr = Win32.CreateFile($#"\\.\{volumePath.TrimEnd('\\')}", Win32.GENERIC_READ, Win32.FILE_SHARE_READ | Win32.FILE_SHARE_WRITE | Win32.FILE_SHARE_DELETE,
0, Win32.OPEN_EXISTING, 0, 0);
if (handlePtr == IntPtr.Zero - 1)
return 0;
var iosb = new Win32.IO_STATUS_BLOCK();
var fsInfo = new Win32.FILE_FS_VOLUME_INFORMATION();
var bufferSize = Marshal.SizeOf(fsInfo) + 32; //32 =maximum ntfs volume label length
var buffer = Marshal.AllocHGlobal(bufferSize);
var result = Win32.NtQueryVolumeInformationFile(handlePtr, out iosb, buffer, (uint)bufferSize,
Win32.FSINFOCLASS.FileFsVolumeInformation);
if (result != 0)
{
Marshal.FreeHGlobal(buffer);
Win32.CloseHandle(handlePtr);
return 0;
}
fsInfo = Marshal.PtrToStructure<Win32.FILE_FS_VOLUME_INFORMATION>(buffer);
Marshal.FreeHGlobal(buffer);
return fsInfo.VolumeSerialNumber;
}

Marshalling C++ char[] members results in empty string

Im attempting to marshal a C++ struct containing char[] arrays to C# but on the unmanaged side I see the char arrays as empty and not sure what I'm missing
C# structure
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1), Serializable]
public struct MParams
{
public int action;
public int response;
public long serial_no;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 251)]
public string address; // public char[] address;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 81)]
public string description; // public char[] description;
}
C++ Structure
typedef struct
{
int action;
int response;
LONG serial_no;
char address[251];
char description[81];
}PARAMS;
C++ Exported function
__declspec(dllexport) (int) test_Email(void *params)
{
PARAMS *l_params = (PARAMS *)params;
// params->address // always empty expected abc#abc.com
}
C# Usage
[DllImport(#"test.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint ="?test_Email##YAHPAX#Z")]
public static extern int EMailExists(IntPtr valParams);
MParams mParams = new MParams {
action = 3,
serial_no = 0,
address = abc#abc.com,
description = string.Empty
};
IntPtr pAddr = Marshal.AllocHGlobal(Marshal.SizeOf(mParams));
Marshal.StructureToPtr(mParams, pAddr, false);
EMailExists(pAddr);
mParams = (MParams)Marshal.PtrToStructure(pAddr, typeof(MParams));
I've attempted using char[] to marshall but that too did not help. I reckon I'm missing on something very obvious and help to understand where I'm wrong is much appreciated.

Programmatically add route

I write a simple utility that adds a route for specific interface. Code is very simple:
using System;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Text;
class Program
{
static void Main(string[] args)
{
const string firstConnection = "xxxx.yyyyy";
const string routeAddMask = "route add XX.XX.XX.XX mask 255.255.255.255 XXX.XXX.XXX.XXX METRIC 99 IF {0}";
StartProcess("rasdial", firstConnection);
var interfaceId = GetInterfaceId(firstConnection);
string routeAdd = string.Format(routeAddMask, interfaceId);
StartProcess("route", routeAdd);
}
private static int GetInterfaceId(string name)
{
NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
var adapter = Array.Find(adapters, ni => ni.Name == name);
var props = adapter.GetIPProperties().GetIPv4Properties();
return props.Index;
}
private static void StartProcess(string name, string args)
{
var process = new Process
{
StartInfo = new ProcessStartInfo(name, args)
{
UseShellExecute = false,
RedirectStandardOutput = true,
StandardOutputEncoding = Encoding.ASCII
}
};
process.Start();
while (!process.HasExited)
{
Console.WriteLine(process.StandardOutput.ReadToEnd());
}
process.WaitForExit();
Console.WriteLine("Process {0} finished, exit code = {1}", name, process.ExitCode);
}
}
rasdial works fine and I get interface number, but when I'm running route I get an error:
Invalid MASK generates an error, that is when (DEST & MASK) != DEST.
I think problem is that process start args are not passed because I get the same error while sending null instead of routeAdd parameter meanwhile this command works fine when i'm prompting it in cmd.
Executable is running as Administrator.
I'm trying to create it with winapi, but it fails too
const string firstConnection = "someconnect";
StartProcess("rasdial", firstConnection);
var interfaceIndex = GetInterfaceIndex(firstConnection); //Everything is fine
var route = new MIB_IPFORWARDROW
{
dwForwardDest = BitConverter.ToUInt32(IPAddress.Parse("XX.XX.XX.XX").GetAddressBytes(), 0),
dwForwardMask = BitConverter.ToUInt32(IPAddress.Parse("255.255.255.255").GetAddressBytes(), 0),
dwForwardNextHop = BitConverter.ToUInt32(IPAddress.Parse("XXX.XXX.XXX.XXX").GetAddressBytes(), 0),
dwForwardMetric1 = 99,
dwForwardIfIndex = interfaceIndex
};
var ipForwardEntry = RouteInterop.CreateIpForwardEntry(ref route);
Console.WriteLine(ipForwardEntry);
returns ERROR_INVALID_PARAMETER
I know that question is not very complex, but I didn't encounter any explanation in the internet, this is why I think this answer would be helpful and this is why I'm writing it instead of deleting my initial question.
You just should specify more parameters to make it work
var route = new MIB_IPFORWARDROW
{
dwForwardDest = BitConverter.ToUInt32(IPAddress.Parse("XX.XX.XX.XX").GetAddressBytes(), 0),
dwForwardMask = BitConverter.ToUInt32(IPAddress.Parse("255.255.255.255").GetAddressBytes(), 0),
dwForwardNextHop = BitConverter.ToUInt32(IPAddress.Parse("XXX.XXX.XXX.XXX").GetAddressBytes(), 0),
dwForwardMetric1 = 99,
dwForwardType = ForwardType.Indirect,
dwForwardProto = ForwardProtocol.NetMGMT,
dwForwardAge = 0,
dwForwardIfIndex = interfaceIndex
};
var ipForwardEntry = RouteInterop.CreateIpForwardEntry(ref route);
Elaborating on Alex Zhukovskiy answer as I've combined his answer with a bunch of MSDN articles. The code below uses the Win32 API's, specifically the "iphlpapi.h" module, the comprehensive documentation can be found in this link on managing routing. The PMIB_IPFORWARDTABLE structure and enums are documented here.
The primary methods for mimicking the "route print", "route add", and "route delete" command are
GetIpForwardTable - Gets the network routing table, "route PRINT"
CreateIpForwardEntry - Add Route, like "route ADD"
DeleteIpFowardEntry - Delete Route, like "route DELETE"
SetIpForwardEntry - Modify existing route, like "route CHANGE"
The comprehensive code using C# can be found in this github repository (Ip4RouteTable) - https://github.com/CodeCowboyOrg/Ip4RouteTable
Setting up the Win32 API Calls in C#
internal static class NativeMethods
{
[DllImport("iphlpapi", CharSet = CharSet.Auto)]
public extern static int GetIpForwardTable(IntPtr /*PMIB_IPFORWARDTABLE*/ pIpForwardTable, ref int /*PULONG*/ pdwSize, bool bOrder);
[DllImport("iphlpapi", CharSet = CharSet.Auto)]
//public extern static int CreateIpForwardEntry(ref /*PMIB_IPFORWARDROW*/ Ip4RouteTable.PMIB_IPFORWARDROW pRoute); Can do by reference or by Pointer
public extern static int CreateIpForwardEntry(IntPtr /*PMIB_IPFORWARDROW*/ pRoute);
[DllImport("iphlpapi", CharSet = CharSet.Auto)]
public extern static int DeleteIpForwardEntry(IntPtr /*PMIB_IPFORWARDROW*/ pRoute);
}
public class Ip4RouteTable
{
[ComVisible(false), StructLayout(LayoutKind.Sequential)]
internal struct IPForwardTable
{
public uint Size;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public PMIB_IPFORWARDROW[] Table;
};
[ComVisible(false), StructLayout(LayoutKind.Sequential)]
internal struct PMIB_IPFORWARDROW
{
internal uint /*DWORD*/ dwForwardDest;
internal uint /*DWORD*/ dwForwardMask;
internal uint /*DWORD*/ dwForwardPolicy;
internal uint /*DWORD*/ dwForwardNextHop;
internal uint /*DWORD*/ dwForwardIfIndex;
internal uint /*DWORD*/ dwForwardType;
internal uint /*DWORD*/ dwForwardProto;
internal uint /*DWORD*/ dwForwardAge;
internal uint /*DWORD*/ dwForwardNextHopAS;
internal uint /*DWORD*/ dwForwardMetric1;
internal uint /*DWORD*/ dwForwardMetric2;
internal uint /*DWORD*/ dwForwardMetric3;
internal uint /*DWORD*/ dwForwardMetric4;
internal uint /*DWORD*/ dwForwardMetric5;
};
static IPForwardTable ReadIPForwardTable(IntPtr tablePtr)
{
var result = (IPForwardTable)Marshal.PtrToStructure(tablePtr, typeof(IPForwardTable));
PMIB_IPFORWARDROW[] table = new PMIB_IPFORWARDROW[result.Size];
IntPtr p = new IntPtr(tablePtr.ToInt64() + Marshal.SizeOf(result.Size));
for (int i = 0; i < result.Size; ++i)
{
table[i] = (PMIB_IPFORWARDROW)Marshal.PtrToStructure(p, typeof(PMIB_IPFORWARDROW));
p = new IntPtr(p.ToInt64() + Marshal.SizeOf(typeof(PMIB_IPFORWARDROW)));
}
result.Table = table;
return result;
}
public static void RoutePrint(bool testing)
{
var fwdTable = IntPtr.Zero;
int size = 0;
var result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);
fwdTable = Marshal.AllocHGlobal(size);
result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);
var forwardTable = ReadIPForwardTable(fwdTable);
Marshal.FreeHGlobal(fwdTable);
Console.Write("\tNumber of entries: {0}\n", forwardTable.Size);
for (int i = 0; i < forwardTable.Table.Length; ++i)
{
Console.Write("\n\tRoute[{0}] Dest IP: {1}\n", i, new IPAddress((long)forwardTable.Table[i].dwForwardDest).ToString());
Console.Write("\tRoute[{0}] Subnet Mask: {1}\n", i, new IPAddress((long)forwardTable.Table[i].dwForwardMask).ToString());
Console.Write("\tRoute[{0}] Next Hop: {1}\n", i, new IPAddress((long)forwardTable.Table[i].dwForwardNextHop).ToString());
Console.Write("\tRoute[{0}] If Index: {1}\n", i, forwardTable.Table[i].dwForwardIfIndex);
Console.Write("\tRoute[{0}] Type: {1}\n", i, forwardTable.Table[i].dwForwardType);
Console.Write("\tRoute[{0}] Proto: {1}\n", i, forwardTable.Table[i].dwForwardProto);
Console.Write("\tRoute[{0}] Age: {1}\n", i, forwardTable.Table[i].dwForwardAge);
Console.Write("\tRoute[{0}] Metric1: {1}\n", i, forwardTable.Table[i].dwForwardMetric1);
}
}
public static void RoutePrint()
{
List<Ip4RouteEntry> routeTable = GetRouteTable();
RoutePrint(routeTable);
}
public static void RoutePrint(List<Ip4RouteEntry> routeTable)
{
Console.WriteLine("Route Count: {0}", routeTable.Count);
Console.WriteLine("{0,18} {1,18} {2,18} {3,5} {4,8} ", "DestinationIP", "NetMask", "Gateway", "IF", "Metric");
foreach (Ip4RouteEntry entry in routeTable)
{
Console.WriteLine("{0,18} {1,18} {2,18} {3,5} {4,8} ", entry.DestinationIP, entry.SubnetMask, entry.GatewayIP, entry.InterfaceIndex, entry.Metric);
}
}
public static List<Ip4RouteEntry> GetRouteTable()
{
var fwdTable = IntPtr.Zero;
int size = 0;
var result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);
fwdTable = Marshal.AllocHGlobal(size);
result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);
var forwardTable = ReadIPForwardTable(fwdTable);
Marshal.FreeHGlobal(fwdTable);
List<Ip4RouteEntry> routeTable = new List<Ip4RouteEntry>();
for (int i = 0; i < forwardTable.Table.Length; ++i)
{
Ip4RouteEntry entry = new Ip4RouteEntry();
entry.DestinationIP = new IPAddress((long)forwardTable.Table[i].dwForwardDest);
entry.SubnetMask = new IPAddress((long)forwardTable.Table[i].dwForwardMask);
entry.GatewayIP = new IPAddress((long)forwardTable.Table[i].dwForwardNextHop);
entry.InterfaceIndex = Convert.ToInt32(forwardTable.Table[i].dwForwardIfIndex);
entry.ForwardType = Convert.ToInt32(forwardTable.Table[i].dwForwardType);
entry.ForwardProtocol = Convert.ToInt32(forwardTable.Table[i].dwForwardProto);
entry.ForwardAge = Convert.ToInt32(forwardTable.Table[i].dwForwardAge);
entry.Metric = Convert.ToInt32(forwardTable.Table[i].dwForwardMetric1);
routeTable.Add(entry);
}
return routeTable;
}
The C# wrapper functions
public class Ip4RouteEntry
{
public IPAddress DestinationIP { get; set; }
public IPAddress SubnetMask { get; set; }
public IPAddress GatewayIP { get; set; }
public int InterfaceIndex { get; set; }
public int ForwardType { get; set; }
public int ForwardProtocol { get; set; }
public int ForwardAge { get; set; }
public int Metric { get; set; }
}
public static void RoutePrint()
{
List<Ip4RouteEntry> routeTable = GetRouteTable();
RoutePrint(routeTable);
}
public static void RoutePrint(List<Ip4RouteEntry> routeTable)
{
Console.WriteLine("Route Count: {0}", routeTable.Count);
Console.WriteLine("{0,18} {1,18} {2,18} {3,5} {4,8} ", "DestinationIP", "NetMask", "Gateway", "IF", "Metric");
foreach (Ip4RouteEntry entry in routeTable)
{
Console.WriteLine("{0,18} {1,18} {2,18} {3,5} {4,8} ", entry.DestinationIP, entry.SubnetMask, entry.GatewayIP, entry.InterfaceIndex, entry.Metric);
}
}
public static List<Ip4RouteEntry> GetRouteTable()
{
var fwdTable = IntPtr.Zero;
int size = 0;
var result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);
fwdTable = Marshal.AllocHGlobal(size);
result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);
var forwardTable = ReadIPForwardTable(fwdTable);
Marshal.FreeHGlobal(fwdTable);
List<Ip4RouteEntry> routeTable = new List<Ip4RouteEntry>();
for (int i = 0; i < forwardTable.Table.Length; ++i)
{
Ip4RouteEntry entry = new Ip4RouteEntry();
entry.DestinationIP = new IPAddress((long)forwardTable.Table[i].dwForwardDest);
entry.SubnetMask = new IPAddress((long)forwardTable.Table[i].dwForwardMask);
entry.GatewayIP = new IPAddress((long)forwardTable.Table[i].dwForwardNextHop);
entry.InterfaceIndex = Convert.ToInt32(forwardTable.Table[i].dwForwardIfIndex);
entry.ForwardType = Convert.ToInt32(forwardTable.Table[i].dwForwardType);
entry.ForwardProtocol = Convert.ToInt32(forwardTable.Table[i].dwForwardProto);
entry.ForwardAge = Convert.ToInt32(forwardTable.Table[i].dwForwardAge);
entry.Metric = Convert.ToInt32(forwardTable.Table[i].dwForwardMetric1);
routeTable.Add(entry);
}
return routeTable;
}
public static bool RouteExists(string destinationIP)
{
List<Ip4RouteEntry> routeTable = Ip4RouteTable.GetRouteTable();
Ip4RouteEntry routeEntry = routeTable.Find(i => i.DestinationIP.ToString().Equals(destinationIP));
return (routeEntry != null);
}
public static List<Ip4RouteEntry> GetRouteEntry(string destinationIP)
{
List<Ip4RouteEntry> routeTable = Ip4RouteTable.GetRouteTable();
List<Ip4RouteEntry> routeMatches = routeTable.FindAll(i => i.DestinationIP.ToString().Equals(destinationIP));
return routeMatches;
}
public static List<Ip4RouteEntry> GetRouteEntry(string destinationIP, string mask)
{
List<Ip4RouteEntry> routeTable = Ip4RouteTable.GetRouteTable();
List<Ip4RouteEntry> routeMatches = routeTable.FindAll(i => i.DestinationIP.ToString().Equals(destinationIP) && i.SubnetMask.ToString().Equals(mask));
return routeMatches;
}
public static void CreateRoute(Ip4RouteEntry routeEntry)
{
var route = new PMIB_IPFORWARDROW
{
dwForwardDest = BitConverter.ToUInt32(IPAddress.Parse(routeEntry.DestinationIP.ToString()).GetAddressBytes(), 0),
dwForwardMask = BitConverter.ToUInt32(IPAddress.Parse(routeEntry.SubnetMask.ToString()).GetAddressBytes(), 0),
dwForwardNextHop = BitConverter.ToUInt32(IPAddress.Parse(routeEntry.GatewayIP.ToString()).GetAddressBytes(), 0),
dwForwardMetric1 = 99,
dwForwardType = Convert.ToUInt32(3), //Default to 3
dwForwardProto = Convert.ToUInt32(3), //Default to 3
dwForwardAge = 0,
dwForwardIfIndex = Convert.ToUInt32(routeEntry.InterfaceIndex)
};
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PMIB_IPFORWARDROW)));
try
{
Marshal.StructureToPtr(route, ptr, false);
var status = NativeMethods.CreateIpForwardEntry(ptr);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
public static void CreateRoute(string destination, string mask, int interfaceIndex, int metric)
{
NetworkAdaptor adaptor = NicInterface.GetNetworkAdaptor(interfaceIndex);
var route = new PMIB_IPFORWARDROW
{
dwForwardDest = BitConverter.ToUInt32(IPAddress.Parse(destination).GetAddressBytes(), 0),
dwForwardMask = BitConverter.ToUInt32(IPAddress.Parse(mask).GetAddressBytes(), 0),
dwForwardNextHop = BitConverter.ToUInt32(IPAddress.Parse(adaptor.PrimaryGateway.ToString()).GetAddressBytes(), 0),
dwForwardMetric1 = Convert.ToUInt32(metric),
dwForwardType = Convert.ToUInt32(3), //Default to 3
dwForwardProto = Convert.ToUInt32(3), //Default to 3
dwForwardAge = 0,
dwForwardIfIndex = Convert.ToUInt32(interfaceIndex)
};
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PMIB_IPFORWARDROW)));
try
{
Marshal.StructureToPtr(route, ptr, false);
var status = NativeMethods.CreateIpForwardEntry(ptr);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
public static void DeleteRoute(Ip4RouteEntry routeEntry)
{
var route = new PMIB_IPFORWARDROW
{
dwForwardDest = BitConverter.ToUInt32(IPAddress.Parse(routeEntry.DestinationIP.ToString()).GetAddressBytes(), 0),
dwForwardMask = BitConverter.ToUInt32(IPAddress.Parse(routeEntry.SubnetMask.ToString()).GetAddressBytes(), 0),
dwForwardNextHop = BitConverter.ToUInt32(IPAddress.Parse(routeEntry.GatewayIP.ToString()).GetAddressBytes(), 0),
dwForwardMetric1 = 99,
dwForwardType = Convert.ToUInt32(3), //Default to 3
dwForwardProto = Convert.ToUInt32(3), //Default to 3
dwForwardAge = 0,
dwForwardIfIndex = Convert.ToUInt32(routeEntry.InterfaceIndex)
};
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PMIB_IPFORWARDROW)));
try
{
Marshal.StructureToPtr(route, ptr, false);
var status = NativeMethods.DeleteIpForwardEntry(ptr);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
public static void DeleteRoute(string destinationIP)
{
List<Ip4RouteEntry> routeMatches = Ip4RouteTable.GetRouteEntry(destinationIP);
if (routeMatches == null) return;
foreach (Ip4RouteEntry routeEntry in routeMatches)
{
DeleteRoute(routeEntry);
}
}
public static void DeleteRoute(string destinationIP, string mask)
{
List<Ip4RouteEntry> routeMatches = Ip4RouteTable.GetRouteEntry(destinationIP, mask);
if (routeMatches == null) return;
foreach (Ip4RouteEntry routeEntry in routeMatches)
{
DeleteRoute(routeEntry);
}
}
public static void DeleteRoute(int interfaceIndex)
{
var fwdTable = IntPtr.Zero;
int size = 0;
var result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);
fwdTable = Marshal.AllocHGlobal(size);
result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);
var forwardTable = ReadIPForwardTable(fwdTable);
Marshal.FreeHGlobal(fwdTable);
List<PMIB_IPFORWARDROW> filtered = new List<PMIB_IPFORWARDROW>();
for (int i = 0; i < forwardTable.Table.Length; ++i)
{
if (Convert.ToInt32(forwardTable.Table[i].dwForwardIfIndex).Equals(interfaceIndex))
{
filtered.Add(forwardTable.Table[i]);
}
}
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PMIB_IPFORWARDROW)));
try
{
foreach (PMIB_IPFORWARDROW routeEntry in filtered)
{
Marshal.StructureToPtr(routeEntry, ptr, false);
var status = NativeMethods.DeleteIpForwardEntry(ptr);
}
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}

Trouble with marshal c# class to c++ structure

i have C++ structure
struct DressKey
{
int keyId;
GENDER gender;
DRESS_CLASS dressClass;
unsigned int descriptor[KEY_SIZE];
float confidence;
short keyLength;
short metric;
DressKey():
keyId(0),
gender(GENDER_UNDEFINED),
dressClass(CLASS_UNDEFINED),
confidence(0.0f),
keyLength(KEY_SIZE),
metric(0)
{
descriptor[0] = 0;
}
};
Type of GENDER and DRESS_CLASS is enum
And i try pass it in method:
virtual ERROR_CODE ExtractDressKey(
const unsigned char *frame,
int width,
int height,
int lineLength,
int format,
DressKey *dressKey);
I have wrap this method and structure in c# at this way:
[DllImport("DSE.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?ExtractDressKey#DSE#dse##UEAA?AW4ERROR_CODE#2#PEBEHHHHPEAUDressKey#2##Z")]
private static extern ERROR_CODE ExtractDressKey(IntPtr self, IntPtr frame, int width, int height, int lineLength, int format, ref DressKey dressKey);
[StructLayout(LayoutKind.Sequential)]
public class DressKey
{
public const int KEY_SIZE = 5768;
public int keyId; //!< serialization key id
public GENDER gender; //!< gender
public DRESS_CLASS dressClass; //!< dress category
[MarshalAs(UnmanagedType.ByValArray, SizeConst = KEY_SIZE)]
public uint[] descriptor = new uint[KEY_SIZE]; //!< comparable part
public double confidence; //!< key confidence
public short keyLength; //!< actual numer of elements in descriptor
public short metric; //!< ID of a metric revision
}
I got AccessViolationException. What is wrong in my wrapper?
UPD:
usage:
var imgPath = #"C:\1.jpg";
using (var dse = new DSE())
{
using (var img = CV.LoadImageM(imgPath, LoadImageFlags.AnyColor))
{
var subImg = img;
using (subImg)
{
var dk = new DressKey();
var type = subImg.Channels == 1 ? 0 : 1;
var res = dse.ExtractDressKey(subImg.Data, subImg.Cols, subImg.Rows, subImg.Cols, type, ref dk);
if (res == ERROR_CODE.ERROR_OK)
Console.WriteLine("id={0}&key={1}", 123, JsonConvert.SerializeObject(dk));
else
{
Console.WriteLine( res.ToString());
}
}
}
}
You cannot expect to p/invoke C++ instance methods. P/invoke is used to call non-member functions. You need to do one of the following:
Wrap the C++ library in a mixed mode C++/CLI assembly, and have the C# code consume it as a managed reference.
Expose the C++ library using COM.
Wrap the C++ library in a C style procedural interface and access that using p/invoke.

Categories

Resources