Поделиться через


Неявные переводы сигнатур метода в взаимодействиях .NET

Чтобы оставаться не зависящим от языка программирования, система COM Windows и многие API Windows возвращают 4 байтов целочисленного типа, вызываемого для HRESULT указания успешности или сбоя API, а также некоторые сведения о сбое. Другие значения, которые необходимо передать вызывающему объекту, "возвращаются" с помощью параметров указателя, которые действуют как "out" и обычно являются последним параметром в сигнатуре. Языки, такие как C# и Visual Basic, традиционно переводят код сбоя в исключение, чтобы соответствовать тому, как ошибки обычно распространяются на языке, и ожидают, что подписи методов взаимодействия не включаются HRESULT. Чтобы преобразовать сигнатуру метода в собственную сигнатуру, среда выполнения перемещает HRESULT возвращаемое значение метода в дополнительный параметр out с еще одним уровнем косвенного обращения (другими словами, делает его указателем на тип возвращаемой подписи) и предполагает возвращаемое значение. Если управляемый метод возвращается void, дополнительный параметр не добавляется, а возвращаемое значение становится HRESULT. Например, см. следующие два метода COM C#, которые преобразуют в ту же собственную сигнатуру:

int Add(int a, int b);

void Add(int a, int b, out int sum);
HRESULT Add(int a, int b, /* out */ int* sum);

СохранитьSig в COM

Все методы COM в C#, как ожидается, будут использовать преобразованную подпись по умолчанию. Чтобы использовать и экспортировать методы без перевода подписей и обработки значений HRESULT , добавьте PreserveSigAttribute его в метод COM-интерфейса. Если атрибут применяется к методу, преобразование не выполняется в сигнатуру, а исключения не создаются для неудачных HRESULT значений. Это относится как к встроенному COM, так и к созданному источником COM. Например, см. следующую сигнатуру метода C# с атрибутом PreserveSig и соответствующей собственной сигнатурой.

[PreserveSig]
int Add(int a, int b, out int sum);
HRESULT Add(int a, int b, int* sum);

Это может быть полезно, если метод может возвращать разные HRESULT значения, которые не являются сбоями, но должны обрабатываться по-другому. Например, некоторые методы могут возвращать значение S_FALSE , если метод не завершается ошибкой, но возвращает только частичные результаты, а S_OK когда возвращает все результаты.

PreserveSig с помощью P/Invokes

Атрибут DllImportAttribute также имеет bool PreserveSig поле, которое работает аналогично значению PreserveSigAttribute, но по умолчанию true. Чтобы указать, что среда выполнения должна преобразовывать управляемую подпись и обрабатывать HRESULT возвращаемую, задайте PreserveSig поле false в поле DllImportAttribute. Например, см. следующие сигнатуры двух P/Invokes в одном и том же собственном методе, один с PreserveSig заданным значением falseи один из них слева от значения по умолчанию 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);

Примечание.

Созданные источником P/Invokes, которые используют LibraryImportAttributeполе, не PreserveSig имеют поля. Созданный код всегда предполагает, что собственная и управляемая сигнатура идентичны. Дополнительные сведения см. в разделе "Источник" для P/Invokes.

Обработка значений вручную HRESULT

При вызове PreserveSig метода, возвращающего объект HRESULT, можно использовать ThrowExceptionForHR метод для вызова соответствующего исключения, если HRESULT указывает на сбой. Аналогичным образом при реализации PreserveSig метода можно использовать GetHRForException метод для возврата HRESULT соответствующего значения исключения.

Маршал HRESULTs в виде структур

При использовании метода, как ожидается, int будет управляемым типом PreserveSig для HRESULT. Однако использование пользовательской структуры 4-байтов в качестве возвращаемого типа позволяет определять вспомогательные методы и свойства, которые могут упростить работу с HRESULTним. В встроенном маршаллинге это работает автоматически. Чтобы использовать структуру вместо int управляемого HRESULT представления в исходном маршаллинге, добавьте MarshalAsAttribute атрибут в Error качестве аргумента. Присутствие этого атрибута переосмыслеет биты HRESULT структуры.

См. также