Вопреки предложениям некоторых других ответов, использование DllImport
атрибута по-прежнему является правильным подходом.
Я, честно говоря, не понимаю, почему вы не можете поступить так же, как все в мире, и указать относительный путь к своей DLL. Да, путь, по которому ваше приложение будет установлено, различается на компьютерах разных людей, но в основном это универсальное правило, когда дело доходит до развертывания. DllImport
Механизм разработан с учетом этого.
На самом деле, дело даже не в DllImport
этом. Это собственные правила загрузки Win32 DLL, которые управляют вещами, независимо от того, используете ли вы удобные управляемые оболочки (маршаллер P / Invoke просто вызывает LoadLibrary
). Эти правила перечислены здесь очень подробно , но здесь приведены выдержки из наиболее важных:
Прежде чем система выполнит поиск DLL, она проверяет следующее:
- Если DLL с тем же именем модуля уже загружена в память, система использует загруженную DLL, независимо от того, в каком каталоге она находится. Система не ищет DLL.
- Если DLL находится в списке известных DLL для версии Windows, в которой запущено приложение, система использует свою копию известной DLL (и зависимые библиотеки DLL известной DLL, если таковые имеются). Система не ищет DLL.
Если SafeDllSearchMode
он включен (по умолчанию), порядок поиска следующий:
- Каталог, из которого загружено приложение.
- Системный каталог. Используйте
GetSystemDirectory
функцию, чтобы получить путь к этому каталогу.
- 16-битный системный каталог. Нет функции, которая получает путь к этому каталогу, но он ищется.
- Каталог Windows. Используйте
GetWindowsDirectory
функцию, чтобы получить путь к этому каталогу.
- Текущий каталог.
- Каталоги, перечисленные в
PATH
переменной среды. Обратите внимание, что это не включает путь для каждого приложения, указанный в разделе реестра App Paths. Ключ App Paths не используется при вычислении пути поиска DLL.
Итак, если вы не называете свою DLL так же, как системная DLL (чего, очевидно, не следует делать ни при каких обстоятельствах), порядок поиска по умолчанию начнет поиск в каталоге, из которого было загружено ваше приложение. Если вы поместите туда DLL во время установки, она будет найдена. Все сложные проблемы исчезнут, если вы просто используете относительные пути.
Просто пиши:
[DllImport("MyAppDll.dll")]
static extern bool MyGreatFunction(int myFirstParam, int mySecondParam);
Но если это не сработает по какой-либо причине и вам нужно заставить приложение искать DLL в другом каталоге, вы можете изменить путь поиска по умолчанию с помощью этой SetDllDirectory
функции .
Обратите внимание, что согласно документации:
После вызова SetDllDirectory
стандартный путь поиска DLL:
- Каталог, из которого загружено приложение.
- Каталог, указанный
lpPathName
параметром.
- Системный каталог. Используйте
GetSystemDirectory
функцию, чтобы получить путь к этому каталогу.
- 16-битный системный каталог. Нет функции, которая получает путь к этому каталогу, но он ищется.
- Каталог Windows. Используйте
GetWindowsDirectory
функцию, чтобы получить путь к этому каталогу.
- Каталоги, перечисленные в
PATH
переменной среды.
Итак, если вы вызываете эту функцию перед вызовом функции, импортированной из DLL, в первый раз, вы можете изменить путь поиска по умолчанию, используемый для поиска DLL. Преимущество, конечно же, в том, что вы можете передать этой функции динамическое значение, которое вычисляется во время выполнения. Это невозможно с DllImport
атрибутом, поэтому вы все равно будете использовать относительный путь (только имя DLL) и полагаться на новый порядок поиска, чтобы найти его за вас.
Вам нужно будет P / Invoke этой функции. Объявление выглядит так:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);