我有一个本机的非托管 C++ DLL (symulator.dll),我必须从托管 C# 应用程序加载和调用它。
DLL 使用 C++ 类和动态内存分配(通过new
操作符)。
它导出一个被调用的函数Init
,其定义如下:
extern "C" __declspec( dllexport ) int Init( void )
{
sym = new CSymulator();
sym->Init();
return 0;
}
CSymulator
DLL 中包含的类有一个相当简单的构造函数:
CSymulator::CSymulator( void )
{
memset( mem, 0, sizeof( mem ) );
memset( &rmr, 0, sizeof( rmr ) );
md = 0;
ma = 0;
tacts = 0;
}
DLL导出CSymulator::Init()
的Init()
函数调用的方法定义如下:
int CSymulator::Init( void )
{
int *a = new int;
*a = 1;
FILE *f = fopen( "tmp.log", "wb" );
fprintf( f, "%i", *a );
fclose( f );
delete a;
return 0;
}
我正在使用以下代码将本机 C++ DLL 加载到托管 C# 应用程序中:
public partial class Form1 : Form
{
public IntPtr SimHandle;
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadLibrary(string libname);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool FreeLibrary(IntPtr hModule);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
delegate int SimInit();
SimInit DLL_Init;
public void InicjujDLL()
{
IntPtr adres;
adres = GetProcAddress(SimHandle, "Init");
DLL_Init = (SimInit)Marshal.GetDelegateForFunctionPointer(adres, typeof(SimInit));
int rc = DLL_Init();
}
private void WczytajDLL()
{
String fileName = "D:\\prg\\kompilator\\Debug DLL\\symulator.dll";
SimHandle = LoadLibrary(fileName);
if (SimHandle == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Exception(string.Format("Blad przy wczytywaniu biblioteki ({0})", errorCode));
}
else
{
InicjujDLL();
}
}
private void Form1_Load(object sender, EventArgs e)
{
WczytajDLL();
}
}
此代码应生成一个名为tmp.log的文件,其中包含 的内容1
。但出于某种原因,tmp.log包含垃圾数据(一个随机的 32 位整数值而不是 1;例如,2550276
)。
它不是产生垃圾输出的唯一函数。任何尝试动态分配内存的 DLL 函数在这样做后都无法使用它。
就好像本机 C++ DLL 以某种方式通过 C# 垃圾收集器清除了其内存。
如何防止这种行为?
等一下:看看下面的参考:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int MultiplyByTen(int numberToMultiply);
我没有注意到您的委托没有相同的属性。
作为参考,我没有看到您执行 LoadLibrary: Dynamically Loading a Native Library 的方式有任何异常
我自己使用确切的参考做了这个,没有问题。我建议暂时删除在 DLL 内执行的所有代码,并只做一个简单的传递值。现在 Init() 总是返回 0。尝试别的东西,因为你之前已经将内存清零,得到零可能只是 mem-zero 操作的副作用。返回 1974 年什么的。
确保您启用了允许不安全代码并使用内存查看器查看堆栈(您将返回一个指针,以便您有一个起点)。如果你在 IL 旁边这样做,你可能会发现你的记忆被破坏了。
HTH
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句