Page 1 of 2

COM Interface to MSXML

Posted: Fri May 14, 2004 10:04 pm
by Karbon
So I downloaded the MSXML SDK, in it is a few header files and a static library (that I hope I can somehow link?).. Anyway, I used the interface importer to import the header files and I got a great but PB file with all sorts of definitions in there.. All well and good. Now I need some (simple?) help..

Using this interface, how do I "create" the object?

In the SDK help file there is a VB example, straight forward as it is,

Set xmldoc = New DOMDocument30

.. So how do I do that in PB? :-)

Code: Select all

Interface IXMLDOMDocument
  QueryInterface(a.l, b.l)
  AddRef()
  Release()
  GetTypeInfoCount(a.l)
  GetTypeInfo(a.l, b.l, c.l)
  GetIDsOfNames(a.l, b.l, c.l, d.l, e.l)
  Invoke(a.l, b.l, c.l, d.l, e.l, f.l, g.l, h.l)
  get_nodeName(a.l)
  get_nodeValue(a.l)
  put_nodeValue(a.l)
  get_nodeType(a.l)
  get_parentNode(a.l)
  get_childNodes(a.l)
  get_firstChild(a.l)
  get_lastChild(a.l)
  get_previousSibling(a.l)
  get_nextSibling(a.l)
  get_attributes(a.l)
  insertBefore(a.l, b.l, c.l)
  replaceChild(a.l, b.l, c.l)
  removeChild(a.l, b.l)
  appendChild(a.l, b.l)
  hasChildNodes(a.l)
  get_ownerDocument(a.l)
  cloneNode(a.l, b.l)
  get_nodeTypeString(a.l)
  get_text(a.l)
  put_text(a.l)
  get_specified(a.l)
  get_definition(a.l)
  get_nodeTypedValue(a.l)
  put_nodeTypedValue(a.l)
  get_dataType(a.l)
  put_dataType(a.l)
  get_xml(a.l)
  transformNode(a.l, b.l)
  selectNodes(a.l, b.l)
  selectSingleNode(a.l, b.l)
  get_parsed(a.l)
  get_namespaceURI(a.l)
  get_prefix(a.l)
  get_baseName(a.l)
  transformNodeToObject(a.l, b.l)
  get_doctype(a.l)
  get_implementation(a.l)
  get_documentElement(a.l)
  putref_documentElement(a.l)
  createElement(a.l, b.l)
  createDocumentFragment(a.l)
  createTextNode(a.l, b.l)
  createComment(a.l, b.l)
  createCDATASection(a.l, b.l)
  createProcessingInstruction(a.l, b.l, c.l)
  createAttribute(a.l, b.l)
  createEntityReference(a.l, b.l)
  getElementsByTagName(a.l, b.l)
  createNode(a.l, b.l, c.l, d.l)
  nodeFromID(a.l, b.l)
  load(a.l, b.l)
  get_readyState(a.l)
  get_parseError(a.l)
  get_url(a.l)
  get_async(a.l)
  put_async(a.l)
  abort()
  loadXML(a.l, b.l)
  save(a.l)
  get_validateOnParse(a.l)
  put_validateOnParse(a.l)
  get_resolveExternals(a.l)
  put_resolveExternals(a.l)
  get_preserveWhiteSpace(a.l)
  put_preserveWhiteSpace(a.l)
  put_onreadystatechange(a.l)
  put_ondataavailable(a.l)
  put_ontransformnode(a.l)
EndInterface

Posted: Sat May 15, 2004 12:29 am
by freak
To do this in PB, you will need some more info from the sdk.

1) The interface identifyer (IID) of that IXMLDOMDocument, usually named
IID_IXMLDOMDocument

2) The class id (CLSID) for the class of the object to create.

These must be defined in some header file, usually through a macro or something.
They are basically a data structure of 1 LONG, 2 WORD and 8 BYTE, which
is a globale unique identifyer (GUID).

For PB, the most common used way is to put them in a datasection like this:

Code: Select all

DataSection

  IID_IXMLDOMDocument:
    Data.l $XXXXXXXX
    Data.w $XXXX, $XXXX
    Data.b $XX, $XX, $XX, $XX, $XX, $XX, $XX, $XX

EndDataSection
This way, you can access them simply as ?IID_IXMLDOMDocument.

Now the code to create the object would look like this:

Code: Select all

; CLSCTX enumeration, needed for CoCreateInstance_()
;
#CLSCTX_INPROC_SERVER        = $1
#CLSCTX_INPROC_HANDLER       = $2 
#CLSCTX_LOCAL_SERVER         = $4
#CLSCTX_INPROC_SERVER16      = $8
#CLSCTX_REMOTE_SERVER        = $10
#CLSCTX_INPROC_HANDLER16     = $20
#CLSCTX_RESERVED1            = $40
#CLSCTX_RESERVED2            = $80
#CLSCTX_RESERVED3            = $100
#CLSCTX_RESERVED4            = $200
#CLSCTX_NO_CODE_DOWNLOAD     = $400
#CLSCTX_RESERVED5            = $800
#CLSCTX_NO_CUSTOM_MARSHAL    = $1000
#CLSCTX_ENABLE_CODE_DOWNLOAD = $2000
#CLSCTX_NO_FAILURE_LOG       = $4000
#CLSCTX_DISABLE_AAA          = $8000
#CLSCTX_ENABLE_AAA           = $10000
#CLSCTX_FROM_DEFAULT_CONTEXT = $20000


; You must call CoUninitialize_() for every SUCCESSFULL call to
; CoInitialize_(0), so save the result for later.
; COM will be initialize, whether this function fails or not.
; Failure only indicates, that COM was allready initialized for the same thread.
;
CoInit = CoInitialize_(0)

; Now create the object
;
If CoCreateInstance_(?CLSID_YourClassHere, #NULL, #CLSCTX_INPROC_SERVER, ?IID_IXMLDOMDocument, @XMLDoc.IXMLDOMDocument) = #S_OK
  
  ; You now have the IXMLDOMDocument interface of your Object accessible
  ; through XMLDoc.
  
  ; You should free it by calling it's Release() method when it is no more needed:
  ;
  XMLDoc\Release()
  
  ; #CLSCTX_INPROC_SERVER was used here, because the code for the object is
  ; from within your program. This can be a static lib, or a loaded dll.
  ; Mostly this is needed.
  
  ; Other values of the enumeration are used when the code is executed in a different app,
  ; or even on a different computer.

Else
  ; 
  ; cannot create the object
  ;
EndIf


; Now uninitialize COM if needed.
;
If CoInit = #S_OK
  CoUninitialize_()
EndIf



; Of course, the DataSection is missing here, as i don't know these guids.
I hope this makes some sense.... (and works !?) :)

Timo

Posted: Sat May 15, 2004 2:59 pm
by Karbon
Timo, you are the man. Thank you very much!!!

I'm going to try it - I'm sure I'll pester you more later!

Posted: Sat May 15, 2004 7:40 pm
by aXend
There is already an IXMLDOMDocument interface in the residents (see Structures/Interfaces).

Posted: Sat May 15, 2004 9:30 pm
by Edwin Knoppert
Do you use some tool to generate code?

Like the VTABLE?

Posted: Sun May 16, 2004 1:12 am
by Karbon
aXend wrote:There is already an IXMLDOMDocument interface in the residents (see Structures/Interfaces).
Huh? Where? What or where is Structures/Interfaces?

Posted: Sun May 16, 2004 1:35 pm
by freak
Just open the StructureViewer in the PB ide. It has a tab that shows all
predefined interfaces. It is in the list :wink:

So you can use it like a predefined structure, too.

Timo

Posted: Sun May 16, 2004 5:04 pm
by Karbon
So it's the IXMLDOMNode object that has the transformNode member I'm looking for..

When I used the interface imported on the MSXML 3.0 SDK I downloaded the interface(s) are quite a bit different. Were the ones included in PB an older version or something?

From Interface Importer :

Code: Select all

Interface IXMLDOMDocumentM
  QueryInterface(a.l, b.l)
  AddRef()
  Release()
  GetTypeInfoCount(a.l)
  GetTypeInfo(a.l, b.l, c.l)
  GetIDsOfNames(a.l, b.l, c.l, d.l, e.l)
  Invoke(a.l, b.l, c.l, d.l, e.l, f.l, g.l, h.l)
  get_nodeName(a.l)
  get_nodeValue(a.l)
  put_nodeValue(a.l)
  get_nodeType(a.l)
  get_parentNode(a.l)
  get_childNodes(a.l)
  get_firstChild(a.l)
  get_lastChild(a.l)
  get_previousSibling(a.l)
  get_nextSibling(a.l)
  get_attributes(a.l)
  insertBefore(a.l, b.l, c.l)
  replaceChild(a.l, b.l, c.l)
  removeChild(a.l, b.l)
  appendChild(a.l, b.l)
  hasChildNodes(a.l)
  get_ownerDocument(a.l)
  cloneNode(a.l, b.l)
  get_nodeTypeString(a.l)
  get_text(a.l)
  put_text(a.l)
  get_specified(a.l)
  get_definition(a.l)
  get_nodeTypedValue(a.l)
  put_nodeTypedValue(a.l)
  get_dataType(a.l)
  put_dataType(a.l)
  get_xml(a.l)
  transformNode(a.l, b.l)
  selectNodes(a.l, b.l)
  selectSingleNode(a.l, b.l)
  get_parsed(a.l)
  get_namespaceURI(a.l)
  get_prefix(a.l)
  get_baseName(a.l)
  transformNodeToObject(a.l, b.l)
  get_doctype(a.l)
  get_implementation(a.l)
  get_documentElement(a.l)
  putref_documentElement(a.l)
  createElement(a.l, b.l)
  createDocumentFragment(a.l)
  createTextNode(a.l, b.l)
  createComment(a.l, b.l)
  createCDATASection(a.l, b.l)
  createProcessingInstruction(a.l, b.l, c.l)
  createAttribute(a.l, b.l)
  createEntityReference(a.l, b.l)
  getElementsByTagName(a.l, b.l)
  createNode(a.l, b.l, c.l, d.l)
  nodeFromID(a.l, b.l)
  load(a.l, b.l)
  get_readyState(a.l)
  get_parseError(a.l)
  get_url(a.l)
  get_async(a.l)
  put_async(a.l)
  abort()
  loadXML(a.l, b.l)
  save(a.l)
  get_validateOnParse(a.l)
  put_validateOnParse(a.l)
  get_resolveExternals(a.l)
  put_resolveExternals(a.l)
  get_preserveWhiteSpace(a.l)
  put_preserveWhiteSpace(a.l)
  put_onreadystatechange(a.l)
  put_ondataavailable(a.l)
  put_ontransformnode(a.l)
EndInterface

Posted: Sun May 16, 2004 5:04 pm
by Karbon
By the way, what I'm trying to do is create some HTML based on XML with an XSL stylesheet :-)

Posted: Sun May 16, 2004 5:10 pm
by Karbon
AND, if I try to use the new interface gathered by the importer tool I get a syntax error!

Code: Select all

If CoCreateInstance_(?CLSID_DOMDocument, #Null, #CLSCTX_INPROC_SERVER, ?IID_IXMLDOMDocument, @XMLDoc.IXMLDOMDocumentM) = #S_OK
Adding that M to the interface define and this call was the only change made..

What gives?

I put up the SDK for download if anyone want to take a look..

http://www.ksoftware.net/MSXML.zip for the full SDK

http://www.ksoftware.net/msxml2.h for the header

Posted: Tue May 18, 2004 6:41 am
by aXend
I have created an example with the IXMLDOMDocument. This works, that is, I can create an instance. Here is the code:

Code: Select all

; This program creates an XMLDOMDocument object

;- Interface definitions
Interface myIXMLDOMNode Extends IDispatch
  get_nodeName(a.l) ; 
  get_nodeValue(a.l) ; 
  put_nodeValue(a.l) ; 
  get_nodeType(a.l) ; 
  get_parentNode(a.l) ; 
  get_childNodes(a.l) ; 
  get_firstChild(a.l) ; 
  get_lastChild(a.l) ; 
  get_previousSibling(a.l) ; 
  get_nextSibling(a.l) ; 
  get_attributes(a.l) ; 
  insertBefore(a.l,b.l,c.l) ; 
  replaceChild(a.l,b.l,c.l) ; 
  removeChild(a.l,b.l) ; 
  appendChild(a.l,b.l) ; 
  hasChildNodes(a.l) ; 
  get_ownerDocument(a.l) ; 
  cloneNode(a.l,b.l) ; 
  get_nodeTypeString(a.l) ; 
  get_text(a.l) ; 
  put_text(a.l) ; 
  get_specified(a.l) ; 
  get_definition(a.l) ; 
  get_nodeTypedValue(a.l) ; 
  put_nodeTypedValue(a.l) ; 
  get_dataType(a.l) ; 
  put_dataType(a.l) ; 
  get_xml(a.l) ; 
  transformNode(a.l,b.l) ; 
  selectNodes(a.l,b.l) ; 
  selectSingleNode(a.l,b.l) ; 
  get_parsed(a.l) ; 
  get_namespaceURI(a.l) ; 
  get_prefix(a.l) ; 
  get_baseName(a.l) ; 
  transformNodeToObject(a.l,b.l) ; 
EndInterface

Interface myIXMLDOMDocument Extends myIXMLDOMNode
  get_doctype(a.l) ; 
  get_implementation(a.l) ; 
  get_documentElement(a.l) ; 
  put_documentElement(a.l) ; 
  createElement(a.l,b.l) ; 
  createDocumentFragment(a.l) ; 
  createTextNode(a.l,b.l) ; 
  createComment(a.l,b.l) ; 
  createCDATASection(a.l,b.l) ; 
  createProcessingInstruction(a.l,b.l,c.l) ; 
  createAttribute(a.l,b.l) ; 
  createEntityReference(a.l,b.l) ; 
  getElementsByTagName(a.l,b.l) ; 
  createNode(a.l,b.l,c.l,d.l) ; 
  nodeFromID(a.l,b.l) ; 
  load(a.l,b.l) ; 
  get_readyState(a.l) ; 
  get_parseError(a.l) ; 
  get_url(a.l) ; 
  get_async(a.l) ; 
  put_async(a.l) ; 
  abort() ; 
  loadXML(a.l,b.l) ; 
  save(a.l) ; 
  get_validateOnParse(a.l) ; 
  put_validateOnParse(a.l) ; 
  get_resolveExternals(a.l) ; 
  put_resolveExternals(a.l) ; 
  get_preserveWhiteSpace(a.l) ; 
  put_preserveWhiteSpace(a.l) ; 
  put_onreadystatechange(a.l) ; 
  put_ondataavailable(a.l) ; 
  put_ontransformnode(a.l) ; 
EndInterface

Global oXML.myIXMLDOMDocument

;- Start of program
CoInitialize_(0)

If CoCreateInstance_(?CLSID_XMLDOM,0,1,?IID_IXMLDOMDocument,@oXML)<>#S_OK
  MessageRequester("Warning:","Couldn't init oXML",0)
  End
EndIf 
Debug oXML

If oXML
  oXML\Release()
EndIf

CoUninitialize_()

End

;- Datasection
DataSection
  CLSID_XMLDOM:      ;{2933BF90-7B36-11D2-B20E-00C04F983E60}
  Data.l $2933BF90
  Data.w $7B36,$11D2
  Data.b $B2,$0E,$00,$C0,$4F,$98,$3E,$60
EndDataSection

DataSection
  IID_IXMLDOMDocument:      ;{2933BF81-7B36-11D2-B20E-00C04F983E60}
  Data.l $2933BF81
  Data.w $7B36,$11D2
  Data.b $B2,$0E,$00,$C0,$4F,$98,$3E,$60
EndDataSection
May be this helps :?:

Posted: Tue May 18, 2004 1:05 pm
by Karbon
Thank you VERY much for all this help.. I'll pester you a little more, I hope you don't mind..

Some of the interface procedures require 2 args but the documentation only shows 1 argument so I can't really figure out what it's wanting..

myIXMLDOMDocument\load() for example,

Code: Select all

load(a.l,b.l)
Though the examples I see show that as the function (or method) to call to actually load an XML doc from a file - so load("myxml.xml") - but there is that second mystery arg.. Is this something that happens often? Does it need 8 bytes of data? Maybe something to do with unicode?

Newest Work

Posted: Tue May 18, 2004 2:10 pm
by Karbon
Download the whole thing, including the XML/XSL from http://www.ksoftware.net/pb_xmltest.zip

It's still not working correctly (crashes when you try to load the XSL sheet) and it's HORRIBLY sloppy. It is a start, though!

Code: Select all

#VT_EMPTY = 0
#VT_NULL = 1
#VT_I2 = 2
#VT_I4 = 3
#VT_R4 = 4
#VT_R8 = 5
#VT_CY = 6
#VT_DATE = 7
#VT_BSTR = 8
#VT_DISPATCH = 9
#VT_ERROR = 10
#VT_BOOL = 11
#VT_VARIANT = 12
#VT_UNKNOWN = 13
#VT_DECIMAL = 14
#VT_I1 = 16
#VT_UI1 = 17
#VT_UI2 = 18
#VT_UI4 = 19
#VT_I8 = 20
#VT_UI8 = 21
#VT_INT = 22
#VT_UINT = 23
#VT_VOID = 24
#VT_HRESULT = 25
#VT_PTR = 26
#VT_SAFEARRAY = 27
#VT_CARRAY = 28
#VT_USERDEFINED = 29
#VT_LPSTR = 30
#VT_LPWSTR = 31
#VT_RECORD = 36
#VT_FILETIME = 64
#VT_BLOB = 65
#VT_STREAM = 66
#VT_STORAGE = 67
#VT_STREAMED_OBJECT = 68
#VT_STORED_OBJECT = 69
#VT_BLOB_OBJECT = 70
#VT_CF = 71
#VT_CLSID = 72
#VT_BSTR_BLOB = $FFF
#VT_VECTOR = $1000
#VT_ARRAY = $2000
#VT_BYREF = $4000
#VT_RESERVED = $8000
#VT_ILLEGAL = $FFFF
#VT_ILLEGALMASKED = $FFF
#VT_TYPEMASK = $FFF
#DISP_E_PARAMNOTFOUND = $80020004 

Structure VARIANT
  vt.w
  wReserved1.w
  wReserved2.w   
  wReserved3.w
  StructureUnion
    value.l
    bstrVal.l
    scode.l
  EndStructureUnion
EndStructure

;- Interface definitions
Interface myIXMLDOMNode Extends IDispatch
  get_nodeName(a.l) ;
  get_nodeValue(a.l) ;
  put_nodeValue(a.l) ;
  get_nodeType(a.l) ;
  get_parentNode(a.l) ;
  get_childNodes(a.l) ;
  get_firstChild(a.l) ;
  get_lastChild(a.l) ;
  get_previousSibling(a.l) ;
  get_nextSibling(a.l) ;
  get_attributes(a.l) ;
  insertBefore(a.l,b.l,c.l) ;
  replaceChild(a.l,b.l,c.l) ;
  removeChild(a.l,b.l) ;
  appendChild(a.l,b.l) ;
  hasChildNodes(a.l) ;
  get_ownerDocument(a.l) ;
  cloneNode(a.l,b.l) ;
  get_nodeTypeString(a.l) ;
  get_text(a.l) ;
  put_text(a.l) ;
  get_specified(a.l) ;
  get_definition(a.l) ;
  get_nodeTypedValue(a.l) ;
  put_nodeTypedValue(a.l) ;
  get_dataType(a.l) ;
  put_dataType(a.l) ;
  get_xml(a.l) ;
  transformNode(a.l,b.l) ;
  selectNodes(a.l,b.l) ;
  selectSingleNode(a.l,b.l) ;
  get_parsed(a.l) ;
  get_namespaceURI(a.l) ;
  get_prefix(a.l) ;
  get_baseName(a.l) ;
  transformNodeToObject(a.l,b.l) ;
EndInterface

Interface myIXMLDOMDocument Extends myIXMLDOMNode
  get_doctype(a.l) ;
  get_implementation(a.l) ;
  get_documentElement(a.l) ;
  put_documentElement(a.l) ;
  createElement(a.l,b.l) ;
  createDocumentFragment(a.l) ;
  createTextNode(a.l,b.l) ;
  createComment(a.l,b.l) ;
  createCDATASection(a.l,b.l) ;
  createProcessingInstruction(a.l,b.l,c.l) ;
  createAttribute(a.l,b.l) ;
  createEntityReference(a.l,b.l) ;
  getElementsByTagName(a.l,b.l) ;
  createNode(a.l,b.l,c.l,d.l) ;
  nodeFromID(a.l,b.l) ;
  load(a.l,b.l) ;
  get_readyState(a.l) ;
  get_parseError(a.l) ;
  get_url(a.l) ;
  get_async(a.l) ;
  put_async(a.l) ;
  abort() ;
  loadXML(a.l,b.l) ;
  save(a.l) ;
  get_validateOnParse(a.l) ;
  put_validateOnParse(a.l) ;
  get_resolveExternals(a.l) ;
  put_resolveExternals(a.l) ;
  get_preserveWhiteSpace(a.l) ;
  put_preserveWhiteSpace(a.l) ;
  put_onreadystatechange(a.l) ;
  put_ondataavailable(a.l) ;
  put_ontransformnode(a.l) ;
EndInterface


Procedure.s Uni2Ansi(unicodestr.l)
  lenA = WideCharToMultiByte_(#CP_ACP, 0, unicodestr, -1, 0, 0, 0, 0);
  ansistr.s = Space(lenA)
  If (lenA > 0)
    WideCharToMultiByte_(#CP_ACP, 0, unicodestr, -1, @ansistr, lenA, 0, 0);
  EndIf
  ProcedureReturn ansistr
EndProcedure

Procedure.l Ansi2Uni(ansistr.s)
  lenA.l = Len(ansistr)
  lenW = MultiByteToWideChar_(#CP_ACP, 0, ansistr, lenA, 0, 0)
  If (lenW > 0) ; Check whether conversion was successful
    unicodestr = SysAllocStringLen_(0, lenW)
    MultiByteToWideChar_(CP_ACP, 0, ansistr, lenA, unicodestr, lenW)
    result = unicodestr
    SysFreeString_(unicodestr)
    ProcedureReturn result
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure.s GetHResultMessage(HResult.l)
  ;Converts a COM HResult value into a more meaningful message.
  ;Params:
  ;     HResult.l A HResult value return from a COM call
  
  Message.s = ""
  Select HResult
    Case #S_OK
      Message = "OK"
    Case #CLASS_E_CLASSNOTAVAILABLE
      Message = "Class Not Available"
    Case #E_NOINTERFACE
      Message = "No Interface"
    Case #CO_E_NOTINITIALIZED
      Message = "CO_E_NOTINITIALIZED"
    Case #CO_E_ALREADYINITIALIZED
      Message = "CO_E_ALREADYINITIALIZED"
    Case #CO_E_CANTDETERMINECLASS
      Message = "CO_E_CANTDETERMINECLASS"
    Case #CO_E_CLASSSTRING
      Message = "The registered CLSID for the ProgID is invalid"
    Case #CO_E_IIDSTRING
      Message = "CO_E_IIDSTRING"
    Case #CO_E_APPNOTFOUND
      Message = "CO_E_APPNOTFOUND"
    Case #CO_E_APPSINGLEUSE
      Message = "CO_E_APPSINGLEUSE"
    Case #CO_E_ERRORINAPP
      Message = "CO_E_ERRORINAPP"
    Case #CO_E_DLLNOTFOUND
      Message = "CO_E_DLLNOTFOUND"
    Case #CO_E_ERRORINDLL
      Message = "CO_E_ERRORINDLL"
    Case #CO_E_WRONGOSFORAPP
      Message = "CO_E_WRONGOSFORAPP"
    Case #CO_E_OBJNOTREG
      Message = "CO_E_OBJNOTREG"
    Case #CO_E_OBJISREG
      Message = "CO_E_OBJISREG"
    Case #CO_E_OBJNOTCONNECTED
      Message = "CO_E_OBJNOTCONNECTED"
    Case #CO_E_APPDIDNTREG
      Message = "CO_E_APPDIDNTREG"
    Case #CO_E_RELEASED
      Message = "CO_E_RELEASED"
    Case #REGDB_E_WRITEREGDB
      Message = "An error occurred writing the CLSID To the registry."
    Case #E_OUTOFMEMORY
      Message = "Out of memory."
    Case #STG_E_INSUFFICIENTMEMORY
      Message = "Out of memory."
    Case #E_INVALIDARG
      Message = "One or more of the arguments is invalid."
    Case #DISP_E_UNKNOWNNAME
      Message = "One Or more of the names could not be found."
    Case #DISP_E_UNKNOWNLCID
      Message = "The locale identifier (LCID) could not be found in the OLE DLLs."
    Default
      Message = "Error Number: $" + Hex(HResult)
  EndSelect
  
  ProcedureReturn Message
EndProcedure

Global oXML.myIXMLDOMDocument
Global oXSL.myIXMLDOMDocument

Global XML_file.VARIANT
Global XSL_file.VARIANT
Global VBool1.VARIANT
Global VBool2.VARIANT

XML_file\vt = #VT_BSTR
XML_file\bstrVal = SysAllocString_(Ansi2Uni("C:\XML\xmlsheet.xml"))

XSL_file\vt = #VT_BSTR
XSL_file\bstrVal = SysAllocString_(Ansi2Uni("C:\XML\xslsheet.xsl"))

VBool1\vt = #VT_BOOL
VBool2\vt = #VT_BOOL

;- Start of program
CoInitialize_(0)

If CoCreateInstance_(?CLSID_XMLDOM,0,1,?IID_IXMLDOMDocument,@oXML)<>#S_OK
  MessageRequester("Warning:","Couldn't init oXML",0)
  End
EndIf

If CoCreateInstance_(?CLSID_XMLDOM,0,1,?IID_IXMLDOMDocument,@oXSL)<>#S_OK
  MessageRequester("Warning:","Couldn't init oXSL",0)
  End
EndIf

*My_xml_result.VARIANT = oXML\load(XML_file,VBool1)

Debug "XML " + GetHResultMessage(My_xml_result)

;
; Crashes as soon as you try to load the XSL sheet.
;

;buffer.s = Space(1024)
;
;*My_xsl_result.VARIANT = oXSL\load(XSL_file,VBool2)
; 
;Debug "XSL " + GetHResultMessage(My_xsl_result)

;oXML\transformNode(@oXSL,@buffer)

If oXML
  oXML\Release()
EndIf

If oXSL
  oXSL\Release()
EndIf

CoUninitialize_()

End

;- Datasection
DataSection
CLSID_XMLDOM:      ;{2933BF90-7B36-11D2-B20E-00C04F983E60}
Data.l $2933BF90
Data.w $7B36,$11D2
Data.b $B2,$0E,$00,$C0,$4F,$98,$3E,$60
EndDataSection

DataSection
IID_IXMLDOMDocument:      ;{2933BF81-7B36-11D2-B20E-00C04F983E60}
Data.l $2933BF81
Data.w $7B36,$11D2
Data.b $B2,$0E,$00,$C0,$4F,$98,$3E,$60
EndDataSection 

Posted: Tue May 18, 2004 3:04 pm
by aXend
Nice work! :D

I have done almost the same. I got the load-method to work by changing the parameters to load(a,a,a,a,b). This makes it possible to pass a VARIANT in chunks of 4 LONG's. This is not ideal, but it works. I don't know if it's possible to change this behaviour.

Please look at my code. I've been able to load XML and XSL and perform a transform. The output looks very nice. I also added some code to walk down a node.

The code is below. You can download including the XML and XSL from:
http://home.planet.nl/~aXend/purebasic/xmltest.zip

Code: Select all

;---------------------------------------------------------------------------------------------   
; This program uses the MSXML interface to work with XML and XSL
;
; aXend, 2004
;---------------------------------------------------------------------------------------------   

; Variant stuff 

Enumeration 
  #VT_EMPTY           = 0 
  #VT_NULL            = 1 
  #VT_I2              = 2 
  #VT_I4              = 3 
  #VT_R4              = 4 
  #VT_R8              = 5 
  #VT_CY              = 6 
  #VT_DATE            = 7 
  #VT_BSTR            = 8 
  #VT_DISPATCH        = 9 
  #VT_ERROR           = 10 
  #VT_BOOL            = 11 
  #VT_VARIANT         = 12 
  #VT_UNKNOWN         = 13 
  #VT_DECIMAL         = 14 
  #VT_I1              = 16 
  #VT_UI1             = 17 
  #VT_UI2             = 18 
  #VT_UI4             = 19 
  #VT_I8              = 20 
  #VT_UI8             = 21 
  #VT_INT             = 22 
  #VT_UINT            = 23 
  #VT_VOID            = 24 
  #VT_HRESULT         = 25 
  #VT_PTR             = 26 
  #VT_SAFEARRAY       = 27 
  #VT_CARRAY          = 28 
  #VT_USERDEFINED     = 29 
  #VT_LPSTR           = 30 
  #VT_LPWSTR          = 31 
  #VT_RECORD          = 36 
  #VT_FILETIME        = 64 
  #VT_BLOB            = 65 
  #VT_STREAM          = 66 
  #VT_STORAGE         = 67 
  #VT_STREAMED_OBJECT = 68 
  #VT_STORED_OBJECT   = 69 
  #VT_BLOB_OBJECT     = 70 
  #VT_CF              = 71 
  #VT_CLSID           = 72 
  #VT_BSTR_BLOB       = $0fff 
  #VT_VECTOR          = $1000 
  #VT_ARRAY           = $2000 
  #VT_BYREF           = $4000 
  #VT_RESERVED        = $8000 
  #VT_ILLEGAL         = $ffff 
  #VT_ILLEGALMASKED   = $0fff 
  #VT_TYPEMASK        = $0fff 
EndEnumeration 

Structure VARIANT 
  vt.w 
  wReserved1.w 
  wReserved2.w    
  wReserved3.w 
  StructureUnion 
    value.l 
    bstrVal.l 
    scode.l
  EndStructureUnion
EndStructure 

;- Constants
#DISP_E_PARAMNOTFOUND = $80020004
#CRLF.s = Chr(13)+Chr(10)
#BR.s = "<br>"

Enumeration
  #Window
  #Statusbar
  #ButtonBack
  #ButtonNext
  #ButtonStop
  #ButtonGo
  #Url
  #Frame
  #Webpage
EndEnumeration

;- Interface definitions
Interface myIXMLDOMNode Extends IDispatch
  get_nodeName(a.l) ; 
  get_nodeValue(a.l) ; 
  put_nodeValue(a.l) ; 
  get_nodeType(a.l) ; 
  get_parentNode(a.l) ; 
  get_childNodes(a.l) ; 
  get_firstChild(a.l) ; 
  get_lastChild(a.l) ; 
  get_previousSibling(a.l) ; 
  get_nextSibling(a.l) ; 
  get_attributes(a.l) ; 
  insertBefore(a.l,b.l,c.l) ; 
  replaceChild(a.l,b.l,c.l) ; 
  removeChild(a.l,b.l) ; 
  appendChild(a.l,b.l) ; 
  hasChildNodes(a.l) ; 
  get_ownerDocument(a.l) ; 
  cloneNode(a.l,b.l) ; 
  get_nodeTypeString(a.l) ; 
  get_text(a.l) ; 
  put_text(a.l) ; 
  get_specified(a.l) ; 
  get_definition(a.l) ; 
  get_nodeTypedValue(a.l) ; 
  put_nodeTypedValue(a.l) ; 
  get_dataType(a.l) ; 
  put_dataType(a.l) ; 
  get_xml(a.l) ; 
  transformNode(a.l,b.l) ; 
  selectNodes(a.l,b.l) ; 
  selectSingleNode(a.l,b.l) ; 
  get_parsed(a.l) ; 
  get_namespaceURI(a.l) ; 
  get_prefix(a.l) ; 
  get_baseName(a.l) ; 
  transformNodeToObject(a.l,b.l) ; 
EndInterface

Interface myIXMLDOMNodeList Extends IDispatch
  get_item(a.l,b.l) ; 
  get_length(a.l) ; 
  nextNode(a.l) ; 
  reset() ; 
  get__newEnum(a.l) ; 
EndInterface

Interface myIXMLDOMDocument Extends myIXMLDOMNode
  get_doctype(a.l) ; 
  get_implementation(a.l) ; 
  get_documentElement(a.l) ; 
  put_documentElement(a.l) ; 
  createElement(a.l,b.l) ; 
  createDocumentFragment(a.l) ; 
  createTextNode(a.l,b.l) ; 
  createComment(a.l,b.l) ; 
  createCDATASection(a.l,b.l) ; 
  createProcessingInstruction(a.l,b.l,c.l) ; 
  createAttribute(a.l,b.l) ; 
  createEntityReference(a.l,b.l) ; 
  getElementsByTagName(a.l,b.l) ; 
  createNode(a.l,b.l,c.l,d.l) ; 
  nodeFromID(a.l,b.l) ; 
  load(a.l,a.l,a.l,a.l,b.l) ; I changed this method to pass a VARIANT to it 
  get_readyState(a.l) ; 
  get_parseError(a.l) ; 
  get_url(a.l) ; 
  get_async(a.l) ; 
  put_async(a.l) ; 
  abort() ; 
  loadXML(a.l,b.l) ; 
  save(a.l) ; 
  get_validateOnParse(a.l) ; 
  put_validateOnParse(a.l) ; 
  get_resolveExternals(a.l) ; 
  put_resolveExternals(a.l) ; 
  get_preserveWhiteSpace(a.l) ; 
  put_preserveWhiteSpace(a.l) ; 
  put_onreadystatechange(a.l) ; 
  put_ondataavailable(a.l) ; 
  put_ontransformnode(a.l) ; 
EndInterface

Interface myIXMLDOMParseError Extends IDispatch
  get_errorCode(a.l) ; 
  get_url(a.l) ; 
  get_reason(a.l) ; 
  get_srcText(a.l) ; 
  get_line(a.l) ; 
  get_linepos(a.l) ; 
  get_filepos(a.l) ; 
EndInterface

;- Variables
Global oXML.myIXMLDOMDocument
Global oXSL.myIXMLDOMDocument

vTRUE.VARIANT\vt = #VT_BOOL
vTRUE\value = $FFFF
vFALSE.VARIANT\vt = #VT_BOOL
vFALSE\value = $0

;I use this to pass a VARIANT to a method
Structure pToVariant
  a.l[4]
EndStructure

;---------------------------------------------------------------------------------------------   
;- Unicode procedures
;---------------------------------------------------------------------------------------------   
Procedure.s Uni2Ansi(unicodestr.l)
  lenA = WideCharToMultiByte_(#CP_ACP, 0, unicodestr, -1, 0, 0, 0, 0);
  ansistr.s = Space(lenA)
  If (lenA > 0)
    WideCharToMultiByte_(#CP_ACP, 0, unicodestr, -1, @ansistr, lenA, 0, 0);
  EndIf
  ProcedureReturn ansistr
EndProcedure

Procedure.l Ansi2Uni(ansistr.s)
  lenA.l = Len(ansistr)
  lenW = MultiByteToWideChar_(#CP_ACP, 0, ansistr, lenA, 0, 0)
  If (lenW > 0) ; Check whether conversion was successful
    unicodestr = SysAllocStringLen_(0, lenW)
    MultiByteToWideChar_(#CP_ACP, 0, ansistr, lenA, unicodestr, lenW)
    result = unicodestr
    SysFreeString_(unicodestr)
    ProcedureReturn result
  Else 
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure ResizeWebWindow()
  ResizeGadget(#Webpage, -1, -1, WindowWidth(), WindowHeight()-52)
  ResizeGadget(#Url, -1, -1, WindowWidth()-185, -1)
  ResizeGadget(#ButtonGo, WindowWidth()-25, -1, -1, -1)
  ResizeGadget(#Frame, -1, -1, WindowWidth(), -1)
EndProcedure

Procedure SizeCallback(WindowID, Message, wParam, lParam)
  ReturnValue = #PB_ProcessPureBasicEvents
  If Message = #WM_SIZE 
;     UpdateStatusBar(0)
    ResizeWebWindow()
    ReturnValue = 1
  EndIf
  ProcedureReturn  ReturnValue
EndProcedure

;---------------------------------------------------------------------------------------------   
;Browse file
;---------------------------------------------------------------------------------------------   
Procedure Browse(url.s)
  If OpenWindow(#Window, 100, 200, 800, 500, #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget, "PureBasic XMLBrowser v1.0")
    CreateStatusBar(#Statusbar, WindowID())
    StatusBarText(#Statusbar, 0, "Welcome to the world of Interfacing ! :)", 0)
    CreateGadgetList(WindowID())
    ButtonGadget(#ButtonBack,   0, 0, 50, 25, "Back")
    ButtonGadget(#ButtonNext,  50, 0, 50, 25, "Next")
    ButtonGadget(#ButtonStop, 100, 0, 50, 25, "Stop")
    StringGadget(#Url, 155, 5, 0, 20, url)
    ButtonGadget(#ButtonGo, 0, 0, 25, 25, "Go")
    Frame3DGadget(#Frame, 0, 30, 0, 2, "", 2) ; Nice little separator
    If WebGadget(#Webpage, 0, 31, 0, 0, url) = 0 : MessageRequester("Error", "ATL.dll not found", 0)
      End
    EndIf
    AddKeyboardShortcut(#Window, #PB_Shortcut_Return, 0)
    ResizeWebWindow()
    SetWindowCallback(@SizeCallback())
    Repeat
      Event = WaitWindowEvent()
      Select Event
        Case #PB_Event_Gadget
          Select EventGadgetID()
            Case #ButtonBack
              SetGadgetState(#Webpage, #PB_Web_Back)
            Case #ButtonNext
              SetGadgetState(#Webpage, #PB_Web_Forward)
            Case #ButtonStop
              SetGadgetState(#Webpage, #PB_Web_Stop)
            Case #Url
              SetGadgetText(#Webpage, GetGadgetText(#Url))
          EndSelect      
        Case #PB_Event_Menu ; We only have one shortcut
          SetGadgetText(#Webpage, GetGadgetText(#Url))
      EndSelect
    Until Event = #PB_Event_CloseWindow
    CloseWindow(#Window)
    SetWindowCallback(#Null)
  EndIf
EndProcedure

;---------------------------------------------------------------------------------------------   
;Write the html to a file to display in browser
;---------------------------------------------------------------------------------------------   
Procedure Write(html.s)
  filename.s = "temp.htm"
  path.s = Space(1000)
  GetCurrentDirectory_(1000,@path)
  hFile = CreateFile(#PB_Any, filename)
  If hFile
    WriteString(html)
    CloseFile(hFile)
    Browse("file://" + path + "\" + filename)
    If DeleteFile(filename) = 0
      MessageRequester("Error","Could not delete tempfile",0)
    EndIf
  Else
    MessageRequester("Error","Could not create tempfile",0)
  EndIf
EndProcedure

;---------------------------------------------------------------------------------------------   
;Show XML errors
;---------------------------------------------------------------------------------------------   
Procedure XMLError()
  oXML\get_parseError(@oError.myIXMLDOMParseError)
  oError\get_errorCode(@errorcode.l)
  oError\get_reason(@reason)
  reason$ = Uni2Ansi(reason)
  oError\get_srcText(@srctext) ;
  Debug Uni2Ansi(srctext) 
  oError\get_line(@line) ; 
  oError\get_linepos(@linepos) ; 
  srctxt$ = Uni2Ansi(srctext)
  srctxt$ = ReplaceString(srctxt$,"<","<")
  srctxt$ = ReplaceString(srctxt$,">",">")
  msg.s = "<font face='Courier New, Courier, mono' size='2'>"
  msg = msg + reason$ + #BR
  msg = msg + "at line " + Str(line) + " at position " + Str(linepos) + #BR
  msg = msg + srctxt$ + #BR
  msg = msg + RSet("^",linepos,"-")
  msg = msg + "</font>"
  Write(msg)
  oError\Release()
  Goto Finish
EndProcedure

;---------------------------------------------------------------------------------------------   
;Transform the XML file with the XSL file make up by XSLT
;---------------------------------------------------------------------------------------------   
Procedure Transform()
  If oXML\transformNode(oXSL,@transform.l) = #S_OK
    Write(Uni2Ansi(transform))
  Else
    SetErrorNumber(err)
  EndIf
EndProcedure

;---------------------------------------------------------------------------------------------   
;Scan all the elements of a given tagname
;---------------------------------------------------------------------------------------------   
Procedure ShowElements(tagname.s)
  nodetxt.s = Space(1000)
  If oXML\getElementsByTagName(Ansi2Uni(tagname),@oNodelist.myIXMLDOMNodeList) = #S_OK
    oNodelist\get_length(@length)
    For i=0 To length-1
      oNodelist\get_item(i,@oNode.myIXMLDOMNode)
      oNode\get_nodeName(@name)
      oNode\get_text(@value) ; 
      nodetxt = nodetxt + Uni2Ansi(name)+":"+Uni2Ansi(value) + #BR
      oNodelist\NextNode(@oNode.myIXMLDOMNode)
    Next
    Write(nodetxt)
  Else
    XMLError()
  EndIf
  If oNode
    oNode\Release()
  EndIf
  If oNodelist
    oNodelist\Release()
  EndIf
EndProcedure

;---------------------------------------------------------------------------------------------   
;- Start of program
;---------------------------------------------------------------------------------------------   
OnErrorGoto(?Error)

CoInitialize_(0)

If CoCreateInstance_(?CLSID_XMLDOM,0,1,?IID_IXMLDOMDocument,@oXML)<>#S_OK
  MessageRequester("Warning:","Couldn't init oXML",0)
  End
EndIf 
Debug oXML
If CoCreateInstance_(?CLSID_XMLDOM,0,1,?IID_IXMLDOMDocument,@oXSL)<>#S_OK
  MessageRequester("Warning:","Couldn't init oXML",0)
  End
EndIf 
Debug oXSL

;---------------------------------------------------------------------------------------------   
;Turn off asynchronized loading, to make sure that the parser will not continue execution before the document is fully loaded
;---------------------------------------------------------------------------------------------   
oXML\put_async(#False)

;---------------------------------------------------------------------------------------------   
;The XML file must be passed as VARIANT
;---------------------------------------------------------------------------------------------   
loadXML.VARIANT\vt = #VT_BSTR
loadXML\bstrVal = Ansi2Uni("test_ie.xml")
;---------------------------------------------------------------------------------------------   
;At the moment the VARIANT needs to be split in 4 LONGS to pass to MSXML
;---------------------------------------------------------------------------------------------   
*V1.pToVariant = loadXML

;---------------------------------------------------------------------------------------------   
;Load the document
;---------------------------------------------------------------------------------------------   
If oXML\load(*V1\a[0],*V1\a[1],*V1\a[2],*V1\a[3],@success.l) <> #S_OK
  XMLError()
EndIf

;---------------------------------------------------------------------------------------------   
;Turn off asynchronized loading, to make sure that the parser will not continue execution before the document is fully loaded
;---------------------------------------------------------------------------------------------   
oXSL\put_async(#False)

;---------------------------------------------------------------------------------------------   
;The XML file must be passed as VARIANT
;---------------------------------------------------------------------------------------------   
loadXSL.VARIANT\vt = #VT_BSTR
loadXSL\bstrVal = Ansi2Uni("test_ie.xsl")
;---------------------------------------------------------------------------------------------   
;At the moment the VARIANT needs to be split in 4 LONGS to pass to MSXML
;---------------------------------------------------------------------------------------------   
*V2.pToVariant = loadXSL

;---------------------------------------------------------------------------------------------   
;Load the document
;---------------------------------------------------------------------------------------------   
If oXSL\load(*V2\a[0],*V2\a[1],*V2\a[2],*V2\a[3],@success.l) <> #S_OK
  XMLError()
EndIf

;---------------------------------------------------------------------------------------------
;This procedure will show the XML file in the format as defined by the XSL file  
;---------------------------------------------------------------------------------------------   
Transform()

;---------------------------------------------------------------------------------------------
;This procedure will show the content of a given elementtag  
;---------------------------------------------------------------------------------------------   
ShowElements("Name")

;---------------------------------------------------------------------------------------------   
;- End program
;---------------------------------------------------------------------------------------------   
Finish:
If oXSL
  oXSL\Release()
EndIf
If oXML
  oXML\Release()
EndIf

CoUninitialize_()

End

;---------------------------------------------------------------------------------------------   
;- Error handler
;---------------------------------------------------------------------------------------------   
Error:
error.s = Space(500)
error   = GetErrorDescription()
MessageRequester("Error", Str(GetErrorLineNR()) + ":" + error + " (" + Hex(GetErrorNumber()) + " )" + #CRLF, 0)
Goto Finish

;---------------------------------------------------------------------------------------------   
;- Datasection
;---------------------------------------------------------------------------------------------   
DataSection
  CLSID_XMLDOM:             ;{2933BF90-7B36-11D2-B20E-00C04F983E60}
  Data.l $2933BF90
  Data.w $7B36,$11D2
  Data.b $B2,$0E,$00,$C0,$4F,$98,$3E,$60
EndDataSection

DataSection
  IID_IXMLDOMDocument:      ;{2933BF81-7B36-11D2-B20E-00C04F983E60}
  Data.l $2933BF81
  Data.w $7B36,$11D2
  Data.b $B2,$0E,$00,$C0,$4F,$98,$3E,$60
EndDataSection

Posted: Tue May 18, 2004 3:23 pm
by Karbon
AWESOME! THANK YOU!