2017-03-06 72 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