调用IStorage的EnumElements时发生访问冲突
本文关键字:访问冲突 EnumElements IStorage 调用 | 更新日期: 2023-09-27 18:28:45
我正在读取一个结构化存储文件。并尝试获取根结构的所有子元素。但我在这样做的时候得到了访问违规异常。
这是本地方法,
[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);
注意,如果我调用另一个方法,如果IStorage,如OpenStream,工作正常,
_storageObject.OpenStream(streamName, IntPtr.Zero, (int)accessMode, 0);
当我打开文件时,我尝试了STM标志的不同组合,但它不起作用。
这是一个不同于.NET接口的细节,CLR知道如何将接口方法绑定到它们的实现,并且它可以这样做,因为它可以访问声明和实现。但它不能访问COM方法实现,它们被隐藏在视线之外,通常在用C++或Delphi编写的DLL中。
您的OpenStream()测试实际上不起作用。您将它声明为第一个方法,但实际上它是第二个方法。您实际上正在调用CreateStream()。它没有爆炸是一个意外,CreateStream碰巧也有5个论点,它们是相似的。这种运气在EnumElements()中耗尽了,它实际上是接口的第9个方法。您正在调用第二个方法OpenStream。这次的论点完全错误,卡博姆。
可以在接口声明上使用快捷方式,但必须为要跳过的方法使用占位符。类似:
[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声明。这里的情况并非如此,但如果接口继承自IUnknown或IDispatch以外的基接口,则还必须声明继承的方法。
或者只复制/粘贴引用源中的声明(如果可用),这通常是最好的。它们是,这里和这里