PInvoke - как представить поле из интерфейса COM - PullRequest
1 голос
/ 22 октября 2009

Я ссылаюсь на структуру 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;
...

Источник: http://dxr.proximity.on.ca/dxr/mozilla-central/netwerk/cache/public/nsICacheSession.idl.html#58

Я нашел код для импорта этого интерфейса в мое приложение 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 и как мне ссылаться на это из моего кода?

EDIT

Я изменил свой код на следующий, что привело к «System.AccessViolationException: попытка чтения или записи в защищенную память yada yada ...»:

[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{
    void set_doomEntriesIfExpired(bool enabled);
    bool get_doomEntriesIfExpired();
...

Ответы [ 3 ]

3 голосов
/ 27 октября 2009

Ответ, который вы вставили, хороший. В COM Interop bools маршалируются как VARIANT_BOOL по умолчанию, поэтому добавление вами атрибута MarshalAs, указывающего маршалеру использовать стандартный 4-байтовый тип BOOL, является правильным, хотя для получающей части уравнения также необходим добавленный атрибут.

В общем, мне нравится оставлять свойства, определенные в интерфейсе, как свойства, а не разбивать их на методы получения и установки. Он лучше соответствует семантике определения интерфейса и, как правило, легче читается. Чтобы сохранить атрибут атрибута doomEntriesIfExpired, вы должны будете переписать определение импорта COM следующим образом:

[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport, 
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{

    bool doomEntriesIfExpired 
    { 
        [param:MarshalAs(UnmanagedType.Bool)]set; 
        [return:MarshalAs(UnmanagedType.Bool)]get; 
    }

...

1 голос
/ 22 октября 2009

Оказывается, ответ был следующим:

[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();
1 голос
/ 22 октября 2009

Тот факт, что вы указали [return: MarshalAs(UnmanagedType.Bool)] для вашего void set метода, очевидно, является источником ошибки.

Тем не менее, мне удалось закодировать плагин C ++ для Mozilla без тегов [return ...] в .idl, например:

[scriptable, uuid(ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e)]
interface nsICacheSession : nsISupports
{
    void set_doomEntriesIfExpired(in bool value);
    bool get_doomEntriesIfExpired();
}

Кстати, вы уверены, что можете закодировать плагин nsi в C #?

...