Czy możliwe jest aby wyeksportować funkcję i użyć ją w innym języku takim jak C++? Bibliotekę kompilowałem z Unmanaged Exports i C# ale nie da się tego użyć w C++.
Jest możliwość użycia biblioteki napisanej w C# (normalnie napisanej, bez kombinowania) w C++/CLI.
Visual C++ pozwala włączyć tryb C++/CLI dla pojedynczego pliku .cpp w projekcie, nie trzeba koniecznie od razu całego projektu kompilować jako C++/CLI.
W tym jednym .cpp będzie wtedy dostęp do klas z C#.
Tylko nie wiem czy to u mnie przejdzie bo program był pisany i kompilowany w GCC. Czyli jednak nie da się tak wyeksportować funkcji z biblioteki tak jak w C++?
tl;dr
U mnie działa. Pierwsza rzecz, jaka mi się rzuciła w oczy - pamiętasz, że Class Library musi być x86 albo x64, a nie Any CPU - masz tak zrobione? Głupi błąd, ale często się o tym zapomina. Używam VS2017, a nie Xamarin Studio, nie wiem czy Xamarin Studio poprawnie radzi sobie z dodatkowymi skryptami w NuGetach.
Zasadniczo dotychczas uważałem, że się nie da wyeksportować funkcji z .NET-owego assembly dla aplikacji natywnych.
Przejrzałem jednak tego UnmanagedExports i działa... dziwnie. Bo kiedy stworzyłem sobie dwie funkcje, w tym jedną taką, jak Twoja, to według Dll Export Viewer nie ma tam nic. Jednak z kolei dumpbin
, PEInfo oraz FileAlyzer już pokazuje poprawnie oba eksporty, więc, wierzę, że jednak tam są ;-)
Niby sam skrypt przy budowaniu projektu coś tam robi:
1> Found method: ClassLibrary1.Class1..method public hidebysig static void 'Test'(int32 'a') cil managed
1> Removing RGiesecke.DllExport.DllExportAttribute from ClassLibrary1.Class1.Test
1> old declaration: .method public hidebysig static void 'Test'(int32 'a') cil managed
1> new declaration: .method public hidebysig static void modopt(['mscorlib']'System.Runtime.CompilerServices.CallConvStdcall') 'Test'(int32 'a')
1> exporting as Test and index 1
1> Deleting unused reference to RGiesecke.DllExport.Metadata.
1> Parsing 114 lines of IL took 25 ms.
Potem napisałem bardzo skomplikowany program, używając mojego braku skilli do C++, i zadziałało!
#include "stdafx.h"
#include <Windows.h>
int main()
{
typedef int(CALLBACK* LPFNDLLFUNC1)(int);
typedef char*(CALLBACK* LPFNDLLFUNC2)(char*);
HINSTANCE hDLL; // Handle to DLL
LPFNDLLFUNC1 lpfnDllFunc1; // Function pointer
LPFNDLLFUNC2 lpfnDllFunc2;
int uParam2, uReturnVal;
hDLL = LoadLibrary(L"ClassLibrary1");
if (hDLL != NULL)
{
lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL,
"Test");
if (!lpfnDllFunc1)
{
// handle the error
FreeLibrary(hDLL);
return 3;
}
else
{
// call the function
uReturnVal = lpfnDllFunc1(3);
printf("%d", uReturnVal);
}
lpfnDllFunc2 = (LPFNDLLFUNC2)GetProcAddress(hDLL,
"ImageToBase64");
if (!lpfnDllFunc2)
{
// handle the error
FreeLibrary(hDLL);
return 4;
}
else
{
// call the function
printf("%s", lpfnDllFunc2("E:\\Marcin\\Temp\\a.txt"));
}
}
return 0;
}
A biblioteka C# wygląda następująco:
using RGiesecke.DllExport;
using System;
namespace ClassLibrary1
{
public static class Class1
{
[DllExport(CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall, ExportName = "ImageToBase64")]
public static string ImageToBase64(string filename)
{
var arr = System.IO.File.ReadAllBytes(filename);
return Convert.ToBase64String(arr);
}
[DllExport(CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall, ExportName = "Test")]
public static int Test(int a)
{
return 4;
}
}
}