C++ managed wrapper called from C# - c#

I have some native C++ code and I have then created a wrapper to go around it.
creator.h
#pragma once
#include "file.h"
#define EXPORT __declspec(dllexport)
class EXPORT creator{
public:
creator();
~creator();
bool function1(int);
bool startFunction1(char *in, char *cache, char *out, long, double);
};
wrapper.h
#pragma once
using namespace System;
namespace nativeWrapper
{
public ref class Wrapper{
public:
creator *c;
Wrapper();
~Wrapper();
bool wStartCreating(System::String ^_in, System:: ^_cache, System:: ^_out);
};
}
wrapper.cpp
Lets just go straight to the wStartCreating function
bool Wrapper::wStartCreating(System::String ^_in, System:: ^_cache, System:: ^_out)
{
char *in = marshaling(_in);
char *out = marshaling(_out);
char *cache = marshaling(_cache);
return c->startFunction(in, cache, out, 0.0, 0.0);
}
in the c# code:
[DllImport("wrapper.dll")]
private static extern bool wStartCreating(String _in, String cache, String _out);
Then, I want to call wStartCreating(String, String, String) but I get a dllnotfoundexception whenever I try to make the call. I tried to add the reference (by the way this is in Visual studio 2005) and in the build event I copied the dll over to the referenced folder. Need some help as to why this runtime error may be coming up.
Thanks
-Tommy

Related

Passing bytes by reference from C# into C++/CLI wrapper to call the InterlockedOr8 function

I am trying to pass bytes by reference from C# such that I can call the atomic operation InterlockedOr8 on them. I have the following static library in C++:
Bitwise.h:
char EightBitOr(char volatile* destination, char value);
Bitwise.cpp:
#include "Bitwise.h"
char EightBitOr(char volatile* destination, char value)
{
return InterlockedOr8(destination, value);
}
I am calling it from this C++/CLI wrapper DLL:
Wrapper.h:
#include "..\Bitwise\Bitwise.h"
using namespace System;
namespace Wrapper {
public ref class Bitwise
{
public:
static char InterlockedEightBitOr(volatile char* destination, char value);
};
}
Wrapper.cpp:
#include "Wrapper.h"
char Wrapper::Bitwise::InterlockedEightBitOr(volatile char* destination, char value)
{
return EightBitOr(destination, value);
}
I am trying to call the wrapper from a .NET 5.0 (Core) C# Console Application as follows:
var map = new byte[268435456];
Bitwise.InterlockedEightBitOr(ref map[0], (byte)1);
But I get the following error:
CS0570 'Bitwise.InterlockedEightBitOr(sbyte*, sbyte)' is not supported
by the language
I also noticed the wrapper has translated the method signature into sbyte Bitwise.InterlockedEightBitOr(sbyte* destination, sbyte value); whereas I'd much rather pass unsigned bytes and I am not sure how to change this behavior. Anyways, I was wondering if anyone knew if there is any way I can pass bytes by reference into this CLI wrapper? What changes would I need to make?

how to use byte array as parameter when calling a WindowsPhoneRuntimeComponent?

First of all hey guys! I would like to access 2 C++ functions from my windows phone app.
so i followed every step of this tutorial and i managed to call the function as the poster of the tutorial. Now i wanted to access my own functions so i created the class in the header and in the .cpp file and the project is building ok as long as my functions are not public. Means i cant access them.
public ref class Base64Encoding sealed
{
public:
char *EncodeData(char *data, int length, int *resultLength); //this doesnt compile
char *DecodeString(char *data, int *resultLength); //this compiles buts inaccessible
};
i get a return exception saying error C3992: signature of public member contains invalid type char.
I did some googling and as far as i understand i cannot send parameters of type char since its unmanaged code or something like that.
So what is the issue here? why i cannot pass parameters of type char?
Update
i followed robwirving suggestion and now the header looks like this.
public ref class Base64Encoding sealed
{
public : Platform::String^ EncodeData(String^ StringData);
public : Platform::String^ DecodeString(String^ StringData);
};
in order now to get char* data from the String^ StringData parameter i did in my .cpp
#include <string>
#include <iostream>
#include <msclr\marshal_cppstd.h>
using namespace Platform;
using namespace std;
String^ EncodeData(String^ StringData)
{
// base64 lookup table. this is the encoding table for all 64 possible values
static char *figures = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
msclr::interop::marshal_context context;
std::string s = context.marshal_as<std::string>(StringData);
char *data = new char[s.size() + 1];
int length = s.length;
int *resultLength = s.length;
data[s.size()] = 0;
/* bla bla some functions irrelevant*/
.
.
.
return StringFromAscIIChars(result);
}
static String^ StringFromAscIIChars(char* chars)
{
size_t newsize = strlen(chars) + 1;
wchar_t * wcstring = new wchar_t[newsize];
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, wcstring, newsize, chars, _TRUNCATE);
String^ str = ref new Platform::String(wcstring);
delete[] wcstring;
return str;
}
but now i get 2 errors on building.
1: error C1114: WinRT does not support #using of a managed assembly
2: IntelliSense: an ordinary pointer to a C++/CX mapping ref class or interface class is not allowed
You said the answer right in your question. You can't use a char in a public function of a WinRT component. You can however use strings, I'd suggest changing your functions to the following:
public ref class Base64Encoding sealed
{
public:
Platform::String^ EncodeData(Platform::String^ data);
Platform::String^ DecodeString(Platform::String^ data);
};
In the definition of your encode/decode functions you can then convert your inputs from a Platform::String^ to a char array, call your original C++ function, then convert the return value back to a Platform::String^
I know this may seem like a lot of extra work, but it makes the interop a lot easier for the C# that will consume your WinRT component.
Update:
I think your additional errors probably come from the including msclr\marshal_cppstd.h and the way you are converting your Platform::String^ to a std::string.
Reference this post for how to convert from Platform::String^ to a char*: How to convert Platform::String to char*?

How do I load a C dll into a C# code?

I am in the need of using some functions in a C made program. To test I defined the following :
This is my .h file :
namespace amt
{
class AMT_EXPORT FaceRecognition
{
public:
std::string amt_test_string(std::string in);
};
};
This is my .cpp file :
#include <memory.h>
#include <string>
#include <iostream>
#include <fstream>
#include "api_shared.h"
#include <sys/stat.h>
using namespace std;
std::string amt::FaceRecognition::amt_test_string (std::string in)
{
std::string s="in: "+in;
std::cout<<s<<std::endl;
return s;
}
I am trying to invoke the method like this :
const string str = "C:\\minimal.dll";
[DllImport(str)]
public static extern string amt_test_string(string input);
static void Main(string[] args)
{
string myinput = "12";
string myoutput = "";
myoutput = amt_test_string(myinput);
Console.WriteLine(myoutput);
Console.Read();
}
But im getting an error saying that it cannot find the entry point named amt_test_string..why so? I am a newbie in C btw
That's not a C DLL, that's a C++ DLL. C and C++ are not the same language. In particular, C++ has name mangling, so the function name which gets exported to the DLL is decorated.
I'd strongly recommend that you avoid having C++ exports in your DLL for that reason. If you use only C exports, the symbol name will be predictable (i.e. will not depend on the specific details of how your C++ compiler decorates names), and you won't have to worry about runtime differences, like how your C++ standard library implements std::string.
I'd recommend your DLL export look like this:
extern "C" // This says that any functions within the block have C linkage
{
// Input is 'in', output gets stored in the 'out' buffer, which must be 'outSize'
// bytes long
void DLLEXPORT amt_FaceRecogniztion_amt_test_string(const char *in, char *out, size_t outSize)
{
...
}
}
This interface does not rely on any particular library's std::string implementation, and C# knows how to martial char* parameters as C strings. However, memory management is more complicated, as you need to figure out an upper bound on how big the output is going to be and pass in an appropriately sized bufer.

Dll Import : Unable to find Entry Point "fnMultiply" in DLL "ImportDLL"

I am trying to use DLLImport for using Win32 dll method in C#.
Win32 dll C++
// .h file
#ifdef IMPORTDLL_EXPORTS
#define IMPORTDLL_API __declspec(dllexport)
#else
#define IMPORTDLL_API __declspec(dllimport)
#endif
// This class is exported from the ImportDLL.dll
class IMPORTDLL_API CImportDLL {
public:
CImportDLL(void);
// TODO: add your methods here.
int Add(int a , int b);
};
extern IMPORTDLL_API int nImportDLL;
IMPORTDLL_API int fnImportDLL(void);
IMPORTDLL_API int fnMultiply(int a,int b);
// .cpp file
// ImportDLL.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "ImportDLL.h"
// This is an example of an exported variable
IMPORTDLL_API int nImportDLL=0;
// This is an example of an exported function.
IMPORTDLL_API int fnImportDLL(void)
{
return 42;
}
IMPORTDLL_API int fnMultiply(int a , int b)
{
return (a*b);
}
Once i build this i get ImportDLL.dll
Now i create Windows Application and add this dll in debug folder and try to use this method using DLLImport
[DllImport("ImportDLL.dll")]
public static extern int fnMultiply(int a, int b);
And I try to call this in C#
int a = fnMultiply(5, 6); // This line gives error Unable to find an entry point
Can any body tell what i am missing?
Thanks.
If you are exporting a C function from a native DLL, you may want to use the __stdcall calling convention (which is equivalent to WINAPI, i.e. the calling convention used by most Win32 API C-interface functions, and which is the default for .NET P/Invoke):
extern "C" MYDLL_API int __stdcall fnMultiply(int a, int b)
{
return a*b;
}
// Note: update also the .h DLL public header file with __stdcall.
In addition, if you want to avoid name mangling, you may want to export using .DEF files.
e.g. Add a .DEF file to your native DLL project, and edit its content something like this:
LIBRARY MYDLL
EXPORTS
fnMultiply #1
...
(You can use the command line tool DUMPBIN/EXPORTS, or a GUI tool like Dependency Walker, to check the actual name with which the function is exported from the DLL.)
Then you can use P/Invoke like this from C#:
[DllImport("MyDLL.dll")]
public static extern int fnMultiply(int a, int b);
Turn off name mangling for the function your exporting. Should assist greatly. Alternative you could load the name mangled (there is a way to config the DllImport attribute to do this, so I hear, but I'm not a C# engineer, so I leave that to you to find if it exists).
extern "C" IMPORTDLL_API int fnMultiply(int a , int b)
{
return (a*b);
}

Best practice to share a struct from a C# program to a C++ win32 DLL?

What is the best practice to share memory of a struct from a C# program to a C++ win32 DLL?
I've used structs in managed shared memory using Boost between two C++ programs and it worked great. I'm lost on the best way to accomplish this between where the struct gets populated in the C# program and the C++ DLL that is an SNMP subagent.
Here's the C++ DLL:
//==================== Code Excerpt from the main cpp file ======================
#include "stdafx.h"
//================= Here we are setting up the shared memory area =====================
#pragma data_seg (".SHAREDMEMORY")
struct sharedData {
int sharedA;
int sharedB;
};
static sharedData A;
#pragma data_seg()
#pragma comment(linker,"/SECTION:.SHAREDMEMORY,RWS")
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
return TRUE;
}
//=============================================================================================
//====================== Here we are writing wrappers to the shared memory area ===========================
//=You must declare it as an Extern "C" to prevent name mangling. This is absolutely necessary in order to import it into c# =
//=============================================================================================
extern "C" __declspec(dllexport) sharedData __stdcall getMyData()
{
A.sharedA = 1237;
A.sharedB = 31337;
//return gshared_nTest;
return A;
}
extern "C" __declspec(dllexport) void __stdcall setMyData( sharedData buff )
{
A = buff;
}
Here's the calling C# function:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace sharedMemTestCS
{
public partial class frmSharedMemTestCS : Form
{
struct sharedData {
int sharedA;
int sharedB;
};
static sharedData A;
//============== here we are importing the methods from the win32 dll into the c# console application =================
[DllImport(#"C:\Documents and Settings\My Documents\Visual Studio 2010\Projects\sharedMemTestCPP\Debug\sharedMemTestCPP.dll")]
public static extern sharedData getMyData();
[DllImport(#"C:\Documents and Settings\My Documents\Visual Studio 2010\Projects\sharedMemTestCPP\Debug\sharedMemTestCPP.dll")]
public static extern void setMyData(int data);
public frmSharedMemTestCS()
{
InitializeComponent();
//============== here i am incrementing the value =================
//== i use a message box so that i can have multiple console applications running at once and it will pause at the messagebox (if i don't click ok)
//== i do this so i can see the values changing in the shared memory.
//MessageBox.Show( getMyData().ToString() );
getMyData();
//txtBoxA.Text = (getMyData().ToString() );
}
private void btnAdd_Click(object sender, EventArgs e)
{
//setMyData( getMyData() + 100 );
//txtBoxA.Text = (getMyData().ToString() );
}
}
}
The error message I get is:
Error 1 Inconsistent accessibility: return type
'sharedMemTestCS.frmSharedMemTestCS.sharedData' is less accessible
than method
'sharedMemTestCS.frmSharedMemTestCS.getMyData()' c:\documents and
settings\mconrad\my documents\visual studio
2010\Projects\sharedMemTestCS\sharedMemTestCS\Form1.cs 23 37 sharedMemTestCS
The best practice for sharing memory would be to use the MemoryMappedFile class in C# and CreateFileMapping/MapViewOfFile in C++.
First thing, you cannot straightway use Boost for data sharing. You need to have some well-defined data-structures that you share between the managed and unmanaged worlds.
You may start here
Well your actual problem is your p/invoke expression is public but your struct is private, which is what the error is telling you. Making your p/invoke expression private or your struct public will resolve the immediate issue.
As for the actual data sharing, I've never tried doing it quite like that so I can't tell you if it will or won't work. All the pieces I've worked with are marshalled back and forth. Looking at your example code, it's quite possible it could work. You'll probably want to either copy the data to a new struct for c# or pin your struct that you get back so the GC won't move it around in memory.

Categories

Resources