[英]Call a C# method/function from a C++ DLL (which is loaded from C# with “Dllimport”)
在單個標題中恢復它有點困難,所以這就是我的情況。
我正在構建一個加載C ++庫的C#應用程序。
我從該C ++ DLL調用函數。
但是我也想讓我的C ++ DLL從C#應用程序中調用函數(正在導入/運行它)...
這是一段使它更全面的代碼:
// I'm importing functions from my native code
[DllImport(dllFilePath, CallingConvention = CallingConvention.Cdecl)]
public static extern int returnIntValue(int value);
[DllImport(dllFilePath, CallingConvention = CallingConvention.Cdecl)]
public static extern int returnIntArrValueAt(int[] values, int index);
// Here is the kind of code it should be
// [DllImport(dllFilePath, CallingConvention = CallingConvention.Cdecl)]
// public static extern void callCSharpFunction( FunctionPointer fctPointer );
main
{
// I run the function
int intValue1 =
MyAddIn.returnIntValue(147852369);
int intValue2 =
MyAddIn.returnIntArrValueAt( new int[] { 9, 4, 3, 2, 1, 0 }, 5);
// Here is an example function I use to call my C# func from C++
// MyAddIn.returnIntValue( &myCSharpFunction );
}
// This is the method I'd like to call from my C++ imported library
static public void myCSharpFunction()
{
MessageBox.Show("Called from C++ code !!");
}
因此,恢復:
這是我對這個問題的回答 ,這是相似的。 我的示例不對回調使用參數。 由於您的參數是整數,因此,您應該不會有任何問題。
基本上, Marshal.GetFunctionPointerForDelegate
方法從委托創建一個IntPtr
。 該委托應具有與C ++庫中使用的函數指針相同的簽名。
// This is the delegate type that we use to marshal
// a function pointer for C to use. You usually need
// to specify the calling convention so it matches the
// convention of your C library. The signature of this
// delegate must match the signature of the C function
// pointer we want to use.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void FunctionPointer();
// This is the function we import from the C library.
[DllImport(dllFilePath)]
static extern void callCSharpFunction(IntPtr fctPointer);
// This is the placeholder for the function pointer
// we create using Marshal.GetFunctionPointerForDelegate
IntPtr FctPtr;
// This is the instance of the delegate to which our function
// pointer will point.
FunctionPointer MyFunctionPointer;
// This calls the specified delegate using the C library.
void CallFunctionPointer(FunctionPointer cb)
{
// make sure the delegate isn't null
if (null == cb) throw new ArgumentNullException("cb");
// set our delegate place holder equal to the specified delegate
MyFunctionPointer = cb;
// Get a pointer to the delegate that can be passed to the C library
FctPtr = Marshal.GetFunctionPointerForDelegate(MyFunctionPointer );
// call the imported function with that function pointer.
callCSharpFunction(FctPtr);
}
可以做到,總的來說沒什么大不了的。 但是,有幾點需要考慮。
由於您說的是C ++而不是C,因此請注意,除了靜態類,實例方法,朋友函數等之外,由於名稱修改,還有一些無法通過DllImport加載的函數。 避免使用COM,將C ++換行有時會用作一種更可移植的策略,以允許庫被其他語言.Net或其他語言包裝。 同樣,其中一些相同的注意事項也適用於您所包裝的庫中的回調。 盡管來自DLL的原型似乎沒有問題,但如果它確實是由C ++編譯器構建的,則可能值得查看導出的符號名稱以確保。
在搜索時告訴幫助,您需要了解詞匯表。 通常,當一個函數將另一個要在函數調用期間或之后調用的函數作為參數時,稱為回調 。 在C和C ++的世界中,這是基於一種稱為功能指針的語言功能(該功能還用於回調以外的目的)。 在MS文檔中,通常將在運行時將不同功能動態綁定到不同調用者的整個過程稱為委托 。 與C#等效的函數指針是使用C#關鍵字proxy創建的稱為委托的對象。 我建議首先使用此功能在C#中創建一些實驗程序,以首先了解其工作原理。
而且DllImport是實現的一部分,您正在使用的實際.Net工具是pinvoke 。 尋找更多信息時也應該如此。 然后,您要做的是通過將pinvoke 編組為函數指針來導出您的委托。 也就是說,.Net將為運行本機代碼創建一個填充函數 。 經常需要嘗試兩次的兩個大問題區域是:1)確保此shim函數/編組的委托本身具有正確的調用約定 ,以及2)此幕后shim函數的對象生存期使得它在以下情況下仍然存在:本機DLL將要使用它。 有時,此曲線球可能需要手動覆蓋垃圾回收行為,但這通常意味着僅保留對其的引用。
我實際上認為, Mono文檔在這方面也比MSDN更好。
好的,經過幾次測試,從零開始,我終於設法使此回調運行!
所以這是我創建的使用回調的測試項目。
LIBRARY TestCallBack
EXPORTS
callCSharpFunction
__declspec(dllexport) void callCSharpFunction ( void *fctPointer(int) )
{
fctPointer(123456);
}
該C ++項目將作為“ DLL”文件構建,並放在C#的項目文件夾中的“ lib”項目中。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
// Set the library path
const string dllFilePath =
"C:\\PathToProject\\TestCallBack\\ConsoleApp\\lib\\TestCallBack.dll";
// This is the delegate type that we use to marshal
// a function pointer for C to use. You usually need
// to specify the calling convention so it matches the
// convention of your C library. The signature of this
// delegate must match the signature of the C function
// pointer we want to use.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void FunctionPointer( int nb);
// This is the function we import from the C library.
//[DllImport(dllFilePath)]
[DllImport(dllFilePath, CallingConvention = CallingConvention.Cdecl)]
public static extern void callCSharpFunction(IntPtr fctPointer);
// This is the placeholder for the function pointer
// we create using Marshal.GetFunctionPointerForDelegate
static IntPtr FctPtr;
// This is the instance of the delegate to which our function
// pointer will point.
FunctionPointer MyFunctionPointer;
// This calls the specified delegate using the C library.
void CallFunctionPointer(FunctionPointer cb)
{
// make sure the delegate isn't null
if (null == cb) throw new ArgumentNullException("cb");
// set our delegate place holder equal to the specified delegate
MyFunctionPointer = cb;
// Get a pointer to the delegate that can be passed to the C lib
FctPtr = Marshal.GetFunctionPointerForDelegate(MyFunctionPointer);
// call the imported function with that function pointer.
callCSharpFunction(FctPtr);
}
static void Main(string[] args)
{
// This is the instance of the delegate to which our function
// pointer will point.
FunctionPointer printInConsoleDelegate;
// Create the delegate object "MyFunctionPointer" that references
printInConsoleDelegate = new FunctionPointer(printInConsole);
// Get a pointer to the delegate that can be passed to the C lib
IntPtr printInConsolePtr =
Marshal.GetFunctionPointerForDelegate(printInConsoleDelegate);
Console.WriteLine(
"Call C++ which's calling back C# func \"printInConsole\"");
// Call C++ which calls C#
callCSharpFunction(printInConsolePtr);
// Stop the console until user's pressing Enter
Console.ReadLine();
}
public static void printInConsole(int nb)
{
// Write the parameter in the console
Console.WriteLine("value = " + nb + "; ");
}
}
}
不受管理的出口項目可能會幫助您:
https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports
基本上,它允許您使用DllExport屬性從程序集中導出函數。 然后可以像正常的本機Dll導出一樣使用這些功能。 這有點像缺少DllImport屬性的對應項。
然后,您將這樣聲明您的方法:
[DllExport("myCSharpFunction")]
static public void myCSharpFunction()
{
MessageBox.Show("Called from C++ code !!");
}
但是,這種雙向依賴關系在我看來通常也是可疑的。 在您的情況下,也許也可以使用回調,例如ken建議。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.