C#4.0动态对象和IShellItem之类的WinAPI接口(没有在C#源中定义它们)

时间:2010-12-15 13:00:01

标签: c# winapi interface dynamic interop

是否可以(使用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 的方法,而 SHCreateItemFromParsingName 返回的 nativeShellItem 动态对象应实现此功能接口

1 个答案:

答案 0 :(得分:3)

是的,这不起作用,DLR没有关于COM对象的类型信息。这是shell编程中一个臭名昭着的问题,它使用从IUnknown派生的接口,而不是IDispatch,因此不支持后期绑定。并且没有可用的类型库,.NET可以轻松地为接口类型生成互操作库。

IShellItem在ShObjIdl.idl中声明,它用cpp_quote()填充。这使得使用midl.exe生成类型库的任何尝试失败,只能创建.h文件。已经提供了btw,ShObjIdl.h。只有C ++编译器才能使用它。

使用[ComImport],[Guid]和[PreserveSig]属性在技术上重新声明C#中的接口。你必须非常小心地这样做,幸运的是IShellItem直接来自IUnknown,所以你可以躲避多重继承子弹。没有用的是接口方法使用不自动编组的本机C类型。值得注意的是GetDisplayName()接受一个LPWSTR,一个指向Unicode字符串的原始指针。不是BSTR,自动化兼容的字符串类型。这需要你在C#代码中弄乱不安全的指针。最好的办法是将其声明为IntPtr,使用Marshal.AllocCoTaskMem()分配一块内存,并在使用Marshal.PtrToStringUni()调用后自己编组该字符串。

Yuck,shell编程是一个完整的皮塔饼。谷歌出了这个,所以你可以复制/粘贴已知可行的东西。如果它是空的,使用C ++ / CLI,所以你可以使用ShObjIdl.h绝对是一个更好的方法。祝你好运。