PInvoke - как представить поле из COM-интерфейса
Вопрос
Я ссылаюсь на структуру COM, которая начинается следующим образом:
[scriptable, uuid(ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e)]
interface nsICacheSession : nsISupports
{
/**
* Expired entries will be doomed or evicted if this attribute is set to
* true. If false, expired entries will be returned (useful for offline-
* mode and clients, such as HTTP, that can update the valid lifetime of
* cached content). This attribute defaults to true.
*/
attribute PRBool doomEntriesIfExpired;
...
Я нашел код для импорта этого интерфейса в мое приложение на C #.Однако код, должно быть, неправильный, так как set
метод не кажется полезным, а также выдает ошибку, когда я пытаюсь вызвать его, просто чтобы посмотреть, что произойдет:
[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{
[return: MarshalAs(UnmanagedType.Bool)]
void set_doomEntriesIfExpired();
[return: MarshalAs(UnmanagedType.Bool)]
bool get_doomEntriesIfExpired();
...
Каков правильный способ установить значение doomEntriesIfExpired
и как мне сослаться на это из моего кода?
Редактировать
Я изменил свой код на следующий, который выдал "System.AccessViolationException:Попытка чтения или записи защищенной памяти, бла-бла-бла...":
[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{
void set_doomEntriesIfExpired(bool enabled);
bool get_doomEntriesIfExpired();
...
Решение
Ответ, который вы вставили, хорош.В COM-интерфейсе bools по умолчанию маршалируются как VARIANT_BOOL , поэтому ваше добавление атрибута MarshalAs для указания маршалеру использовать стандартный 4-байтовый тип BOOL является правильным, хотя для части получения уравнения также требуется добавление атрибута.
В общем, мне нравится оставлять свойства, определенные в интерфейсе, как свойства, а не разбивать их на их получатели и установщики.Он лучше соответствует семантике определения интерфейса и, как правило, также легче читается.Вы должны иметь возможность переписать свое определение импорта COM следующим образом, чтобы сохранить природу атрибута doomEntriesIfExpired:
[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport,
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{
bool doomEntriesIfExpired
{
[param:MarshalAs(UnmanagedType.Bool)]set;
[return:MarshalAs(UnmanagedType.Bool)]get;
}
...
Другие советы
Тот факт, что вы заявляете о [return: MarshalAs(UnmanagedType.Bool)]
для вашего void set
метод, очевидно, является источником ошибок.
Тем не менее, мне удалось закодировать плагин mozilla на C ++ без тегов [return ...] в .idl, например:
[scriptable, uuid(ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e)]
interface nsICacheSession : nsISupports
{
void set_doomEntriesIfExpired(in bool value);
bool get_doomEntriesIfExpired();
}
Кстати, вы уверены, что можете закодировать плагин nsi на C #?
Оказывается, ответ был следующим:
[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{
void set_doomEntriesIfExpired([In, MarshalAs(UnmanagedType.Bool)] ref bool enabled);
bool get_doomEntriesIfExpired();