VC++ DLL throws error when call it from C#[EntryPointNotFound] - c#

Here i created in DLL project in vc++ 2008. Following are two code files lib.h and lib.cpp.
lib.h
#include "stdafx.h";
class __declspec(dllexport) test
{
public:
test();
static void hello();
static void hello1();
};
class __declspec(dllexport) test1
{
public:
test1();
void hello_test1();
void hello1_test1();
};
lib.cpp
#include "stdafx.h"
#include "lib.h"
#include <stdio.h>
void test::hello()
{
printf("Hello");
}
void test::hello1()
{
printf("Hello1");
}
void test1::hello_test1()
{
printf("Hello_test1");
}
void test1::hello1_test1()
{
printf("Hello1_test1");
}
stdafx.h
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN
// Windows Header Files:
#include <windows.h>
dllMain.cpp
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I have written C# code to call the method of test and test1 classes:
ConsoleApp
[DllImport("lib.dll" )]
public static extern void hello();
[DllImport("lib.dll")]
public static extern void hello1();
[DllImport("lib.dll")]
public static extern void hello_test1();
[DllImport("lib.dll")]
public static extern void hello1_test1();
static void Main()
{
hello();
hello1();
hello_test1();
hello1_test1();
Console.ReadKey();
}
when i run above code i have got following error:
EntryPointNotFoundException: Unable to find an entry point named 'hello' in DLL 'lib.dll'
I know about how to call function only(without using Class) of vc++ DLL from C# but i don't know how to call method of any class and how to code that in proper way in vc++.
I know somewhere is mistake in my above code, please experts guide me about my mistake because i tried all from my side.
If anyone has full example like above then suggest me.
Thanks in advance..

As far as I'm aware there is no way to directly call a native class method from c#. The typical way to get around this is to make non-member functions that call the class methods and interact with those. Please refer to the following link for more specifics. It includes a direct example of what you are trying to do.
using a class defined in a c++ dll in c# code
After reading more of the answers it might be possible but it appears that the link shows the examples you are looking for.

#Jarrett Thanks for moving me towards to Marshal concept.
I added testClass.h and testClass.cpp in this project to marshal C++ classes
testClass.h
#ifndef __testClass_h__
#define __testClass_h__
#include "lib.h"
#ifdef __cplusplus
extern "C" {
#endif
extern LIBDLL_API test* createTestClass();
extern LIBDLL_API void disposeTestClass(test* pObject);
extern LIBDLL_API void callHello(test* pObject);
extern LIBDLL_API void callHelloTest1Class(test1* pObject);
#ifdef _cplusplus
#endif
}
#endif
testClass.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "stdafx.h"
#include "testClass.h"
extern "C" LIBDLL_API test* createTestClass()
{
return new test();
}
extern "C" LIBDLL_API void disposeTestClass(test* pObject)
{
if(pObject!=NULL)
{
delete pObject;
pObject=NULL;
}
}
extern "C" LIBDLL_API void callHello(test* pObject)
{
if(pObject!=NULL)
{
pObject->hello();
}
}
extern "C" LIBDLL_API void callHelloTest1Class(test1* pObject)
{
if(pObject!=NULL)
{
pObject->hello_test1();
}
}
lib.h
#include "stdafx.h";
#ifdef LIB_EXPORTS
#define LIBDLL_API __declspec(dllexport)
#else
#define LIBDLL_API __declspec(dllimport)
#endif
class LIBDLL_API test
{
public:
test();
virtual ~test();
static void hello();
static void hello1();
};
class LIBDLL_API test1
{
public:
test1();
void hello_test1();
void hello1_test1();
};
lib.cpp
#pragma once
#include "stdafx.h"
#include "lib.h"
#include <stdio.h>
#include <iostream>
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
test::test()
{}
test::~test()
{}
void test::hello()
{
printf("\nHello");
}
void test::hello1()
{
printf("Hello1");
}
void test1::hello_test1()
{
printf("\nHello_test1");
}
void test1::hello1_test1()
{
printf("Hello1_test1");
}
And now create a console application and add some code in program.cs file
Program.cs
namespace ConsoleApplication1
{
class ConsoleApplication1
{
static void Main()
{
CS_Test_Class testClass = new CS_Test_Class();
testClass.hello();
testClass.hello_test1();
Console.ReadKey();
testClass.Dispose();
}
}
}
program.cs call the method of CS_Test_Class.cs So....
CS_Test_Class.cs
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
public class CS_Test_Class:IDisposable
{
[DllImport("lib.dll")]
public static extern IntPtr createTestClass();
[DllImport("lib.dll")]
static private extern void disposeTestClass(IntPtr pTestClassObject);
[DllImport("lib.dll")]
static private extern void callHello(IntPtr pTestClassObject);
[DllImport("lib.dll")]
static private extern void callHelloTest1Class(IntPtr pTestClassObject);
private IntPtr nativeObject;
public CS_Test_Class()
{
this.nativeObject = createTestClass();
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool bDisposing)
{
disposeTestClass(this.nativeObject);
this.nativeObject = IntPtr.Zero;
if (bDisposing)
GC.SuppressFinalize(this);
}
~CS_Test_Class()
{
Dispose(false);
}
public void hello()
{
callHello(this.nativeObject);
}
public void hello_test1()
{
callHelloTest1Class(this.nativeObject);
}
}
}
Marshling allows you to acces the class and method of c++ Dll. Microsoft provides facility to Marshal C-functions and also provides the mechanism to Marshal c++ clases.
Enjoy Marshling...
Thank you.

Related

Swig : How to get string in a callback

I achieved interoperability between C# & C++ using SWIG.
However, the C ++ to C # callback does not work properly.
If you pass "std::wstring" to the callback on the C++ side, it will be treated as a "string" on the C# side, but only the first character of the string passed on the C++ side will be stored.
My goal is using "std::string" in argument of callback.
Creating a base class with virtual function in C++ and derive a class in C# which implement the virtual method.
I referred to this link.
Callback from C++ to C# using SWIG
My code what callback from C++ to C# using SWIG is following.
C++ : Header.h
#include <string>
#include <vector>
class CallbackBase
{
public:
virtual void Callback(const std::wstring& str) = 0;
};
class CppClass
{
public:
void SetString(const std::wstring &str);
std::wstring GetString();
void SetCallback(CallbackBase& callbackObject);
void ExeCallback();
private:
std::wstring string;
CallbackBase* pCallbackObj = NULL;
void InvokeCallback();
};
typedef CppClass* (*GetInstanceFuncPointer)(void);
extern "C" __declspec(dllexport) CppClass * CreateInstance(void);
C++ : Impl.cpp
#include <thread>
#include "Header.h"
void CppClass::SetString(const std::wstring& str)
{
string = str;
}
std::wstring CppClass::GetString()
{
return string;
}
void CppClass::SetCallback(CallbackBase &callbackObj)
{
pCallbackObj = &callbackObj;
}
void CppClass::ExeCallback()
{
std::thread *th = new std::thread(&CppClass::InvokeCallback, this);
th->join();
}
void CppClass::InvokeCallback()
{
if (pCallbackObj != NULL)
{
pCallbackObj->Callback(string);
}
}
__declspec(dllexport) CppClass* CreateInstance(void)
{
return new CppClass;
}
Swig : Interface file
%include <windows.i>
%include <wchar.i>
%include <std_wstring.i>
%module (directors="1") MyDLL
%{
#include "Header.h"
%}
%feature("director") CallbackBase;
%include "Header.h"
C# : main.cs
using System.Diagnostics;
namespace CsharpApp
{
public class MyCallback : CallbackBase
{
public override void Callback(string str)
{
Debug.WriteLine($"str = {str}"); // --> str = H
}
}
class Program
{
static void Main(string[] args)
{
MyCallback myCallbackObj = new MyCallback();
CppClass instance = MyDLL.CreateInstance();
string str = "Hello World!";
instance.SetString(str);
Debug.WriteLine($"str = {instance.GetString()}"); // --> str = Hello World!
instance.SetCallback(myCallbackObj);
instance.ExeCallback();
}
}
}
I'm getting the string twice on the C# side.
The first is "GetString()" in the main function.
In this case, "Hello World!" Is stored.
The second time I get it as an argument of the callback function.
In this case, only "H" is stored.
How can I correctly store the string in the callback function argument?

GO redirect STD error from C# managed side

I have a test code that has this stack C#->C->GO->C#(ERROR HERE).
Whenever an error happens on C# and if that C# code is called by GOLANG the error is not redirected to error.std file. However, if I start the code from VS with the attached debugger the error is redirected to the file.
C#:
Program.cs
class Program {
[DllImport("gotestDLL.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern void Error();
[DllImport("gotestDLL.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern void SetCSharpPointerHandler(IntPtr ptr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate IntPtr CSharpPointerHandler(IntPtr message);
private static CSharpPointerHandler _messageHandlerCb = new CSharpPointerHandler(SomeMethodWithError);
private static IntPtr _messageHandlerCbPtr = Marshal.GetFunctionPointerForDelegate(_messageHandlerCb);
static void Main(string[] args) {
SetCSharpPointerHandler(_messageHandlerCbPtr);
Console.WriteLine("|-C#->START OF C#");
Error();
Console.WriteLine("|-C#->Waiting for program to crash");
do {
} while (true);
}
private static IntPtr SomeMethodWithError(IntPtr messagePtr) {
Console.WriteLine("|-C#->Back to C#");
var a = 0;
Console.WriteLine("|-C#->ERROR HAPPENS HERE C#");
var b = 10 / a;
Console.WriteLine(b);
return IntPtr.Zero;
}
}
C:ctestdll.C
#include <stdio.h>
#include "gotestDLL.h"
void Error() {
printf("|-C--->START OF C\n");
RedirectStdError();
printf("|-C--->START ERROR\n");
StartError();
printf("|-C--->END START ERROR\n");
printf("|-C-->END OF C\n");
}
int main() {
}
H:ctestDLL.h
#include <stdio.h>
#include <stdbool.h>
typedef char* CSharpPointerHandler(char* query);
static inline char* RunCSharpPointerHandler(CSharpPointerHandler* handler, char* in) {
return handler(in);
}
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) void SetCSharpPointerHandler(CSharpPointerHandler* handler);
__declspec(dllexport) void Error();
#ifdef __cplusplus
}
#endif
GO:gotestDLL.go
package main
/*
#include<stdio.h>
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include "ctestDLL.h"
*/
import "C"
import "fmt"
import "os"
var queryHandler *C.CSharpPointerHandler = nil
//export SetCSharpPointerHandler
func SetCSharpPointerHandler(handler *C.CSharpPointerHandler) {
queryHandler = handler
}
//export StartError
func StartError() {
inc := C.CString("TEST")
fmt.Println("|-GO--->Calling Handler from GO->C#")
C.RunCSharpPointerHandler(queryHandler, inc)
fmt.Println("|-GO--->END Calling Handler from GO")
}
//export RedirectStdError
func RedirectStdError() {
f, err := os.OpenFile("error.std", os.O_WRONLY | os.O_CREATE | os.O_SYNC, 0777)
if err != nil {
fmt.Println("os.OpenFile")
}
newfd := C._open_osfhandle(C.intptr_t(f.Fd()), C._O_APPEND | C._O_TEXT)
if newfd == C.int(-1) {
fmt.Println("failed to create osfhandle: _open_osfhandle(%v, _O_APPEND|_O_TEXT)", C.intptr_t(f.Fd()))
}
stderr_fd := C._fileno(C.stderr)
forwarded := C._dup2(newfd, stderr_fd)
if forwarded == C.int(-1) {
fmt.Println("failed to duplicate stderr fd: _dup2(%v, %v): %v", newfd, stderr_fd, forwarded)
}
os.Stderr = f
}
func main() {
// Need a main function to make CGO compile package as C shared library
}
OUTPUT:
|-C#->START OF C#
|-C--->START OF C
|-C--->START ERROR
|-GO--->Calling Handler from GO->C#
|-C#->Back to C#
|-C#->ERROR HAPPENS HERE C#

c++ CLR to bridge a c++ dll with a c# application

I am trying to follow this example: http://blogs.artinsoft.net/Mrojas/archive/2008/06/19/Log4NET-for-C++.aspx
to get Log4Net running in a c++ dll.
I created an empty CLR project, changed the output type to lib, and added the following code:
//Bridge.cpp
#include <atlstr.h>
using namespace System;
/// <summary>
/// Example of how to simply configure and use log4net
/// </summary>
ref class LoggingExample
{
private:
// Create a logger for use in this class
static log4net::ILog^ log = log4net::LogManager::GetLogger("LoggingExample"); static LoggingExample()
{
log4net::Config::BasicConfigurator::Configure();
}
public:static void ReportMessageWarning(char* msg)
{
String^ data = gcnew String(msg);
log->Warn(data);
}
static void ReportMessageError(char* msg)
{
String^ data = gcnew String(msg);
log->Error(data);
}
static void ReportMessageInfo(char* msg)
{
String^ data = gcnew String(msg);
log->Info(data);
}static void ReportMessageDebug(char* msg)
{
String^ data = gcnew String(msg);
log->Debug(data);
}
};
extern "C"
{
_declspec(dllexport) void ReportMessageWarning(char* msg)
{
LoggingExample::ReportMessageWarning(msg);
}
_declspec(dllexport) void ReportMessageError(char* msg)
{
LoggingExample::ReportMessageError(msg);
}
_declspec(dllexport) void ReportMessageInfo(char* msg)
{
LoggingExample::ReportMessageInfo(msg);
}
_declspec(dllexport) void ReportMessageDebug(char* msg)
{
LoggingExample::ReportMessageDebug(msg);
}
}
I have created a c++ console application project, and added this code:
#include "stdafx.h"
#include <iostream>
#include <atlstr.h>
extern "C"
{
//log4net from the wrapper lib
_declspec(dllimport) void ReportMessageWarning(char* msg);
__declspec(dllexport) void RunTest()
{
std::string message = "hey it seems it is working";
ReportMessageWarning(_strdup(message.c_str()));
}
}
This will be a c++ dll that is called from another C# application.
I have compiled the clr lib, and linked it in the dependencies of the c++ application.
However, the c++ dll will not compile as is, giving me:
Error LNK2001 unresolved external symbol __imp_ReportMessageWarning
What have i missed here?

P/Invoke external method from C# to C++

I have written the following C++ shared library:
#include "iostream"
#if defined(_WIN32) || defined(_WIN64)
#define Q_DECL_EXPORT __declspec(dllexport)
#define Q_DECL_IMPORT __declspec(dllimport)
#else
#define Q_DECL_EXPORT
#define Q_DECL_IMPORT
#endif
#ifdef MATINCHESS_LIBRARY
# define MATINCHESS_API Q_DECL_EXPORT
#else
# define MATINCHESS_API Q_DECL_IMPORT
#endif
using namespace std;
string* memory;
extern "C"
{
MATINCHESS_API void Initialize();
MATINCHESS_API void Uninitialize();
MATINCHESS_API void Put(string text);
MATINCHESS_API string Get();
void Initialize()
{
memory = new string;
}
void Uninitialize()
{
delete memory;
}
void Put(string text)
{
memory->assign(text);
}
string Get()
{
return *memory;
}
}
And here is my C# console application:
using System;
using System.Runtime.InteropServices;
namespace MatinChess
{
class MainClass
{
const string MatinChessDLL = "libMatinChessDLL.so";
[DllImport(MatinChessDLL)]
public static extern void Initialize();
[DllImport(MatinChessDLL)]
public static extern void Uninitialize();
[DllImport(MatinChessDLL)]
public static extern void Put(string text);
[DllImport(MatinChessDLL)]
public static extern string Get();
public static void Main (string[] args)
{
Console.WriteLine ("Initializing...");
Initialize ();
Console.WriteLine ("Initialized");
Console.WriteLine ("Write: ");
Put (Console.ReadLine ());
Console.WriteLine ("Value is put.");
Console.WriteLine ("You wrote \"" + Get () + "\"");
Console.ReadKey ();
Console.WriteLine ("Uninitializing...");
Uninitialize ();
Console.WriteLine ("Uninitialized");
}
}
}
It safely initializes and puts the string from ReadLine, but when it wants to invoke Get method, it crashes with a long stack trace.
Please help me to find the issue.
You cannot marshal std::string from C++ to C#. You have to use a character buffer. See this question: Passing strings from C# to C++ dll and back -- minimal example

NUnit does not capture output of std::cerr

I have an nunit Test in C#, that calls a C# wrapper of a function in a C++ DLL.
The C++ code uses std::cerr to output various messages.
These messages cannot be redirected using nunit-console /out /err or /xml switch.
In nunit (the GUI version) the output does not appear anywhere.
I would like to be able to see this output in nunit (GUI version).
Ideally I would like to be able to access this output in the Test.
Thanks for any help.
Redirecting std::cerr is a matter of replacing the stream buffer with your own.
It is important to restore in original buffer before we exit. I don't know what your wrapper looks like, but you can probably figure out how to make it read output.str().
#include <iostream>
#include <sstream>
#include <cassert>
using namespace std;
int main()
{
streambuf* buf(cerr.rdbuf());
stringstream output;
cerr.rdbuf(output.rdbuf());
cerr << "Hello, world!" << endl;
assert(output.str() == "Hello, world!\n");
cerr.rdbuf(buf);
return 0;
}
Thanks for the hint.
This is what I ended up doing:
.CPP file ------------------------
#include <iostream>
#include <sstream>
static std::stringstream buffer;
static std::streambuf * savedBuffer = NULL;
extern "C" __declspec(dllexport) bool Redirect()
{
if (savedBuffer)
{
return false;
}
std::streambuf * buf(std::cerr.rdbuf());
std::cerr.rdbuf(buffer.rdbuf());
// This two lines are for illustration purposes only!
std::cerr << "Hello world" << std::endl;
return true;
}
extern "C" __declspec(dllexport) void Revert()
{
if (savedBuffer)
{
std::cerr.rdbuf(savedBuffer);
}
savedBuffer = NULL;
}
extern "C" __declspec(dllexport) const char * getCerr()
{
return _strdup(buffer.str().c_str());
}
extern "C" __declspec(dllexport) void freeCharPtr(char *ptr)
{
free(ptr);
}
.CS file ------------------------------------------
public static class Redirector
{
// PRIVATE ------------------------------------------------------------
private const String LibraryName = "MyCpp.dll";
[DllImport(LibraryName, CharSet = CharSet.Ansi)]
private static extern IntPtr getCerr();
// PUBLIC -------------------------------------------------------------
[DllImport(LibraryName, CharSet = CharSet.Ansi)]
public static extern bool Redirect();
[DllImport(LibraryName, CharSet = CharSet.Ansi)]
public static extern void Revert();
[DllImport(LibraryName, CharSet = CharSet.Ansi)]
internal static extern void freeCharPtr(IntPtr ptr);
public static string GetCerr()
{
IntPtr temp = getCerr();
string result = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(temp);
freeCharPtr(temp);
return result;
}
}
NUnit Test -----------------------
[Test]
// [Ignore]
public void TestRedirect()
{
Redirector.Redirect();
// Call more functions that output to std::cerr here.
Redirector.Revert();
System.Console.WriteLine(Redirector.GetCerr());
}
The freeCharPtr() stuff is necessary to free the allocated memory from _strdup(), since I could not work out (if it's even possible) how to marshal an std::string.
Note: This is not thread safe!

Categories

Resources