[英]Cant re-load C++ dll in C# Project
I hope there is someone there that can help me with loading and reloading a C++ dll into a C# project. 我希望那里有人可以帮助我将C ++ DLL加载和重新加载到C#项目中。
I am loading a C++ dll into my project using a file picker and then copying it to a file called Process.dll. 我正在使用文件选择器将C ++ DLL加载到我的项目中,然后将其复制到名为Process.dll的文件中。 I then use this dll to do its thing and then later I need the ability to load a new dll and for it to do its thing.
然后我使用这个dll来做它的事情然后我需要能够加载一个新的dll并让它做它的事情。
So it goes like this: 所以它是这样的:
I have 2 classes 我有2节课
The code looks like this: 代码如下所示:
class ProcessorTab
{
private void buttonLoadProcDll_Click(object sender, RoutedEventArgs e)
{
// Open dll and copy it to "\\Processor.dll"
processorPlugIn = new ProcessorPlugIn(this);
return;
}
private void DestroyProcessor_Click(object sender, RoutedEventArgs e)
{
processorPlugIn.UnloadModule("Processor.dll");
processorPlugIn = null;
}
}
class ProcessorPlugIn
{
public const string PluginName = "Processor.dll";
public LibraryInfo info;
ErrorCode err;
private IntPtr pRxClass;
private IntPtr pTxClass;
[DllImport("kernel32", SetLastError = true)]
static extern bool FreeLibrary(IntPtr hModule);
[System.Runtime.InteropServices.DllImportAttribute(PluginName, CallingConvention = CallingConvention.Cdecl)]
public static extern ErrorCode VE_ProcessorPluginLib_Rx_API_Constructor(ref IntPtr pRx);
[System.Runtime.InteropServices.DllImportAttribute(PluginName, CallingConvention = CallingConvention.Cdecl)]
public static extern ErrorCode VE_ProcessorPluginLib_Rx_API_Destructor(ref IntPtr pRx);
[System.Runtime.InteropServices.DllImportAttribute(PluginName, CallingConvention = CallingConvention.Cdecl)]
public static extern ErrorCode VE_ProcessorPluginLib_Tx_API_Constructor(ref IntPtr pTx);
[System.Runtime.InteropServices.DllImportAttribute(PluginName, CallingConvention = CallingConvention.Cdecl)]
public static extern ErrorCode VE_ProcessorPluginLib_Tx_API_Destructor(ref IntPtr pTx);
public ProcessorPlugIn(MainWindow mWindow)
{
pRxClass = new IntPtr();
pTxClass = new IntPtr();
if (VE_ProcessorPluginLib_Rx_API_Constructor(ref pRxClass) != ErrorCode.EC_OK) // ERROR HERE: AccessViolationException was unhandled
MessageBox.Show("Error constructing Rx");
if (VE_ProcessorPluginLib_Tx_API_Constructor(ref pTxClass) != ErrorCode.EC_OK)
MessageBox.Show("Error constructing Tx");
}
public void UnloadModule(string moduleName)
{
if (VE_ProcessorPluginLib_Rx_API_Destructor(ref pRxClass) != ErrorCode.EC_OK)
MessageBox.Show("Error destropying Rx");
if (VE_ProcessorPluginLib_Tx_API_Destructor(ref pTxClass) != ErrorCode.EC_OK)
MessageBox.Show("Error destropying Rx");
foreach (ProcessModule mod in Process.GetCurrentProcess().Modules)
{
if (mod.ModuleName == moduleName)
{
FreeLibrary(mod.BaseAddress);
}
}
}
}
Everything works fine and i call the methods in the C++ dll and get the expected outputs etc, but when I try to destroy it and reload it I get an error AccessViolationException was unhandled as shown in the comments in the code. 一切正常,我调用C ++ DLL中的方法并获得预期的输出等,但是当我尝试销毁它并重新加载它时,我得到一个错误AccessViolationException未处理,如代码中的注释所示。
Does anyone have any idea how I can solve this? 有谁知道如何解决这个问题?
Many thanks in advance 提前谢谢了
P/Invoke is not meant to handle this case. P / Invoke并不意味着处理这种情况。 It assumes the library never changes and I'm sure it doesn't expect you to call
FreeLibrary
on modules it imports. 它假设库永远不会改变,我相信它不会指望你在它导入的模块上调用
FreeLibrary
。
If you want to use dlls dynamically , you'll have to manually do the equivalent of what P/Invoke does under the hood: use LoadLibrary
/ GetProcAddress
: 如果你想动态使用dll,你必须手动完成P / Invoke所做的相同操作:使用
LoadLibrary
/ GetProcAddress
:
private static class UnsafeNativeMethods
{
[DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)]
static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32", SetLastError=true)]
static extern bool FreeLibrary(IntPtr hModule);
}
You use these like this: 你使用这样的:
Define a delegate: 定义委托:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate ErrorCode ProcessorFunction(ref IntPtr pRx);
Load the library: 加载库:
IntPtr hLib = UnsafeNativeMethods.LoadLibrary("Processor.dll");
Get a delegate: 获得代表:
IntPtr ctorPtr = UnsafeNativeMethods.GetProcAddress(hLib, "VE_ProcessorPluginLib_Rx_API_Constructor"); ProcessorFunction constructorFn = (ProcessorFunction)Marshal.GetDelegateForFunctionPointer(ctorPtr, typeof(ProcessorFunction));
Call it: 叫它:
conctructorFn(ref pRxClass);
When you're done, free the library (best in a finally
block, SafeHandle
or something to ensure this step is done): 完成后,释放库(最好在
finally
一个块, SafeHandle
或其他东西,以确保完成此步骤):
UnsafeNativeMethods.FreeLibrary(hLib);
Then repeat all these steps for the second lib. 然后为第二个lib重复所有这些步骤。
Obviously I can't test this because I don't have your libs, but it should put you on the right track. 显然我无法测试这个,因为我没有你的库,但它应该让你走上正轨。
I've left adding the failure checks for brevity but you definitely should add these. 为了简洁,我已经添加了故障检查,但你肯定应该添加这些。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.