Я пытаюсь разобраться в путанице определений взаимодействия COM, которые мы разбросали по разным проектам, и собрать их в едином, хорошо известном месте, которое может принести пользу всей команде разработчиков.Часть этих усилий включает в себя очистку определений, накопленных за эти годы.
Некоторые из них заимствованы из другого исходного кода, некоторые были дословно скопированы с pinvoke.net, а некоторые выглядят как прямые переводы из заголовков SDK.Одна вещь, которую я замечаю, заключается в том, что нет единого мнения о том, когда использовать различные атрибуты маршаллинга (даже среди примеров pinvoke.net это довольно непросто).Часть проблемы в том, что я не думаю, что кто-то здесь (включая меня) полностью понимает, когда нужны различные атрибуты или нет, или что они на самом деле делают.До этого момента их правильное восприятие представляло собой комбинацию догадок и случайных изменений до тех пор, пока исключение COMException не перестанет происходить, но я бы предпочел, чтобы переводы были правильными, потому что кто-то действительно смотрел на них и объявлял их так.
Итак, я начинаю с [In]
и [Out]
.Я знаю, что эти два атрибута делают концептуально: они сообщают маршаллеру, в каком направлении должны идти данные.Я предполагаю, что маршаллер, например, не потрудится скопировать [In]
данные обратно вызывающей стороне, или знает, что [Out]
данные, возможно, потребуется освободить на стороне вызываемого и т. Д.Не знаю:
- Когда необходимо использовать эти атрибуты?То есть, когда поведение маршаллинга по умолчанию неверно, так что атрибуты делают его правильным?
- Когда можно безопасно использовать эти атрибуты?То есть указание того, что уже должно быть поведением по умолчанию, изменит способ работы маршаллера?
- Когда опасно использовать эти атрибуты?Я предполагаю, что явная маркировка выходного параметра
[In]
- это плохо, но помечает ли входной параметр [In, Out]
что-нибудь действительно сломавшееся?
Итак, учитывая гипотетический метод COM-интерфейса, IDL которого выглядит какэто:
HRESULT Foo(
[in] ULONG a,
[out] ULONG * b
[in, out] ULONG * c);
Я мог бы перевести это как любое из следующего:
void Foo(
uint cb,
out uint b,
ref uint c);
void Foo(
uint cb,
[Out] out uint b,
[In, Out] ref uint c);
void Foo(
[In] uint cb,
[Out] out uint b,
[In, Out] ref uint c);
Есть ли функциональная разница между этими тремя?Считается ли кто-то из них «лучше» других по причинам, помимо технической корректности?