SHCreateItemFromParsingName 和 System.AccessViolationException

SHCreateItemFromParsingName and System.AccessViolationException

我正在 COM 中迈出第一步,但我不断收到 System.AccessViolationException,这是其中一个异常,它没有告诉您任何有价值的信息。我正在尝试使用 SHCreateItemFromParsingName 创建一个 IShellItem。我从另一个项目复制了接口的定义,所以我知道它没有任何问题,问题很可能在我的函数 definition/call 中,这是我自己写的用于学习目的。

我想调用非托管函数而不返回 IShellItem 接口,而是将它的引用传递给调用中的最后一个参数。

函数声明:

[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
internal static extern uint SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IBindCtx pbc, Guid riid, out IShellItem ppv);

函数调用:

IShellItem file;

SHCreateItemFromParsingName(@"C:\file.txt", null, typeof(IShellItem).GUID, out file);

我发现 IDL 相当神秘,但我的推理是:

SHCreateItemFromParsingName function

问题出在REFIID类型参数上。它不是 GUID(16 字节结构),而是 GUID 引用(REFIID),指针(因此 4 或 8 字节取决于进程位数)。

所以你可以这样定义方法,使用 ref 关键字(这样结构将通过引用传递,作为指针):

internal static extern uint SHCreateItemFromParsingName(
    [MarshalAs(UnmanagedType.LPWStr)] string pszPath,
    IBindCtx pbc,
    ref Guid riid,
    out IShellItem ppv);

但我推荐这种方式,它更易于使用并且避免了周围的 creating/copying GUID(您将以与您相同的方式调用它):

internal static extern uint SHCreateItemFromParsingName(
    [MarshalAs(UnmanagedType.LPWStr)] string pszPath,
    IBindCtx pbc,
    [MarshalAs(UnmanagedType.LPStruct)] Guid riid,
    out IShellItem ppv);