Our project uses MSXML 6.0
com object for working with XML
through ComImport
attribute. Below com Class which provides access to existing MSXML COM
(I left only SelectNodes for clarify problem ).
[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;
}
}
And We have problem with some parts of code. Example :
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()
Obtained object resultQuery
as result of execution of SelectNodes
has problem with GetEnumerator depending on some outside factors:
In windows 7 or more early systems (system without support of WinRT technology)
resultQuery
has type System.__ComObject
In windows 8 or more later systems (system with support of WinRT technology)
resultQuery
has type Windows.Data.Xml.Dom.XmlNodeList
. This is WinRt type.System.ArgumentException: The object's type must not be a Windows Runtime type
. I figured out that source of exception is Marshal.GetComObjectData
. It means that our Marshalling process failsIn windows 8 or more later systems with version of imported com MSXML 3.0
:
resultQuery
has type System.__ComObject
At this moment I found three workarounds for point 2 (using msxml on windows with WinRT) but not the solutions for us (It can be helpful for developers with the same issue):
SelectNodes
with using ICustomMarshaler which will create wrapper over WinRT type and provide custom GetEnumerator through for
.I need help to find source of problem in point 2 and understand how to fix it. Thanks
After deep investigation i have found solution:
1) I generated interop C# dll for msxml6 com with TLBimp.exe
2) Opened generated dll with decompiler
3) Found generated interface IXMLDOMNodeList
.
It has next implementation:
[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();
}
How can we see generated interface has some additioanl methods : nextNode
reset
and overrided 'GetEnumerator'
I addes missed methods to my implementation of IXMLDOMNodeList
and this fixed all problem with GetEnumerator
in systems with WinRT.