Niejawne tłumaczenia podpisów metod w międzyoperacyjności platformy .NET
Aby zachować niezależny język programowania, system Windows COM i wiele interfejsów API systemu Windows zwraca typ liczby całkowitej 4 bajtów o nazwie , HRESULT
aby wskazać, czy interfejs API zakończył się powodzeniem, czy niepowodzeniem, wraz z pewnymi informacjami na temat błędu. Inne wartości, które należy przekazać do elementu wywołującego, są "zwracane" za pośrednictwem parametrów wskaźnika, które działają jako parametry "out" i są zazwyczaj ostatnim parametrem w podpisie. Języki takie jak C# i Visual Basic tradycyjnie tłumaczą kod błędu na wyjątek, aby dopasować się do sposobu, w jaki błędy są zwykle propagowane w języku i oczekują, że podpisy metod międzyoperacyjności nie zawierają HRESULT
elementu . Aby przetłumaczyć sygnaturę metody na sygnaturę natywną, środowisko uruchomieniowe przenosi wartość zwracaną metody do dodatkowego parametru "out" z jeszcze jednym poziomem pośrednim (innymi słowy, sprawia, że wskaźnik do typu zwracanego podpisu zarządzanego) i przyjmuje wartość zwracaną HRESULT
. Jeśli metoda zarządzana zwraca void
wartość , żaden dodatkowy parametr nie zostanie dodany, a wartość zwracana stanie się wartością HRESULT
. Zobacz na przykład dwie następujące metody com języka C#, które przekładają się na ten sam podpis macierzysty:
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 w modelu COM
Wszystkie metody COM w języku C# powinny domyślnie używać przetłumaczonego podpisu. Aby używać i eksportować metody bez tłumaczenia podpisów HRESULT
i obsługi wartości, dodaj metodę PreserveSigAttribute do metody interfejsu COM. Po zastosowaniu atrybutu do metody żadne tłumaczenie nie jest wykonywane do podpisu, a wyjątki nie są zgłaszane w przypadku wartości zakończonych niepowodzeniem HRESULT
. Dotyczy to zarówno wbudowanego modelu COM, jak i modelu COM wygenerowanego przez źródło. Zobacz na przykład następujący podpis metody języka C# z atrybutem PreserveSig
i odpowiadającym mu podpisem natywnym.
[PreserveSig]
int Add(int a, int b, out int sum);
HRESULT Add(int a, int b, int* sum);
Może to być przydatne, jeśli metoda może zwracać różne HRESULT
wartości, które nie są błędami, ale muszą być obsługiwane inaczej. Na przykład niektóre metody mogą zwracać wartość S_FALSE
, gdy metoda nie zakończy się niepowodzeniem, ale zwraca tylko częściowe wyniki, a S_OK
gdy zwraca wszystkie wyniki.
PreserveSig
z wywołaniami P/Invoke
Atrybut DllImportAttribute zawiera bool PreserveSig
również pole, które działa podobnie do PreserveSigAttribute
, ale domyślnie ma wartość true
. Aby wskazać, że środowisko uruchomieniowe powinno przetłumaczyć sygnaturę zarządzaną i obsłużyć HRESULT
zwróconą wartość , ustaw PreserveSig
pole na false
wartość w elem.DllImportAttribute
Zobacz na przykład następujące podpisy dwóch wywołań P/Invoke do tej samej natywnej metody, po której PreserveSig
ustawiono false
wartość , i jedną z nią pozostawioną do wartości domyślnej 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);
Uwaga
Wygenerowane przez źródło elementy P/Invoke, które używają LibraryImportAttributepola , nie PreserveSig
mają żadnego pola. Wygenerowany kod zawsze zakłada, że sygnatura natywna i zarządzana są identyczne. Aby uzyskać więcej informacji, zobacz Generowanie źródła P/Invokes.
Ręczne obsługiwanie HRESULT
wartości
Podczas wywoływania metody zwracającej PreserveSig
HRESULT
element można użyć ThrowExceptionForHR metody , aby zgłosić odpowiedni wyjątek, jeśli HRESULT
wskazuje błąd. Podobnie podczas implementowania PreserveSig
metody można użyć GetHRForException metody , aby zwrócić HRESULT
wartość wskazującą odpowiednią wartość dla wyjątku.
Marshal HRESULTs jako struktury
W przypadku używania PreserveSig
metody int
oczekiwany jest typ zarządzany dla klasy HRESULT
. Jednak użycie niestandardowej struktury 4-bajtowej jako typu zwracanego umożliwia zdefiniowanie metod i właściwości pomocnika, które mogą uprościć pracę z elementem HRESULT
. W wbudowanym marshalingu działa to automatycznie. Aby użyć struktury zamiast int
zarządzanej HRESULT
reprezentacji w generowaniu źródła marshalling, dodaj MarshalAsAttribute atrybut z Error jako argument. Obecność tego atrybutu ponownie interpretuje bity HRESULT
elementu jako struktury.