Implicit metodsignaturöversättningar i .NET interop
För att hålla programmeringsspråket agnostiskt returnerar Windows COM-systemet och många Windows-API:er en heltalstyp med 4 byte som kallas för HRESULT
att ange om ett API lyckades eller misslyckades, tillsammans med viss information om felet. Andra värden som måste skickas till anroparen "returneras" via pekarparametrar som fungerar som "out"-parametrar och är vanligtvis den sista parametern i signaturen. Språk som C# och Visual Basic översätter traditionellt en felkod till ett undantag för att matcha hur fel vanligtvis sprids på språket och förväntar sig att interop-metodsignaturer inte ska innehålla HRESULT
. Om du vill översätta metodsignaturen till en intern signatur flyttar körningen returvärdet för metoden till ytterligare en "out"-parameter med ytterligare en indirekt nivå (med andra ord en pekare till den hanterade signaturens returtyp) och förutsätter ett HRESULT
returvärde. Om den hanterade metoden returnerar void
läggs ingen ytterligare parameter till och returvärdet blir en HRESULT
. Se till exempel följande två C#COM-metoder som översätts till samma interna signatur:
int Add(int a, int b);
void Add(int a, int b, out int sum);
HRESULT Add(int a, int b, /* out */ int* sum);
PreserveSig i COM
Alla COM-metoder i C# förväntas använda den översatta signaturen som standard. Om du vill använda och exportera metoder utan signaturöversättning och hantering av HRESULT
värden lägger du till PreserveSigAttribute i en COM-gränssnittsmetod. När attributet tillämpas på en metod görs ingen översättning till signaturen och undantag genereras inte för misslyckade HRESULT
värden. Detta gäller både inbyggd COM och källgenererad COM. Se till exempel följande C#-metodsignatur med ett PreserveSig
attribut och dess motsvarande interna signatur.
[PreserveSig]
int Add(int a, int b, out int sum);
HRESULT Add(int a, int b, int* sum);
Detta kan vara användbart om metoden kan returnera olika HRESULT
värden som inte är fel, men som måste hanteras på olika sätt. Vissa metoder kan till exempel returnera värdet S_FALSE
när en metod inte misslyckas utan bara returnerar partiella resultat och S_OK
när den returnerar alla resultat.
PreserveSig
med P/Invokes
Attributet DllImportAttribute har också det bool PreserveSig
fält som fungerar på samma sätt PreserveSigAttribute
som , men som standard .true
Om du vill ange att körningen ska översätta den hanterade signaturen och hantera den HRESULT
som returneras anger du PreserveSig
fältet till false
i DllImportAttribute
. Se till exempel följande signaturer för två P/Invokes till samma interna metod, en med PreserveSig
inställd på false
och en med kvar till standardvärdet true
.
[DllImport("shlwapi.dll", EntryPoint = "SHAutoComplete", ExactSpelling = true, PreserveSig = false)]
public static extern void SHAutoComplete(IntPtr hwndEdit, SHAutoCompleteFlags dwFlags);
[DllImport("shlwapi.dll", EntryPoint = "SHAutoComplete", ExactSpelling = true)]
public static extern int SHAutoCompleteHRESULT(IntPtr hwndEdit, SHAutoCompleteFlags dwFlags);
Kommentar
Källgenererade P/Invokes, som använder fältet LibraryImportAttribute, har inget PreserveSig
fält. Den genererade koden förutsätter alltid att den interna och hanterade signaturen är identiska. Mer information finns i Källgenererade P/Invokes.
Hantera värden manuellt HRESULT
När du anropar en PreserveSig
metod som returnerar en HRESULT
kan du använda ThrowExceptionForHR -metoden för att utlösa motsvarande undantag om HRESULT
det indikerar ett fel. När du implementerar en PreserveSig
metod kan du på samma sätt använda GetHRForException metoden för att returnera HRESULT
som anger ett motsvarande värde för undantaget.
Marshal HRESULTs som structs
När du använder en PreserveSig
metod int
förväntas vara den hanterade typen för HRESULT
. Men om du använder en anpassad 4-bytes struct som returtyp kan du definiera hjälpmetoder och egenskaper som kan förenkla arbetet med HRESULT
. I inbyggd marshalling fungerar detta automatiskt. Om du vill använda en struct i stället för int
som den hanterade representationen av HRESULT
i källgenererad marshalling lägger du till MarshalAsAttribute attributet med Error som argument. Förekomsten av det här attributet omtolkar bitar av HRESULT
som struct.