Type conversion issue in C# - c#

I'm trying something (originally comes from here) about Heap and Pointer on C# Console project. And my program looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
public class Win32
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr malloc(int size);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int free(IntPtr region); //Change IntPtr befroe free method to int ---update---
}
public class Program
{
public unsafe void Heap()
{
int* num1, num2, answer;
num1 = Win32.malloc(sizeof(int));
*num1 = 999; // 999 should be the value stored at where pointer num1 refers to
num2 = Win32.malloc(sizeof(int));
*num2 = 1; // 1 should be the value stored at where pointer num2 refers to
answer = Win32.malloc(sizeof(int));
*answer = *num1 + *num2; // 1000 should be the value of pointer answer's reference
Console.WriteLine(*answer); // 1000?
Win32.free(num1);
Win32.free(num2);
Win32.free(answer);
}
}
After debugging, got error message says:
Error 1 Cannot implicitly convert type 'System.IntPtr' to 'int*'. An
explicit conversion exists (are you missing a cast?)
error CS1502: The best overloaded method match for 'Win32.free(System.IntPtr)' has some invalid arguments
error CS1503: Argument 1: cannot convert from 'int*' to 'System.IntPtr'
My questions here are why can't i use IntPtr before malloc and free, since both method return void? What changes should i make on my codes?
Thank you for help.
---Update---
change: public static extern IntPtr free(int hWnd); to public static extern int free(IntPtr region); , free(*num) to free(num)
gives extra 'CS1502' and 'CS1503' two errors.
---second Update---
C# deal heap thing automatically. There is no equivalent of malloc in C#. It's a dead end. T_T

A few mistakes:
in C/C++
void * malloc(int sizeToAllocate);
int free(void * region);
you pass into free the value returned by malloc. Thus your imports should be:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr malloc(int size);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int free(IntPtr region);
and consequently your freeing code should then become:
var num1Ptr = Win32.malloc(sizeof(int));
int * num1 = (int*) num1Ptr.ToPointer();
...
var num2Ptr = Win32.malloc(sizeof(int));
int * num2 = (int*) num2Ptr.ToPointer();
...
var answerPtr = Win32.malloc(sizeof(int));
int * answer = (int*) answerPtr.ToPointer();
...
Win32.free(num1Ptr);
Win32.free(num2Ptr);
Win32.free(answerPtr);

Related

Unable to get result of std::string function in C++ to C# Interop

What I am trying to achieve: I am trying to access a C++ application's functions through its DLL in a C# (Interop).
Issue which I am facing right now: When i create a std::string return type function in C++ and calls it through its DLL in C# code there is now output at all.
Code which I have written for C++ APP
extern "C"
{
__declspec(dllexport) int SM_Interop_API_Add(int a, int b)
{
return a + b;
}
__declspec(dllexport) std::string SM_Interop_API_getLanguage()
{
return "This is Test String";
//return getLanguage();
}
}
Code which I have written for C# APP
class Program
{
[DllImport(#"CPPSample.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi,EntryPoint = "SM_Interop_API_Add")]
public static extern int SM_Interop_API_Add(int a, int b);
[DllImport(#"CPPSample.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "SM_Interop_API_getLanguage")]
public static extern string SM_Interop_API_getLanguage();
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
int sum = SM_Interop_API_Add(10, 10);
Console.WriteLine($"Result: {sum}");
string result = SM_Interop_API_getLanguage();
Console.WriteLine($"Sm Language: {result}");
Console.WriteLine("----EOP----");
}
}
In the above code for C++, SM_Interop_API_getLanguage is supposed to return a string, and when I calls it through its DLL in C# code it does not return any result at all, first, I tried by returning the actual output of getLanguage which did not work then I tried to return some hard codded string but that is also coming as output.
Also to mention the function with int return type works perfectly only std::string return type is not working here in my case.
Kindly guide me if I am doing anything wrong or missing anything. Any help is appreciated.
std::string will never work here as the marshaller does not know how to free it.
Instead, you need to pass in a buffer from the C# side, like this
class Program
{
[DllImport(#"CPPSample.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi,EntryPoint = "SM_Interop_API_Add")]
public static extern int SM_Interop_API_Add(int a, int b);
[DllImport(#"CPPSample.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "SM_Interop_API_getLanguage")]
public static extern void SM_Interop_API_getLanguage(StringBuilder buffer)
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
int sum = SM_Interop_API_Add(10, 10);
Console.WriteLine($"Result: {sum}");
var result = new StringBuilder(200);
SM_Interop_API_getLanguage(result);
Console.WriteLine($"Sm Language: {result}");
Console.WriteLine("----EOP----");
}
}
Then on the C++ side, you simply copy it in (not great with C++, guessing a bit)
__declspec(dllexport) void SM_Interop_API_getLanguage(char* buffer)
{
strcpy(buffer, "This is Test String");
//return getLanguage();
}
Passing a buffer size and checking that it's large enough would be wise also.

C# interop returning System.Access.Violation

I am attempting to use a C function through C# Interop and I am receiving an access violation on one function. I have tried a number of things and I can't seem to solve this.
Here is the C code that needs to be changed into c# code:
typedef struct
{
char SerNo[64];
unsigned char hwVer;
HANDLE device; // Set by the API on return from SelectDevice()
} DeviceT;
This struct is used by the following function:
error = GetDevices(DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs)
There is one other function in the C code:
error = SelectDevice(DeviceT *device)
So I began by defining DeviceT. I tried a few ways, but settled on this since it is simple:
[StructLayout(LayoutKind.Sequential)]
public struct DeviceT
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public char[] SerNo;
public byte hwVer;
public IntPtr device;
}
The GetDevices function was set to this:
[DllImport("file.dll", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern ErrT GetDevices([In, Out] DeviceT[] devices, uint* numDevs, uint maxDev);
The SelectDevices function was set to this:
[DllImport("file.dll", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern ErrT SelectDevice([In, Out] DeviceT devices);
The code goes like this:
uint numDevs = 6;
uint maxDev = 6;
uint chosenIdx = 0;
DeviceT[] devices = new DeviceT[6];
err = GetDevices(devices, &NumberOfDevices, maxDev))
At this point everything is correct. The devices array has the correct information in it.
I now continue with (I just hard code select the first device)
chosenIdx = 0;
var chosenDevice = devices[chosenIdx];
err = SelectDevice(chosenDevice);
This last function returns a System.Access Violation
I tried a whole bunch of things but all end up with the same result. I suspect it has something to do with the HANDLE but I am not sure.
Thanks for any help.
SelectDevice takes a DeviceT *, but your P/Invoke signature takes a DeviceT. That is, you're passing in DeviceT by value rather than passing a pointer.
Try:
[DllImport("file.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern ErrT SelectDevice([In, Out] ref DeviceT devices);
err = SelectDevice(ref chosenDevice);

Why does accessing unmanaged memory cause a System.AccessViolationException? [duplicate]

This question already has an answer here:
Use XGBoost DLL from c# via p/invoke
(1 answer)
Closed 6 years ago.
I'm trying to use XGBoost's dll (libxgboost.dll) to create a DMatrix (which is like a 2D array) and get how many columns it has. It runs fine until it throws a System.AccessViolationException at the int cols = ... line in the code below:
using System;
using System.Runtime.InteropServices;
namespace basicXgboost
{
class Program
{
[DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, IntPtr outputPtr);
[DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, IntPtr dmatrixColumnsPtr);
static void Main(string[] args)
{
IntPtr dmatrixPtr = Marshal.AllocHGlobal(1000000);
IntPtr dmatrixColumnsPtr = Marshal.AllocHGlobal(10);
int result = XGDMatrixCreateFromFile("../../libs/test.txt", 0, dmatrixPtr);
int cols = XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr);
Marshal.FreeHGlobal(dmatrixPtr);
Marshal.FreeHGlobal(dmatrixColumnsPtr);
}
}
}
Why does accessing unmanaged memory allocated with XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr) cause a System.AccessViolationException?
One possibility might be that I'm using pinvoke incorrectly for these functions. Below are the definitions for each dll function I use:
XGDMatrixCreateFromFile()
/*!
* \brief load a data matrix
* \param fname the name of the file
* \param silent whether print messages during loading
* \param out a loaded data matrix
* \return 0 when success, -1 when failure happens
*/
XGB_DLL int XGDMatrixCreateFromFile(const char *fname,
int silent,
DMatrixHandle *out);
XGDMatrixNumCol()
/*!
* \brief get number of columns
* \param handle the handle to the DMatrix
* \param out The output of number of columns
* \return 0 when success, -1 when failure happens
*/
XGB_DLL int XGDMatrixNumCol(DMatrixHandle handle,
bst_ulong *out);
Here is the repo for my project. I'm using Visual Studio Enterprise 2015 . It's built in "Debug" mode (targeting x64) on Windows 10 Pro (64-bit). x64 binaries for libxgboost.dll can be found here. Although the linked repo does contain a copy of libxgboost.dll.
Here's the solution I've got thanks to NineBerry's answer.
using System;
using System.Runtime.InteropServices;
namespace basicXgboost
{
class Program
{
[DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, out IntPtr outputPtr);
[DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, out ulong dmatrixColumnsPtr);
static void Main(string[] args)
{
IntPtr dmatrixPtr;
ulong dmatrixColumns;
int result = XGDMatrixCreateFromFile("../../libs/test.txt", 0, out dmatrixPtr);
int cols = XGDMatrixNumCol(dmatrixPtr, out dmatrixColumns);
}
}
}

IndexOutOfRangeException - Cannot see call stack using PInvoke

I'm developing a C# app that takes data from a SerialPort, then it uses a C++ project (that I cannot change) to compute the read data.
The C++ project is using some native C code, that will call C# functions when the data are computed.
This is some examples of the called C# code which calls the C++ function using PInvoke:
[DllImport("MyLib.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void PacketHandler_HandlePacket(IntPtr packetHandler, IntPtr packet, int packetType);
[SuppressUnmanagedCodeSecurity]
[DllImport("MyLib.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern float DeviceManager_AddSampleToBattery(IntPtr self, float sample, double sampleRate);
[SuppressUnmanagedCodeSecurity]
[DllImport("MyLib.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern double DeviceManager_GetTimestamp(IntPtr self, int packetType);
[DllImport("MyLib.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern void PacketHandler_AddCallbackBattery(IntPtr self, Delegate #delegate);
Then, the C++ code:
extern "C"
{
__declspec(dllexport) void _cdecl PacketHandler_HandlePacket(int * packetHandler, char * packet, int packetType){
PacketHandler_handlePacket((PacketHandlerStruct *)packetHandler, packet, (PacketHandlerPacketType)packetType);}
}
This C function is calling a C# function that I've set like this:
__declspec(dllexport) void _cdecl PacketHandler_AddCallbackBattery(int * packetHandler, void(*f)(void * obj, unsigned short int sample)){
PacketHandlerStruct * myPointer = ((PacketHandlerStruct *)packetHandler);
myPointer->delegate.addSampleToBattery = f;
}
Finally, the C code will call the "addSampleToBattery" function which is this C# callback (in where the first two are PInvoke calls like the first one I've posted)
private static float CallbackBattery(IntPtr self, ushort sample)
{
var value = DeviceManager_AddSampleToBattery(DeviceManager, sample, Const.BaseBvpSampleRate);
var timestamp = DeviceManager_GetTimestamp(DeviceManager, (int)PacketHandlerPacketType.Battery);
SocketManager.OnNewBatteryArrived(value, timestamp);
return value;
}
Other details:
The C# delegates are declared as follows:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate float DelegateBattery(IntPtr self, short sample);
private static readonly DelegateBattery DelegateCallbackBattery = CallbackBattery;
And setted like this:
var intptrDelegate = Marshal.GetFunctionPointerForDelegate(DelegateCallbackBattery);
var a = Marshal.GetDelegateForFunctionPointer(intptrDelegate, typeof(DelegateBattery));
PacketHandler_AddCallbackBattery(packetHandler, a);
So, everything seems to works, but a lot of times a IndexOutOfRangeException occurs. The main issue is that, even in Debug Mode with all the symbols loaded, I can't see the line that is throwing the exception because only the Disassembly View is available, and of course I can't get meaningful info from it.
Unhandled Exception: 'MyProgram.exe' (Win32):
The program '[3000] MyProgram.exe' has exited with code 0 (0x0).
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at System.Threading.ThreadPoolWorkQueue.Dequeue(ThreadPoolWorkQueueThreadLocals tl, IThreadPoolWorkItem& callback, Boolean& missedSteal)
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
Thanks!
Semantics in correspondence with an IndexOutOfRangeException indicate that you've attempted to access memory too far from a base memory address, and thus you shouldn't be trying to deference that point in memory.
Think of an int array of 3 elements. If you try to index [3], that is *(base_address + (sizeof(int) * 3))* being dereferenced so that the next 4 bytes at that place in memory are provided for the value as an int. The only valid indexes are 0, 1, and 2, because those offsets are within the range of the 3 elements that we've allocated the space for.
We still need more code, as I don't see where any of this is relevant to the exception message.

calling function from regular dll from c# - memory allocation issue?

Hi chaps(and chappettes)
Have a regular C dll with an exported function
int GetGroovyName(int grooovyId,char * pGroovyName, int bufSize,)
Basically you pass it an ID (int), a char * buffer with memory pre-allocated and the size of the buffer passed in.
pGroovyName gets filled with some text. (i.e. its a lookup basied on the groovyID)
The question is how do I best call that from c# ?
cheers
Buzz
On the C# side, you would have:
[DllImport("MyLibrary")]
extern static int GetGroovyName(int grooovyId, StringBuilder pGroovyName, int bufSize);
And you call it like:
StringBuilder sb = new StringBuilder (256);
int result = GetGroovyName (id, sb, sb.Capacity); // sb.Capacity == 256
You may use DLLImport in C#.
Check this http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute.aspx
Code from MSDN
using System;
using System.Runtime.InteropServices;
class Example
{
// Use DllImport to import the Win32 MessageBox function.
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);
static void Main()
{
// Call the MessageBox function using platform invoke.
MessageBox(new IntPtr(0), "Hello World!", "Hello Dialog", 0);
}
}
Have a look at this snippet demonstrating (theoretically) how it should look:
using System;
using System.Runtime.InteropServices;
using System.Text; // For StringBuilder
class Example
{
[DllImport("mylib.dll", CharSet = CharSet.Unicode)]
public static extern int GetGroovyName(int grooovyId, ref StringBuilder sbGroovyName, int bufSize,)
static void Main()
{
StringBuilder sbGroovyNm = new StringBuilder(256);
int nStatus = GetGroovyName(1, ref sbGroovyNm, 256);
if (nStatus == 0) Console.WriteLine("Got the name for id of 1. {0}", sbGroovyNm.ToString().Trim());
else Console.WriteLine("Fail!");
}
}
I set the stringbuilder to be max capacity of 256, you can define something smaller, assuming it returns 0 is success, it prints out the string value for groovy id of 1, otherwise prints fail.
Hope this helps.
Tom

Categories