Inno设置 - 依赖关系的外部.NET DLL



我试图在安装过程中使用Inno设置脚本中的自定义DLL。我编写了一个非常简单的功能,它基本上使用mySQL .NET连接器检查了MySQL数据库的连接字符串(目标服务器上没有MySQL客户端)。此导出功能的代码是:

public class DbChecker
{
    [DllExport("CheckConnexion", CallingConvention.StdCall)]
    public static int CheckConnexion([MarshalAs(UnmanagedType.LPStr)] string connexionString)
    {
        int success;
        try
        {
            MySqlConnection connection = new MySqlConnection(connexionString);
            connection.Open();
            connection.Close();
            success = 0;
        }
        catch (Exception)
        {
            success = 1;
        }
        return success;
    }
}

该函数是在Inno设置中导入的:

[Files]
Source: "....MyDllbinx86Release*"; Flags: dontcopy;

[Code]
function CheckConnexion(connexionString: AnsiString): Integer;
external 'CheckConnexion@files:MyDll.dll,MySql.Data.dll stdcall setuponly loadwithalteredsearchpath';`

问题是设置在运行时抛出异常:

运行时错误(在53:207):

外部异常E0434352。

我认为我必须使用files前缀,因为在将文件复制到{app}目录之前,该函数在NextButtonClick事件处理程序中调用。

MyDll.dllMySql.Data.dll在运行时正确提取到{tmp}目录。

我在有和没有loadwithalteredsearchpath标志的情况下尝试了相同的结果。

我发现此错误代码是一个通用.NET运行时错误代码。

如果我使用 MySql.Data删除零件,它可以很好地工作(除了什么都不做...)

正如其他线程所建议的那样,我一直在尝试使用EventLogUnhandledException在.NET代码中记录错误,但是即使没有MySQL部分,我也有相同的例外(也没有创建日志源)。我在计算机上检查了EventLog权限。

看来,只要我使用其他任何"基本" C#代码(每当我尝试加载另一个dll)。

可能有更好的方法,但这会做到。

实现一个初始化功能(此处的Init),该功能设置了AppDomain.AssemblyResolve处理程序,该处理程序在主(执行)汇编的路径中寻找一个汇编:

[DllExport("Init", CallingConvention.StdCall)]
public static void Init()
{
    AppDomain currentDomain = AppDomain.CurrentDomain;
    currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);
}
private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
    string location = Assembly.GetExecutingAssembly().Location;
    AssemblyName name = new AssemblyName(args.Name);
    string path = Path.Combine(Path.GetDirectoryName(location), name.Name + ".dll");
    if (File.Exists(path))
    {
        return Assembly.LoadFrom(path);
    }
    return null;
}

将其导入Inno设置:

procedure Init(); external 'Init@files:MyDll.dll stdcall setuponly';

并在调用需要依赖关系的功能之前调用它(CheckConnexion)。


另一个解决方案可能是:
将dll嵌入汇编的可执行文件


btw,无需loadwithalteredsearchpath标志。它对.NET组件IMO没有影响。它们是本机DLL依赖性所需的:在Inno设置中加载DLL在Inno设置中加载dll会在"卸载器"中使用"无法导入dll",但可以在安装程序中工作。

我发现了其他可能对绊倒此页面的人有帮助的东西。

在我的情况下,我使用dllexport从innosetup调用了几种C#方法。在其中一种方法中,我称之为另一种方法。这导致Inno投掷"外部异常E0434352"。

如果我将代码移至Innosetup未调用的方法,一切都很好。

所以...

[DllExport("Fu", CallingConvention = CallingConvention.StdCall)]
public static int Fu()
{
    // Stuff
}
[DllExport("Bar", CallingConvention = CallingConvention.StdCall)]
public static int Bar()
{
    Fu();
}

...导致Innosetup哭泣,但是:

[DllExport("Fu", CallingConvention = CallingConvention.StdCall)]
public static int Fu()
{
    LocalFu();  
}
private static int LocalFu()
{
    // Stuff
}
[DllExport("Bar", CallingConvention = CallingConvention.StdCall)]
public static int Bar()
{
    // Stuff
    LocalFu();
    // Other stuff
}

...很好。

我不知道这是由Inno还是Dllexport造成的,所以我会放弃直接嘲笑,并将社会整体归咎于我迷失的早晨。(或者我本人是这个事物的新手。)

我想扩展马丁的答案。有一种方法可以解决程序集,而不必首先调用init方法,也就是在您的.NET类中包括一个静态构造函数:

public class MyClass
{
    static MyClass()
    {
        AppDomain currentDomain = AppDomain.CurrentDomain;
        currentDomain.AssemblyResolve += MyResolveEventHandler;
    }
    private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
    {
        var location = Assembly.GetExecutingAssembly().Location;
        var assemblyName = new AssemblyName(args.Name);
        var path = Path.Combine(Path.GetDirectoryName(location), assemblyName.Name + ".dll");
        if (File.Exists(path))
        {
            return Assembly.LoadFrom(path);
        }
        return null;
    }
}

最新更新