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 voidlä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 PreserveSigAttributesom , 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å falseoch 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 HRESULTkan 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.

Se även