AccessViolationException when calling C++/CLI wrapper from C# - c#

I am trying to create a C++/CLI wrapper for passing class objects from unmanaged C++ DLL into managed C# code (which subsequently displays the content of the objects on web pages). I have this function in the unmanaged C++ code:
ProbeState _cdecl ManagerAPI::getProbeState()
{
ProbeState ps = psdao.getLastProbeStateByProbeId(1);
return ps;
}
I call the function in the C++/CLI wrapper:
using namespace System;
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "../ManagerApp/ProbeState.h"
typedef ProbeState(*PSFunc)(void);
public ref class ManagerAPIWrapper
{
private:
HINSTANCE managerApp;
public:
ManagerAPIWrapper()
{
managerApp = LoadLibrary(L"ManagerApp.dll");
}
System::String^ testFunc()
{
PSFunc psFunc = (PSFunc)GetProcAddress(managerApp, "?getProbeState#ManagerAPI##QAA?AVProbeState##XZ");
ProbeState *ps = new ProbeState(psFunc());
System::String ^s = gcnew System::String(ps->getName().c_str());
delete ps;
return s;
}
};
And finally I call the wrapper from my C# controller:
ManagerAPIWrapper.ManagerAPIWrapper wrapper = new ManagerAPIWrapper.ManagerAPIWrapper();
ViewBag.DllMessage = wrapper.testFunc();
It always throws an exception on the line ProbeState *ps = new ProbeState(psFunc());
Strange thing, though, is when I compile the C++/CLI wrapper as a console application with added main function:
int _tmain(int argc, _TCHAR* argv[])
{
ManagerAPIWrapper::ManagerAPIWrapper wrapper;
System::Console::WriteLine(wrapper.testFunc());
getchar();
return 0;
}
This code works just fine and prints out the name of the state retrieved from the database by the C++ DLL. How come the C++/CLI works in console app and throws an exception when called from C#?
P.S.: The wrapper is compiled with /clr option. When I compiled the wrapper with /clr:pure, the exception was the same as with the C# call. Does it mean that when the wrapper is compiled within and called from C# app, it takes the pure option?
The wrapper is meant to convert the data between C++ and C#, so according to my opinion it should not be compiled with more strict options in the C# app. Is there any way to tell the C# compiler that this assembly contains mixed code?

OK, I finally got through this. After many hours spent with try&fail way of finding a solution, I tried to call a function from the unmanaged DLL directly from the C# code first, and then called a constructor of the wrapper, which succeeded in the LoadLibrary call. Code in the C# controller now looks like this:
[DllImport("C:\\ManagerApp.dll", CharSet = CharSet.Unicode,
EntryPoint = "?initFunc#ManagerAPI##QAEHXZ")]
private static extern int initFunc();
public ActionResult APITest()
{
ViewBag.Message = "API output test page.";
if (initFunc() == 0)
{
ViewBag.Error = "Could not initialize the library.";
return View();
}
ManagerAPIWrapper.ManagerAPIWrapper wrapper = new ManagerAPIWrapper.ManagerAPIWrapper();
ViewBag.DllMessage = wrapper.testFunc();
return View();
}
I am thinking it might help to add a dependency to the wrapper DLL on the unmanaged DLL and therefore get rid of the necessity of calling the initFunc.

Related

How to call C++ code, and the code it calls, from C#

TL;DR
I have legacy c++ code which does stuff (sometimes returns stuff), calls other cpp code, but is not a full class/obj. This code I cannot alter. I am making fresh c# code which I am looking to call the c++ code from. I don't understand whether to create a dll that calls the original legacy c++, or create a CLR?? which also calls the legacy cpp. Below I have example code that I have implemented (with problems).
Main
I have legacy.cpp and legacy.h which I can not alter.
This is not a class/object and only has public functions, values, and #defines.
legacy.cpp and .h both #include other files and cpp libraries to do its job.
I have a new project where I can add C#, C++ code
I am having trouble understanding what I need to do/research in order to call any of the functions defined in legacy.cpp (or the values/defines) from within my new C# code.
Some of what I have looked at include
Managed CLR wrappers
https://drthitirat.wordpress.com/2013/06/03/use-c-codes-in-a-c-project-wrapping-native-c-with-a-managed-clr-wrapper/
https://web.archive.org/web/20140806022309/http://blogs.msdn.com/b/borisj/archive/2006/09/28/769708.aspx
DLLs??
How to call C++ DLL in C#
CLR
I have currently tried to create a CLR (thought I feel like it is not what I need in this situation), but I had problems in the clr_wrapper.cpp, it could not find the reference to foo()
//Wrapper.cpp
#include "Wrapper.h"
#include "abs\path\to\legacy\code\legacy.h"
#include "abs\path\to\legacy\code\legacy.cpp"
int foo_Wrapper()
{
return foo(); //int foo() is declared in legacy.h and defined in legacy.cpp
}
#pragma once
#include "abs\path\to\legacy\code\legacy.h"
#include "abs\path\to\legacy\code\legacy.cpp"
using namespace System; //What things use this?
//Can I just prepend System:: to whatever needs it?
namespace Wrapper {
public ref class Wrapper
{
public:
int foo_Wrapper();
};
}
the foo_Wrapper() is not able to call foo().
My confusion with this method is that it looks like I would need to make the clr wrapper an object class with member functions that will be called as needed. Leading to a syntax of obj.foo(). Is this what needs to be done if I chose to do some sort of CLR wrapper?
DLL
I have also looked at making this all a dll like in (How to call C++ DLL in C#)
However I am confused on setting this up. My current idea is to have a cpp dll call the original cpp (ie create legacyDll.dll which would make calls to foo(), then my main c# would call the __declspec(dllexport) functions defined within extern "C" {}
current setup (from "How to call c dll in c sharp")
dllmain.cpp
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <iostream>
#include <Windows.h>
using namespace std;
extern "C"
{
__declspec(dllexport) void bar_Dll()
{
cout << "calling bar() in legacy code" << endl;
}
__declspec(dllexport) int foo_Dll()
{
cout << "calling foo() in legacy code" << endl;
//realistically I would have,
//return foo()
}
}
Class1.cs
using System;
using System.Runtime.InteropServices;
namespace Test_DLL_Calling
{
class Class1
{
[DllImport("dllmain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void bar_Dll();
[DllImport("dllmain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int foo_Dll();
public static void Main(string[] arg)
{
bar_Dll(); //The specified module could not be found (Exception)
Console.WriteLine(foo_Dll()); //Im guessing this will also ^^
}
}
}
This part I don't follow. What and why are the attributes done the way they are?
Alright, so you have a header and cpp which you need to use. In order to use it you have to have make the c++ into C code. This is pretty much what you see in the DLL example code that you showed. However, I do suggest that you remove the includes from the header as I'm unsure how that would translate to the C code. Put the includes in the cpp files instead.
I find it rather difficult to answer this questions other than just showing a whole bunch of example code. Full code in: https://github.com/ze413X/Cpp-Code-Gems/ Where "CSharpExampleUsingCpp" calls from MainWindow.xaml.cs the "DLLExample" which uses the file in the directory includes and source.
DLL:
The header which is exposing functions to be used:
#pragma once
#define DLLExport _declspec(dllexport)
extern "C" DLLExport void __cdecl GetCppText(char* str, int* strLength);
extern "C" DLLExport void __cdecl DLLPrint();
.cpp
#include "../includes/DLLExampleCode.h"
#include <string>
#include <iostream>
void __cdecl GetCppText(char* str, int* strLength)
{
std::string text = "This is called from within the DLL.\0";
if (*strLength < text.length() || str == nullptr)
{
return;
}
memset((void*)str, 0, (*strLength) * sizeof(char));
strcpy_s(str, *strLength,text.c_str());
*strLength = text.length();
}
void __cdecl DLLPrint()
{
std::cout << "This is printed from inside DLLExample.dll.\n";
}
C#:
using System.Runtime.InteropServices;
namespace CSharpExampleUsingCpp
{
public partial class MainWindow : Window
{
const string PATH = "DLLExample.dll";
[DllImport(PATH, CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void GetCppText(byte[] str, out System.Int32 strLength);
....
private void CppInteropButton_Click(object sender, RoutedEventArgs e)
{
System.Int32 size = 256;
System.Byte[] str = new byte[size];
for (int i = 0; i < size; i++)
{
str[i] = (byte)'1';
}
GetCppText(str, out size);
string result = System.Text.Encoding.UTF8.GetString(str, 0, size);
CppInteropButtonTextBox.Text = result;
}
Although, rereading my solution of obtaining a string might not be the best way of doing it. You could probably marshal that thing to avoid all this stupid char* conversions. I probably had some good reason at that point in time when I wrote it. That should be much easier to google though.

Passing Pointer between C++ Project and C# Project without using unsafe on C# project

Stuck in very naive issue. I have two project, One in C++ and other in C#. Idea is to use C++ project as wrapper around some C libs. and performing actual logic in C#.
Passing the Value type is very convenient. But with reference type i am having hard time WITHOUT USING unsafe or DllImport attribute.
C++
Cryptoki.Wrapper.h File
using namespace System;
#pragma comment(lib, "legacy_stdio_definitions.lib")
namespace CryptokiWrapper {
public ref class CryptokiInit
{
public:
char* TESTString(char* test);
double TESTDouble(double test);
};
}
Cryptoki.Wrapper.cpp File
#include "stdafx.h"
#include "Cryptoki.Wrapper.h"
using namespace std;
using namespace CryptokiWrapper;
char* CryptokiInit::TESTString(char* test)
{
char* r = test;
return r;
}
double CryptokiInit::TESTDouble(double test)
{
unsigned long int r = test;
return r;
}
C# Code
using System;
using System.Runtime.InteropServices;
using CryptokiWrapper;
namespace CallCryptoki
{
class Program
{
//[MarshalAs(UnmanagedType.LPTStr)]
//public String msg = "Hello World";
static void Main(string[] args)
{
CryptokiInit ob = new CryptokiInit();
//This Works
doubled d = ob.TESTDouble(99);
//But having hard time accepting the char* reference
//or sending string as refrence without using unsafe
// like
string text = "Hello World!";
string res = (*something*)ob.TESTString((*something*)text);
}
}
}
IS there any type of cast (i.e. something) .....
is there anyway where i am able to easily perform this action. (only reference transfer will be sufficient, then i can build string or object)
Like on another function works, using the double as parameter and return type.
Though above example speak of string only, but would like to understand as concept so that i could write interop for any reference type between two project(i.e. C# and C++)
Thanks in advance for help!
First, that's not plain C++, but C++/CLI - which is primarily designed for managed/unmanaged code interoperability.
Your C++/CLI function can use .NET's string type like this:
System::String^ TESTString(System::String^ test);
^ means managed reference, think of it as the managed equivalent of *.
Now, to use the string data in pure C++, you have two choices:
marshal it - see Overview of Marshaling in C++
For instance, if you need to convert it to a const char*, do the following:
#include <msclr/marshal.h>
msclr::interop::marshal_context ctx;
auto testCStr = ctx.marshal_as<const char*>(test);
// testCStr is freed when ctx goes out of scope
This will copy the string data, as the memory representation needs to change from 2 bytes par character to a single one.
access the memory directly as const wchar_t*. You need to pin the string beforehand so it's not moved by the GC.
#include <vcclr.h>
pin_ptr<const wchar_t> testCStr = PtrToStringChars(test);
// testCStr behaves just like a const wchar_t*
Do not modify the string data this way.
To send a string back to the managed side, you can either use marshal_as<System::String^>(yourCString), or call gcnew System::String(yourCString);

Is gcroot and /clr mixed mode and a C++ wrapper the shortest path from pure C to C#?

So I am writing a plug-in DLL which is pure C (and a heap of foreign includes), but most of the real code is in an existing C# class library. I'm looking for the shortest path from C (not C++) to C#. The foreign includes are not C++ safe.
There are heaps of samples around for C++, not much for pure C.
It seems I should be able to compile the whole DLL as /clr but compile the C as not; then include in the same DLL a C++ wrapper that presents a C API but contains managed code to call the C# class.
So instantiate the C# class and hang onto it in a gcroot in a C++ class, and pass the C++ class pointer as a void* back for the the C code to keep for future calls.
Quite a few details to get right, but not all that much code. Is there a better way?
Thought it was time to add a bit of code.
// Wrapper.h
#pragma once
// API for call by C
#ifdef __cplusplus
extern "C" {
#endif
void* wrap_create();
void wrap_doit(void* wrapper, char* input, char* output, int maxlen);
#ifdef __cplusplus
}
#endif
// Wrapper.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <vcclr.h>
#include "Wrapper.h"
using namespace System;
class Wrapper {
public:
gcroot<Wrappee::Evaluator^> eval;
Wrapper() {}
};
void* wrap_create() {
Wrapper* w = new Wrapper();
w->eval = gcnew Wrappee::Evaluator();
return w;
}
void wrap_doit(void* wrapper, char* input, char* output, int maxlen) {
Wrapper* w = (Wrapper*)wrapper;
String^ s = w->eval->Doit(gcnew String(input));
pin_ptr<const wchar_t> wch = PtrToStringChars(s);
wcstombs(output, wch, maxlen);
}
// Wrappee.cs
using System;
namespace Wrappee {
public class Evaluator {
string _s;
public static Evaluator Create() {
return new Evaluator {
_s = "wrapped evaluator"
};
}
public string Doit(string s) {
return _s + ":" + s;
}
}
}
Why wouldn't that work? The code is based on this link: https://msdn.microsoft.com/EN-US/library/481fa11f%28v=VS.140,d=hv.2%29.aspx.
The answer is no, that won't work. The managed class depends on the CLR runtime, which needs to be hosted by the application. For a managed app that happens automatically (mscoree.dll during startup), but for a native app there is no host so no CLR.
So we have to provide one. As #hanspassant helpfully pointed out, this is "Reverse P/Invoke" and it really is different. You have to get there by the COM hosting interfaces, specifically ICLRMetaHost.
And the good news is that there is a sample here to show how it's done: https://code.msdn.microsoft.com/windowsdesktop/CppHostCLR-e6581ee0.
There are other samples too: search for CppHostCLR.

How to get string from managed c++ dll (using wrapper class) in c#

i have done this using unmanaged dll but having some difficulty using managed dll.
I want to pass a string to my managed c++ wrapper class which process it and return modified string
the purpose of c++ dll is to return hex code of a file(and later modifies it to do some complicated tasks within dll) which i pass it as a string, for this approcach i have used managed c++ dll instead of unmanaged one.
my c++ class is as follows :
using namespace std;
//main function - entry point of program __declspec(dllexport)
const char* hexclass:: getfilename(char* filename)
{
//to open file
ifstream::pos_type size;
string virusScanStatus;
char* fileAccessError;
string errorDes ="Exception has Occured With Current File Operation";
//hexcode logic goes here
fileAccessError = new char[errorDes.size()];
errorDes.copy(fileAccessError,errorDes.size());
return fileAccessError;
}
my c++ wrapper class is as follows :
header file including c++ file here (not shown for code readabitily)
using namespace System;
namespace CWrapperHexValue {
public ref class cWrapperHexValue
{
public:
cWrapperHexValue();
const char* hexValue;
const char* getHexValue(char* fileName);
private:
hexclass* pHexClass;
};
}
and my wrapper class is as follows :
// This is the main DLL file.
#pragma once
#include "stdafx.h"
#include "CWrapperHexValue.h"
#include "D:\Projects\program10\program10\hexclass.cpp"
#include "D:\Projects\program10\program10\hexclass.h"
CWrapperHexValue::cWrapperHexValue::cWrapperHexValue()
{
pHexClass = new hexclass();
}
const char* CWrapperHexValue::cWrapperHexValue::getHexValue(char* fileName)
{
hexValue= pHexClass -> getfilename(fileName);
return hexValue;
}
and finally my c# code to send filename is as follows :
//my c++ dll name is CWrapperHexValue
CWrapperHexValue.cWrapperHexValue objHexClass = new CWrapperHexValue.cWrapperHexValue();
byte[] fileNameBytes = Encoding.ASCII.GetBytes(fileNameForHexScan);
unsafe
{
fixed (byte* p= fileNameBytes)
{
sbyte* sp = (sbyte*)p;
sbyte* returnSp = objHexClass.getHexValue(sp);
}
}
now how do i get back the returnSp value as a string or any other better way to pass and get string, please provide useful code because i have not much experience with c++/c# cli conversion
please advice how can i improve my code for better memory management becuase i have to pass a whole lot of system files one by one and get their hex code
Depending on what
// hexcode logic
is, it might be better/easier to implement it in C# and forget about the marshaling.
If you really need to marshal strings from C++ to C#, this topic will likely help you quite a bit: How to marshall c++ char* to C# string using P/INVOKE (code is here)
Basically just build a native DLL out of your native code and you can just pinvoke it from C# rather than have the intermediate managed C++ class if all you need is a string.
In terms of memory management, if you can move the hexcode logic into C#, that would eliminate the need to marshal strings and likely save you some processing, but more importantly, be less painful to debug. Namely, why can't you do this?
C#
public void SomeFunction()
{
string filepath = "foo.bar"
string hexVal = HexCodeLogicInManaged(filepath);
... other code ...
}
private string HexCodeLogicInManaged(string filepath)
{
// hexcode logic converted from native to managed
}

How do you call a c# method in c++?

here and here they do talk about what to do, but i seem to be unable to find my c# project in c++.
I have added the c# project as a reference in the c++ project but whenever i try to use the method i need, it can't find the namespace. i have added it by right clicking the c++ project and going for 'reference' then added the c# project with add new reference. both projects are in the same solution.
In the below code excamples i have given the full c# code (except for usings) and a part of the c++ code (the method where i am trying to call the c# method from). I have also changed some of the namespacing to be more generic and contain no sensitive information.
the c# code is like this.
namespace Company.Pins.Bank.Decryption
{
public class Decrypt
{
[DllImport("decryptsn.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr decryptsn(byte[] InpData);
//__declspec(dllimport) char* decryptsn(char* InpData);
public static String Decryption(string param2)
{
byte[] InpData = new byte[255];
InpData = StrToByteArray(param2);
return Marshal.PtrToStringAnsi(decryptsn(InpData));
}
public static byte[] StrToByteArray(string str)
{
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
return encoding.GetBytes(str);
}
}
}
C++ code
CPReSInterfaceApp theApp;
extern "C" DllExport BOOL WINAPI UserInstruction(
HWND hWnd, HINSTANCE hInst, double* lpNumeric,
TCHAR* lpAlpha1, TCHAR* lpAlpha2)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (lpNumeric == NULL || lpAlpha1 == NULL || lpAlpha2 == NULL)
return FALSE;
ReconcileUHParameter(lpNumeric, lpAlpha1, lpAlpha2);
int iCommand = (int)lpNumeric[0];
lpNumeric[0] = 6;
lpAlpha2 = Company.Pins.Bank.Decryption.Decrypt.Decryption("123456");
return TRUE;
}
You need to add a #using directive to the code. For example, if your C# dll were named Decrypt.dll, add this to the top of your C++ compiland:
#using "Decrypt.dll"
You also need to make sure the C++ code that calls a managed method is also compiled as managed using the /clr compiler option.
Also, I believe you need to use :: as a namespace separator, rather than ..
lpAlpha2 = Company::Pins::Bank::Decryption::Decrypt::Decryption("123456");

Categories