I've looked up on Internet to see if someone encountered that problem, but haven't found anything.
So I'm trying to use a C++ DLL in a C# UWP application. This DLL has a log file which is opened at the beginning of the code with the following function:
#include <string>
#include <iostream>
using namespace std;
int Logger::set(string file_name, bool clear_log) {
_file_stream.exceptions(ofstream::failbit | ofstream::badbit);
try {
_file_stream.open(file_name, ios_base::out | (clear_log ? ios_base::trunc : ios_base::app));
}
catch (ofstream::failure) {
return -1;
}
_file_stream << "";
return 0;
}
Here is the code of the Logger class:
class Logger {
private:
std::ofstream _file_stream;
public:
Logger() {};
~Logger() { _file_stream.close(); };
int set(std::string file_name, bool clear_log);
}
Now, this code works fine when I use the DLL in standalone mode. But when called via the UWP app, the open() function throws an ofstream::failure exception saying:
ios_base::failbit set: iostream stream error
I first thought this was due to UWP's weird access rights policies, but after debugging, file_name points to the correct package folder in AppData, so it should be okay to write a file here.
What could be the problem?
EDIT: I found out that for some reason, the C file API works as expected. That is, the following code successfully creates the file:
#include <iostream>
using namespace std;
int Logger::set(string file_name, bool clear_log) {
FILE* test = fopen(file_name.c_str(), clear_log ? "w" : "a");
if(!test)
{
return -1;
}
fprintf(test, "");
return 0;
}
I figured out myself after some more active debugging. Somewhere before in the code this similar (indirect) call to ofstream::open didn't fail:
ofstream out("out.txt", ios_base::trunc);
And by putting breakpoints on the right place, I was able to determine that in that case, the value of the open mode (the ios_base::trunc argument) resolved to 18 (the expected value), whereas it resolved to the weird value 1594 in the problematic case, when using the ternary operator.
Replacing the ternary operator by a if-else block resolved the problem:
int Logger::set(string file_name, bool clean_log) {
_file_stream.exceptions(ofstream::failbit | ofstream::badbit);
try
{
if (clean_log)
_file_stream.open(file_name, ios_base::trunc);
else
_file_stream.open(file_name, ios_base::app);
}
catch (ofstream::failure)
{
return -1;
}
return 0;
}
Related
I'm trying to build a a simple C# application to test passing data between languages. I have a simple main in C# calling a function that I wish to pass to C++:
using System;
namespace CS_Console
{
class Program
{
static void Main(string[] args)
{
CPP_Sum(5, 2); //pseudo code
}
}
}
and then the function in a C++ project:
CPP_Sum(int x, int y)
{
return x+y;
}
The problem is, I don't even know where to start on how to pass these between each other.
This is being done via two projects, CS_Console and CPP_Console, in the same solution in Visual Studio.
It has already been mentioned by #steveo314. The easiest way to call a C++-based function from C# is using PInvoke. I assume you can create a DLL without any documentation but this looks like it will give you all the information you need to use your DLL from C#.
Basically:
Put your function as a C++ DLL; then
Use a DllImport attribute to create a function prototype in your C# code.
Make sure you export your C++ function definitions.
Daniel's answer above is also correct, but if you really want to dive into the guts of this, you may want to learn C++/CLI, as that's more or less C++ running on top of the .NET framework, with more precise interop, and depending on where/what your DLL is, communication both ways (P/Invoke is just calling C++, not calling back into .NET... usually).
C++/CLI allows this kind of thing:
public class Program
{
public void main(String [] args)
{
NativeWrapper wrapper = new NativeWrapper(); // C++/CLI ref class
wrapper.doStuff("hey there!");
}
}
In a C++/CLI DLL, in the .h file:
// This is C++/CLI
class NativeClass; // Forward declare
ref class NativeWrapper
{
public:
NativeWrapper(); // Constructor - MUST be in .cpp file, as size of NativeClass not known here
~NativeWrapper(); // Destructor - MUST be in .cpp file, same reason as above
void doStuff(System::String^ inputString);
private:
NativeClass* mp_impl;
};
In a C++/CLI .cpp file:
class NativeClass // True C++ class, could be defined elsewhere!
{
public:
void nativeDoStuff(const std::string& inputString)
{
std::cout << "Previous input was: '" << cachedResult << "'";
cachedResult = inputString;
}
private:
std::string cachedResult{};
};
NativeWrapper::NativeWrapper()
{
mp_impl = new NativeClass();
}
NativeWrapper::~NativeWrapper()
{
delete mp_impl;
mp_impl = nullptr;
}
// Utility function!
std::string _convertClrString(System::String^ instr)
{
marshal_context context;
std::string mystring{ context.marshal_as<const char*>(instr) };
return mystring;
}
void NativeWrapper::doStuff(System::String^ inputString)
{
auto native_string = _convertClrString(inputString);
mp_impl->nativeDoStuff(native_string);
}
It's a toy example (necessary includes removed), but hopefully that gets the idea across of what's possible with C++/CLI. The link I put near the top is the main start of the resources at Microsoft for doing this. Keep in mind what files are compiling as .NET, which aren't (you can do it per-file), and what that all means.
I am kinda stuck on not being able to dispose .NET 3.5 dlls from the process.
AppDomain support is off in unity, there is no way to unload a dll from the process using the .NET api, because the C# functions are not implemented.
Anyone could get me some hints on how / where should I start to remove the dll from the memory / process somehow, so I can re-load the dll whenever I want?
Alright, after this time I thought that this is some sort of heavy research, and there are no publications related to this. So here is what you have to do. First head over to https://github.com/mono/mono/branches/all and determine which mono version you are going to require. In my case I was doing this for an old game, and I needed the 2014 version of mono.
My project is discontinued so there is no point for me to keep this as a secret. The following examples will show you a way, but It probably won't be enough for you to get what you want on a newer mono version.
Using this way, you are able to unload every dll in a new AppDomain. You can extend It to create multiple appdomains, or unload only a specific dll. If It is working on a newer mono version then please let me know! Credits go to me, and 4g3v.
Once you have done that you are going to need exactly the same environment, and compilers for that version. In my case that was the Visual Studio 2010 compilers, and I didn't need to refactor most of the things.
You will need more than just following my instructions, you will have to play with mono, and get to know how the project works.
So hence as stated: C# API doesn't support AppDomains, but mono by default does. You just need to make some improvements, and extensions for It. Here is what you need to do:
Define two new functions in mono.def for example
mono_rb_create_domain and
mono_rb_unload_domain
The above two functions will be responsible to create, and dispose a domain.
Head over to: mono/metadata/object.c
Find function mono_runtime_unhandled_exception_policy_set and add (We will create the function later below):
mono_add_internal_call("YourDLLNameSpace.Icalls::mono_rb_load_plugin", ves_icall_mono_rb_load_plugin); //Last mono function unity calls before adding their own icalls (mono_runtime_unhandled_exception_policy_set). Adding them at runtime doesn't work, so this should be a pretty good place.
The above code will define a C# function that will be able to handle the loading of a custom DLL loaded in our own AppDomain. Make sure that your C# class, and function is public. Reminder: This should be somewhere in your unity project already. (For example Assembly-CSharp or whatever). It is crucial, because this will be handling the loading of your new dlls, and they will go to a new appdomain.
[MethodImpl(MethodImplOptions.InternalCall)]
public extern Assembly mono_rb_load_plugin(IntPtr data, uint dataLen);
Alright, we have to add some additional checks to avoid crashes in unity/unity_liveness.c Look for function mono_add_process_object and make it look like the following. This might differ in newer mono versions. =) What we have done here is basically ensuring that the received object has a VTable (which should be the class), and It isn't null.
static void mono_add_process_object (MonoObject* object, LivenessState* state)
{
gboolean has_references = 0;
MonoClass* klass; // Define the class
if (object && !IS_MARKED(object))
{
klass = GET_VTABLE(object)->klass; // Get the VTable
// Ensure that the class isn't f***ed up. Read: https://en.wikipedia.org/wiki/Hexspeak
if(klass == NULL || klass == 0xBAADF00D || klass == 0xFEEEFEEE)
{
return;
}
has_references = klass->has_references;
if(has_references || should_process_value(object,state) != LIVENESS_DONT_PROCESS)
{
if (array_is_full(state->all_objects))
array_safe_grow(state, state->all_objects);
array_push_back(state->all_objects, object);
MARK_OBJ(object);
}
// Check if klass has further references - if not skip adding
if (has_references)
{
if(array_is_full(state->process_array))
array_safe_grow(state, state->process_array);
array_push_back(state->process_array, object);
}
}
}
The above code will ensure that the processed class isn't faulty, or points somewhere else where It shouldn't.
Let's create our domain handlers.
Make sure to create this under the mono project.
My header file was named as mono_rustbuster.h, and contained:
static MonoDomain* rustBusterDomain;
GHashTable* pluginHashTable;
void mono_method_info_object();
MonoReflectionAssembly* ves_icall_mono_rb_load_plugin(void* objectPtr, char* data, guint32 dataLen) MONO_INTERNAL;
Then we created mono_rustbuster.c, and wrote the following:
#include "metadata\metadata-internals.h"
#include "metadata\image.h"
#include "metadata\assembly.h"
#include "metadata\debug-helpers.h"
#include "metadata\class-internals.h"
#include "metadata\object-internals.h"
static MonoDomain* rustBusterDomain;
GHashTable* pluginHashTable;
void mono_method_info_object()
{
}
int mono_rb_create_domain()
{
pluginHashTable = g_hash_table_new(g_str_hash, g_str_equal);
rustBusterDomain = mono_domain_create_appdomain("PluginDomain", NULL);
return 0x01;
}
int mono_rb_unload_domain()
{
mono_domain_unload(rustBusterDomain);
return 0x01;
}
MonoReflectionAssembly* ves_icall_mono_rb_load_plugin(void* objectPtr, char* data, guint32 dataLen)
{
MonoAssembly* ass;
MonoImage* img;
MonoImageOpenStatus status;
MonoDomain* current;
char *assNameBuf;
current = mono_domain_get();
mono_domain_set(rustBusterDomain, FALSE);
img = mono_image_open_from_data_full(data, dataLen, TRUE, NULL, FALSE);
ass = mono_assembly_load_from_full(img, "", &status, FALSE);
assNameBuf = (char*)malloc(256);
sprintf(assNameBuf, "%s", ass->aname.name);
g_hash_table_insert(pluginHashTable, (gpointer)assNameBuf, (gpointer)ass);
mono_domain_set(current, FALSE);
return mono_assembly_get_object(rustBusterDomain, ass);
}
After this setup your loaded DLLs might whine about missing references. This mostly happens when you load a new DLL in all by yourself using these functions. We added some layers into mono/metadata/assembly.c for this fix.
Find mono_assembly_load_reference This method works with the assembly's references, find where It is calling the reference variable and add:
if(reference == NULL && strstr(image->name, "data-"))
{
reference = (MonoAssembly*)g_hash_table_lookup(pluginHashTable, aname.name);
}
Hint: Mono add's data- to all of the dll's, so that way we can use that memory pointer to find the references. Basically fixes the unresolved referencess.
Head over to mono/metadata/class.c and find: mono_class_is_assignable_from
Before function would return data using the last function check if the class names are equal.
The last return looks something like this:
return mono_class_has_parent (oklass, klass);
Add:
if(!mono_class_has_parent (oklass, klass))
{
if(strstr(klass->image->name, "data-"))
{
if(!strcmp((oklass)->supertypes [(klass)->idepth - 1]->name, klass->name))
{
//OutputDebugStringA("mono_class_is_assignable_from(): Class names are equal so true is returned");
return TRUE;
}
}
}
The above code will add fixes to ScriptableObject cast exceptions.
You are sort of done. You may encounter additional issues. Here is how it works in C#:
[DllImport("mono.dll")]
internal static extern int mono_rb_create_domain();
[DllImport("mono.dll")]
internal static extern int mono_rb_unload_domain();
Handle loading of a new dll:
var icalls = new Icalls();
int domaincreation = RustBuster.mono_rb_create_domain();
byte[] bytes = getyourdllsbytearraysomehow;
IntPtr pluginMem = Marshal.AllocHGlobal(bytes.Length);
for (int i = 0; i < bytes.Length; i++)
{
Marshal.WriteByte(pluginMem, i, bytes[i]);
}
assembly = icalls.mono_rb_load_plugin(pluginMem, (uint) bytes.Length);
Unload:
int domaincheck2 = RustBuster.mono_rb_unload_domain();
I need to call a native method of an unmanaged DLL From C#.
DLL source code is not available of course (provided by a "third party").
Native DLL method is supposed to accept two arguments and returns a (native) integer code:
MyDLLNativeMethod(string filename, int returncode)
The first argument of native DLL method is a string (filename) & second has to be a "reference" to gather return code after execution. I'm confused about how to get return code. DLL calls are working properly, producing expected files based on first argument.
How should I implement the desired callback to perform operation on different return codes values retrieved?
// ~~~~~~~~~~~~~~~~~~~~
// Main entry point
// ~~~~~~~~~~~~~~~~~~~~
namespace MyProject
{
class Program
{
static void Main(string[] args)
{
MyDLLCaller _dllcaller = new MyDLLCaller();
_dllcaller.MyDLLNativeMethod("test_file.txt");
}
}
}
// ~~~~~~~~~~~~~~~~~~~~
// DLL calling class
// ~~~~~~~~~~~~~~~~~~~~
namespace MyProject
{
class MyDLLCaller
{
// DLL Loading
[DllImport(#"C:\test\mydll.dll")]
public static extern int MyDLLNativeMethod(string _filename);
// Native DLL method pseudo code :
// MyDLLNativeMethod(string filename, int returncode).
}
}
Thanks in advance
If the return code is the second parameter I think you should use out keyword for this:
int returncode = 0;
[DllImport(#"C:\test\mydll.dll")]
public static extern int MyDLLNativeMethod(string _filename, out int returncode);
if(returnCode != 0)
{
// something went wrong
}
Try it with some file that you know should return error code.
If the above declaration for the external call works with your library, you get the return code from the call.
var retCode = _dllcaller.MyDLLNativeMethod("test_file.txt");
I have created console Application from which I have called the Win32 Project where it throws an access violation exception. I have attached My custom filter in SetUnhandledExceptionFilter. When I use !clrstack command, it shows the unmanaged call stack but MSDN says Clrstack will provide a stack trace of managed code only.
https://msdn.microsoft.com/en-us/library/bb190764(v=vs.110).aspx
Please help .
Program.cs
public void ExceptionMethod()
{
ExceptionCreator.CreateAccessViolationException();
}
Win32 Project:
ErrorReportWritter.h
#pragma once
#include "stdafx.h"
#include "DbgHelp.h"
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Text;
public ref class ErrorReportWritter
{
public:
static void InstallHandler();
};
ErrorReportWritter.cpp
LONG WINAPI MyExceptionFilter(__in struct _EXCEPTION_POINTERS *ExceptionInfo)
{
//For test purpose, Dump location will be the solution location itself
HANDLE hFile = CreateFileA("Test.dmp", GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
{
// Create the maxidump
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithFullMemory |
MiniDumpWithFullMemoryInfo |
MiniDumpWithHandleData |
MiniDumpWithThreadInfo |
MiniDumpWithUnloadedModules);
//MINIDUMP_TYPE mdt = MiniDumpNormal;
MINIDUMP_EXCEPTION_INFORMATION mei;
mei.ThreadId = GetCurrentThreadId();
mei.ClientPointers = FALSE;
mei.ExceptionPointers = ExceptionInfo;
BOOL rv = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, mdt, &mei, 0, 0);
//TODO: put a check for failure return value and throw exception in that case
// Close the file
CloseHandle(hFile);
}
//TODO: Still need to decide if the search next functionality is needed for final solution
if (oldFilter == NULL)
{
return EXCEPTION_CONTINUE_SEARCH;
}
LONG ret = oldFilter(ExceptionInfo);
return ret;
}
void ErrorReportWritter::InstallHandler()
{
//Returns the address of the previous exception filter established with the function.
//A NULL return value means that there is no current top-level exception handler.
oldFilter = SetUnhandledExceptionFilter(MyExceptionFilter);
}
The code you have is managed C++. (or C++/CLI or whatever your Visual Studio version supports).
To create an unmanaged Win32 project, for example in Visual Studio 2015, got to File -> New Project and then select Templates -> Visual C++ -> Win32 Project.
I've been working on DLL which uses OpenCV to do some tracking. Got everything working on a C console project using VS 2008 (for testing purposes). Then I made a new DLL project and got it compiled. I setted up everything so I just had put a single function on a Thread Class to call a single function.
Then I created a C# project for GUI and other stuff. The DLL loads fine (using System.Runtime.InteropServices, the method starts (I can see the capture window created by OpenCV) but the tracking is not being done. To verify the DLL was actually working, I loaded on Python and called the method and it ran fine (tracking was being made).
I'm new to working with unmanaged DLL's on managed code. Any ideas on what am I doing wrong or how can I debug this? If you need anything else to help me solve this problem I'll provide it.
Thanks in advance.
Edit:
I'm not using a class on the DLL, I'm using a single function, the Thread class comes from the System.Threading on C#
The way I'm using the DLL is like this.
namespace GUI
{
static class NativeTracking
{
[DllImport(#"__Tracking.dll")]
public static extern void _Tracking();
}
}
The I put it on a thread like his
public GUI()
{
InitializeComponent();
_tracking = new Thread(_Tracking);
_tracking.Start();
}
public _Tracking()
{
while(True)
{
NativeTracking.Tracking();
}
}
Edit: Native Coded
Native Code, sorry for the messy format.
Header File
#include <cv.h>
#include <stdio.h>
#include <ctype.h>
#include <windows.h>
#include <highgui.h>
#include "..\original\project\myheader.h"
#include "..\original\project\myheader1.h"
#include "..\original\project\myheader2.h"
#include "..\original\project\myheader3.h"
#include "..\original\project\myheader4.h"
#ifdef __cplusplus
extern "C"{
#endif
_declspec(dllexport) void Tracking();
#ifdef __cplusplus
}
#endif
Implementation
#include "exposed.h"
void Tracking( )
{
int flag = 1, i=0;
iplImgs imgs;
trackingTool tools;
helperTools helperTools;
CvCapture* capture = 0;
capture = cvCaptureFromCAM( 0 );
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 320);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 240);
cvSetCaptureProperty(capture, CV_CAP_PROP_FPS, 20.0f);
imgs.image = 0;
cvNamedWindow( "Window", 0 );
initHelperTools(&helperTools);
initTools(&imgs, &tools);
for(;;){
int c;
IplImage* frame = 0;
frame = cvQueryFrame( capture );
if( !frame )
break;
if( !imgs.image ){
/* allocate all the buffers */
prepareImages(&imgs, &tools, frame);
}
cvCopy( frame, imgs.image, 0 );
cvCvtColor( imgs.image, imgs.grey, CV_BGR2GRAY );
if( flag == 1 || conditionB ){
someOperations(&imgs, &tools);
if (conditionC)
flag = 0;
}
else if( conditionD ){
otherOps(&helperTools, imgs.grey);
someTrack(&imgs, &tools, &helperTools, drawPoints);
someCorrections(&tools);
if ( condition ){
if (!wasReset){
wasReset = 0;
continue;
}
if ( validation )
someMoreOperations(&tools, corretions);
}
}
bufferHandlingOps(&imgs);
c = cvWaitKey(10);
if( (char)c == 27 )
break;
switch ((char)c){
case 'p':
drawPoints ^= 1;
break;
default:
;
}
}
cvReleaseCapture( &capture );
cvDestroyWindow("Window");
}
One problem I see is that you're using the default C calling convention in your native code, which is "__cdecl", and in your P/Invoke "DLLImport" attribute you're letting it use the default calling for C# which is "__stdcall". This is probably throwing a run time exception whenever you invoke your native method.
Also, I realize that you're not passing any arguments or expecting any results, but the calling convention does denote the way the function is decorated, which can lead to name mangling problems.
You can:
Change your native export to "__declspec(dllexport) void __stdcall Tracking();"
Or change the "CallingConvention" property on your DLLImport attribute: [DllImport(#"__Tracking.dll") CallingConvention = CallingConvention=CallingConvention.Cdecl]
One of the problem of DllImport (P/Invoke) is that is not type safe. You knows it's working only runtime because you don't have a way to check it at compile time if:
the signature of the method is the right one;
the mangling of the method is correct.
It's very popular for WIN32 methods because you'll find plenty of examples that work, but for the lib you are using, it's a matter of trying and trying until it works or you find the specific problem that's blocking you (remember to verify the dll is in the same directory, or in system directory, of the executable when it runs).
My advice is to create a proper wrapper in C++/CLI. It doesn't have the problems above and it's esier to debug in case of problems. Here is a more complex example I wrote in the case of a callback in C to expose in C#.