SEHException with simple DLL - c#

I am currently trying to use a simple C++ DLL in a C# program for a school project but I have trouble making the DLL and Program link with each other. When I try to call the DLL's function in the main program, I get a SEHExcpetion thrown from the DLL.
Here is the DLL code
#include <stdio.h>
#include <string>
using namespace std;
extern "C"
{
__declspec(dllexport) string Crypter(string sIn)
{
return sIn+ " from DLL";
}
}
And here's the C# code
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 WindowsFormsApplication1
{
public partial class Form1 : Form
{
[DllImport("CryptoDLL2.dll")]
public static extern string Crypter(string sIn);
public Form1()
{
InitializeComponent();
}
private void BTN_Crypter_Click(object sender, EventArgs e)
{
TB_OUT.Text = ("");
TB_OUT.Text = Crypter(TB_IN.Text); //exception thrown here
}
}
}

Strings in C# and C++ - Those are completely different types, layouts, etc. And you expect them to work.
Check out char* with marshalling.

you cannot use std::string from C#, it is a c++ class, .NET does not know how to handle it.
Try using wchar_t* or BSTR.

I did a test to make sure the linking was fine, here is a sample app showing it does work.
#include <stdio.h>
#include <string>
using namespace std;
extern "C"
{
__declspec(dllexport) string Crypter(string sIn)
{
printf("test");
return "from DLL";
}
}
And
public class Test
{
[DllImport("TestDll.dll")]
public static extern string Crypter(string sIn);
static void Main(string[] args)
{
Console.WriteLine(Crypter("a"));
}
}
This prints me out
test
followed by a newline.
You need to probably marshal the data from c++ to .net, or use a c++/clr managed dll which would make things easier on you.

Related

Calling integer method works but string method return null when call DLL from C++ in C#

I am trying to implement a CLR concept on C++ and C#. I am create two simple method on C++.
this is test.cpp as main file
#include <iostream>
#include "test.h"
using namespace std;
string SayHi(){
return "hi";
}
int CallNumber(){
return 911;
}
This is test.h as header
#include <iostream>
using namespace std;
#define EXPORT_API __declspec(dllexport)
extern "C" EXPORT_API string SayHi();
extern "C" EXPORT_API int CallNumber();
Then I compile them using
g++ -shared -o test.dll test.cpp
On my C# program, I try to call them
using System;
namespace Test.Main
{
class Program
{
[DllImport(#"test.dll")]
public static extern string SayHi();
[DllImport(#"test.dll")]
public static extern int CallNumber();
static void Main(string[] args)
{
Console.WriteLine(SayHi());
Console.WriteLine(CallNumber());
Console.ReadKey();
}
}
}
This program show
`dDO↓☻
911
The 911 integer works perfectly but the string show weird thing. And that 'dDO↓☻ always change every time I run the C# program.
I am using
G++ version 9.4.0
.Net Framework 4.8
Is there something I miss here? Any help appreciated. Thanks.

Call c++ DLL from C# application

I have C# as my front end application and I want to call c++ dll from my c# but I am getting error.
I am posting my code here please help me out how to resolve this:
Program.cs
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestCSharp
{
class Program
{
[DllImport("C:\\Users\\xyz\\source\\repos\\Project1\\Debug\\TestCpp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void DisplayHelloFromDLL(StringBuilder name, int appId);
static void Main(string[] args)
{
try
{
StringBuilder str = new StringBuilder("name");
DisplayHelloFromDLL(str, str.Length);
str.Clear();
}
catch(DllNotFoundException exception)
{
Console.WriteLine(exception.Message);
}
catch(Exception exception)
{
Console.WriteLine("General exception " + exception.Message);
}
finally
{
Console.WriteLine("Try again");
}
}
}
}
and cpp code like below:
Header: source.h
#include <string>
using namespace std;
extern "C"
{
namespace Test
{
class test
{
public:
test();
__declspec(dllexport) void DisplayHelloFromDLL(char * name, int appId);
}
}
}
c++ class: source.cpp
#include <stdio.h>
#include "source.h"
Test::test::test()
{
printf("This is default constructor");
}
void Test::test::DisplayHelloFromDLL(char * name, int appId)
{
printf("Hello from DLL !\n");
printf("Name is %s\n", name);
printf("Length is %d \n", appId);
}
Code is building successfully but when I run this I got Unable to find an entry point named 'DisplayHelloFromDLL' in DLL.
Same CPP code when I am writing without using namespace and class, it is working fine.
i.e.
Header: source.h
extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL(char * name, int appId);
}
c++ class: source.cpp
#include "source.h"
void DisplayHelloFromDLL(char * name, int appId)
{
printf("Hello from DLL !\n");
printf("Name is %s\n", name);
printf("Length is %d \n", appId);
}
So how do I use DLL which has namespaces and claases in my c# application.
Thanks for the answers.
I resolved the issue by making one extra class(Wrapper class) that contains the managed code. This wrapper class is called by the c# classes in the same way as I mentioned in the question. This wrapper class than call the c++ class and return the result to the UI.
The easiest way is to create a "proxy": set of clear-C functions, these will call your c++ functions.
I think calling c++ function is not good idea: name decoration is changed from version to version of compiler.
Do you have this project hosted somewhere?
On the first view I would say that you need to build the c++ project first (only the c++!!!) and then run the C# project.
Perhaps you would like to have a look here: Testprojects
Especially the "MessageBox" stuff shows how to use C++ with C#. There are some Testprojects with UWP as well.

Basic C# GUI crashes in main

I have a very basic unmanaged C++ project, C++/CLI wrapper and C# GUI. I've built all 3 projects as x64. I try and run the C# project and I get the following exception:
First-chance exception at 0x000007fefd84cacd in TestAppGUI.exe:
Microsoft C++ exception: EEFileLoadException * __ptr64 at memory
location 0x0057b498.
Does anyone know what could be causing the issue?
These are my classes:
Test.h (unmanaged code)
#define DllExport __declspec( dllexport )
#include <iostream>
namespace Test
{
class DllExport BasicTest
{
public:
BasicTest();
~BasicTest();
};
}
Test.cpp
#include "Test.h"
Test::BasicTest::BasicTest()
{
}
Test::BasicTest::~BasicTest()
{
}
TestCLR.h (wrapper)
// TestCLR.h
#pragma once
#include "../TestApp/Test.h"
using namespace System;
using namespace Test;
namespace TestCLR {
public ref class Class1
{
// TODO: Add your methods for this class here.
public:
Class1();
private:
BasicTest *bsTest;
};
}
TestCLR.cpp
// This is the main DLL file.
#include "stdafx.h"
#include "TestCLR.h"
TestCLR::Class1::Class1()
{
bsTest = new BasicTest();
}
TestAppGUI Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using TestCLR;
namespace TestAppGUI
{
public partial class Form1 : Form
{
Class1 obj = new Class1();
public Form1()
{
InitializeComponent();
}
}
}

Calling C# method within a Java program

C# methods cannot be called directly in Java using JNI due to different reasons. So first we have to write a wrapper for C# using C++ then create the dll and use it through JNI in Java.
I have problem in calling C# code in C++. I'm adding C# .netmodule file to a C++ project. Code is pasted below. Please guide me if i'm doing anything wrong.
This is my managed C++ class UsbSerialNum.h:
#using <mscorlib.dll>
#include <iostream>
#using "UsbSerialNumberCSharp.netmodule"
using namespace std;
using namespace System;
public __gc class UsbSerialNum
{
public:
UsbSerialNumberCSharp::UsbSerialNumberCSharp __gc *t;
UsbSerialNum() {
cout<<"Hello from C++";
t = new UsbSerialNumberCSharp::UsbSerialNumberCSharp();
}
void CallUsbSerialNumberCSharpHello() {
t->hello();
}
};
C# UsbSerialNumberCSharp.cs file from which i've created the .netmodule file:
using System.Collections.Generic;
using System.Text;
namespace UsbSerialNumberCSharp
{
public class UsbSerialNumberCSharp
{
public UsbSerialNumberCSharp(){
Console.WriteLine("hello");
}
public static void hello()
{
Console.WriteLine("hello");
}
public void helloCSharp ()
{
Console.WriteLine("helloCSharp");
}
}
}
Here is my main makeDLL.cpp file from which makeDLL.dll is created:
#include "jni.h"
#include <iostream>
// This is the java header created using the javah -jni command.
#include "testDLL.h"
// This is the Managed C++ header that contains the call to the C#
#include "UsbSerialNum.h"
using namespace std;
JNIEXPORT void JNICALL Java_testDLL_hello
(JNIEnv *, jobject) {
// Instantiate the MC++ class.
UsbSerialNum* serial = new UsbSerialNum();
serial->CallUsbSerialNumberCSharpHello();
}
Here is my java class:
public class testDLL {
static {
System.loadLibrary("makeDLL");
}
/**
* #param args
*/
public static void main (String[] args) {
// new testDLL().GetUSBDevices("SCR3", 100);
new testDLL().hello();
}
public native void hello();
}
EDIT:
If i simply ignore the call to UsbSerial.h in my main file i.e. use simple C++ then my code is working fine in Java. Basically C++ managed class is not working properly.
Please guide me. Thanks.
It would be useful to know what you need this interoperability for exactly. In any case, you should look into IKVM; alternatively you can (as has been suggested for a similar problem) use COM as a bridge: expose the C#/CLR as a COM interface and then use com4j in Java.
You can avoid C# and still can query WMI using C++ only. See Using WMI to call method on objects

Returning Struct from VC++ to C#

I have written a structure in VC++. I have made a dll of the VC++ code and calling this dll in C# using PInvoke.
The VC++ dll looks like this
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <iostream>
#if defined(_MSC_VER)
#include <windows.h>
#define DLL extern "C" __declspec(dllexport)
#else
#define DLL
#endif
struct SYSTEM_OUTPUT
{
int status;
};
DLL SYSTEM_OUTPUT* getStatus()
{
SYSTEM_OUTPUT* output;
output->status = 7;
return output;
}
I am calling the getStatus() function from the dll in my C# code, which looks as follows;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace UsingReturnStructDLL
{
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_OUTPUT
{
[MarshalAs(UnmanagedType.I4)]
int Status;
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public SYSTEM_OUTPUT output;
[DllImport("ReturnStructDLL", EntryPoint = "getStatus")]
[return: MarshalAs(UnmanagedType.Struct)]
public extern static SYSTEM_OUTPUT getStatus();
private void button1_Click(object sender, EventArgs e)
{
try
{
SYSTEM_OUTPUT output = getStatus();
}
catch (AccessViolationException e)
{
label1.Text = e.Message;
}
}
}
}
I want to retrieve the values in the struct in my C# code. With the above setup of my code, I am getting the following error;
Cannot marshal 'return value': Invalid managed/unmanaged type combination (Int32/UInt32
must be paired with I4, U4, or Error).
Can someone please help me with the issue?
Thanks.
Make your C++ code work first. It is junk as posted, you don't initialize the pointer. It will crash with an AccessViolation.
Returning pointers to structures is very hard to get right in C/C++ as well, the client of your code won't know how the memory needs to be released. Which plays havoc on the P/Invoke marshaller as well, it is going to try to release the pointer with CoTaskMemFree(). That's a kaboom on Vista and up, a memory leak on XP.
All of these problems disappear if you let the client pass a pointer to the structure as an argument:
void getStatus(SYSTEM_OUTPUT* buffer)
Which then in C# becomes:
[DllImport("mumble.dll")]
private static extern void getStatus(out SYSTEM_OUTPUT buffer);

Categories