SHCreateItemFromParsingName和System.AccessViolationException

时间:2017-10-18 13:18:11

标签: c# com com-interop access-violation

我正在迈出COM的第一步,但我一直在收到System.AccessViolationException,这是一个不会告诉你任何价值的例外情况。我正在尝试使用SHCreateItemFromParsingName创建一个IShellItem。我从另一个项目中复制了界面的定义,所以我知道它没有任何问题,问题很可能发生在我的函数定义/调用中,我自己为了学习目的而编写。

我想调用非托管函数,而不返回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相当神秘,但我的理由是:

  • HRESULT = uint
  • [in] PCWSTR = [MarshalAs(UnmanagedType.LPWStr)] string
  • [in,optional] IBindCtx = IBindCtx
  • [in] REFIID = Guid
  • [out] void = out IShellItem

SHCreateItemFromParsingName function

1 个答案:

答案 0 :(得分:1)

问题来自REFIID类型参数。它不是GUID(16字节结构),而是GUID引用( REF IID),一个指针(所以4或8个字节取决于进程位数)。

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

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

但我建议这种方式更容易使用,并避免创建/复制GUID(您将以与您相同的方式调用它):

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