无法在C#项目中重新加载C++ dll

3
我希望有人能帮我将C++ dll加载到C#项目中并重新加载。

我使用文件选择器将C++ dll加载到项目中,然后将其复制到名为Process.dll的文件。然后我使用这个dll来完成它的任务,稍后我需要能够加载一个新的dll并让它完成它的任务。

步骤如下:

  1. 用户选择一个dll
  2. dll被复制到Processor.dll
  3. 创建我的处理器类,该类使用dll导入使用dll
  4. 使用dll并调用其各种函数等
  5. 回到第1步。

我有两个类

  1. ProcessTab - C# 类,其中包含GUI并调用ProcessPlugin中的类
  2. 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未处理,如代码中的注释所示。

有谁知道我该如何解决这个问题吗?

提前感谢您的帮助。


你能发布完整的错误信息吗? - IdeaHat
只有在调用了 LoadLibrary 后,才能调用 FreeLibrary - David Heffernan
1个回答

5
P/Invoke不适用于处理这种情况。它假设库永远不会改变,我确信它不会期望您在导入的模块上调用FreeLibrary

如果您想要动态使用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);
}

您可以这样使用它们:
  • 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):

    UnsafeNativeMethods.FreeLibrary(hLib);
    
  • Then repeat all these steps for the second lib.

很明显我无法测试这个,因为我没有你的库,但这应该能让你走上正确的道路。
出于简洁起见,我没有添加失败检查,但你一定要添加这些。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接