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

时间:2014-11-11 19:52:45

标签: c# c++ .net dll

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

我正在使用文件选择器将C ++ dll加载到我的项目中,然后将其复制到名为Process.dll的文件中。然后我使用这个dll做它的事情然后我需要能够加载一个新的dll并让它做它的事情。

所以它是这样的:

  1. 用户选择一个dll
  2. dll被复制到Processor.dll
  3. 使用dll导入的我的Processor类来使用dll
  4. 使用dll并调用其各种功能等
  5. 回到1。
  6. 我有2个班级

    1. ProcessTab - 具有GUI并在ProcessPlugin中调用类的C#类
    2. ProcessPlugin - 调用C ++类的C#类,它使用dllImport等
    3. 代码如下所示:

      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未处理,如代码中的注释所示。

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

      非常感谢提前

1 个答案:

答案 0 :(得分: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);
}

您可以像这样使用这些:

  • 定义委托:

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    private delegate ErrorCode ProcessorFunction(ref IntPtr pRx);
    
  • 加载库:

    IntPtr hLib = UnsafeNativeMethods.LoadLibrary("Processor.dll");
    
  • 获得代表:

    IntPtr ctorPtr = UnsafeNativeMethods.GetProcAddress(hLib, "VE_ProcessorPluginLib_Rx_API_Constructor");
    ProcessorFunction constructorFn = (ProcessorFunction)Marshal.GetDelegateForFunctionPointer(ctorPtr, typeof(ProcessorFunction));
    
  • 称呼它:

    conctructorFn(ref pRxClass);
    
  • 完成后,请释放库(最好放在finally块,SafeHandle或其他内容以确保完成此步骤:

    UnsafeNativeMethods.FreeLibrary(hLib);
    
  • 然后为第二个lib重复所有这些步骤。

显然我无法测试这个,因为我没有你的书架,但它应该让你走上正轨。
为了简洁起见,我已经添加了故障检查,但你肯定应该添加它们。