我们的项目使用MSXML 6.0
com对象来处理XML
到ComImport
属性。 com com下面提供对现有MSXML COM
的访问权限(我只留下SelectNodes以澄清问题)。
[ComImport]
[ComSourceInterfaces("MSXML2.XMLDOMDocumentEvents")]
[TypeLibType(TypeLibTypeFlags.FCanCreate)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("88d96a06-f192-11d4-a65f-0040963251e5")]
public class FreeThreadedDOMDocumentClass : IXMLDOMDocument2
{
[return: MarshalAs(UnmanagedType.Interface)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x1d)]
public extern object SelectNodes([In, MarshalAs(UnmanagedType.BStr)] string queryString);
}
[ComImport, Guid("2933BF95-7B36-11D2-B20E-00C04F983E60"), TypeLibType((short)0x10c0)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IXMLDOMDocument2
{
[return: MarshalAs(UnmanagedType.Interface)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x1d)]
object SelectNodes([In, MarshalAs(UnmanagedType.BStr)] string queryString);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix"), ComImport]
[Guid("2933BF82-7B36-11D2-B20E-00C04F983E60")]
[TypeLibType(TypeLibTypeFlags.FDispatchable)]//(short) 0x10c0
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IXMLDOMNodeList: IEnumerable
{
[DispId(0)]
IXMLDOMNode this[int index]
{
[return: MarshalAs(UnmanagedType.Interface)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(0)]
get;
}
[DispId(0x4a)]
int Count
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(0x4a)]
get;
}
}
我们对代码的某些部分有问题。示例:
string xmlText = "<Item> <Element></Element></Item>";
IXMLDOMDocument2 domDocument = new FreeThreadedDOMDocumentClass();
domDocument.LoadXml(xmlText);
string xPath = "//Item";
IXMLDOMNodeList resultQuery = domDocument.SelectNodes(xPath) as IXMLDOMNodeList;
resultQuery.GetEnumerator()
由于执行resultQuery
而获取的对象SelectNodes
在GetEnumerator方面存在问题,具体取决于一些外部因素:
在Windows 7或更早版本的系统中(不支持WinRT技术的系统)
resultQuery
的类型为System.__ComObject
在Windows 8或更高版本的系统(支持WinRT技术的系统)中
resultQuery
的类型为Windows.Data.Xml.Dom.XmlNodeList
。这是WinRt类型。System.ArgumentException: The object's type must not be a Windows Runtime type
。我发现异常来源是Marshal.GetComObjectData
。这意味着我们的编组过程失败在Windows 8或更高版本的系统中,使用导入的com MSXML 3.0
版本:
resultQuery
的类型为System.__ComObject
此时我发现了第2点的三个解决方法(在Windows上使用带有WinRT的msxml)但不是我们的解决方案(对于具有相同问题的开发人员可能会有所帮助):
SelectNodes
创建自定义编组,这将使用WinRT类型创建包装并通过for
提供自定义GetEnumerator。我需要帮助才能在第2点找到问题的根源,并了解如何解决问题。 感谢
答案 0 :(得分:1)
经过深入调查后,我找到了解决方案:
1)我使用TLBimp.exe
为msxml6 com生成了互操作C#dll2)用反编译器打开生成的dll
3)找到生成的接口IXMLDOMNodeList
。
它有下一个实现:
[Guid("2933BF82-7B36-11D2-B20E-00C04F983E60"), TypeLibType(TypeLibTypeFlags.FDual | TypeLibTypeFlags.FNonExtensible | TypeLibTypeFlags.FDispatchable)]
[ComImport]
public interface IXMLDOMNodeList : IEnumerable
{
// Token: 0x1700012B RID: 299
[DispId(0)]
IXMLDOMNode this[[In] int index]
{
[DispId(0)]
[MethodImpl(MethodImplOptions.InternalCall)]
[return: MarshalAs(UnmanagedType.Interface)]
get;
}
// Token: 0x1700012C RID: 300
// (get) Token: 0x060003D5 RID: 981
[DispId(74)]
int length
{
[DispId(74)]
[MethodImpl(MethodImplOptions.InternalCall)]
get;
}
// Token: 0x060003D6 RID: 982
[DispId(76)]
[MethodImpl(MethodImplOptions.InternalCall)]
[return: MarshalAs(UnmanagedType.Interface)]
IXMLDOMNode nextNode();
// Token: 0x060003D7 RID: 983
[DispId(77)]
[MethodImpl(MethodImplOptions.InternalCall)]
void reset();
// Token: 0x060003D8 RID: 984
[TypeLibFunc(TypeLibFuncFlags.FRestricted | TypeLibFuncFlags.FHidden), DispId(-4)]
[MethodImpl(MethodImplOptions.InternalCall)]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(EnumeratorToEnumVariantMarshaler))]
IEnumerator GetEnumerator();
}
我们怎样才能看到生成的界面有一些额外的方法:nextNode
reset
并覆盖'GetEnumerator'
我为IXMLDOMNodeList
的实施添加了错过的方法,这解决了使用WinRT的系统中GetEnumerator
的所有问题。