Send string array in c# to c++ dll - c#

my c# part
[DllImport("asdf.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
unsafe extern public static int CompareDB(string[] filename);
Below is c++ part
extern "C" __declspec(dllexport)int CompareDB(char** name)
{
CString filename="It is already assigned in previous code"
strcpy(name[1], (const char *)fileName);
}
Error is related with attempting to read or write protected memory.
Somebody help me please.

Related

C# WPF passing UTF16 string to a function that accepts char *

I've created a wpf project which has a helper static class that contains all my c++ backend code. One such function is defined as:
public static unsafe class Backend {
[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void write(void* ptr, char* path);
}
public partial class MainWindow : Window
{
public MainWindow()
{
string path = "mypath";
InitializeComponent();
unsafe
{
char *p; //convert
void* myObj = Backend.init_obj(1920, 1080);
Backend.gen(myObj);
Backend.write(myObj, p);
}
}
}
The void* ptr is actually my object that is casted in order to marshall it onto the C# side. The problem I face is that whenever I try to invoke this with a string literal in wpf, I get that Visual C# cannot convert this because string literals are encoded in UTF16. Naturally I tried many things other than manually copying the relevant bytes to a char array. Any tips?
One of the things the CLR can do pretty well for interop with C/C++ code is marshalling data structures between managed and unmanaged code. Since strings are pretty important, a lot of work went into making strings marshal as well as possible.
As a side note, you're using void* for the context object that's created by init and passed to write. Since you're just handing it back, you can replace it with IntPtr and avoid unsafe blocks altogether. IntPtr is always the size of a pointer in the current architecture.
First, let's change the declaration of the imported functions. CharSet.Ansi tells it to marshal strings as ANSI. The ptr parameter becomes IntPtr
[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static IntPtr init(int width, int height);
[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void gen(IntPtr ptr);
[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void write(IntPtr ptr, string path);
And from there, you can figure out how to modify the function to deallocate ptr and any others you have to call.
Using those functions becomes a lot easier and a lot cleaner. You don't need the unsafe block and you can pass path directly to write.
public MainWindow()
{
string path = "mypath";
InitializeComponent();
IntPtr myObj = Backend.init_obj(1920, 1080);
Backend.gen(myObj);
Backend.write(myObj, path);
}
Original comment that got it working:
Instead of trying to create the char* parameter yourself, change the declaration so the second parameter is string and let the Runtime marshal it for you. Because it's an ANSI string, you're never going to get full unicode fidelity but that's a problem created by the C++ code.

Calling Pocketsphinx in C# AccesViolationException

I'm trying to do the pocketsphinx tutorial in C# using pinvoke but get an AccessViolationException when I try to decode using ps_decode_raw().
IntPtr ps = PocketSphinx.ps_init(config);
IntPtr fh = Win32Util.fopen(#"goforward.raw", "rb");
int rv = PocketSphinx.ps_decode_raw(ps, fh, "goforward", -1);
The functions are wrapped as follows
//ps_decoder_t* ps_init(cmd_ln_t* config)
[DllImport("pocketsphinx.dll",
SetLastError = true,
CallingConvention = CallingConvention.Cdecl)]
public extern static IntPtr ps_init(
IntPtr config);
//int ps_decode_raw(ps_decoder_t *ps, FILE *rawfh, char const *uttid, long maxsamps);
[DllImport("pocketsphinx.dll",
SetLastError = true,
CallingConvention = CallingConvention.Cdecl)]
public extern static int ps_decode_raw(
IntPtr ps,
IntPtr rawfh,
[MarshalAs(UnmanagedType.LPStr)] string uttid,
int maxsamps);
[DllImport("msvcrt.dll",
SetLastError = true,
CallingConvention = CallingConvention.Cdecl)]
public extern static IntPtr fopen(
[MarshalAs(UnmanagedType.LPStr)] string _Filename,
[MarshalAs(UnmanagedType.LPStr)] string _Mode);
I wrapped C's fopen as well just because it was the quickest way I can think of implementing the tutorial.
I tried calling cmd_ln_retain on ps to make sure that ps wasn't causing the problem. (it wasn't). I also removed my debug code in the above.
I'm pretty sure something is up with the fopen but I'm not sure what.
Someone asked for the pocketsphinx log. https://justpaste.it/h52t
You don't check for errors anywhere. And it's wrong to set SetLastError to true for these functions. They won't call SetLastError.
Your big problem though is that the library uses a particular instance of the C runtime, depending on how you built it. And your fopen import is from a different instance of the C runtime.
You'll need to add some code to the library that exposes functions to create and destroy FILE* objects. By doing that you'll get a FILE* made by the correct runtime.

Attempted to read or write protected memory with dllimport in c#

I have a problem with my project:
In dll c++:
extern "C" __declspec(dllexport) int results(char* imgInput, void* tree)
{
struct kd_node* nodeTree = new(tree)kd_node ; // new kd_tree with data from memory address
...
...
int ret = atoi(retValueStr.c_str());
return ret;
}
extern "C" __declspec(dllexport) void* buildKDTree(char* folder)
{
struct kd_node* kd_root;
....
feature *LFData = listFeat.data();
kd_root = kdtree_build(LFData,listFeat.size());
void* address_kdtree = (void*)&kd_root; // get memory address of kd_tree
return address_kdtree;
}
and I use to dllimport in c#:
[DllImport(#"kdtreeWithsift.dll", EntryPoint = "buildKDTree", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern void* buildKDTree(byte[] urlImage);
[DllImport(#"kdtreeWithsift.dll", EntryPoint = "results", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
[return:MarshalAs(UnmanagedType.I4)]
public unsafe static extern int results(byte[] imgInput, void* tree);
static unsafe void Main()
{
string urlImg1 = "C:/Users../test img/1202001T1.jpg";
string urlImg = "C:/export_features";
try
{
IntPtr result;
int result1;
result1 = results(convertStringToByte(urlImg1), 5, buildKDTree(convertStringToByte(urlImg))); // this error
Console.WriteLine("results = %d",result1);
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
}
}
when i run the program, this program show error :
Attempted to read or write protected memory. This is often an indication that other memory is corrupt
what error do you know and how to resolved ?
thank you!
You don't need a convertStringToByte method here. You can tell the runtime to marshal your string as a char *. Also, I would suggest that you make the method return an IntPtr, like this:
[DllImport(#"kdtreeWithsift.dll", EntryPoint = "buildKDTree",
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr buildKDTree([MarshalAs(UnmanagedType.LPStr)]string urlImage);
[DllImport(#"kdtreeWithsift.dll", EntryPoint = "results",
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
[return:MarshalAs(UnmanagedType.I4)]
public static extern int results([MarshalAs(UnmanagedType.LPStr)]string imgInput, IntPtr tree);
You can then call it with:
IntPtr tree = buildKDTree(urlImg);
int result1 = results(urlImg, 50, tree);
Console.WriteLine("results = {0}",result1);
Well, for one thing, the C function is called buildKDTree, but you are importing it in the C# code with entry point "buildKDTreeWithFeatures". Try making these consistent and see if you get better results.
I try to call it :
IntPtr tree = buildKDTree(urlImg);
int result1 = results(urlImg, 50, tree);
Console.WriteLine("results = {0}",result1);
but it is not your fault where you said.
I think the variable intPtr tree in function results([MarshalAs(UnmanagedType.LPStr)]string imgInput, IntPtr tree); that caused the error
I think its similar problem due to char* parameters, in my own problem thanks to this below link question solves the problem.
So your only solution is to pass the string parameters as IntPtr.
Allocate the memory with Marshal.StringToHGlobalAnsi
Attempted to read or write protected memory with dllimport in c#

C# C++ Interop Delegate

I would like to preface this with the fact I have no formal C++ training, so if you have suggestions, please provide in a way that a super noob can implement.
Thank you in advance.
What I am trying to do is call a C++ function from C# pass in a structure and a delegate.
My code works, but if I access a value in the delegate, I receive this error:
Here is my c# code:
public delegate void CallBackMethodDelegate(MP4CreateClipProcessingData data);
[DllImport("libmp4v2.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.LPStr)]
public extern static string MP4CreateClip(ref MP4CreateClipProcessingData data, CallBackMethodDelegate del);
And here is my C++ Code:
struct MP4CreateClipProcessingData
{
bool err;
char* sourcePath;
char* targetPath;
char* error;
uint32_t startTime;
uint32_t duration;
};
extern "C" __declspec(dllexport) void MP4CreateClip(MP4CreateClipProcessingData data, void (_stdcall *func)(MP4CreateClipProcessingData))
{
func(data);
}
This is where, in my C# code I call the function:
var data = new NativeMethods.MP4CreateClipProcessingData(file, Path.Combine(targetPath, Path.GetFileName(file).ToString()));
NativeMethods.CallBackMethodDelegate retDel = new NativeMethods.CallBackMethodDelegate(NativeMethods.returnCall);
NativeMethods.MP4CreateClip(ref data, retDel);

Entry Point Not Found Exception

I'm trying to use a C++ unmanaged dll in a C# project and I'm getting an error when trying to call a function that says that entry point cannot be found.
public class Program
{
static void Main(string[] args)
{
IntPtr testIntPtr = aaeonAPIOpen(0);
Console.WriteLine(testIntPtr.ToString());
}
[DllImport("aonAPI.dll")]
public static extern unsafe IntPtr aaeonAPIOpen(uint reserved);
}
Here is the dumpbin for the function:
5 4 00001020 ?aaeonAPIOpen##YAPAXK#Z
I changed the dll import to [DllImport("aonAPI.dll", EntryPoint="?aaeonAPIOpen")] and [DllImport("aonAPI.dll", EntryPoint="_aaeonAPIOpen")] and no luck.
Using the undname.exe utility, that symbol demangles to
void * __cdecl aaeonAPIOpen(unsigned long)
Which makes the proper declaration:
[DllImport("aonAPI.dll", EntryPoint="?aaeonAPIOpen##YAPAXK#Z",
ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr aaeonAPIOpen(uint reserved);
It looks like the function you're trying to call is compiled as a C++ function and hence has it's name mangled. PInvoke does not support mangled name. You need to add an extern "C" block around the function definition to prevent name mangling
extern "C" {
void* aaeonAPIOpen(uint reserved);
}

Categories

Resources