2017-08-30 59 views
2

我想在安装期间在Inno安装脚本中使用自定义DLL。我写了一个非常简单的函数,它基本上使用MySQL .NET连接器检查MySQL数据库的连接字符串(目标服务器上没有MySQL客户端)。这个导出函数的代码是:Inno安装程序 - 依赖关系的外部.NET DLL

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 Setup的:

[Files] 
Source: "..\..\MyDll\bin\x86\Release\*"; Flags: dontcopy; 

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

的问题是,设置抛出异常的运行时间:

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

外部异常E0434352。

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

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

我试着用和不用loadwithalteredsearchpath标志都有相同的结果。

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

如果我删除使用MySql.Data它工作完全正常(除了它什么也不做......)

诚如其他线程上我一直在试图将错误使用EventLog我的.NET代码的一部分和UnhandledException,但是无论什么(也没有创建日志源),我都有相同的异常,即使没有MySQL部分也是如此。我在我的电脑上检查了EventLog权限。

看来,只要我使用其他任何“基本”C#代码(每当我尝试加载另一个DLL)时,都会抛出异常。

+0

CheckConnexion在NextButtonClick事件处理程序中调用。 如果我没有使用'MySql.Data'的第二个函数,它正在工作。纯粹的参考似乎不是问题。 – tvarnier

+0

使用'File.WriteAllLines',调用没有引用'MySql.Data'的函数,记录并正确返回。使用'MySql.Data'的人在没有记录任何东西的情况下仍然以相同的方式失败。 – tvarnier

+0

由于引用,'MySql.Data' dll被复制到'MyDll'的bin目录中。整个目录导入到我的原始文章中描述的'[files]'部分。 我可以在运行时看到在Inno-Setup临时目录中提取的'MySql.Data.dll'和'MyDll.dll'。 – tvarnier

回答

2

有可能是一种更好的方式,但是这样做。

实现一个初始化函数(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 Setup的:

procedure Init(); external '[email protected]:MyDll.dll stdcall setuponly'; 

在调用需要依赖项的函数之前调用它(CheckConnexion)。


另一种解决方案可能是这样的:
Embedding DLLs in a compiled executable


顺便说一句,没有必要为loadwithalteredsearchpath标志。它对.NET组件imo没有影响。

+0

这个伎俩!我确实看到了这里的逻辑,但是我们必须这样做,这是一种耻辱,尤其是在Windows ^^上。似乎IDD,'loadwithalteredsearchpath'标志不适用于.NET程序集。非常感谢 ! – tvarnier

+0

完成:)顺便说一句,我试图嵌入当时的dll。它在我的开发计算机上工作,但不在CI服务器上,因为Costura是为.NET 4.5.x编译的,而且似乎.NET 4和4.5编译器具有接口差异。这就是为什么我不得不直接引用'MySql.Data'。但是这个解决方法是简单架构上的一个很好的解决方案。 – tvarnier