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