Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как импортировать длл, с заранее не известным именем 
V
    Опции темы
emmanuil
Дата 20.4.2007, 10:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 380
Регистрация: 9.1.2007

Репутация: нет
Всего: 3



Загружаю dll'ки из каталога, заранее их имена и количество не известны. Как передать не const в DllImport? Или может есть еще какой нибудь способ загрузки длл?

Код

        private static class DllImporter
        {
            const String DllName = "My.dll";

            [DllImport(DllName, CharSet = CharSet.Auto)]
            public static extern int StartUp(Delegate callBackFunction);
        }

PM MAIL   Вверх
Exception
Дата 20.4.2007, 22:45 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 4525
Регистрация: 26.12.2004

Репутация: 29
Всего: 186



Код

Вот это вынеси в отдельный файл:

Код
/// <summary>Нативные функции.</summary>
internal static class LibraryLoaderNative
{
    /// <summary>Ищем в разных диреториях.</summary>
    public static const uint LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;

    /// <summary>
    /// Загружает в память DLL.
    /// </summary>
    /// <param name="dllFilePath">Путь к библиотеке.</param>
    /// <param name="hFile">Указывайте IntPtr.Zero.</param>
    /// <param name="dwFlags">Дополнительные параметры загрузки:
    /// <para>LOAD_LIBRARY_AS_DATAFILE</para>
    /// <para>DONT_RESOLVE_DLL_REFERENCES</para>
    /// <para>LOAD_WITH_ALTERED_SEARCH_PATH</para>
    /// <para>LOAD_IGNORE_CODE_AUTHZ_LEVEL</para>
    /// </param>
    /// <returns>Указатель на загруженную DLL.</returns>
    [DllImport("kernel32.dll")]
    public static extern IntPtr LoadLibraryEx(string dllFilePath, IntPtr hFile, uint dwFlags);
    
    /// <summary>
    /// Выгружает DLL из памяти.
    /// </summary>
    /// <param name="dllPointer">Указатель на загруженную DLL.</param>
    /// <returns>Истинно, если операция прошла успешно.</returns>
    [DllImport("kernel32.dll")]
    public static extern bool FreeLibrary(IntPtr dllPointer);
    
    /// <summary>
    ///  Получает указатель на функцию из DLL.
    /// </summary>
    /// <param name="dllPointer">Указатель на загруженную DLL.</param>
    /// <param name="functionName">Имя функции.</param>
    /// <returns>Указатель на функцию библиотеки.</returns>
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
    public static extern IntPtr GetProcAddress(IntPtr dllPointer, string functionName);
}

/// <summary>Класс, представляющий собой библиотеку DLL.</summary>
public class Library : IDisposable
{
    private bool _disposed;

    /// <summary>Указатель на DLL.</summary>
    private IntPtr _pointer;

    /// <summary>Прячем конструктор без параметров.</summary>
    private Library () {}

    /// <summary>Конструктор.</summary>
    /// <param name="fileName">Путь к DLL.</summary>
    public Library (string fileName)
    {
        this._pointer = Library.GetPointer (fileName);
    }

    /// <summary>Загружает DLL по имени.</summary>
    /// <param name="fileName">Путь к DLL.</summary>
    /// <returns>Указатель на загруженную библиотеку.</returns>
    public static IntPtr GetPointer (fileName)
    {
            IntPtr moduleHandle = LibraryLoaderNative.LoadLibraryEx (fileName, IntPtr.Zero, LibraryLoaderNative.LOAD_WITH_ALTERED_SEARCH_PATH);
            if (moduleHandle == IntPtr.Zero)
                int errorCode = Marshal.GetLastWin32Error();
                throw new ApplicationException (
                    string.Format("Произошла ошибка при загрузке библиотеки {0}, код ошибки: {1}.", fileName, errorCode)
                );
            }
            return moduleHandle;
    }

    /// <summary>Возвращает делегат на функцию из DLL.</summary>
    /// <param name="functionName">Имя функции.</param>
    /// <typeparam name="TDelegate">Тип делегата запрашиваемой функции.</param>  
    protected TDelegate GetDelegate<TDelegate> (string functionName)
        where TDelegate : Delegate
    {
        if (this._disposed) 
        {
            throw new ApplicationException (
                string.Format ("Не удаётся запустить функцию {0}; библиотека уже выгружена из памяти!", functionName)
            );
            return null;
        }
        IntPtr proc = LibraryLoaderNative.GetProcAddress (this._pointer, functionName);
        TDelegate del = Marshal.GetDelegateForFunctionPointer (proc, typeof (TDelegate)) as TDelegate;
        if (del == null)
        {
            throw new ApplicationException (
                string.Format ("Не найдена функция {0}!", functionName)
            );
        }
        return del;
    }

     /// <summary>Выгружаем библиотеку</summary>
    public void Dispose ()
    {
        if (!this._disposed)
        {
            LibraryLoaderNative.UnloadLibrary (this._pointer);
        }
    }

    /// <summary>Финалайзер.</summary>
    public ~Library ()
    {
        this.Dispose ();
    }
}


Как этим добром пользоваться?

Во-первых, объявим класс-обёртку для библиотеки, наследник Library:

Код

class MyLibrary : Library
{

}


Во-вторых, добавим в него определение какой-нибудь функции:

Код
    public delegate int MyFunctionDelegate (int a, string b);


Далее, напишем метод-обёртку:

Код

    public int MyFunction (int a, string b)
    {
        MyFunctionDelegate del = base.GetDelegate<MyFunctionDelegate> ("MyFunction");
        return del (a, b);
    }


Не забудьте определить конструктор:

Код

    public MyLibrary (string fileName) : base (fileName) {}


Вот и всё!

Использование:

Код
using (MyLibrary lib = new MyLibrary ("C:\MyLibrary.dll"))
{
    Console.WriteLine (lib.MyFunction (10, "Hello world!"));
}


Разумеется, никто не мешает хранить lib в поле какого-нибудь класса, но тогда не забудьте вызвать метод Dispose () по окончании работы с библиотекой!

Замечания

За основу был взят этот код.
Код не проверял на работоспособность, так как писал прямо в браузере.
Проверяйте сами smile !

Это сообщение отредактировал(а) Exception - 20.4.2007, 23:27
PM   Вверх
emmanuil
Дата 23.4.2007, 06:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 380
Регистрация: 9.1.2007

Репутация: нет
Всего: 3



Exception, спасибо! Получается компилятор должен знать пути при компиляции. Как все запущено! Неужели нельзя было предусмотреть такую мелочь, как загрузка длл с динамическим путем?! Или может я чего-то не понимаю?!
В твоем коде, на делегат ругается в этом условии : where TDelegate : Delegate, пишет, что неможет быть классом Delegate
PM MAIL   Вверх
mr.DUDA
Дата 23.4.2007, 12:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 110
Всего: 232



emmanuil, LoadLibrary загрузит длл-ку если та лежит в текущей папке или по одному из путей в переменной PATH. Иначе нужно указывать полный путь к длл.


--------------------
user posted image
PM MAIL WWW   Вверх
emmanuil
Дата 23.4.2007, 12:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 380
Регистрация: 9.1.2007

Репутация: нет
Всего: 3



Код Exception'а вполне рабочий, только если исправить метод GetDelegate. класс Delegate является абстрактным классом, может поэтому нельзя сделать where TDelegate : Delegate.
Всем спасибо, особенно Exception'у
PM MAIL   Вверх
Exception
Дата 23.4.2007, 18:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 4525
Регистрация: 26.12.2004

Репутация: 29
Всего: 186



Вопрос на засыпку: а как тогда указать что TDelegate это делегат?
У меня сейчас компилятора нет под рукой..
PM   Вверх
emmanuil
Дата 24.4.2007, 05:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 380
Регистрация: 9.1.2007

Репутация: нет
Всего: 3



Если только так
Код

public Delegate GetDelegate<TDelegate>(string functionName)

Нужно тогда просто кроме делегата ничего не подавать, но это не решение! От System.Delegate нельзя сделать даже производный класс! 
System.Delegate - абстрактный класс! Может я что попутал?! Может ктонибудь знает как это сделать?!
PM MAIL   Вверх
Exception
Дата 25.4.2007, 16:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 4525
Регистрация: 26.12.2004

Репутация: 29
Всего: 186



Цитата(emmanuil @  24.4.2007,  06:39 Найти цитируемый пост)
От System.Delegate нельзя сделать даже производный класс! 
System.Delegate - абстрактный класс!


Сам себе противоречишь smile . Наоборот, если класс абстрактный, его можно и нужно наследовать, т.к. его объект создать нельзя smile .
Да и конструкция

Код

class MyClass
{
    public delegate void MyDelegate ();
}


на самом деле компилируется в 


Код

class MyClass
{
    public class MyClass$MyDelegate : System.Delegate
    {
        // ...
    }
}


Это сообщение отредактировал(а) Exception - 25.4.2007, 16:11
PM   Вверх
marcusmae
Дата 26.5.2007, 17:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


stravaganza
**


Профиль
Группа: Участник
Сообщений: 874
Регистрация: 26.3.2006

Репутация: 22
Всего: 39



Цитата(Exception @  23.4.2007,  18:14 Найти цитируемый пост)
Вопрос на засыпку: а как тогда указать что TDelegate это делегат?У меня сейчас компилятора нет под рукой..


Delegate и Multicast delegate - специальные классы. Их нельзя программно наследовать, но при этом все объявленные делегаты от них неявно наследуются. Кому-нибудь известна мотивация?
Впрочем, если бы было иначе, то в where их указать всё-равно не удастся, поскольку constraint where принимает только interface-ы и new() - наличие конструктора по умолчанию.

+ Интересная тема.



--------------------
ἀπὸ μηχανῆς θεός
PM MAIL ICQ GTalk   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.1322 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.