powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / MarshalDirectiveException при вызове метода через COM-interop wrapper
3 сообщений из 3, страница 1 из 1
MarshalDirectiveException при вызове метода через COM-interop wrapper
    #39970039
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Попросили тут разобраться с вызовом метода одного достаточно специфичного и проприетарного COM-компонента, и я наткнулся на загадочную фигню. Этот метод в IDL выглядит так:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
VARIANT _stdcall GenerateFromHTML(
  [in] BSTR HTMLPath, 
  [in] BSTR ResultPath, 
  [in] long AutoSize, 
  [in, optional] long ImageLeft, 
  [in, optional] long ImageTop, 
  [in, optional] long ImageRight, 
  [in, optional] long ImageBottom);


причем интерфейс не дуальный.
Когда я добавляю этот COM-компонент в референсы проекта, то в сгенерённой студией сборке COM-interop враппера у этого метода такая сигнатура:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
[return: MarshalAs(UnmanagedType.Struct)]
object GenerateFromHTML(
  [In] [MarshalAs(UnmanagedType.BStr)] string HTMLPath,
  [In] [MarshalAs(UnmanagedType.BStr)] string ResultPath,
  [In] int AutoSize,
  [Optional] [In] int ImageLeft,
  [Optional] [In] int ImageTop,
  [Optional] [In] int ImageRight,
  [Optional] [In] int ImageBottom
);


Пытаюсь дернуть этот метод с использованием этого COM-interop враппера:
Код: c#
1.
2.
var foo = new Foo();
var res = foo.GenerateFromHTML(@"D:\Trash\1.htm", @"D:\Trash\1.png", -1, 0, 0, 0);


- и получаю исключение на вызове GenerateFromHTML:

Код: plaintext
System.Runtime.InteropServices.MarshalDirectiveException Method's type signature is not Interop compatible

которое, согласно документации , выбрасывается в случае наличия в сигнатуре неправильного атрибута MarshalAs для какого-либо аргумента.
Вызываю этот же метод через поднее связывание:
Код: c#
1.
2.
dynamic foo = Type.GetTypeFromProgID("Lib.Foo", true);
var res = foo.GenerateFromHTML(@"D:\Trash\1.htm", @"D:\Trash\1.png", -1, 0, 0, 0);


- отрабатывает нормально.
Почему не получается вызвать метод через COM-interop враппер? Студия его неправильно сгенерила? Как в таком случае он должен выглядеть? Может, дело в самом компоненте? В глаза бросается, что метод вместо общепринятого в COM HRESULT (в IDL) возвращает VARIANT (который, кстати, при вызове через позднее связывание ничего не содержит - равен null).
А Powershell при вызове этого метода вообще падает с ошибкой FullyQualifiedErrorId : MethodNotFound.
...
Рейтинг: 0 / 0
MarshalDirectiveException при вызове метода через COM-interop wrapper
    #39970234
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сделал тест: сляпал нативный COM-компонент вот с таким интерфейсом:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
[
  odl,
  uuid(D1947B0F-754A-4374-A22A-E74BA1D40625),
  helpstring("Dispatch interface for Foo Object"),
  oleautomation
]
interface IFoo : IDispatch {
  HRESULT _stdcall Bar(
    [in] BSTR HTMLPath, 
    [in] BSTR ResultPath, 
    [in] long AutoSize, 
    [in, optional] long ImageLeft, 
    [in, optional] long ImageTop, 
    [in, optional] long ImageRight, 
    [in, optional] long ImageBottom, 
    [out, retval] VARIANT* Res);
  VARIANT _stdcall Zot(
    [in] BSTR HTMLPath, 
    [in] BSTR ResultPath, 
    [in] long AutoSize, 
    [in, optional] long ImageLeft, 
    [in, optional] long ImageTop, 
    [in, optional] long ImageRight, 
    [in, optional] long ImageBottom);
};


и подцепил его в референсы проекта. Создался COM-interop враппер вот с такими методами:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
[ComImport]
[Guid("D1947B0F-754A-4374-A22A-E74BA1D40625")]
[TypeLibType(4352)]
public interface IFoo
{
  [MethodImpl(MethodImplOptions.InternalCall)]
  [return: MarshalAs(UnmanagedType.Struct)]
  object Bar(
    [In] [MarshalAs(UnmanagedType.BStr)] string HTMLPath,
    [In] [MarshalAs(UnmanagedType.BStr)] string ResultPath,
    [In] int AutoSize,
    [Optional] [In] int ImageLeft,
    [Optional] [In] int ImageTop,
    [Optional] [In] int ImageRight,
    [Optional] [In] int ImageBottom);

  [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
  [return: MarshalAs(UnmanagedType.Struct)]
  object Zot(
    [In] [MarshalAs(UnmanagedType.BStr)] string HTMLPath,
    [In] [MarshalAs(UnmanagedType.BStr)] string ResultPath,
    [In] int AutoSize,
    [Optional] [In] int ImageLeft,
    [Optional] [In] int ImageTop,
    [Optional] [In] int ImageRight,
    [Optional] [In] int ImageBottom);
}


- сигнатуры абсолютно идентичны, за исключением того, что у Zot еще добавлен MethodImplOptions.PreserveSig.
Ну, и тест:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
public static void Main(string[] args)
{
  var foo = new TestLib.Foo();
  try
  {
      Console.WriteLine("Bar:");
      var res = foo.Bar(".", ".", -1, 0, 0, 0);
      Console.WriteLine("Ok: {0}", res);
  }
  catch (Exception e)
  {
    Console.WriteLine(e);
  }
  try
  {
    Console.WriteLine("Zot:");
    var res = foo.Zot(".", ".", -1, 0, 0, 0);
    Console.WriteLine("Ok: {0}", res);
  }
  catch (Exception e)
  {
    Console.WriteLine(e);
  }
  Console.WriteLine("done");
}


Код: plaintext
1.
2.
3.
4.
5.
6.
Bar:
Ok: Ok
Zot:
System.Runtime.InteropServices.MarshalDirectiveException: Method's type signature is not Interop compatible.
   at TestLib.FooClass.Zot(String HTMLPath, String ResultPath, Int32 AutoSize, Int32 ImageLeft, Int32 ImageTop, Int32 ImageRight, Int32 ImageBottom)
   at test2.Program.Main(String[] args) in D:\Projects\.Net\_tests\test2\test2\Program.cs:line 27
done

- видимо, действительно, COM-методы, возвращающие не HRESULT, дают вот такой эффект.
...
Рейтинг: 0 / 0
MarshalDirectiveException при вызове метода через COM-interop wrapper
    #39970439
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Из документации :
A return type is compatible with Automation if its type is an HRESULT, SCODE or void. However, MIDL requires that interface methods return either HRESULT or SCODE. Returning void generates a compiler error.
Получается-таки, что да, у исходного компонента интерфейс не подходит для автоматизации/маршаллинга. Tlbimp могла бы об этом предупреждать (проверил с ключом /verbose - ничего не говорит про этот нюанс).
...
Рейтинг: 0 / 0
3 сообщений из 3, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / MarshalDirectiveException при вызове метода через COM-interop wrapper
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]