На відміну від пропозицій деяких інших відповідей, використання DllImport
атрибута все-таки є правильним підходом.
Я, чесно кажучи, не розумію, чому ви не можете робити так, як усі в світі, і вказати відносний шлях до DLL. Так, шлях, по якому буде встановлено ваш додаток, відрізняється на комп'ютерах різних людей, але це в основному універсальне правило, що стосується розгортання. DllImport
Механізм розроблений з урахуванням цього.
Насправді це навіть не з DllImport
цим справляється. Це рідні правила завантаження DLL Win32, які керують речами, незалежно від того, використовуєте ви зручні керовані обгортки (маршалок P / Invoke просто дзвонить LoadLibrary
). Ці правила перераховані в деталях тут , але важливі з них взяті тут:
Перш ніж система шукає DLL, вона перевіряє наступне:
- Якщо DLL з тим же ім'ям модуля вже завантажено в пам'ять, система використовує завантажену DLL, незалежно від того, в якому каталозі вона знаходиться. Система не шукає DLL.
- Якщо DLL знаходиться у списку відомих DLL для версії Windows, на якій працює програма, система використовує свою копію відомої DLL (та відомих 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. Перевага, звичайно, полягає в тому, що ви можете передавати динамічне значення цій функції, яка обчислюється під час виконання. Це неможливо з DllImport
атрибутом, тому ви все одно будете використовувати відносний шлях (назва лише DLL) там і покладайтеся на новий порядок пошуку, щоб знайти його для вас.
Вам доведеться P / Invoke цю функцію. Декларація виглядає приблизно так:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);