Contrariamente ai suggerimenti di alcune delle altre risposte, l'utilizzo DllImportdell'attributo è ancora l'approccio corretto.
Onestamente non capisco perché non puoi fare come tutti gli altri nel mondo e specificare un percorso relativo alla tua DLL. Sì, il percorso in cui verrà installata l'applicazione differisce sui computer di persone diverse, ma questa è fondamentalmente una regola universale quando si tratta di distribuzione. Il DllImportmeccanismo è progettato pensando a questo.
In realtà, non è nemmeno DllImportquello che lo gestisce. Sono le regole di caricamento della DLL Win32 native che governano le cose, indipendentemente dal fatto che tu stia utilizzando i pratici wrapper gestiti (il marshaller P / Invoke chiama semplicemente LoadLibrary). Queste regole sono elencate qui in dettaglio , ma quelle importanti sono tratte qui:
Prima che il sistema cerchi una DLL, controlla quanto segue:
- Se una DLL con lo stesso nome di modulo è già caricata in memoria, il sistema utilizza la DLL caricata, indipendentemente dalla directory in cui si trova. Il sistema non cerca la DLL.
- Se la DLL è nell'elenco delle DLL conosciute per la versione di Windows su cui è in esecuzione l'applicazione, il sistema utilizza la sua copia della DLL nota (e delle eventuali DLL dipendenti della DLL nota). Il sistema non cerca la DLL.
Se SafeDllSearchModeè abilitato (impostazione predefinita), l'ordine di ricerca è il seguente:
- La directory da cui è stata caricata l'applicazione.
- La directory di sistema. Utilizzare la
GetSystemDirectoryfunzione per ottenere il percorso di questa directory.
- La directory di sistema a 16 bit. Non esiste alcuna funzione che ottiene il percorso di questa directory, ma viene cercata.
- La directory di Windows Utilizzare la
GetWindowsDirectoryfunzione per ottenere il percorso di questa directory.
- La directory corrente.
- Le directory elencate nella
PATHvariabile di ambiente. Si noti che ciò non include il percorso per applicazione specificato dalla chiave del Registro di sistema Percorsi app. La chiave Percorsi app non viene utilizzata durante il calcolo del percorso di ricerca DLL.
Quindi, a meno che tu non stia nominando la tua DLL come una DLL di sistema (cosa che ovviamente non dovresti mai fare, in nessun caso), l'ordine di ricerca predefinito inizierà a cercare nella directory da cui è stata caricata la tua applicazione. Se si inserisce la DLL lì durante l'installazione, verrà trovata. Tutti i complicati problemi scompaiono se si utilizzano solo percorsi relativi.
Scrivi e basta:
[DllImport("MyAppDll.dll")] // relative path; just give the DLL's name
static extern bool MyGreatFunction(int myFirstParam, int mySecondParam);
Ma se ciò non funziona per qualsiasi motivo, ed è necessario forzare l'applicazione a cercare una directory diversa per la DLL, è possibile modificare il percorso di ricerca predefinito utilizzando la SetDllDirectoryfunzione .
Si noti che, come da documentazione:
Dopo aver chiamato SetDllDirectory, il percorso di ricerca DLL standard è:
- La directory da cui è stata caricata l'applicazione.
- La directory specificata dal
lpPathNameparametro
- La directory di sistema. Utilizzare la
GetSystemDirectoryfunzione per ottenere il percorso di questa directory.
- La directory di sistema a 16 bit. Non esiste alcuna funzione che ottiene il percorso di questa directory, ma viene cercata.
- La directory di Windows Utilizzare la
GetWindowsDirectoryfunzione per ottenere il percorso di questa directory.
- Le directory elencate nella
PATHvariabile di ambiente.
Quindi, finché si chiama questa funzione prima di chiamare la funzione importata dalla DLL per la prima volta, è possibile modificare il percorso di ricerca predefinito utilizzato per individuare le DLL. Il vantaggio, ovviamente, è che puoi trasferire un valore dinamico a questa funzione che viene calcolata in fase di esecuzione. Ciò non è possibile con l' DllImportattributo, quindi dovrai comunque utilizzare un percorso relativo (solo il nome della DLL) e fare affidamento sul nuovo ordine di ricerca per trovarlo.
Dovrai P / Invocare questa funzione. La dichiarazione è simile alla seguente:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);