Inno Setup - 具有依赖项的外部 .NET DLL
Inno Setup - External .NET DLL with dependencies
我试图在安装期间在 Inno Setup 脚本中使用自定义 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 Setup 中函数是这样导入的:
[Files]
Source: "..\..\MyDll\bin\x86\Release\*"; Flags: dontcopy;
和
[Code]
function CheckConnexion(connexionString: AnsiString): Integer;
external 'CheckConnexion@files:MyDll.dll,MySql.Data.dll stdcall setuponly loadwithalteredsearchpath';`
问题是安装程序在运行时抛出异常:
Runtime Error (at 53:207):
External exception E0434352.
我想我必须使用 files
前缀,因为在将文件复制到 {app}
目录之前,该函数在 NextButtonClick
事件处理程序中被调用。
MyDll.dll
和 MySql.Data.dll
都在运行时正确解压缩到 {tmp}
目录。
我尝试了使用和不使用 loadwithalteredsearchpath
标志,结果相同。
我发现这个错误代码是一个通用的 .NET 运行时错误代码。
如果我使用 MySql.Data
删除该部分,它工作得很好(除了它什么都不做...)
根据其他线程的建议,我一直在尝试使用 EventLog
和 UnhandledException
在我的 .NET 代码中记录错误,但无论如何我都有相同的异常(并且没有日志源已创建),即使没有 MySQL 部分。我检查了计算机上的事件日志权限。
似乎只要我使用任何其他 "basic" 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 Setup:
procedure Init(); external 'Init@files:MyDll.dll stdcall setuponly';
并在调用需要依赖的函数之前调用它(CheckConnexion
)。
另一种解决方案可能是这样的:
Embedding DLLs in a compiled executable
顺便说一句,不需要 loadwithalteredsearchpath
标志。它对 .NET 程序集 imo 没有影响。本机 DLL 依赖项需要它们:.
我发现了一些可能对偶然发现此页面的人有所帮助的其他内容。
在我的方案中,我有几个使用 DllExport 从 InnoSetup 调用的 C# 方法。在其中一种方法中,我调用了另一种方法。这导致 Inno 抛出 "External exception 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 造成的,所以我将放弃直接嘲笑并为我失去的早晨责怪整个社会。 (或者我自己是这个东西的新手。)
我想扩展一下 Martin 的回答。有一种无需先调用 Init 方法即可解析程序集的方法,那就是在 .NET 中包含一个静态构造函数 class:
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;
}
}
我试图在安装期间在 Inno Setup 脚本中使用自定义 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 Setup 中函数是这样导入的:
[Files]
Source: "..\..\MyDll\bin\x86\Release\*"; Flags: dontcopy;
和
[Code]
function CheckConnexion(connexionString: AnsiString): Integer;
external 'CheckConnexion@files:MyDll.dll,MySql.Data.dll stdcall setuponly loadwithalteredsearchpath';`
问题是安装程序在运行时抛出异常:
Runtime Error (at 53:207):
External exception E0434352.
我想我必须使用 files
前缀,因为在将文件复制到 {app}
目录之前,该函数在 NextButtonClick
事件处理程序中被调用。
MyDll.dll
和 MySql.Data.dll
都在运行时正确解压缩到 {tmp}
目录。
我尝试了使用和不使用 loadwithalteredsearchpath
标志,结果相同。
我发现这个错误代码是一个通用的 .NET 运行时错误代码。
如果我使用 MySql.Data
删除该部分,它工作得很好(除了它什么都不做...)
根据其他线程的建议,我一直在尝试使用 EventLog
和 UnhandledException
在我的 .NET 代码中记录错误,但无论如何我都有相同的异常(并且没有日志源已创建),即使没有 MySQL 部分。我检查了计算机上的事件日志权限。
似乎只要我使用任何其他 "basic" 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 Setup:
procedure Init(); external 'Init@files:MyDll.dll stdcall setuponly';
并在调用需要依赖的函数之前调用它(CheckConnexion
)。
另一种解决方案可能是这样的:
Embedding DLLs in a compiled executable
顺便说一句,不需要 loadwithalteredsearchpath
标志。它对 .NET 程序集 imo 没有影响。本机 DLL 依赖项需要它们:
我发现了一些可能对偶然发现此页面的人有所帮助的其他内容。
在我的方案中,我有几个使用 DllExport 从 InnoSetup 调用的 C# 方法。在其中一种方法中,我调用了另一种方法。这导致 Inno 抛出 "External exception 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 造成的,所以我将放弃直接嘲笑并为我失去的早晨责怪整个社会。 (或者我自己是这个东西的新手。)
我想扩展一下 Martin 的回答。有一种无需先调用 Init 方法即可解析程序集的方法,那就是在 .NET 中包含一个静态构造函数 class:
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;
}
}