I'm having a problem trying to import a c++ dll into c#
I always get the error "attempted to read or write protected memory" when I call the constructor of the dll class. I've been locking in other solutions for the same answer but I couldn't found solution.
I decided to use a simple function to discard that the error came from the c++ part but I'm having the same problem...
Here is my code:
main.cpp:
#include "main.h"
simple_dll::simple_dll(int num) : numero(num) {}
int simple_dll::getNumero() {
return this->numero;
}
extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
// attach to process
// return FALSE to fail DLL load
break;
case DLL_PROCESS_DETACH:
// detach from process
break;
case DLL_THREAD_ATTACH:
// attach to thread
break;
case DLL_THREAD_DETACH:
// detach from thread
break;
}
return TRUE; // succesful
}
main.h:
#ifndef __MAIN_H__
#define __MAIN_H__
#include <windows.h>
/* To use this exported function of dll, include this header
* in your project.
*/
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
// void DLL_EXPORT SomeFunction(const LPCSTR sometext);
class DLL_EXPORT simple_dll {
public:
DLL_EXPORT simple_dll(int num);
DLL_EXPORT int getNumero();
int numero;
};
#ifdef __cplusplus
}
#endif
#endif // __MAIN_H__
And the C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
namespace prueba_dll_VS
{
unsafe class Program
{
[System.Runtime.InteropServices.DllImport("simple_dll.dll", EntryPoint = "_ZN10simple_dllC2Ei")]
private static extern System.IntPtr simple_dll(int num);
[System.Runtime.InteropServices.DllImport("simple_dll.dll", EntryPoint = "_ZN10simple_dll9getNumeroEv")]
private static extern int getNumero(System.IntPtr hObject);
static void Main(string[] args)
{
System.IntPtr ptr_simple_dll = simple_dll(4); //HERE IS WHERE THE ERROR RAISES
int hora = getNumero(ptr_simple_dll);
Console.WriteLine(hora);
Console.ReadLine();
}
}
}
I'm getting mad, this can't be so difficult.
Thanks in advance.
The problem is the calling convention. In the current form, the functions are exported in thiscall, but the DllImport attribute defaults to stdcall (or cdecl on smartphones).
Related
I am calling unamanaged function from the managed code. But Unamanaged call is not happening.
Managed C# code:
(Created a project (Sampletest) from Visual C# -> Console App)
Sampletest:
namespace Sampletest
{
class Program
{
const string Dllpath2 = #"C:\Users\Sampletest\SampleDll\Debug\SampleDll.dll";
[DllImport(Dllpath2, EntryPoint = #"IsTherePower", CallingConvention = CallingConvention.Cdecl)]
public static extern Boolean IsTherePower();
static void Main(string[] args)
{
var test = IsTherePower();
Console.ReadKey();
}
}
}
Unmanaged C++ code:
(Created a dll project (SampleDll) from Visual C++ -> Windows Desktop -> Dynamic Link Library)
"IsTherePower()" definition is there in SampleDll.cpp
#include "stdafx.h"
BOOL IsTherePower()
{
BOOL bRetValue = FALSE;
return bRetValue;
}
But when we are making unmanaged call, first it is going to dllmain.cpp file present in unmanaged code.
#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;
}
then it is not going to
BOOL IsTherePower() function
and comming back to the managed call at "var test = IsTherePower();"
showing the error "Unhandled exception at 0x7705D6C7 (ntdll.dll) in Sampletest.exe: 0xC0000096: Privileged instruction.
Settings i Made:
For C# project,
Debug-> Selected "Enable native code debugging"
And I selected "Debug", "x86"
Please help me to resolve this issue.
You have to declare IsUPSPresent using the __declspec(dllexport) attribute or use a .def-file. Also, to overcome C++ name mangling, your definition has to be extern "C" in C++-code.
extern "C" {
BOOL __declspec(dllexport) IsUPSPresent()
{
BOOL bRetValue = FALSE;
return bRetValue;
}
}
I have a very large string in my c++ dll file , I need to pass it to C# as a byte array and I have no idea how to do that !
I know I can use this function in C# :
string result = System.Text.Encoding.UTF8.GetString(bytearray);
My large string is a std::string in C++
I need to know how can I convert my string to A utf8 array and send it to C# and how to get string back in C# application :)
More about the question:
I don't know how to pars byte arrays from C++ to C# like swprintf to StringBuilder .
Here's an example code for my question :
C++ Code:
#include "stdafx.h"
#include <iostream>
#include <cstdio>
#include <fstream>
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;
}
extern "C" __declspec(dllexport) void __stdcall sendasbyte(char* byte_to_send)
{
std::ifstream file_t("testfile.txt");
std::string Read_test_file((std::istreambuf_iterator<char>(file_t)),
std::istreambuf_iterator<char>());
///// NEED TO SEND Read_test_file as byte array to C# HERE :
// <-------- CODE AREA --------->
}
Here's C# Code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace minimal_project_testapp
{
class Program
{
[DllImport("minimal_project_test.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
private static extern void sendasbyte(byte[] get_String_Byte);
private static byte[] data_from_cpp;
static void Main(string[] args)
{
sendasbyte(data_from_cpp);
string result = System.Text.Encoding.UTF8.GetString(data_from_cpp);
Console.WriteLine(result);
Console.ReadLine();
}
}
}
And the testfile.txt : https://textuploader.com/dvvbb
Here's how to Do That clear and perfectly :D
1 > Change your c++ function to this :
extern "C" __declspec(dllexport) char* __stdcall test_int()
{
std::ifstream file_t("testfile.txt");
std::string Read_test_file((std::istreambuf_iterator<char>(file_t)),
std::istreambuf_iterator<char>());
int size_of_st = Read_test_file.length();
std::string test1 = std::to_string(size_of_st);
char* cstr = new char [size_of_st];
std::strcpy(cstr, Read_test_file.c_str());
return cstr;
}
2 > Don't forgot to add #define _CRT_SECURE_NO_WARNINGS
3 > Add Dllimport to your C# application
[DllImport("minimal_project_test.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
private static extern IntPtr test_int();
4 > And finally use it everywhere you need like this :
IntPtr _test_from_Cpp = test_int();
int _test_char_count = <Enter Length of your string>;
byte[] _out_char_value = new byte[_test_char_count];
Marshal.Copy(_test_from_Cpp, _out_char_value, 0, _test_char_count);
string final_string = System.Text.Encoding.UTF8.GetString(_out_char_value);
Boom! it Works !!! ;)
I am writing a simple dll using opencv library.
The code for the dll is as follows :
Dll header file -
#pragma once
#include "stdafx.h"
#ifndef _DLL_TUTORIAL_H_
#define _DLL_TUTORIAL_H_
#include <iostream>
#include "opencv2\opencv.hpp"
#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif
extern "C"
{
DECLDIR int Add(int a, int b);
DECLDIR void Function(void);
}
#endif
Dll source file -
#define DLL_EXPORT
#include <iostream>
#include "ConsoleApplication3.h"
#include "opencv2\opencv.hpp"
extern "C"
{
DECLDIR int Add(int a, int b)
{
//cv::Mat c(100, 100, CV_8UC1);
return(a + b);
}
DECLDIR void Function(void)
{
std::cout << "DLL Called!" << std::endl;
}
}
C# script to call the method in the dll -
using System;
using System.Runtime.InteropServices;
class Sample
{
[DllImport ("ConsoleApplication3.dll")]
public static extern void Function();
public static void Main()
{
System.Console.WriteLine("hello world");
Function();
}
}
The problem is :-
Error :
Unhandled Exception: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
at Sample.Function()
at Sample.Main() in c:\Users\supertramp\Documents\Projects\opencv_dll\opencv_dll\filedll.cs:line 13
1) When I generate a 64-bit dll in VS 2015 the error is thrown.
2) When I generate a 32-bit dll , the error is thrown when I uncomment the line in which I define a cv::Mat variable in the Add method.
I am not able to understand where is the problem. I read other posts related to this mention that the error is related to the 32 or 64 bit dll build, but in my case commenting the line where cv::Mat is defined makes the dll run fine.
What might be the issue ?
From C# code I'm trying to call a API from a *.c file. But I'm getting AccessViolationException.
Earlier I was getting BadImageFormatException, but I solved it by putting both the exe and the dll together in one location.
I suspect that it has something to do with CallingConvention of Cdecl or StdCall or with PlatformType=x86 or x64.
In My C#. exe I've set the CPU to x86 and in my NativeCode.dll the calling convention is mentioned as Cdecl only.
I'm not able to understand that how to solve this issue,there are many posts on web explaining about this problem but somehow I'm not able to find any concrete solution to this issue.
In case of any more details please let me know.
Below mentioned is some code from files which can highlight the problem:
Header.H file
typedef int BOOL;
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
typedef BOOL REGFUNCTION( char *pRegKey, char *pBuffer, int iBufSize );
Implementation.c file
#ifdef SWSCANCODE_EXPORTS
#define SWSCANCODE_API __declspec(dllexport)
#else
#define SWSCANCODE_API __declspec(dllimport)
#endif
#ifdef SWSCAN_APIS
SWSCANCODE_API BOOL SWSetGetRegKeyValue ( REGFUNCTION* pGetRegKeyValue );
#endif
SWGLOBALS* pSWGlobals;
SWSCANCODE_API BOOL SWSetGetRegKeyValue( REGFUNCTION * pGetRegKeyValue )
{
BOOL bInitStatus; // initialization status
bInitStatus = TRUE; // assume initialization will be successful
pSWGlobals->pGetRegKeyValue = pGetRegKeyValue;
if(NULL!=pSWGlobals->pGetRegKeyValue)
{
printf("I don't know");
}
return( bInitStatus );
}
C# code
class Program
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int REGFUNCTION([MarshalAs(UnmanagedType.LPStr)]string pRegKey, [MarshalAs(UnmanagedType.LPStr)]string pBuffer, int iBufSize);
[DllImport("NativeCode.dll", EntryPoint = "SWSetGetRegKeyValue", CallingConvention = CallingConvention.Cdecl)]
[return:MarshalAsAttribute(UnmanagedType.Bool)]
public static extern Boolean SWSetGetRegKeyValue(IntPtr pGetRegKeyValue);
static void Main(string[] args)
{
REGFUNCTION dele = GetRegKeyValue;
IntPtr ptr = Marshal.GetFunctionPointerForDelegate(dele);
GC.KeepAlive(dele);
bool bSetRegKeyValueOk = SWSetGetRegKeyValue(ptr);
}
public static int GetRegKeyValue(string pRegKey, string pBuffer, int iBufSize)
{
Console.WriteLine("Successful in calling the method");
return 0;
}
}
I have created a WIN32 DLL project and its dllmain.cpp is as follows;
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;
}
_declspec(dllexport) float RGBCompare()
{
return 100;
}
My target is to call method RGBCompare from a C# project and as per rule I have mentioned dllexport tag before it.
On the other side in C# project I have defined an entry point as follows;
namespace LogoFinderWrapper
{
public class LogoFinder
{
[DllImport("LogoIdentifier.dll", EntryPoint = "RGBCompare")]
private static extern float Api_RGBCompare();
public static float RGBCompare()
{
return Api_RGBCompare();
}
}
}
When I call DLL it raises exception System.EntryPointNotFoundException.
Please could any one help me in this regard?
Your native code is C++ and the name is mangled before export. Possible solutions:
Use the mangled name in the EntryPoint parameter. Find out the mangled name with dumpbin or Dependency Viewer.
Use a .def file rather than __declspec(dllexport) to control which functions are exported.
Suppress mangling with extern "C" in your C++ source code.
The final option would look like this:
extern "C"
{
__declspec(dllexport) float RGBCompare()
{
return 100;
}
}