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

曲折

我用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;

问题是,external exception E0434352由于某种原因C#DLL无法找到,因此调用该方法会引发问题itextsharp.dll

如果我将其复制itextsharp.dllProject1.exe目录中,则一切正常。
如果我复制Project1.exe'G:\Projects\Test\ClassLibrary1\bin\x86\Release\所有的作品。

我不想将ClassLibrary1.dllitextsharp.dll放在我的EXE程序目录中,但可以从其自己的目录中使用它们。

我试过明确设定SetCurrentDirecory,也试过SetDllDirectory,也试过LoadLibraryEx没有任何帮助。

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

我该怎么办才能解决这个问题?


编辑:查看@Peter Wolf在注释中建议的从单独文件夹加载.NET程序集后的一种可能的解决方案(扭曲的恕我直言),如果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;

publi 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;
        };
    }

    // ...
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章