我希望有人可以帮助我将 C++ dll 加载和重新加载到 C# 项目中。
我正在使用文件选取器将 C++ dll 加载到我的项目中,然后将其复制到名为 Process.dll 的文件中。然后我使用这个 dll 来做它的事情,然后我需要能够加载一个新的 dll 并让它做它的事情。
所以它是这样的:
- 用户选择一个dll
- dll 被复制到 Processor.dll
- 制作我的处理器类,它使用 dll 导入来使用 dll
- 使用dll并调用其各种函数等
- 回到 1。
我有两个类(class)
- ProcessTab - 具有 GUI 并调用 ProcessPlugin 中的类的 C# 类
- ProcessPlugin - 调用 C++ 类的 C# 类,它使用 dllImport 等
代码如下所示:
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);
}
}
}
}
一切正常,我调用 C++ dll 中的方法并获得预期的输出等,但是当我尝试销毁它并重新加载它时,我得到一个错误 AccessViolationException was unhandled,如代码中的注释所示。
有人知道我该如何解决这个问题吗?
提前致谢
最佳答案
P/Invoke 并不意味着处理这种情况。它假设库永远不会改变,我敢肯定它不希望您在它导入的模块上调用 FreeLibrary
。
如果你想动态地使用dlls,你将不得不手动做相当于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);
}
你可以像这样使用它们:
定义委托(delegate):
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate ErrorCode ProcessorFunction(ref IntPtr pRx);
加载库:
IntPtr hLib = UnsafeNativeMethods.LoadLibrary("Processor.dll");
获得委托(delegate):
IntPtr ctorPtr = UnsafeNativeMethods.GetProcAddress(hLib, "VE_ProcessorPluginLib_Rx_API_Constructor"); ProcessorFunction constructorFn = (ProcessorFunction)Marshal.GetDelegateForFunctionPointer(ctorPtr, typeof(ProcessorFunction));
调用它:
conctructorFn(ref pRxClass);
完成后,释放库(最好在
finally
block 、SafeHandle
或其他确保此步骤完成的东西中):UnsafeNativeMethods.FreeLibrary(hLib);
然后对第二个库重复所有这些步骤。
显然我无法测试这个,因为我没有你的库,但它应该会让你走上正轨。
为了简洁起见,我没有添加失败检查,但您绝对应该添加这些。
关于c# - 无法在 C# 项目中重新加载 C++ dll,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26873309/