Quando si chiama le funzioni API di Windows da C #, quale fonte per le firme per la fiducia: il codice sorgente di .NET Framework o PInvoke?
-
29-09-2019 - |
Domanda
Ad esempio, questo è da file sorgente di .NET Framework UnsafeNativeMethods.cs :
[DllImport(ExternDll.User32, ExactSpelling=true, CharSet=CharSet.Auto)]
public static extern bool GetWindowRect(HandleRef hWnd,
[In, Out] ref NativeMethods.RECT rect);
e questo è da PInvoke.Net:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(HandleRef hwnd, out RECT lpRect);
-
Qual è il corretto / migliore firma per questa funzione? (Solo uno di loro ha
[return: MarshalAs(UnmanagedType.Bool)]
, o[In, Out] ref
, ecc.) -
Ho notato che nei file sorgente .NET Framework molti / la maggior parte delle firme hanno
ExactSpelling=true, CharSet=CharSet.Auto
, ma su PInvoke non lo fanno. È questo necessario?
Soluzione
Si saranno entrambi ottenere il lavoro fatto. C'è solo più di un modo per scuoiare un gatto PInvoke. In particolare per questo esempio:
-
ExactSpelling=true
è un'ottimizzazione, si evita di dover la PInvoke marshaller cercando le versioniGetWindowRectA
eGetWindowRectW
. Non esistono per questa particolare funzione API in quanto non fa una stringa. Vedendo una differenza reale in fase di esecuzione sarebbe un miracolo. -
CharSet=CharSet.Auto
è sempre una buona idea, dato il default (ANSI) è così inefficiente. E 'appena il caso di non fare alcuna differenza qui dato che la funzione non accetta argomenti stringa. -
[In, Out]
non è necessaria, perché questo è il valore predefinito per un tipo copiabili. Una parola costoso che significa che il marshaller PInvoke può passare direttamente un puntatore alla memoria gestita, è richiesta alcuna conversione. Il più efficiente possibile. Stessa idea comeCharSet
se, essendo esplicito su di esso aiuta a creare il codice di auto-documentare e ricordare a che fare con il caso insolito. Essere in grado di solo[In]
uso o[Out]
può essere una significativa ottimizzazione, non solo qui in quanto è già ottimizzata. FWIW, [Out] sarebbe stata la scelta giusta. -
out
vsref
, stessa idea come sopra. Utilizzandoout
è più corretto poiché l'API non usa realtà qualsiasi passato in valori all'interno delRECT
. Essa, tuttavia, non fa alcuna differenza in fase di esecuzione in quanto il compilatore JIT inizializza sempre una struttura in ogni caso. -
[return: MarshalAs(UnmanagedType.Bool)]
è inutile, è il marshalling predefinito per unBOOL
di Windows. Non certo perché pinvoke.net include sempre.
Quindi, in poche parole, non è perfetto, ma entrambi funzionerà. Tali sono i rischi di PInvoke.