Вызов функции из DLL с нестатическим путем - PullRequest
1 голос
/ 10 апреля 2009

У меня есть DLL, из которой мне нужно получить доступ к методам.

В большинстве подобных случаев я просто использую [DllImport] для доступа к методам из неуправляемых сборок, но проблема в этом случае в том, что во время создания экземпляра требуется путь к DLL, поэтому постоянная строка.

Эта конкретная DLL-библиотека устанавливается вместе с моим приложением, и я не могу гарантировать, где она будет после установки программы (я бы не стал размещать ее в статическом месте, например% SystemRoot%).

Так есть ли способ в C #, который я могу объявить и использовать метод из DLL во время выполнения с переменным путем?

Любые идеи или предложения будут с благодарностью!

Ответы [ 3 ]

2 голосов
/ 11 апреля 2009

Это немного взломано, но, поскольку вы говорите, что можете найти путь к dll во время выполнения, почему бы не скопировать его в текущий рабочий каталог, прежде чем использовать какую-либо из функций? Таким образом, DLL будет существовать рядом с вашим EXE-файла и будет найден LoadLibrary. Нет необходимости в дополнительном пути в вашем DllImport.

Единственный способ использовать метод из динамического пути - это сделать:
1) Выполните необходимые подписи P / Invoke для LoadLibrary & GetProcAddress
2) Загрузить библиотеку по нужному пути (LoadLibrary)
3) Найти нужную функцию (GetProcAddress)
4) Приведите указатель к делегату Marshal.GetDelegateForFunctionPointer
5) вызвать его.

Конечно, вам нужно будет объявить делегата для каждой функции, которую вы хотите «импортировать» таким образом, так как вы должны привести указатель к делегату.

2 голосов
/ 10 апреля 2009

Не используйте путь вообще. Windows использует метод поиска DLL по умолчанию при попытке динамически или статически загрузить функцию из нее.

Точная логика поиска задокументирована в MSDN в документах для LoadLibrary - в основном, если DLL просто используется вашим приложением, поместите в ту же папку, что и ваше приложение во время установки, и не беспокоиться об этом. Если это часто используемая DLL, поместите ее где-нибудь в структуру папок, которую ищет LoadLibrary (), и она будет найдена.

0 голосов
/ 14 августа 2015

У меня была похожая ситуация. Я использую DLL из SDK, который установлен на машине. Я получаю расположение каталога DLL из этого ключа реестра SDK. Я устанавливаю местоположение DLL в переменной PATH исполняющего пользователя (только временная модификация). По сути, он позволяет вам установить динамический путь к той DLL, которую вы хотите вызвать, поэтому он не должен быть из реестра. Имейте в виду, что переменная PATH - это последнее место, где Windows ищет библиотеки DLL. Но, с другой стороны, это не меняет других мест, где Windows ищет библиотеки DLL.

Пример:

API, который я хочу вызвать, в DLL:

[DllImport("My.DLL")]
private static extern IntPtr ApiCall(int param);

Получить ключ реестра (вам нужно с помощью Microsoft.Win32; ):

private static string GetRegistryKeyPath() {
        string environmentPath = null;

        using (var rk = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\SOMENNAME"))
        {
            if (rk != null)
            {
                environmentPath = rk.GetValue("Path(or whatever your key is)").ToString();
            }
            if (string.IsNullOrEmpty(environmentPath))
            {
                Log.Warn(
                    string.Format("Path not found in Windows registry, using key: {0}. Will default to {1}",
                         @"SOFTWARE\SOMETHING", @"C:\DefaultPath"));
                environmentPath = @"C:\DefaultPath";
            }
        }
        return environmentPath;
     }

Добавьте путь к DLL в переменной PATH (Concat () находится в Linq):

void UpdatePath(IEnumerable<string> paths){
    var path = new[] { Environment.GetEnvironmentVariable("PATH") ?? "" };
    path = path.Concat(paths);
    string modified = string.Join(Path.PathSeparator.ToString(), path);
    Environment.SetEnvironmentVariable("PATH", modified);
}

Начало использования вызова API:

var sdkPathToAdd = GetRegistryKeyPath();
IList<string> paths = new List<string>
        {
            Path.Combine(sdkPathToAdd),
            Path.Combine("c:\anotherPath")
        };
UpdatePath(paths);

//Start using
ApiCall(int numberOfEyes);
...