2009-04-18 11 views
9

Sur le MSDN que j'ai trouvé la description suivante pour les deux attributs:DllImport - attributs PreserverSig et SetLastError

PreserveSig Définissez le champ PreserveSig true pour traduire directement les signatures non gérés avec HRESULT ou valeurs RETVAL; Définissez-le sur false pour convertir automatiquement les valeurs HRESULT ou retval en exceptions. Par défaut, le champ PreserveSig est vrai.

SetLastError Permet à l'appelant d'utiliser la fonction Marshal.GetLastWin32Error API pour déterminer si une erreur s'est produite lors de l'exécution de la méthode. En Visual Basic, la valeur par défaut est true (ce qui ajoute une surcharge); en C# et C++, la valeur par défaut est false.

Ma question est: Comment ces deux se rapportent les uns aux autres? Supposons que PreserveSig soit défini sur 'false' - cela signifie que HRESULT devrait être converti en exception - si la fonction non managée renvoie un entier indiquant qu'une erreur ou aucune erreur s'est produite, comment cela pourrait-il être traduit en exception?

Aussi pourquoi ai-je besoin d'appeler la méthode GetLastWin32Error si j'ai réussi à extraire l'exception à l'aide de PreserveSig?

Amitiés PK

Répondre

14

fonctions Win32 retour presque jamais un HRESULT. Au lieu de cela, ils renvoient un BOOL ou utilisent des valeurs spéciales pour indiquer une erreur (par exemple CreateFile renvoie INVALID_HANDLE_VALUE). Ils stockent le code d'erreur dans une variable par thread, que vous pouvez lire avec GetLastError(). SetLastError=true indique au marshaleur de lire cette variable après le retour de la fonction native et de stocker le code d'erreur que vous pourrez lire plus tard avec Marshal.GetLastWin32Error(). L'idée est que le runtime .NET peut appeler d'autres fonctions Win32 en arrière-plan, ce qui gâchera le code d'erreur de votre appel p/invoke avant que vous ayez l'occasion de l'inspecter.

Les fonctions qui renvoient un HRESULT (ou équivalent, par exemple NTSTATUS) appartiennent à un niveau d'abstraction différent des fonctions Win32. Généralement, ces fonctions sont liées à COM (au-dessus de Win32) ou à ntdll (sous Win32), donc elles n'utilisent pas le code d'erreur dernière Win32 (elles peuvent appeler les fonctions Win32 en interne, cependant).

PreserveSig=false indique au marshaleur de vérifier le retour HRESULT et s'il ne s'agit pas d'un code de réussite, de créer et de lancer une exception contenant le HRESULT. La déclaration gérée de votre fonction ed DllImport a alors le type de retour void. Rappelez-vous, le compilateur C# ou VB ne peut pas vérifier la signature non managée de la fonction DllImport ed, il doit donc faire confiance à ce que vous lui dites. Si vous mettez PreserveSig=false sur une fonction qui renvoie autre chose qu'un HRESULT, vous obtiendrez des résultats étranges (par exemple, des exceptions aléatoires). Si vous mettez SetLastError=true sur une fonction qui ne définit pas le dernier code d'erreur Win32, vous obtiendrez des ordures au lieu d'un code d'erreur utile.

+0

Je n'ai pas d'expérience avec les objets COM alors laissez-moi poser une autre question concernant la création de la signature de la méthode. La question est: quand je vois que la fonction COM renvoie HRESULT, je peux marquer ma méthode comme renvoyant void et définir PreserveSig = false (comme vous l'avez dit), ou définir PreserveSig = true et marquer ma méthode comme renvoyant IntPtr pour examiner manuellement le code retourné? – pkolodziej

+0

Oui, c'est correct, sauf que HRESULTs sont UInt32s, pas IntPtrs. –

+0

Merci - vous avez été très utile. – pkolodziej

Questions connexes