На відміну від пропозицій деяких інших відповідей, використання 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);