MSXML parser returns "" string when program is not ran as administrator
Hello, everybody.
Haven't posted here in a while.
I wrote an app that read XML files and shows them in a listview - nothing fancy.
The user can edit the on screen table, then, using MSXML, the listview is repacked and
the new XML is saved.
The trouble arises in some corporate environments, where ActiveDirectory is employed.
For some reason (limited/restricted accounts), MSXML works when reading the file,
but not when returning the XML string required to write out the file.
File is not saved with the .save() function directly because i use the .xml property to get the string,
then convert it to unicode UTF8 and then save it. Files are required to be UTF8.
Conversion to Unicode works well, this is not the point of failure.
I know this because as i set up a "debug" version with MsgBox() before the UnicodeFileSave() procedure.
No errors, i just a "" string before the file save, instead of the XML.
When running as admin, though, i get the xml string from the .xml property of the MSXML object.
This might be a Windows BUG, for all i know - i was wondering if there is a way around this....
Thanks !
Re: MSXML parser returns "" string when program is not ran as administrator
Quote:
Originally Posted by
AndreiMhz
This might be a Windows BUG, for all i know - i was wondering if there is a way around this....
Bug in Windows is extremely unlikely. You can get around this by debugging your code first incl. removing On Error Resume Next and placing better error handling with logging etc.
You need a stable repro so you have to find/simulate environment where this is failing if custom/AD security is involved.
Another option for what is happening is simply bad input: e.g. try placing < or > in nodes by editing the listview and see what happens on save.
Note that XML nodes cannot contain any of the symbols in Chr(0) to Chr(31) excluding vbTab and vbCrLf under any circumstances i.e. CDATA or not.
cheers,
</wqw>
Re: MSXML parser returns "" string when program is not ran as administrator
Quote:
Originally Posted by
wqweto
You can get around this by debugging your code first incl. removing On Error Resume Next and placing better error handling with logging etc.
There is no "On Error Resume Next" in the procedure.
Quote:
Originally Posted by
wqweto
You need a stable repro so you have to find/simulate environment where this is failing if custom/AD security is involved.
I have it, it's easily reproductible. I cannot run the source code, on the machine, vb6 ide does not run on limited user accounts. My best option is to have a Msgbox() flash the contents of the string - in my case, the string contains the XML file itself.
Quote:
Originally Posted by
wqweto
Another option for what is happening is simply bad input: e.g. try placing < or > in nodes by editing the listview and see what happens on save.
Note that XML nodes cannot contain any of the symbols in Chr(0) to Chr(31) excluding vbTab and vbCrLf under any circumstances i.e. CDATA or not.
You didn't get me here - the problem occurs when MSXML generates the XML file... not when it reads it. I actually get no error message, just a blank string instead of the XML string.
None of the elements in the ListView can have CHR(0) and even CHR(31) - because their source is either another XML file (already parsed), either a text that is entered via a standard textbox. When the item is double clicked in the listview, a text box shows up allowing the user to edit the value.
Re: MSXML parser returns "" string when program is not ran as administrator
> the problem occurs when MSXML generates the XML file
How does MSXML generate the file? You already said .xml property is empty before UnicodeFileSave.
How do you populate the DOM? There call MsgBox on each AppendElement (or similar) if you don't have time to instrument logging.
At least this is what I would do, I'm not official MS support, have nothing to do with Windows OS development too. It's just my experience that *rarely* there are system components bugs of such proportions.
I mean ".xml property is not working" has never happened. It's usually a more mundane reason why the whole export is choking and the first (and second) thing to check is your own code.
cheers,
</wqw>
Re: MSXML parser returns "" string when program is not ran as administrator
Hello.
How does MSXML generate thefile?
Well - i declare some nodes...
Code:
Dim wDoc As MSXML2.DOMDocument
Dim wDocNode As IXMLDOMNode
Dim wDocNode2 As IXMLDOMNode
Dim wDocNodeList As IXMLDOMNodeList
The ListView shows a spreadsheet like table, with a specific structure (rows & columns).
I open a 1 row XML stored in the application folder... this XML already had this specific structure,
so i don't need to recreate it. Then, i just multiply the first row of this blank XML.
Code:
wDoc.loadXML (sBlankXML)
For u = 2 To oLV.ListItems.Count
Set wDocNode = Nothing
Set wDocNode = wDoc.selectSingleNode("//table/row")
Set wDocNodeRoot = wDocNode.parentNode
Set wDocNodeClone = wDocNode.cloneNode(True)
'increment id
wDocNodeClone.Attributes.Item(0).nodeTypedValue = "2"
'add to tree
wDocNodeRoot.appendChild wDocNodeClone
Next u
Now we have a XML with a structure having the same no. of rows and columns as the listview.
After this, i parse the listview and dump each column / row into its place in the xml.
Code:
Set wDocNodeList = wDoc.selectNodes("//table/row")
i = 1
For Each wDocNode In wDocNodeList
wDocNode.Attributes.Item(0).nodeTypedValue = oLV.ListItems.Item(i).Text
K = 0
For Each wDocNode2 In wDocNode.childNodes
wDocNode2.nodeTypedValue = oLV.ListItems.Item(i).SubItem(K).Text
K = K + 1
Next
i = i + 1
Next
In the end i save the XML in UTF-8 format by using the .xml property.
The wDoc.xml returns a string containing the XML file. My problem is that the wDoc.xml returns a "" string if the EXE is not ran as administrator. Without failing, without any error messages.
Code:
bRestult = writeUTF8File(sFilename, wDoc.xml)
Re: MSXML parser returns "" string when program is not ran as administrator
Quote:
save Method
Character encoding is based on the encoding attribute in the XML declaration, such as <?xml version="1.0" encoding="windows-1252"?>. When no encoding attribute is specified, the default setting is UTF-8.
So a lot of pointless gymnastics going on here.
Using a ListView as a grid is another trap for young players. A flexgrid or datagrid are almost always better choices.
I can't think of any reason why an elevated process might make a difference here. My guess is that file virtualization is at work here and the actual file isn't written where you think it is. What directory are you trying to target?
Re: MSXML parser returns "" string when program is not ran as administrator
OK, we'll skip the talk about the listview as a grid. It's a matter of personal preference.
Let's not get off track :)
Instead, i shall tell you how i got to the conclusion that the .xml is that the string is empty.
Here's the actual code... this fails before writing the file.
Code:
If wDoc.xml = "" Then
MsgBox "Could not get the data to save XML.", vbCritical, appName
Exit Function
End If
bRestult = writeUTF8File(sFilename, wDoc.xml)
The file itself, is saved in the app folder.
I also tried not saving the file, and instead sending the string as an HTTP request to a local server - same result.
O also would like to address this :
Code:
wDoc.loadXML (sBlankXML)
The BlankXML is, actually, a copy of the original XML loaded into the app. It's stored as a string, in memory.
So, it's only read from the harddisk once. The fact that the listview gets populated with the data is proof that it's read.
And, to answer another question: the file gets saved, but as a blank file. Saving does not fail. Usually it's the user's desktop.
The original XML, it's also read from various locations.
Re: MSXML parser returns "" string when program is not ran as administrator
Quote:
Originally Posted by
AndreiMhz
The file itself, is saved in the app folder.
Do you mean within the protected filesystem under Program Files? Where standard users normally would not have write access?
If your program has a proper manifest this would raise an error 70 "Permission denied." However if it lacks a manifest with a <trustInfo/> section Windows will chuckle, treat it as legacy code, and apply file virtualization appcompat.
Most likely your file is being written to the the duplicated path below:
C:\Users\{user}\AppData\Local\VirtualStore\Program Files.
Such a program would also fail under WinXP and Win2K without elevated privileges. People used to hand out Power User group membership like candy to let vocational coders ignore the fact they were no longer running on Win9x. This was a major security hole so that group was eliminated beginning back when Vista came out.
Anyway, look under that path and see whether your file is getting written there.
Re: MSXML parser returns "" string when program is not ran as administrator
I see 3 cases where things could go wrong (after the load-phase was sccessful).
- the Async-Property of the XML-instance should be "Off"
- invalid Node-XML-content was added (making the "root-xml-node" behave this way)
.. (there's and error property on the XML-instance to check for "well-formedness" before trying to write it out, IIRC)
- yeah, and last but not least the already mentione File-Virtualization which might kick in
Olaf
Re: MSXML parser returns "" string when program is not ran as administrator
Quote:
Originally Posted by
AndreiMhz
Hello.
How does MSXML generate thefile?
Well - i declare some nodes...
Code:
Dim wDoc As MSXML2.DOMDocument
Dim wDocNode As IXMLDOMNode
Dim wDocNode2 As IXMLDOMNode
Dim wDocNodeList As IXMLDOMNodeList
The ListView shows a spreadsheet like table, with a specific structure (rows & columns).
I open a 1 row XML stored in the application folder... this XML already had this specific structure,
so i don't need to recreate it. Then, i just multiply the first row of this blank XML.
Code:
wDoc.loadXML (sBlankXML)
For u = 2 To oLV.ListItems.Count
Set wDocNode = Nothing
Set wDocNode = wDoc.selectSingleNode("//table/row")
Set wDocNodeRoot = wDocNode.parentNode
Set wDocNodeClone = wDocNode.cloneNode(True)
'increment id
wDocNodeClone.Attributes.Item(0).nodeTypedValue = "2"
'add to tree
wDocNodeRoot.appendChild wDocNodeClone
Next u
Now we have a XML with a structure having the same no. of rows and columns as the listview.
After this, i parse the listview and dump each column / row into its place in the xml.
Code:
Set wDocNodeList = wDoc.selectNodes("//table/row")
i = 1
For Each wDocNode In wDocNodeList
wDocNode.Attributes.Item(0).nodeTypedValue = oLV.ListItems.Item(i).Text
K = 0
For Each wDocNode2 In wDocNode.childNodes
wDocNode2.nodeTypedValue = oLV.ListItems.Item(i).SubItem(K).Text
K = K + 1
Next
i = i + 1
Next
In the end i save the XML in UTF-8 format by using the .xml property.
The wDoc.xml returns a string containing the XML file. My problem is that the wDoc.xml returns a "" string if the EXE is not ran as administrator. Without failing, without any error messages.
Code:
bRestult = writeUTF8File(sFilename, wDoc.xml)
You can instrument logging (or use MsgBox instead) like this
Code:
wDoc.loadXML (sBlankXML)
For u = 2 To oLV.ListItems.Count
Set wDocNode = Nothing
Set wDocNode = wDoc.selectSingleNode("//table/row")
Set wDocNodeRoot = wDocNode.parentNode
Set wDocNodeClone = wDocNode.cloneNode(True)
'increment id
wDocNodeClone.Attributes.Item(0).nodeTypedValue = "2"
'add to tree
wDocNodeRoot.appendChild wDocNodeClone
If wDoc.xml = "" Then
MsgBox "Failed on clone, u=" & u, vbExclamation
Exit Sub
End If
Next u
. . . and here
Code:
Set wDocNodeList = wDoc.selectNodes("//table/row")
i = 1
For Each wDocNode In wDocNodeList
wDocNode.Attributes.Item(0).nodeTypedValue = oLV.ListItems.Item(i).Text
K = 0
For Each wDocNode2 In wDocNode.childNodes
wDocNode2.nodeTypedValue = oLV.ListItems.Item(i).SubItem(K).Text
K = K + 1
Next
If wDoc.xml = "" Then
MsgBox "Failed at set, i=" & i, vbExclamation
Exit Sub
End If
i = i + 1
Next
After days of spent scouring internet forums for issues with MSXML component probably some basic debugging and logging instrumentation might have been better to begin with.
cheers,
</wqw>
Re: MSXML parser returns "" string when program is not ran as administrator
Good idea. Will do this. Still, does not explain why it works with administrator rights...
Re: MSXML parser returns "" string when program is not ran as administrator
Quote:
Originally Posted by
AndreiMhz
Good idea. Will do this. Still, does not explain why it works with administrator rights...
Could it be that the initial contents is different in both cases? So the listview gets populated with different texts.
Or could be that wDoc.loadXML (sBlankXML) does not load anything (i.e. sBlankXML is an empty string) so wDoc.selectNodes("//table/row") returns empty collection so For Each wDocNode In wDocNodeList does not loop even once.
This way in bRestult = writeUTF8File(sFilename, wDoc.xml) you get the initial sBlankXML in xml property which is a blank/empty string.
cheers,
</wqw>
Re: MSXML parser returns "" string when program is not ran as administrator
Yeah, I cobbled up a test case:
Code:
Option Explicit
Private Const INVALID_FILE_ATTRIBUTES As Long = -1
Private Declare Function GetFileAttributes Lib "kernel32" Alias "GetFileAttributesW" ( _
ByVal lpFileName As Long) As Long
Private Const S_OK As Long = 0
Private Const VARIANT_ALPHABOOL As Long = &H2&
Public Enum LCIDs
'Add more as you need them here:
LOCALE_INVARIANT = &H7F&
LOCALE_USER_DEFAULT = &H400&
LOCALE_SYSTEM_DEFAULT = &H800&
End Enum
Private Declare Function VariantChangeTypeEx Lib "oleaut32" ( _
ByRef vargDest As Variant, _
ByRef varSrc As Variant, _
ByVal desiredlcid As Long, _
ByVal wFlags As Integer, _
ByVal vt As VbVarType) As Long
Private Function ToStr(ByVal Value As Variant) As String
Dim Converted As Variant
If VariantChangeTypeEx(Converted, _
Value, _
LOCALE_INVARIANT, _
VARIANT_ALPHABOOL, _
vbString) <> S_OK Then
Err.Raise 5 'Invalid procedure call or argument.
Else
ToStr = LCase$(Converted)
End If
End Function
Private Sub Main()
Const ssfDESKTOP = 0
Dim FileName As String
Dim Doc As MSXML2.DOMDocument
Dim I As Long
Randomize
FileName = CreateObject("Shell.Application").NameSpace(ssfDESKTOP).Self.Path _
& "\" _
& App.EXEName _
& ".xml"
Set Doc = New MSXML2.DOMDocument
With Doc
.preserveWhiteSpace = True
If GetFileAttributes(StrPtr(FileName)) = INVALID_FILE_ATTRIBUTES Then
With .appendChild(.createNode(NODE_ELEMENT, "Doc", vbNullString))
For I = 1 To 5
.insertBefore Doc.createTextNode(vbNewLine & Space$(4)), Nothing
With .appendChild(Doc.createNode(NODE_ELEMENT, "Row", vbNullString))
.Attributes.setNamedItem(Doc.createNode(NODE_ATTRIBUTE, _
"Appended", _
vbNullString)).nodeValue = _
ToStr(False)
.insertBefore Doc.createTextNode(vbNewLine & Space$(8)), Nothing
With .appendChild(Doc.createNode(NODE_ELEMENT, "Col0", vbNullString))
.Text = ChrW$(&H2206&) _
& WeekdayName(Int(Rnd() * 7) + 1) _
& ChrW$(&H2211&)
End With
.insertBefore Doc.createTextNode(vbNewLine & Space$(8)), Nothing
With .appendChild(Doc.createNode(NODE_ELEMENT, "Col1", vbNullString))
.Text = ToStr(Round(Rnd() - 0.5, 3))
End With
.insertBefore Doc.createTextNode(vbNewLine & Space$(4)), Nothing
End With
Next
.insertBefore Doc.createTextNode(vbNewLine), Nothing
End With
.save FileName
Else
.Load FileName
With .documentElement
.insertBefore Doc.createTextNode(Space$(4)), Nothing
With .appendChild(Doc.createNode(NODE_ELEMENT, "Row", vbNullString))
.Attributes.setNamedItem(Doc.createNode(NODE_ATTRIBUTE, _
"Appended", _
vbNullString)).nodeValue = _
ToStr(True)
.insertBefore Doc.createTextNode(vbNewLine & Space$(8)), Nothing
With .appendChild(Doc.createNode(NODE_ELEMENT, "Col0", vbNullString))
.Text = ChrW$(&H2206&) _
& MonthName(Int(Rnd() * 12) + 1) _
& ChrW$(&H2211&)
End With
.insertBefore Doc.createTextNode(vbNewLine & Space$(8)), Nothing
With .appendChild(Doc.createNode(NODE_ELEMENT, "Col1", vbNullString))
.Text = ToStr(Round(Rnd() - 0.5, 3))
End With
.insertBefore Doc.createTextNode(vbNewLine & Space$(4)), Nothing
End With
.insertBefore Doc.createTextNode(vbNewLine), Nothing
End With
.save FileName
End If
End With
MsgBox "Done: File on desktop"
End Sub
"First run" creates the XML file on the user's Desktop. Subsequent runs append another Row.
No issues, whether run elevated or not. UTF-8 output file, just as documented.
Code:
<Doc>
<Row Appended="false">
<Col0>∆Tuesday∑</Col0>
<Col1>-0.275</Col1>
</Row>
<Row Appended="false">
<Col0>∆Wednesday∑</Col0>
<Col1>0.108</Col1>
</Row>
<Row Appended="false">
<Col0>∆Monday∑</Col0>
<Col1>-0.015</Col1>
</Row>
<Row Appended="false">
<Col0>∆Thursday∑</Col0>
<Col1>0.244</Col1>
</Row>
<Row Appended="false">
<Col0>∆Wednesday∑</Col0>
<Col1>0.402</Col1>
</Row>
<Row Appended="true">
<Col0>∆May∑</Col0>
<Col1>-0.352</Col1>
</Row>
<Row Appended="true">
<Col0>∆July∑</Col0>
<Col1>-0.062</Col1>
</Row>
</Doc>
VariantChangeTypeEx() calls are used to help generate proper non-localized values, as required of properly-formed XML documents.