I am trying to invoke a simple C# class method from C, using embedded mono (as described here). I can invoke the method, but the C# function receives 0 as the argument, instead of the number I pass in. The C# function returns a result and the C code is seeing the correct result - I just can't pass arguments in. What am I doing wrong?
The C# assembly (MonoSide.cs) is:
using System;
public class MainEntryPoint
{
static public void Main(string[] args)
{
}
}
namespace Fibonacci
{
public class Fibonacci
{
public long FibonacciNumber(long entryNumber)
{
Console.Write(string.Format("(inside C#) FibonacciNumber({0})", entryNumber));
var sqrt5 = Math.Sqrt(5);
var phi = (1 + sqrt5) / 2;
var exp = Math.Pow(phi, entryNumber);
var sign = ((entryNumber & 1) == 0) ? -1 : 1;
var entry = (exp + sign / exp) / sqrt5;
Console.WriteLine(string.Format(" = {0}.", entry));
return (long) entry;
}
}
}
Here is the C code:
#include <stdio.h>
#include <stdlib.h>
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/debug-helpers.h>
int main(int argc, char **argv)
{
long long entryNumber = (argc > 1) ? atoi(argv[1]) : 10;
// For brevity, null checks after each mono call are omitted.
MonoDomain *domain = mono_jit_init("MainEntryPoint");
MonoAssembly *monoAssembly = mono_domain_assembly_open(domain, "MonoSide.exe");
char *monoArgs[] = {"Mono"};
mono_jit_exec (domain, monoAssembly, 1, monoArgs);
MonoImage * monoImage = mono_assembly_get_image (monoAssembly);
MonoClass * monoClass = mono_class_from_name (monoImage, "Fibonacci", "Fibonacci");
MonoMethod *monoMethod = mono_class_get_method_from_name(monoClass, "FibonacciNumber", 1);
// Invoking method via thunk.
typedef long long (*FibonacciNumber) (long long *);
FibonacciNumber fibonacciNumber = mono_method_get_unmanaged_thunk (monoMethod);
printf("Calling C# thunk function FibonacciNumber(%I64u)...\n", entryNumber);
long long number = fibonacciNumber(&entryNumber);
printf("Fibonacci number %I64u = %I64u\n", entryNumber, number);
mono_jit_cleanup (domain);
return 0;
}
I am compiling it with Dev-Cpp using this makefile:
test.exe: CSide.c MonoSide.exe
gcc CSide.c -o test.exe -m32 -mms-bitfields -IC:/Progra~2/Mono/Include/mono-2.0 -LC:/Progra~2/Mono/lib -L/Embedded -lmono-2.0 -lmono
MonoSide.exe: MonoSide.cs
mcs MonoSide.cs
The output is:
Calling C# thunk function FibonacciNumber(10)...
(inside C#) FibonacciNumber(0) = 0.
Fibonacci number 10 = 0
(Why these functions? This is just a sample, can-I-get-this-to-work program and not my final goal.)
Edit:
It works if I pass the function argument as a pointer in the C code. The C# receives it correctly. The above code has been modified from:
typedef long long (*FibonacciNumber) (long long);
...
long long number = fibonacciNumber(entryNumber);
to:
typedef long long (*FibonacciNumber) (long long *);
...
long long number = fibonacciNumber(&entryNumber);
To me, this means that the safest way to pass anything more complicated between C and C# is via buffers, with matching serializers and deserializers in C and C#.
It works if I pass the function argument as a pointer in the C code. The C# receives it correctly. The above code has been modified from:
typedef long long (*FibonacciNumber) (long long);
...
long long number = fibonacciNumber(entryNumber);
to:
typedef long long (*FibonacciNumber) (long long *);
...
long long number = fibonacciNumber(&entryNumber);
To me, this means that the safest way to pass anything more complicated between C and C# is via buffers, with matching serializers and deserializers in C and C#.
Related
Is there a functional equivalent for the C# function .tostring("X4"), to C++?
I've been scratching my head for a few days wondering why my sensor is reporting a different serial number to what the manufacturer software (written in C#) and what my C++ code reports. The serial number is also written on the sensor, which ties in with what the manufacturer C# code reports. On inspection of their source code, they're using the .tostring("X4") function to convert it to "human readable", which makes sense (from a "oh thats why it's different", not a "why on earth would you do that" point of view).
For further info - https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings
A similar question but C# to Java - C# .ToString("X4") equivalent in Java
There's is no readily available equivalent function in C++, but you could create one that works in a similar way:
#include <iostream>
#include <sstream>
#include <string>
template<class T>
std::string tostringX(unsigned len, T v) {
std::ostringstream os;
os << std::hex << v;
auto rv = os.str();
if(rv.size() < len) rv = std::string(len - rv.size(), '0') + rv;
return rv;
}
int main() {
std::cout << tostringX(4, 0xFEDC) << '\n'; // outputs "fedc"
}
#include <iostream>
#include<sstream>
#include <iomanip>
int main() {
int x = 12;
std::stringstream stream;
stream << std::setfill('0') << std::setw(4)<< std::hex << x;
std::cout << stream.str();
}
Output : 000c
I guess that's the answer you're looking for.
i have template in project c++ and i want to translate code to c# now, and i get some errors in template c#.
In C++
template<typename T>
struct pares
{
DWORD64 first;
T* second;
};
template<typename T>
struct hash_node
{
pares<T> mValue;
hash_node<T>* mpNext;
};
template<typename T>
struct hashtable
{
DWORD64 vtable;
hash_node<T>** mpBucketArray;
unsigned int mnBucketCount;
unsigned int mnElementCount;
//...
};
template<typename T>
struct hashtable_iterator
{
hash_node<T>* mpNode;
hash_node<T>** mpBucket;
};
In C#
public class pair<T>
{
public Int64 first;
public T second;
}
public class hash_node<T>
{
public pair<T> mValue = new pair<T>();
public hash_node<T> mpNext;
}
public class hashtable<T>
{
public Int64 vtable;
public hash_node<T>[] mpBucketArray;
public int mnBucketCount;
public int mnElementCount;
}
public class hashtable_iterator<T>
{
public hash_node<T> mpNode;
public hash_node<T> mpBucket;
}
Inside a function in c++ project i have this line , its fine without error:
hashtable<DWORD64>* table = (hashtable<DWORD64>*)(pObfuscationMgr + 8);
But in C# get error:
Cannot convert type 'long' to 'hashtable'
hashtable<Int64> table = (hashtable<Int64>)(pObfuscationMgr + 8);
The reason for the error is that you are telling the compiler to interpret a memory position as a hashtable<> object. This works in C++ because you have the tool to do that: pointers. A pointer is just a memory position with an associated type.
You have a memory block pointed by pObfuscationMgr, and you intend to create a pointer to a hashtable<> and this way understand the contents at that memory position (plus eight) as a hashtable<>.
If you do a verbatim translation to C#:
hashtable<Int64> table = (hashtable<Int64>)(pObfuscationMgr + 8);
Pointers are lost in that translation, because there are no pointers in C#. So, now pObfuscationMgr is now just a long, and hence the compiler's error: you cannot transform a long into a hashtable<>.
For example, you can do this in C or C++:
void foo()
{
char buffer[1024];
int * ptr1 = (int *) &buffer;
int * ptr2 = (int *) ( &buffer + 8 );
*ptr1 = 40;
*ptr1 += 2;
*ptr2 = 5;
*ptr2 *= 2;
printf( "%d\n", *ptr1 );
printf( "%d\n", *ptr2 );
}
In the code above, you are creating a buffering area in the stack, in the shape of a char array. Then you create the ptr1 and ptr2 pointers, and make them point to the beginning of that area and to the beginning of that area plus eight. Then you can manage both pointers as if they were pointing to real variables. That is more or less similar to what the original code does.
You won't be successful by doing a verbatim translation of C++ code into C#. Of course that translation is achievable, but having a deep knowledge about memory in C++ and how to represent that in C#, i.e., doing a real translation.
Hope this (somehow) helps.
I have a functiong which look somethink like this:
virtual int64_t Read(uint8_t* buffer, int64_t bufferLength) = 0
which we want to overide (as this is an abstract class) and implament from c# code (using director). using
%include "arrays_csharp.i"
%apply uint8_t INPUT[] {uint8_t* buffer}
I was able to get a c# translation with the signature of
public virtual long Read(byte[] buffer, long bufferLength)
which is what I wanted. but when trying to compile the SWIG code we are getting errors as follows:
error C2440: '=': cannot convert from 'void *' to 'unsigned char *'
note: Conversion from 'void*' to pointer to non-'void' requires an explicit cast
because of this lins in the generated swig cc file:
int64_t c_result = SwigValueInit< int64_t >() ;
long long jresult = 0 ;
unsigned char* jbuffer = 0 ;
long long jbufferLength ;
long long jbufferOffset ;
if (!swig_callbackRead__SWIG_0) {
throw Swig::DirectorPureVirtualException("mip::Stream::Read");
} else {
jbuffer = (void *) buffer; <========= FAIL LINE
jbufferLength = bufferLength;
jresult = (long long) swig_callbackRead__SWIG_0(jbuffer, jbufferLength);
c_result = (int64_t)jresult;
}
How can I tell SWIG not to cast to (void *)?
Looks like the directorin typemap isn't quite right here. I think this should be sufficient to fix it, on the line after your %apply directive:
%typemap(directorin) uint8_t *buffer "$input = $1;"
The above typemap only matches non-const uint8_t* parameters named buffer. We can make that much more generic if we want to, e.g.:
%typemap(directorin) SWIGTYPE * "$input = $1;"
Will match anything that doesn't have a better match, const or non-const alike. I can't figure out why that isn't the default anyway, so there's a risk here that it might break something elsewhere that I've not thought of, so you may prefer to continue being selective in where this gets applied..
You can also do something like:
%typemap(directorin) SWIGTYPE * "$input = ($1_ltype)$1;"
Or add another variant:
%typemap(directorin) const SWIGTYPE * "$input = const_cast<$1_ltype>($1);"
The error message from compiler is quite plain. You should explicitly convert void * to unsigned char *.
Try:
jresult = (long long) swig_callbackRead__SWIG_0(static_cast<unsigned char *>(jbuffer), jbufferLength);
How is it possible to write Rust code like the C code below? This is my Rust code so far, without the option to marshal it:
pub struct PackChar {
id: u32,
val_str: String,
}
#[no_mangle]
pub extern "C" fn get_packs_char(size: u32) -> Vec<PackChar> {
let mut out_vec = Vec::new();
for i in 0..size {
let int_0 = '0' as u32;
let last_char_val = int_0 + i % (126 - int_0);
let last_char = char::from_u32(last_char_val).unwrap();
let buffer = format!("abcdefgHi{}", last_char);
let pack_char = PackChar {
id: i,
val_str: buffer,
};
out_vec.push(pack_char);
}
out_vec
}
The code above tries to reproduce the following C code which I am able to interoperate with as is.
void GetPacksChar(int size, PackChar** DpArrPnt)
{
int TmpStrSize = 10;
*DpArrPnt = (PackChar*)CoTaskMemAlloc( size * sizeof(PackChar));
PackChar* CurPackPnt = *DpArrPnt;
char dummyString[]= "abcdefgHij";
for (int i = 0; i < size; i++,CurPackPnt++)
{
dummyString[TmpStrSize-1] = '0' + i % (126 - '0');
CurPackPnt->IntVal = i;
CurPackPnt->buffer = strdup(dummyString);
}
}
This C code could be accessed via DLL import in C# like this:
[Dllimport("DllPath", CallingConvention = CallingConvention.Cdecl)]
public static extern void GetPacksChar(uint length, PackChar** ArrayStructs)
PackChar* MyPacksChar;
GetPacksChar(10, &MyPacksChar);
PackChar* CurrentPack = MyPacksChar;
var contLst = new List<PackChar>();
for (uint i = 0; i < ArrL; i++, CurrentPack++)
contlist.Add(new PackChar() {
IntVal = CurrentPack->IntVal, buffer = contLst->buffer
});
Let's break this down into the various requirements that your Rust code needs to meet:
The DLL needs to expose a function with the correct name GetPacksChar. This is because you declare it with the name GetPacksChar from C# and the names must match.
The function needs the correct calling convention, in this case extern "C". This is because you declare the function as CallingConvention = CallingConvention.Cdecl from C#, which matches the extern "C" calling convention in Rust.
The function needs the correct signature, in this case taking the Rust equivalent of a uint and a PackChar** and returning nothing. This matches the function signature fn (u32, *mut *mut PackChar).
The declaration of PackChar needs to match between C# and Rust. I'll go over this below.
The function needs to the replicate the behavior of the original C function. I'll go over this below.
The easiest part will be declaring the function in Rust:
#[no_mangle]
pub extern "C" fn GetPacksChar(length: u32, array_ptr: *mut *mut PackChar) {}
Next we need to address PackChar. Based on how it's used in the C# code, it looks like it should be declared:
#[repr(C)]
pub struct PackChar {
pub IntVal: i32,
pub buffer: *mut u8,
}
Breaking this down, #[repr(C)] tells the Rust compiler to arrange PackChar in memory the same way a C compiler would, which is important since you're telling C# that it's calling into C. IntVal and buffer are both used from C# and the original C version. IntVal is declared as an int in the C version, so we use i32 in the Rust version, and buffer is treated as an array of bytes in C, so we use a *mut u8 in Rust.
Note that the definition of PackChar in C# should match the declaration in C/Rust, so:
public struct PackChar {
public int IntVal;
public char* buffer;
}
Now all that's left is to reproduce the original behavior of the C function in Rust:
#[no_mangle]
pub extern "C" fn GetPacksChar(len: u32, array_ptr: *const *mut PackChar) {
static DUMMY_STR: &'static [u8] = b"abcdefgHij\0";
// Allocate space for an array of `len` `PackChar` objects.
let bytes_to_alloc = len * mem::size_of::<PackChar>();
*array_ptr = CoTaskMemAlloc(bytes_to_alloc) as *mut PackChar;
// Convert the raw array of `PackChar` objects into a Rust slice and
// initialize each element of the array.
let mut array = slice::from_raw_parts(len as usize, *array_ptr);
for (index, pack_char) in array.iter_mut().enumerate() {
pack_char.IntVal = index;
pack_char.buffer = strdup(DUMMY_STR as ptr);
pack_char.buffer[DUMMY_STR.len() - 1] = b'0' + index % (126 - b'0');
}
}
Important points from the above:
We have to manually include the null terminating character (\0) in DUMMY_STR because it's meant to be a C string.
We call CoTaskMemAlloc() and strdup(), which are both C functions. strdup() is in the libc crate, and you can probably find in the ole32-sys crate.
The function is declared as unsafe because we have to do a number of unsafe things, like calling C functions and doing str::from_raw_parts().
Hope that helps!
I have a C++ class which has a header(matrixheader.h) such that :
#pragma once
class M
{
public:
M(int m,int n);
void MSet(int m,int n,double d);
double MGet(int m,int n);
~M();
private:
double** mat;
};
Class is defined as follows in (matrixbody.cpp):It is built in Win32 Platform.
#pragma once
#include "matrixhead.h"
M::M(int m,int n)
{
mat = new double*[m];
for (int i = 0; i < m; i++)
{
mat[i] = new double[n];
}
}
void M::MSet(int m,int n,double d)
{
mat[m][n] = d;
}
double M::MGet(int m,int n)
{
double d = mat[m][n];
return d;
}
M::~M()
{
delete[] mat;
}
I have made a wrapper for the Class like so(matrixwrapper.cpp):The wrapper is also built in Win32 platform.
#include "matrixhead.h"
#include "matrixbody.cpp"
extern "C" __declspec(dllexport) void* Make(int m,int n)
{
M o(m,n);
return &o;
}
extern "C" __declspec(dllexport) void setData(void* mp,int m,int n,double d)
{
M* ap = (M*)mp;
M a = *ap;
a.MSet(m,n,d);
}
extern "C" __declspec(dllexport) double getData(void* mp,int m,int n)
{
M* bp = (M*)mp;
M b = *bp;
double d = b.MGet(m,n);
return d;
}
I import the class to C# and try to call the C++ dl methods from C#:
using System;
using System.Runtime.InteropServices;
namespace wrappertest
{
class Program
{
[DllImport("matrixwrapper.dll")]
unsafe public static extern void* Make(int m,int n);
[DllImport("matrixwrapper.dll")]
unsafe public static extern void setData(void* mp,int m, int n,double d);
[DllImport("matrixwrapper.dll")]
unsafe public static extern double getData(void* mp,int m, int n);
static unsafe void Main(string[] args)
{
void* p = Make(10, 10);
setData(p,10,1,10);
Console.WriteLine(getData(p,10,1));
}
}
}
But when i try to run the C++ dll methods from C# i get the following error
1//Attempted to read or write protected memory.This is often an indication that other memory is corrupt when running C# code in x64.
2//An attempt was made to load a program with incorrect format when runnning in x86 Active/x86 or in AnyCPU platform.
Questions:
1//What is wrong in the above code ?
2//Considering that my final objective is to make a 2d dynamic array in C++ and read/write data in the array such as the one double**mat in the matrixheader.h file above from C#?is there any other way to implement it ?
Let's get the easy thing first:
An attempt was made to load a program with incorrect format when runnning in x86 Active/x86 or in AnyCPU platform.
This simply means you have a platform mismatch. You're either trying to load an x86 C++ dll in an x64 .NET runtime, or the reverse.
The following error is the real problem:
Attempted to read or write protected memory.This is often an indication that other memory is corrupt when running C# code in x64.
That's to be expected, because your Make function creates an object on the stack, then returns a pointer to it. By the time you read back this object, the contents on the stack has changed (the stack is being reused), and the mat pointer points somewhere else, most probably into unallocated memory.
Please see this answer where I go into deeper detail about this issue (it's C# but it's the same issue).
You have to allocate some dynamic memory to solve your problem. You may try:
extern "C" __declspec(dllexport) void* Make(int m,int n)
{
M* o = new M(m,n);
return o;
}
And of course, you'll have to create one more method to perform the matching delete if you don't want to leak memory.
Also, like Mgetz points out in the comments, you have a memory leak in the M class itself. The delete[] mat; call in the destructor won't free every allocated chunk of memory. You're calling new in the constructor m + 1 times, this means you have to call delete[] m + 1 times also in the destructor, once for each new. You probably should keep m and n as fields in your class (at least m is mandatory to know how many calls to delete[] you have to do).
A much better solution would be to use a single array instead of jagged arrays. You calculate the index i, j in that array as i * m + j. You may also use a std::vector or just do it in C# altogether:
public class M
{
private double[] _items;
private int _m;
private int _n;
public M(int m, int n)
{
_items = new double[m * n];
_m = m;
_n = n;
}
public this[int i, int j]
{
// Here, you should perform a bounds check on i and j against _m and _n
get { return _items[i * _m + j]; }
set { _items[i * _m + j] = value; }
}
}