Contrariamente ai suggerimenti di alcune delle altre risposte, l'utilizzo DllImport
dell'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 DllImport
meccanismo è progettato pensando a questo.
In realtà, non è nemmeno DllImport
quello 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
GetSystemDirectory
funzione 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
GetWindowsDirectory
funzione per ottenere il percorso di questa directory.
- La directory corrente.
- Le directory elencate nella
PATH
variabile 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 SetDllDirectory
funzione .
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
lpPathName
parametro
- La directory di sistema. Utilizzare la
GetSystemDirectory
funzione 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
GetWindowsDirectory
funzione per ottenere il percorso di questa directory.
- Le directory elencate nella
PATH
variabile 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' DllImport
attributo, 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);