2009-04-18 11 views
9

Sulla MSDN ho trovato la seguente descrizione per i due attributi:DllImport - PreserverSig e SetLastError attributi

PreserveSig Impostare il campo PreserveSig su true per tradurre direttamente le firme non gestiti con HRESULT o valori RETVAL; impostarlo su false per convertire automaticamente i valori HRESULT o retval in eccezioni. Per impostazione predefinita, il campo PreserveSig è true.

SetLastError Consente al chiamante di utilizzare la funzione API Marshal.GetLastWin32Error per determinare se si è verificato un errore durante l'esecuzione del metodo. In Visual Basic, il valore predefinito è true (che aggiunge un sovraccarico); in C# e C++, il valore predefinito è falso.

La mia domanda è: come questi due si correlano tra loro? Supponiamo che PreserveSig sia impostato su 'false' - significa che dovrei convertire HRESULT in eccezione - se la funzione non gestita restituisce un intero che indica che si è verificato un errore o nessun errore, come potrebbe essere tradotto in eccezione?

Inoltre, perché è necessario chiamare il metodo GetLastWin32Error se in qualche modo sono riuscito a estrarre l'eccezione utilizzando PreserveSig?

Cordiali saluti PK

risposta

14

funzioni Win32 quasi mai restituire un HRESULT. Invece restituiscono uno BOOL o utilizzano valori speciali per indicare l'errore (ad esempio CreateFile restituisce INVALID_HANDLE_VALUE). Memorizzano il codice di errore in una variabile per-thread, che è possibile leggere con GetLastError(). SetLastError=true indica al marshaler di leggere questa variabile dopo che la funzione nativa è stata restituita e di memorizzare il codice di errore in cui è possibile leggerlo in seguito con Marshal.GetLastWin32Error(). L'idea è che il runtime .NET possa chiamare altre funzioni Win32 dietro le quinte che rovinano il codice di errore dalla tua chiamata p/invoke prima di avere la possibilità di ispezionarlo.

Le funzioni che restituiscono un HRESULT (o equivalente, ad esempio NTSTATUS) appartengono a un diverso livello di astrazione rispetto alle funzioni Win32. Generalmente queste funzioni sono relative al COM (sopra Win32) o dallo ntdll (sotto Win32), quindi non usano l'ultimo codice di errore Win32 (potrebbero chiamare internamente le funzioni Win32, comunque).

PreserveSig=false indica al gestore di marshalling di controllare il ritorno HRESULT e se non è un codice di successo, di creare e lanciare un'eccezione che contiene il HRESULT. La dichiarazione gestita della tua funzione DllImport ha quindi void come tipo di ritorno.

Ricordare che il compilatore C# o VB non può controllare la firma non gestita della funzione DllImport ed è quindi necessario fidarsi di ciò che viene detto. Se si inserisce PreserveSig=false in una funzione che restituisce qualcosa di diverso da uno HRESULT, si otterranno risultati strani (ad esempio eccezioni casuali). Se si inserisce SetLastError=true su una funzione che non imposta l'ultimo codice di errore Win32, si otterrà spazzatura invece di un codice di errore utile.

+0

Non ho esperienza con gli oggetti COM, quindi mi permetta di porre un'altra domanda riguardante la creazione della firma del metodo. La domanda è: quando vedo che la funzione COM restituisce HRESULT, posso contrassegnare il mio metodo come return void e impostare PreserveSig = false (come hai detto), o impostare PreserveSig = true e contrassegnare il mio metodo come restituire IntPtr per esaminare manualmente il codice restituito? – pkolodziej

+0

Sì, è corretto, tranne che HRESULT sono UInt32s, non IntPtrs. –

+0

Grazie - sei stato molto utile. – pkolodziej

Problemi correlati