Backslashes in path in VB.Net - asp.net

It seems I'm not lucky with backslashes in ASP.Net VB.Net.
I'm trying to output some infos about files with ffprobe and my paths are cut randomly at some backslash in every string containing backslash.
I debugged this function to return the path generated by fileToProcess:
Function ffprobe_show_format(ByVal arg As String) As String
Dim myProcess As New System.Diagnostics.Process()
Dim fileToProcess As String = MapPath(".") & "\temps\" & arg
myProcess.StartInfo.FileName = MapPath(".") & "\ffprobe.exe"
myProcess.StartInfo.Arguments = "-show_format " & fileToProcess & " >C:\inetpub\vhosts\mysite.com\httpdocs\absolutefs\ffmpegtemp.txt"
myProcess.StartInfo.UseShellExecute = False
myProcess.StartInfo.RedirectStandardInput = True
myProcess.StartInfo.RedirectStandardOutput = True
myProcess.Start()
Dim myStreamWriter As StreamWriter = myProcess.StandardInput
Dim mystreamreader As StreamReader = myProcess.StandardOutput
Dim str As String = mystreamreader.ReadToEnd
Return str & ";" & "FileToProcess=" & fileToProcess & "MapPath(.) AND ffprobe.exe" & MapPath(".") & "\\ffprobe.exe"
End Function
And it returns ;FileToProcess=C:
It means that
My file is not processed because of some errors
My Path is cut at backslashes
The rest of the string is then broken
Does I need to tell asp.net to represent backslashes in another way?
[EDIT]
I can't choose an answer but will upvote since I made two mistakes:
- To debug, I was reading my value once it was put in SQL variables with limites size then
- ... fetched with Newtonsoft.Json parser that probably was refusing some chars.
I'm new on ASP.Net so I have difficulties finding a good way to debug. So I finally made as usual when I'm not able to debug on a platform: I've written my debug vars in a text file, and everything was there using this way:
Function ffprobe_show_format(ByVal file As String, ByVal app As String) As String
Dim myProcess As New System.Diagnostics.Process()
myProcess.StartInfo.FileName = app
Dim argz As String = FormatCommandLine("-show_format", file)
myProcess.StartInfo.Arguments = argz
myProcess.StartInfo.UseShellExecute = False
myProcess.StartInfo.RedirectStandardOutput = True
myProcess.Start()
Dim mystreamreader As StreamReader = myProcess.StandardOutput str As String = mystreamreader.ReadToEnd
MapPath(".") & "/ffprobe.exe"
Dim objWriter As New System.IO.StreamWriter(MapPath(".") & "\debug.txt")
objWriter.Write(str)
objWriter.Close()
Return str
End Function
I'll add an ffmpeg tag since it's also another example on how to call it and process a file.

You don't need to worry about the backslashes. The backslash is not a special character in VB like it is in C#. In fact if you do double them up you might hit errors.
It's hard to tell where the problem is occurring. Some ideas to try to narrow it down:
Try not redirecting StandardInput since you aren't passing it anything.
Read from StandardError to make sure it is empty. It may contain an error message.
I would make use of Debug.WriteLine to trace the function and try to spot where things begin to go wrong.
This may not matter, but I would place myProcess.WaitForExit after mystreamreader.ReadToEnd.
Larry's suggestion to use System.IO.Path is a good one.
Some hastily modified code based on all this:
Function ffprobe_show_format(ByVal arg As String) As String
Debug.WriteLine("arg: " & arg)
Dim fileToProcess As String = IO.Path.Combine(MapPath("."), "temps\" & arg)
Debug.WriteLine("fileToProcess = " & fileToProcess)
Debug.WriteLine("MapPath AND ffprobe.exe: " & IO.Path.Combine(MapPath(".") & "\\ffprobe.exe"))
Dim myProcess As New System.Diagnostics.Process()
myProcess.StartInfo.FileName = IO.Path.Combine(MapPath("."), "\ffprobe.exe")
myProcess.StartInfo.Arguments = "-show_format " & fileToProcess & " >C:\inetpub\vhosts\mysite.com\httpdocs\absolutefs\ffmpegtemp.txt"
myProcess.StartInfo.UseShellExecute = False
'myProcess.StartInfo.RedirectStandardOutput = True
myProcess.StartInfo.RedirectStandardError = True
myProcess.Start()
'Dim str As String = myProcess.StandardOutput.ReadToEnd
Dim errStr as string = myProcess.StandardError.ReadToEnd
myProcess.WaitForExit()
Debug.WriteLine("myProcess exit code = " & myProcess.ExitCode.ToString())
'Debug.WriteLine("stdOutput: " & str)
Debug.WriteLine("stdError: " & errStr)
Return str & ";" & "FileToProcess=" & fileToProcess
End Function

There are a few things to consider here.
First, the back-slash character is the escape character (i.e. \t \n \r ...) and should be double-escaped \\ IF you MUST embed it into strings.
However, the .NET framework contains a very good class: System.IO.Path that has several Combine method overloads that can help you to construct paths without embedding back-slash characters into strings. This also makes your code more portable in the (somewhat unlikely) event that you would ever run it on a non-Windows platform.
http://msdn.microsoft.com/en-us/library/system.io.path

Try closing the StreamReader before accessing its contents:
Dim myStreamReader As StreamReader = myProcess.StandardOutput
Dim str As String = myStreamReader.ReadToEnd
myStreamReader.Close()
Return str & ";" & "FileToProcess=" & fileToProcess & "MapPath(.) AND ffprobe.exe" & MapPath(".") & "\\ffprobe.exe"
When I run your function in my local devbox:
Function ffprobe_show_format(ByVal arg As String) As String
Dim myProcess As New System.Diagnostics.Process()
Dim fileToProcess As String = HttpContext.Current.Server.MapPath(".") & "\temps\" & arg
myProcess.StartInfo.FileName = HttpContext.Current.Server.MapPath(".") & "\ffprobe.exe"
myProcess.StartInfo.Arguments = "-show_format " & fileToProcess & " >C:\inetpub\vhosts\mysite.com\httpdocs\absolutefs\ffmpegtemp.txt"
'myProcess.StartInfo.UseShellExecute = False
'myProcess.StartInfo.RedirectStandardInput = True
'myProcess.StartInfo.RedirectStandardOutput = True
'myProcess.Start()
'Dim myStreamWriter As StreamWriter = myProcess.StandardInput
'Dim myStreamReader As StreamReader = myProcess.StandardOutput
Dim str As String = String.Empty 'myStreamReader.ReadToEnd
Return str & ";" & "FileToProcess=" & fileToProcess & "MapPath(.) AND ffprobe.exe" & HttpContext.Current.Server.MapPath(".") & "\\ffprobe.exe"
End Function
I get what I consider to be a somewhat normal string returned for ffprobe_show_format:
";FileToProcess=C:\Documents and Settings\Me\My Documents\Proj1\SubApp1\temps\testMapPath(.) AND ffprobe.exeC:\Documents and Settings\Me\My Documents\Proj1\SubApp1\\"
I commented out the System.Diagnostics.Process() as I don't have an executable called ffprobe.exe.
Given that the rest of it works, Try closing the StreamReader before accessing its contents.

You should just need to escape each backslash with another backslash.
Or, you might be able to prefix your string with the # symbol (works in C#, not sure about VB.NET).
I.E.
instead of "C:\this\that.exe"
use "C:\this\that.exe"
or #"C:\this\that.exe"

Related

Loop through website links and get PDF's to my computer

This topic is related to Loop through links and download PDF's
I am trying to convert my current VBA code into VBScript. I have already understood that I have to remove the variable types (As ... part of Dim statements) and use CreatObject to get those objects but otherwise everything should port as-is. DoEvents will also have to be replaced with something like Wscript.sleep.
I came up with some problems. Currently while running VBS file I am getting an error saying "Object required: 'MSHTML'". Pointing to line 65, where I have Set hDoc = MSHTML.HTMLDocument. I have tried to search on Google but got nothing helpful for this one.
How I should proceed with this one?
DownloadFiles("https://www.nordicwater.com/products/waste-water/")
Sub DownloadFiles(p_sURL)
Set xHttp = CreateObject("Microsoft.XMLHTTP")
Dim xHttp
Dim hDoc
Dim Anchors
Dim Anchor
Dim sPath
Dim wholeURL
Dim internet
Dim internetdata
Dim internetlink
Dim internetinnerlink
Dim arrLinks
Dim sLink
Dim iLinkCount
Dim iCounter
Dim sLinks
Set internet = CreateObject("InternetExplorer.Application")
internet.Visible = False
internet.navigate (p_sURL)
Do Until internet.ReadyState = 4
Wscript.Sleep 100
Loop
Set internetdata = internet.document
Set internetlink = internetdata.getElementsByTagName("a")
i = 1
For Each internetinnerlink In internetlink
If Left(internetinnerlink, 36) = "https://www.nordicwater.com/product/" Then
If sLinks <> "" Then sLinks = sLinks & vbCrLf
sLinks = sLinks & internetinnerlink.href
i = i + 1
Else
End If
Next
wholeURL = "https://www.nordicwater.com/"
sPath = "C:\temp\"
arrLinks = Split(sLinks, vbCrLf)
iLinkCount = UBound(arrLinks) + 1
For iCounter = 1 To iLinkCount
sLink = arrLinks(iCounter - 1)
'Get the directory listing
xHttp.Open "GET", sLink
xHttp.send
'Wait for the page to load
Do Until xHttp.ReadyState = 4
Wscript.Sleep 100
Loop
'Put the page in an HTML document
Set hDoc = MSHTML.HTMLDocument
hDoc.body.innerHTML = xHttp.responseText
'Loop through the hyperlinks on the directory listing
Set Anchors = hDoc.getElementsByTagName("a")
For Each Anchor In Anchors
'test the pathname to see if it matches your pattern
If Anchor.pathname Like "*.pdf" Then
xHttp.Open "GET", wholeURL & Anchor.pathname, False
xHttp.send
With CreateObject("Adodb.Stream")
.Type = 1
.Open
.write xHttp.responseBody
.SaveToFile sPath & getName(wholeURL & Anchor.pathname), 2 '//overwrite
End With
End If
Next
Next
End Sub
Function:
Function getName(pf)
getName = Split(pf, "/")(UBound(Split(pf, "/")))
End Function
Instead of Set hDoc = MSHTML.HTMLDocument, use:
Set hDoc = CreateObject("htmlfile")
In VBA/VB6 you can specify variable and object types but not with VBScript. You have to use CreateObject (or GetObject: GetObject function) to instantiate objects like MSHTML.HTMLDocument, Microsoft.XMLHTTP, InternetExplorer.Application, etc instead of declaring those using Dim objIE As InternetExplorer.Application for example.
Another change:
If Anchor.pathname Like "*.pdf" Then
can be written using StrComp function:
If StrComp(Right(Anchor.pathname, 4), ".pdf", vbTextCompare) = 0 Then
or using InStr function:
If InStr(Anchor.pathname, ".pdf") > 0 Then
Also, at the beginning of your sub, you do the following:
Set xHttp = CreateObject("Microsoft.XMLHTTP")
Dim xHttp
You should declare your variables before assigning them values or objects. In VBScript this is very relaxed, your code will work because VBScript will create undefined variables for you but it's good practice to Dim your variables before using them.
Except for Wscript.sleep commands, your VBScript code will work in VB6/VBA so you can debug your script in VB6 or VBA apps (like Excel).

VB Saving img file with path adds folder name to file name

Hi I am having some problems with saving img files using Visual Basic, the files are being named wrongly with the folder name being added to the start of the file name.
I parse a web address and then use the split address values to rename my files however the the path value seems to be added to the file as well.
The files in the photo should be named for example "DCAT040iMBE Test13.jpg"
but this file is being name "Test1DCAT040iMBE Test13.jpg"
Protected Sub GeneratedCode()
Dim path As String = "C:\Users\Grey\Documents\visual studio 2010\Projects\QRCodeGenerator\QRCodeGenerator\Output\"
LogoUpload.SaveAs(path + LogoUpload.FileName)
TextFile.SaveAs(path + TextFile.FileName)
Dim lines() As String = IO.File.ReadAllLines(path + TextFile.FileName)
For Each line As String In lines
Dim count As Integer
Dim encoder As New QRCodeEncoder()
encoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.H
encoder.QRCodeScale = 10
Dim img As Bitmap = encoder.Encode(line)
Dim logo As System.Drawing.Image = System.Drawing.Image.FromFile(path + LogoUpload.FileName)
Dim left As Integer = (img.Width / 2) - (logo.Width / 2)
Dim top As Integer = (img.Height / 2) - (logo.Height / 2)
Dim g As Graphics = Graphics.FromImage(img)
Dim parseLine = line
Dim replaceDelimiter As String
If Not String.IsNullOrWhiteSpace(line) Then
replaceDelimiter = Replace(line, "&", "=")
End If
Dim fileNameSplit() As String = replaceDelimiter.Split("=")
Dim newFileName As String
Dim partTwo = fileNameSplit(1)
Dim partSix = fileNameSplit(5)
Dim objFSO
Dim newFolder As String
newFolder = "C:\Users\Grey\Documents\visual studio 2010\Projects\QRCodeGenerator\QRCodeGenerator\Output\" + partSix
objFSO = CreateObject("Scripting.FileSystemObject")
If (Not System.IO.Directory.Exists(newFolder)) Then
System.IO.Directory.CreateDirectory(newFolder)
End If
count += 1
g.DrawImage(logo, New Point(left, top))
newFileName = partTwo & " " & partSix & count & ".jpg"
img.Save(newFolder + newFileName, ImageFormat.Jpeg)
amountCreatedLbl.Text = count & " QRCodes Created"
logo.Dispose()
Next
End Sub
Could it be that I am generating my newFolder Values wrongly?
edited to add an example of data from the parsed txt file.
https://mywebsite.com/QRCode/default.aspx?materialcode=DTAT050&Logo=MyLogo&Companyloc=Test1
https://mywebsite.com/QRCode/default.aspx?materialcode=DCAT055iMB&Logo=MyLogo&Companyloc=Test1
https://mywebsite.com/QRCode/default.aspx?materialcode=DCAT040iMBE&Logo=MyLogo&Companyloc=Test1
https://mywebsite.com/QRCode/default.aspx?materialcode=DTAB060&Logo=MyLogo&Companyloc=Test1
https://mywebsite.com/QRCode/default.aspx?materialcode=DTAT050&Logo=MyLogo&Companyloc=Test2
https://mywebsite.com/QRCode/default.aspx?materialcode=DCAT055iMB&Logo=MyLogo&Companyloc=Test2
https://mywebsite.com/QRCode/default.aspx?materialcode=DCAT040iMBE&Logo=MyLogo&Companyloc=Test2
https://mywebsite.com/QRCode/default.aspx?materialcode=DTAB060&Logo=MyLogo&Companyloc=Test2
https://mywebsite.com/QRCode/default.aspx?materialcode=DTAT050&Logo=MyLogo&Companyloc=Test3
https://mywebsite.com/QRCode/default.aspx?materialcode=DCAT055iMB&Logo=MyLogo&Companyloc=Test3
https://mywebsite.com/QRCode/default.aspx?materialcode=DCAT040iMBE&Logo=MyLogo&Companyloc=Test3
https://mywebsite.com/QRCode/default.aspx?materialcode=DTAB060&Logo=MyLogo&Companyloc=Test
Looks like you are missing a slash on the line:
img.Save(newFolder + newFileName, ImageFormat.Jpeg)
It should be:
img.Save(newFolder + "\" + newFileName, ImageFormat.Jpeg)
The program doesn't realize that the newDirectory variable is supposed to be a directory, it's just being concatenated to the filename directly. A better option would be to use:
img.Save(System.IO.Path.Combine(newFolder, newFileName), ImageFormat.Jpeg)
The System.IO.Path.Combine() function automatically adds the missing slash between the directory and filename, as well as some additional checks to make sure the result is valid.
As a side note, I would also recommend using & instead of + when joining strings together. Hard to debug issues can come up when you do it that way. I would also recommend turning Option Strict On, you will see a couple of other warnings that come up with your code as is. But, to resolve your issue, the above will work.

JSON.net - Using VB.NET Unable to iterate through results

I am trying to process this json document using JSON.NET.
With the VB.NET code:
Dim o As JObject = JObject.Parse(json)
Dim results As List(Of JToken) = o.Children().ToList
Dim count As Integer = 0
For Each item As JProperty In results
Dim snippet As String = String.Empty
Dim URL As String = String.Empty
Dim source As String = String.Empty
item.CreateReader()
Select Case item.Name
Case "response"
snippet = item.Last.SelectToken("docs").First.Item("snippet").ToString
URL = item.Last.SelectToken("docs").First.Item("web_url").ToString
source = ControlChars.NewLine & "<font size='2'>" & item.First.SelectToken("docs").First.Item("source").ToString & "</font>" & ControlChars.NewLine
tbNews.Text &= "<a href=" & URL & " target='new'>" & snippet & "</a> - " & source
End Select
Next
I am only receiving the first document as a result. Can someone advise as to how I can get the 1st - Nth documents as a complete list?
The docs are 2 levels deep, you're only looping in the top level. Try this...
Dim parsedObject = JObject.Parse(json)
Dim docs = parsedObject("response")("docs")
For Each doc In docs
Dim snippet As String = doc("snippet")
Dim URL As String = doc("web_url")
Dim source As String = doc("source")
'....
Next

ASP Classic to VB.NET - Recursive Function including RecordSets

I'm hoping someone can help me think this one out because I'm stuck.
We are slowly migrating a ASP Classic web site to a .NET web application. I stumbled upon the following function. The function will return an array of strings that consists of hml a-tags.
Private Function getFullPathLinks(lNodeId, sPath, sDocTemplate)
Dim sql, recordSet, rsTmp
Dim arrPath, sResult
Dim lDocId
lDocId = getDocumentId(lNodeId)
sql = "SELECT parent_id, label FROM wt_node WHERE (node_id = " & lNodeId & ")"
Set recordSet = execSqlCache(oConn,sql,Array(),Array("wt_node"))
If Not (recordSet.Bof And recordSet.Eof) Then
If sDocTemplate <> "" Then
sPath = sPath & "|" & "<a href='" & sDocTemplate & "?nodeid=" & lNodeId & "&documentid=" & lDocId & "'>" & recordSet("label") & "</a>"
Else
sPath = sPath & "|" & recordSet("label")
End If
getFullPathLinks recordSet("parent_id"), sPath
End If
recordSet.Close
Set recordSet = Nothing
arrPath = arrReverse(Split(sPath,"|"))
sResult = Join(arrPath,sPathDelimiter)
If Right(sResult,Len(sPathDelimiter)) = sPathDelimiter Then sResult = Left(sResult,Len(sResult)-Len(sPathDelimiter))
getFullPathLinks = sResult
End Function
The function calls itself at the end and this will not work well in my .NET implementation where we are using DataReaders to talk to the SQL database.
Could I follow the same structure as above and instead use something else than a DataReader to achieve this?
I am not sure what SQL Server version you are using, but have you taken a look at recursive queries in SQL? It is designed to retrieve hierarchical data in a single db call. Take a look:
http://msdn.microsoft.com/en-us/library/ms186243(v=sql.105).aspx

creating my own Word wrapper for string

How do I make my own word wrap function for strings? I want each line to be no longer than 50 characters and respect existing CRLFs.
Something like this, it will get you started (just a quick samle i mashed together):
Private Sub Doit()
Dim Source As String = ""
Source &= "How to make my own word wrap function for string, I want each line to be no longer than 50chars and take respect existing CRLFs" & vbCrLf & vbCrLf
Source &= "So this will be a new row."
Dim wrappedtext As String = wrap(Source, 20, vbNewLine)
MsgBox(wrappedtext)
End Sub
Function wrap(ByVal text As String, ByVal maxlength As Integer, ByVal newline As String) As String
Dim tmp() As String = Split(text.Replace(vbCrLf, " | "), " ")
Dim ret As String = ""
Dim wrk As String = ""
For Each word As String In tmp
If word = "|" Then
ret &= newline
wrk = ""
ElseIf word = "" Then
Else
If Len(wrk & word) <= maxlength Then
wrk &= " " & word
Else
ret &= wrk & newline
wrk = word & " "
End If
End If
Next
If wrk <> "" Then ret &= wrk
Return ret
End Function
From which point of view? SW architecture?
Take a look at the decorator pattern. If you like to work with streams, in the book "Heads First: Design Patterns" a string modifier is proposed. It's in Java, but the general programming concept is described in a good way. Some pages are missing but you can find many infos here.
The algorithm itself is trivial, isn't it?

Resources