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 相当神秘,但我的推理是:
- HRESULT = uint
- [in] PCWSTR = [MarshalAs(UnmanagedType.LPWStr)] 字符串
- [输入,可选] IBindCtx = IBindCtx
- [in]REFIID = Guid
- [out] void = out IShellItem
问题出在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);
我正在 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 相当神秘,但我的推理是:
- HRESULT = uint
- [in] PCWSTR = [MarshalAs(UnmanagedType.LPWStr)] 字符串
- [输入,可选] IBindCtx = IBindCtx
- [in]REFIID = Guid
- [out] void = out IShellItem
问题出在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);