【发布时间】:2017-07-26 08:57:56
【问题描述】:
我们的项目使用MSXML 6.0 com 对象来处理XML 到ComImport 属性。下面的 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()
由于执行SelectNodes 获得的对象resultQuery 存在GetEnumerator 问题,具体取决于一些外部因素:
-
在windows 7或以上早期系统(不支持WinRT技术的系统)
- 获得的对象
resultQuery的类型为System.__ComObject - resultQuery.GetEnumerator() 执行没有任何问题并提供有效的 Enumerator
- 获得的对象
-
在 windows 8 或更高版本的系统中(支持 WinRT 技术的系统)
- 获得的对象
resultQuery的类型为Windows.Data.Xml.Dom.XmlNodeList。这是 WinRt 类型。 - resultQuery.GetEnumerator() 抛出异常:
System.ArgumentException: The object's type must not be a Windows Runtime type。我发现异常的来源是Marshal.GetComObjectData。这意味着我们的编组过程失败了
- 获得的对象
-
在 windows 8 或更高版本的系统中,导入的 com
MSXML 3.0版本:- 获得的对象
resultQuery具有类型System.__ComObject - resultQuery.GetEnumerator() 执行没有任何问题并提供有效的 Enumerator
- 获得的对象
此时我发现了第 2 点的三个解决方法(在带有 WinRT 的 Windows 上使用 msxml),但不是我们的解决方案(这对有相同问题的开发人员可能会有所帮助):
- 不要使用 foreach 和 GetEnumerator。很清楚:)
- 使用ICustomMarshaler 为
SelectNodes创建自定义编组,这将创建WinRT 类型的包装器并通过for提供自定义GetEnumerator。 - 将 msxml 的版本从 6 更改为 3。
我需要帮助来找到第 2 点中的问题根源并了解如何解决它。 谢谢
【问题讨论】:
标签: c# .net com marshalling msxml