Sto cercando di trovare un buon modo per rilevare se una funzione esiste prima di P/Invocazione. Per esempio chiamando il nativo StrCmpLogicalW
funzione di:Rilevamento di funzioni durante P/Invocazione in C# e .NET
[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern int StrCmpLogicalW(string psz1, string psz2);
}
sarà in crash su alcuni sistemi che non dispongono di questa funzionalità.
i don't want to perform version checking, come quello è cattiva pratica, ed a volte può essere solo sbagliato (per esempio quando la funzionalità è di back-porting, o quando la funzionalità può essere disinstallato).
Il modo corretto, è quello di verificare la presenza delle esportazioni da shlwapi.dll
:
private static _StrCmpLogicalW: function(String psz1, String psz2): Integer;
private Boolean _StrCmpLogicalWInitialized;
public int StrCmpLogicalW(String psz1, psz2)
{
if (!_StrCmpLogialInitialized)
{
_StrCmpLogicalW = GetProcedure("shlwapi.dll", "StrCmpLogicalW");
_StrCmpLogicalWInitialized = true;
}
if (_StrCmpLogicalW)
return _StrCmpLogicalW(psz1, psz2)
else
return String.Compare(psz1, psz2, StringComparison.CurrentCultureIgnoreCase);
}
Il problema, naturalmente, è che C# non supporta i puntatori a funzione, vale a dire:
_StrCmpLogicalW = GetProcedure("shlwapi.dll", "StrCmpLogicalW");
non può essere eseguito.
Quindi sto cercando di trovare la sintassi alternativa per eseguire la stessa logica in .NET. Ho il seguente pseudo-codice finora, ma sto ottenendo ostacolato:
[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
private Boolean IsSupported = false;
private Boolean IsInitialized = false;
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode, Export="StrCmpLogicalW", CaseSensitivie=false, SetsLastError=true, IsNative=false, SupportsPeanutMandMs=true)]
private static extern int UnsafeStrCmpLogicalW(string psz1, string psz2);
public int StrCmpLogicalW(string s1, string s2)
{
if (!IsInitialized)
{
//todo: figure out how to loadLibrary in .net
//todo: figure out how to getProcedureAddress in .net
IsSupported = (result from getProcedureAddress is not null);
IsInitialized = true;
}
if (IsSupported)
return UnsafeStrCmpLogicalW(s1, s2);
else
return String.Compare(s1, s2, StringComparison.CurrentCultureIgnoreCase);
}
}
e ho bisogno di aiuto.
Un altro esempio di alcune esportazioni che voglio rilevare la presenza di sarebbe:
dwmapi.dll::DwmIsCompositionEnabled
dwmapi.dll::DwmExtendFrameIntoClientArea
dwmapi.dll::DwmGetColorizationColor
dwmapi.dll::DwmGetColorizationParameters
(non documentato , non ancora esportati per nome, ordinale 127)dwmapi.dll::127
(senza documenti , DwmGetColorizationParameters)
come di Windows 7 SP1
Ci deve essere già un modello di progettazione in .NET per verificare la presenza di caratteristiche del sistema operativo. Qualcuno può indicarmi un esempio del modo preferito in .NET per eseguire il rilevamento delle funzionalità?
Lo schema di progettazione nel codice sorgente di .NET Framework è per controllare i numeri di versione del sistema operativo, ma per farlo * in modo intelligente * come conclude Larry Osterman nel suo post sul blog. Sono d'accordo che la soluzione di Johann sia probabilmente migliore, ma sono anche un ragazzo Win32. 'LoadLibrary' e' GetProcAddress' solo * hanno senso * per me. Trascorro la maggior parte del mio tempo scrivendo le definizioni P/Invoke quando scrivo codice .NET. Non sono sicuro che sia effettivamente una buona cosa. –
@Cody: * Non sono sicuro che sia effettivamente una buona cosa * - probabilmente no, no. :-) –
@CodeGray Non si può fare affidamento sui numeri di versione. Una funzionalità potrebbe essere stata trasferita retroattivamente su un sistema operativo (rendendo errati i numeri di versione). Una funzione potrebbe anche non essere installata dall'utente (rendendo errati i numeri di versione). –