2017-03-06 71 views
1

我们的项目使用MSXML 6.0 com对象来处理XMLComImport属性。低于com类提供访问现有MSXML COM(我只留下SelectNodes澄清问题)。MSXMLl 6.0 XmlDOMNodeList在调用时失败GetEnumerator

[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问题:

  1. 在视窗7或更早期的系统(系统没有支撑的WinRT技术的)

    • 获得对象resultQuery具有类型System.__ComObject
    • resultQuery.GetEnumerator()执行没有任何问题和提供工作枚举
  2. 在窗口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。这意味着我们的编组过程失败
  3. 在Windows 8或更晚的系统进口COM MSXML 3.0的版本:

    • 获得对象resultQuery已键入System.__ComObject
    • resultQuery.GetEnumerator()的执行没有任何问题,并提供工作枚举

这时,我发现了2点(使用与WinRT的窗户MSXML)三种解决方法,但不是解决方案为我们(可与相同的问题开发商是有帮助的):

  1. 不要使用的foreach和GetEnumerator的。它很明确:)
  2. 使用ICustomMarshaler创建SelectNodes的自定义编组,它将创建WinRT类型的包装并通过for提供自定义GetEnumerator。
  3. MSXML的变化版本6至3

我需要帮助找到问题的根源在点2,了解如何解决它。 由于

回答

1

深入调查后,我们发现溶液:

1)I生成的互操作C#DLL用于MSXML6 COM与打开TLBimp.exe

2)产生具有反编译

3)实测值生成接口DLL 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(); 
} 

我们怎样才能看到生成的接口有一些additioanl方法:nextNodereset和overrided“的GetEnumerator”

我就将此错过方法对我实施IXMLDOMNodeList这个固定的所有问题在WinRT系统中使用GetEnumerator

+0

Artsiom谢谢你打开它。我正在尝试使用MSXML 6来完成同样的事情(这对我来说不适用于MSXML 3)。我也试图遍历一组检索的节点。你的答案并不清晰,我希望我不必去解构DLL,添加到IXMLDOMNodeList。这似乎是比预期更深的方式,以避免当前MSXML版本中的问题。你有没有发现任何其他方法来编码?我在.NET框架中使用VBScript。谢谢。 – Dave