gpt4 book ai didi

c# - 调用 IStorage 的 EnumElements 时发生访问冲突

转载 作者:行者123 更新时间:2023-11-30 23:31:34 26 4
gpt4 key购买 nike

我正在读取结构化存储文件。并尝试获取根结构的所有子元素。但是我在这样做时遇到了访问冲突异常。

这里是本地方法,

[ComImport][Guid("0000000d-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IEnumSTATSTG
{
[PreserveSig] uint Next(uint celt, [MarshalAs(UnmanagedType.LPArray), Out] System.Runtime.InteropServices.ComTypes.STATSTG[] rgelt, out uint pceltFetched);
}

[ComImport][Guid("0000000b-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IStorage
{
[return: MarshalAs(UnmanagedType.Interface)]
IStream OpenStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr reserved1, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved2);

void EnumElements(
/* [in] */ uint reserved1,
/* [size_is][unique][in] */ IntPtr reserved2,
/* [in] */ uint reserved3,
/* [out] */ out IEnumSTATSTG ppenum);
}

[DllImport("ole32.dll", CharSet = CharSet.Unicode)]
internal static extern uint StgOpenStorageEx
(
[MarshalAs(UnmanagedType.LPWStr)] string name, uint accessMode,
uint storageFileFormat, uint fileBuffering, IntPtr options,
IntPtr reserved, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] ref IStorage stg
);

这是我的调用代码。

IStorage _storageObject;
// Opening file,
NativeMethods.StgOpenStorageEx(path, (uint)STM.Read | STM.ShareDenyWrite, (uint)storageFileFormat, (uint)fileBuffering,
options, IntPtr.Zero, ref _iidIStorage, ref _storageObject);

// Here I am calling EnumElements, I get exception here.
IEnumSTATSTG pIEnumStatStg;
_storageObject.EnumElements(0, IntPtr.Zero, 0, out pIEnumStatStg);

请注意,如果我调用另一个方法 if IStorage,比如 OpenStream,它工作正常,

_storageObject.OpenStream(streamName, IntPtr.Zero, (int)accessMode, 0);

我在打开文件时尝试了不同的 STM 标志组合,但它不起作用。

最佳答案

您可能会怀疑,您的接口(interface)声明是完全错误的。方法的名称无关紧要,就像 COM 中的所有名称一样,重要的是方法的顺序。它们必须与接口(interface)的 v-table 一致。这意味着您不能随便省略方法。

这是一个与 .NET 接口(interface)不同的细节,CLR 弄清楚如何将接口(interface)方法绑定(bind)到它们的实现,并且它可以这样做,因为它可以访问声明和实现。但它无法访问 COM 方法实现,它们隐藏在视线之外,通常在用 C++ 或 Delphi 编写的 DLL 中。

您的 OpenStream() 测试实际上不起作用。您将其声明为第一种方法,但实际上是第二种方法。您实际上是在调用 CreateStream()。它没有炸弹是一个意外,CreateStream 恰好也有 5 个参数,它们是相似的。那种运气跑到了EnumElements(),其实是接口(interface)的第9个方法。您正在调用第二种方法 OpenStream。这次是完全错误的论点,kaboom。

可以在接口(interface)声明上使用快捷方式,但您必须为要跳过的方法使用占位符。喜欢:

[ComImport][Guid("0000000b-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IStorage
{
void Dummy1();
[return: MarshalAs(UnmanagedType.Interface)]
IStream OpenStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr reserved1, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved2);
void Dummy3();
void Dummy4();
void Dummy5();
void Dummy6();
void Dummy7();
void Dummy8();
void EnumElements(
/* [in] */ uint reserved1,
/* [size_is][unique][in] */ IntPtr reserved2,
/* [in] */ uint reserved3,
/* [out] */ out IEnumSTATSTG ppenum);
}

可以省略尾随方法。您必须以相同的方式修复您的 IEnumSTATSTG 声明。此处并非如此,但如果接口(interface)继承自 IUnknown 或 IDispatch 以外的基接口(interface),则您还必须声明继承的方法。

或者只是复制/粘贴引用源中的声明(如果可用)通常是最好的。他们是,herehere

关于c# - 调用 IStorage 的 EnumElements 时发生访问冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34545992/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com