c# - Delphi中加载C# DLL找不到依赖库DLL

标签 c# delphi dll .net-4.5 delphi-7

我用 C# 编写了一个小型互操作 DLL,供 Delphi(而非 COM)使用。
我正在使用 iTextSharp 生成 PDF 文件。
C# DLL 基本上非常简单:

namespace ClassLibrary1
{
    public class Class1
    {        
        [DllExport("Test1", CallingConvention = CallingConvention.StdCall)]
        public static void Test1()
        {
            System.IO.FileStream fs = new FileStream(@"D:\x.pdf", FileMode.Create, FileAccess.Write, FileShare.None);
            Document document = new Document();
            document.SetPageSize(PageSize.A4);
            PdfWriter writer = PdfWriter.GetInstance(document, fs);
            document.Open();
            document.Add(new Paragraph("Hello World"));
            document.Close();
            writer.Close();
            fs.Close();
        }
    }        
}

以及 Delphi 主机应用程序代码(位于不同的文件夹中):

procedure TForm1.Button1Click(Sender: TObject);
type
  TDLLProc = procedure; stdcall;
var
  DLLModule: HMODULE;
  DLLProc: TDLLProc;
begin
  // SetCurrentDir('G:\Projects\Test\ClassLibrary1\bin\x86\Release');
  DLLModule := LoadLibrary('G:\Projects\Test\ClassLibrary1\bin\x86\Release\ClassLibrary1.dll');
  if DLLModule = 0 then RaiseLastWin32Error;
  DLLProc := GetProcAddress(DLLModule, 'Test1');  
  if @DLLProc = nil then RaiseLastWin32Error;
  DLLProc(); // external exception E0434352
end;

问题是调用该方法会引发外部异常 E0434352,因为由于某种原因 C# DLL 找不到 itextsharp.dll

如果我将 itextsharp.dll 复制到 Project1.exe 目录,一切正常。
如果我将 Project1.exe 复制到 'G:\Projects\Test\ClassLibrary1\bin\x86\Release\ 一切正常。

我不希望将 ClassLibrary1.dllitextsharp.dll 放置在我的 EXE 程序目录中,而是从它们自己的目录中使用它们。

我尝试过显式设置SetCurrentDirecory,也尝试过SetDllDirectory,也尝试过LoadLibraryEx。没有任何帮助。

似乎即使我将 itextsharp.dll DLL(仅用于测试)放在 C:\Windows 目录中,我也会遇到相同的异常!

我可以做什么来解决这个问题?


编辑:查看 Loading .NET Assemblies out of Seperate Folders 后可能的解决方案(扭曲的恕我直言) @Peter Wolf 在评论中建议是否使用 System.Reflection.Assembly.LoadFrom 加载 itextsharp.dll 程序集并访问其每个类/方法/成员/通过反射等。即

[DllExport("Test1", CallingConvention = CallingConvention.StdCall)]
public static void Test1()
{
    var asm = System.Reflection.Assembly.LoadFrom(@"G:\Projects\Test\ClassLibrary1\bin\x86\Release\itextsharp.dll");
    Type tDocument = asm.GetType("iTextSharp.text.Document", true, true);
    dynamic document = Activator.CreateInstance(tDocument);
    Type tPageSize = asm.GetType("iTextSharp.text.PageSize", true, true);
    tPageSize.GetMethod("GetRectangle");
    // ETC... ETC... ETC...
}

这确实有效,但是这对我来说看起来很疯狂! 为了能够做到这一点而破坏了一个非常简单且良好的 C# 代码。
我简直不敢相信没有一种正常方式来加载位于与我的主机 Delphi 应用程序不同的文件夹中的 C# DLL。

是否有一种本地/正常且直接的方法可以在没有反射的情况下执行此操作???

最佳答案

您可以通过 AssemblyResolve 连接 C# DLL 中的程序集解析机制。事件。在这里,您有机会找到并加载 .NET 运行时本身无法找到的程序集。您可以安装处理程序,例如在类构造函数中(在您的情况下为 Class1),但如果您的 DLL 在 Class1 之外有一些入口点,这可能还不够。安装处理程序的代码是:

using System;
using System.IO;
using System.Linq;
using System.Reflection;

public class Class1
{
    static Class1()
    {
        var dllDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == args.Name);
            if (assembly != null)
            {
                return assembly;
            }
            var fileName = args.Name.Split(',')[0] + ".dll";
            var filePath = Path.Combine(dllDirectory, fileName);
            if (File.Exists(filePath))
            {
                return Assembly.LoadFile(filePath);
            }
            return null;
        };
    }

    // ...
}

关于c# - Delphi中加载C# DLL找不到依赖库DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57079263/

相关文章:

c# - 使用扩展方法时的意外行为

c# - 从文件名 c# 订购字符串 [] 路径

delphi - 如何将子树从一个 TTreeView 复制到另一个 TTreeView?

c# - 从 C# 调用 Delphi DLL 产生意外结果

c# - 将 c++ dll 自动包装到 c# 中

dll - Dumpbin 输出含义如下 .dll 导入部分

c - 隐藏依赖的DLL函数

javascript - 使用 jquery 添加元素到空列表

c# - 如何从 dll 中反编译/提取 (cshtml--(razor view))

delphi - 从 Chromium 嵌入式框架 3 打印