Inno Setup - внешняя.NET DLL с зависимостями

Я пытаюсь использовать пользовательские библиотеки DLL в сценарии установки Inno во время установки. Я написал очень простую функцию, которая в основном проверяет строку подключения для базы данных MySQL, используя коннектор MySQL .NET (на целевом сервере нет клиента 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';`

Проблема состоит в том, что установка выдает исключение во время выполнения:

Ошибка выполнения (в 53:207):

Внешнее исключение E0434352.

Я думаю, что я должен использовать files префикс, потому что функция вызывается в NextButtonClick обработчик событий, перед тем как файлы будут скопированы в {app} каталог.

И то и другое MyDll.dll а также MySql.Data.dll правильно извлечены в {tmp} каталог во время выполнения.

Я пробовал как с, так и без loadwithalteredsearchpath флаг с тем же результатом.

Я обнаружил, что этот код ошибки является общим кодом ошибки.NET во время выполнения.

Если я удаляю часть, используя MySql.Data он отлично работает (кроме того, что ничего не делает...)

Как советовали в других темах, я пытался записать ошибку в мой код.NET, используя EventLog а также UnhandledException но у меня есть одно и то же исключение, несмотря ни на что (и источник журналов не создается), даже без части MySQL. Я проверил разрешения EventLog на моем компьютере.

Кажется, что исключение выдается, как только я использую что-нибудь еще, что "основной" код C# (всякий раз, когда я пытаюсь загрузить другую DLL).

3 ответа

Решение

Возможно, есть лучший способ, но это подойдет.

Реализовать функцию инициализации (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).


Другое решение может быть таким:
Встраивание DLL в скомпилированный исполняемый файл


Кстати, нет необходимости в loadwithalteredsearchpath флаг. Это не влияет на сборки.NET IMO.

Я нашел кое-что еще, что могло бы быть полезным для любого, кто натыкается на эту страницу.

В моем сценарии у меня есть несколько методов C#, которые я вызываю из InnoSetup, используя DllExport. В одном из этих методов я вызываю другой из методов. Это заставило 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;
    }
}
Другие вопросы по тегам