2017-03-06 4 views
1

Notre projet utilise MSXML 6.0 objet com pour travailler avec XML grâce à l'attribut ComImport. Ci-dessous la classe com qui fournit un accès à MSXML COM existant (j'ai quitté seulement SelectNodes pour clarifier le problème).MSXMLl 6.0 XmlDOMNodeList échoue quand est appelé 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; 
    } 
} 

Et nous avons des problèmes avec certaines parties du code. Exemple:

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() 

objet obtenu resultQuery à la suite de l'exécution de SelectNodes a un problème avec GetEnumerator en fonction de certains facteurs extérieurs:

  1. Dans Windows 7 ou systèmes plus tôt (système sans le soutien de la technologie WinRT)

    • objet obtenu resultQuerySystem.__ComObject est de type
    • resultQuery.GetEnumerator() exécute sans problème et fournir de travail recenseur
  2. Dans Windows 8 ou plus systèmes ultérieurs (système avec le soutien de la technologie WinRT)

    • objet obtenu resultQuery est de type Windows.Data.Xml.Dom.XmlNodeList. C'est un type WinRt.
    • resultQuery.GetEnumerator() déclenche une exception: System.ArgumentException: The object's type must not be a Windows Runtime type. J'ai compris que cette source d'exception est Marshal.GetComObjectData. Cela signifie que notre processus de sérialisation échoue
  3. Dans Windows 8 ou plusieurs systèmes plus tard avec la version des produits importés com MSXML 3.0:

    • objet obtenu resultQuery est de type System.__ComObject
    • resultQuery.GetEnumerator() est parcouru sans tout problème et fournir recenseur travail

En ce moment, j'ai trouvé trois solutions de contournement pour le point 2 (en utilisant MSXML sur les fenêtres avec WinRT) mais pas les solutions pour nous (Il peut être utile pour les développeurs avec le même numéro):

  1. Ne pas utiliser foreach et GetEnumerator. il est clair :)
  2. Créer un regroupement personnalisé pour SelectNodes en utilisant ICustomMarshaler qui va créer un wrapper sur le type WinRT et fournir GetEnumerator personnalisé via for.
  3. version Changement de MSXML de 6 à 3.

je besoin d'aide pour trouver la source de problèmes au point 2 et comprendre comment y remédier. Merci

Répondre

1

Après enquête profonde que j'ai trouvé la solution:

1) Je généré Interop dll C# pour msxml6 com avec TLBimp.exe

2) Ouvert généré dll avec décompilateur

3) Résultats d'interface générée IXMLDOMNodeList. Il a ensuite la mise en œuvre:

[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(); 
} 

Comment peut-on voir l'interface générée a des méthodes de additioanl: nextNodereset et overrided « GetEnumerator »

J'ADDES manqué des méthodes pour ma mise en œuvre de IXMLDOMNodeList et que ce soit réglé tout problème GetEnumerator dans les systèmes avec WinRT.

+0

Artsiom vous remercie de l'avoir fait. J'essaie de faire exactement la même chose, en utilisant MSXML 6 (il n'est pas possible pour moi de reculer à MSXML 3). Moi aussi j'essaie de parcourir un ensemble de nœuds récupérés. Votre réponse n'est pas très claire, j'espère que je ne devrais pas aller déconstruire les DLL, ajouter à IXMLDOMNodeList. Cela semble beaucoup plus profond que prévu, pour éviter un problème dans une version MSXML actuelle. Avez-vous découvert d'autres approches pour coder cela? J'utilise VBScript dans le framework .NET. Je vous remercie. – Dave