我试图在安装过程中使用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.dll
和MySql.Data.dll
在运行时正确提取到{tmp}
目录。
我在有和没有loadwithalteredsearchpath
标志的情况下尝试了相同的结果。
我发现此错误代码是一个通用.NET运行时错误代码。
如果我使用 MySql.Data
删除零件,它可以很好地工作(除了什么都不做...)
正如其他线程所建议的那样,我一直在尝试使用EventLog
和UnhandledException
在.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;
}
}