Udostępnij za pośrednictwem


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ą HRESULTelementu . 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 voidwartość , ż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 falsewartość , 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 PreserveSigHRESULTelement 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.

Zobacz też