Динамический объект C # 4.0 и интерфейсы WinAPI, такие как IShellItem (без определения их в источнике C #) - PullRequest
2 голосов
/ 15 декабря 2010

Возможно ли (с новым динамическим ключевым словом в C # 4.0) использовать интерфейсы (такие как IShellItem или другие интерфейсы WinAPI), не определяя их в моем исходном коде C #? Или хотя бы не определять членов интерфейса?

Я пытаюсь что-то вроде:

        const string IShellItemGuid = "43826D1E-E718-42EE-BC55-A1E261C37BFE";
        Guid guid = new Guid(IShellItemGuid);
        dynamic nativeShellItem = null;

        // Create and initializes a Shell item object (IShellItem) from a parsing name
        SHCreateItemFromParsingName(@"M:\TEST.TXT", IntPtr.Zero, guid, out nativeShellItem);
        if (nativeShellItem != null)
        {
            MessageBox.Show(nativeShellItem.GetDisplayName(0));
        }

, где

    [DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
    static extern void SHCreateItemFromParsingName(
    [In][MarshalAs(UnmanagedType.LPWStr)] string pszPath,
    [In] IntPtr pbc,
    [In][MarshalAs(UnmanagedType.LPStruct)] Guid iIdIShellItem,
    [Out][MarshalAs(UnmanagedType.Interface, IidParameterIndex = 2)] out dynamic iShellItem);

SHCreateItemFromParsingName работает нормально, и я получаю объект, если файл существует (и правильное сообщение об ошибке, если файл не существует), однако, пытаюсь вызвать nativeShellItem.GetDisplayName дает мне исключение времени выполнения:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException не обработано: «System .__ ComObject» не содержит определения для «GetDisplayName»

хотя IShellItem имеет метод с именем GetDisplayName , и мой динамический объект nativeShellItem , возвращаемый SHCreateItemFromParsingName , должен реализовывать этот интерфейс.

1 Ответ

3 голосов
/ 15 декабря 2010

Да, это не может работать, в DLR нет информации о типе COM-объекта. Это печально известная проблема в программировании оболочки, в которой используются интерфейсы, основанные на IUnknown, а не IDispatch, поэтому позднее связывание не поддерживается. И для них нет доступной библиотеки типов, которая позволяет .NET легко создавать библиотеки взаимодействия для типов интерфейсов.

IShellItem объявлен в ShObjIdl.idl, он заполнен cpp_quote (). Что побеждает любую попытку использовать midl.exe для создания библиотеки типов, может быть создан только файл .h. Уже предоставлено, кстати, ShObjIdl.h. Только компилятор C ++ может использовать его.

Повторное объявление интерфейса в C # технически возможно с атрибутами [ComImport], [Guid] и [PreserveSig]. Вы должны делать это очень осторожно, к счастью, IShellItem наследуется непосредственно от IUnknown, так что вы можете избежать множественного наследования. Что не помогает, так это то, что метод интерфейса использует нативные типы C, которые не выполняются автоматически. В частности, GetDisplayName () принимает LPWSTR, необработанный указатель на строку Unicode. Не BSTR, строковый тип, совместимый с автоматизацией. Это требует от вас возиться с небезопасными указателями в вашем коде C #. Лучше всего объявить это IntPtr, выделить часть памяти с помощью Marshal.AllocCoTaskMem () и выполнить маршалинг строки самостоятельно после вызова с помощью Marshal.PtrToStringUni ().

Тьфу, программирование оболочки - полная лава. Google черт возьми, чтобы вы могли скопировать / вставить то, что, как известно, работает. Если это окажется пустым, лучше использовать C ++ / CLI, чтобы вы могли использовать ShObjIdl.h. Удачи с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...