Concat strings returned from RegQueryValueEx - vb6

I want to read a string value from the registry and concatenate it with another certain string. I'm calling RegQueryValueEx() , like this:
Dim lResult As Long
Dim sLength As Long
Dim sString As String
sString = Space$(256)
sLength = 256
lResult = RegQueryValueEx(hKey, "MyKey", 0, REG_SZ, ByVal sString, sLength)
MsgBox sString & "blah-blah-blah"
RegQueryValueEx() works fine, I'm getting the needed string in sString and even can display it with MsgBox. But when I try to concat it with "some_string" I get only sString showed. Plz, help me.
Thanks

There is probably a null-character in the string, because VB strings store the length of the string in memory just before the contents of the string. In your case that length is 256. When you load the content using RegQueryValueEx, it null-terminates the string (C-style), but does not change its indicated length, so in the VB world it's still 256 characters long. Then when you append the second string, it gets appended after the first 256 characters, but MsgBox only shows the contents up to the null-character.
Because RegQueryValueEx puts the length of the actual data in sLength, you can add this line before the MsgBox
sString = Left$(sString, sLength)

Precedence issue, maybe? How about trying:
MsgBox(sString & "blah-blah-blah")
Or
Dim sDisplay as String
sDisplay = sString & "blah-blah"
MsgBox sDisplay

Perhaps the string contains a 0-character so that it ends prematurely?

You need to get rid of the null character at the end.
I suggest getting an already written and tested registry module for VB6.
Here is another example from vbnet
But if you just want to get rid of nulls here is one I've used.
Public Function StringFromBuffer(ByRef strBuffer As String) As String
' Extracts String From a Buffer (buffer is terminated with null)
' 06/30/2000 - WSR
Dim lngPos As Long
' attempt to find null character in buffer
lngPos = InStr(1, strBuffer, vbNullChar)
' if found
If lngPos > 0 Then
' return everything before it
StringFromBuffer = Left$(strBuffer, lngPos - 1)
' if not found
Else
' return whole string
StringFromBuffer = strBuffer
End If ' lngPos > 0
End Function ' StringFromBuffer

use Mid$ and sLength to pull the string values out of sString. This way you above strangeness due to extra characters (like the null terminator '0')
Remember when you deal with the Win32 API you have to keep in mind that it assumes C conventions which are not the same as VB Convention. So you have to do some cleanup before sending it along.

It worked for me when I did:
sString = Left$(sString, sLength-1)
the problem indeed was the null character at the end of the string.
Thanks, guys!

Related

How can I invert the case of a string in VB6?

I'm trying to make a program that can take the letters of a string and invert their case. I know that in vb.net there exists the IsUpper() command, but I don't know of such a thing in vb6.
What can I use in place of it?
Thanks!
Something like this should work:
Private Function Invert(strIn As String) As String
Dim strOut As String
Dim strChar As String
Dim intLoop As Integer
For intLoop = 1 To Len(strIn)
strChar = Mid(strIn, intLoop, 1)
If UCase(strChar) = strChar Then
strChar = LCase(strChar)
Else
strChar = UCase(strChar)
End If
strOut = strOut + strChar
Next
Invert = strOut
End Function
This loops through the supplied string, and extracts each character. It then tries to convert it to upper case and checks it against the extracted character. If it's the same then it was already upper case, so it converts it to lower case.
It handles non alpha characters just fine as UCase/LCase ignores those.

(VB6) Slicing a string before a certain point

Suppose I have a variable set to the path of an image.
Let img = "C:\Users\Example\Desktop\Test\Stuff\Icons\test.jpg"
I want to slice everything before "\Icons" using Vb6. So after slicing the string it would be "\Icons\test.jpg" only.
I have tried fiddling with the Mid$ function in VB6, but I haven't really had much success. I am aware of the fact that Substring isn't a function available in vb6, but in vb.net only.
After the first \icons
path = "C:\Users\Example\Desktop\Test\Stuff\Icons\test.jpg"
?mid$(path, instr(1, path, "\icons\", vbTextCompare))
> \Icons\test.jpg
Or after the last should there be > 1
path = "C:\Users\Example\Desktop\Test\Icons\Stuff\Icons\test.jpg"
?right$(path, len(path) - InStrRev(path, "\icons\", -1, vbTextCompare) + 1)
> \Icons\test.jpg
This is pretty easy to do generically using the Split function. I wrote a method to demonstrate it's use and for grins it takes an optional parameter to specify how many directories you want returned. Passing no number returns a file name, passing a very high number returns a full path (either local or UNC). Please note there is no error handling in the method.
Private Function GetFileAndBasePath(ByVal vPath As String, Optional ByVal baseFolderLevel = 0) As String
Dim strPathParts() As String
Dim strReturn As String
Dim i As Integer
strPathParts = Split(vPath, "\")
Do While i <= baseFolderLevel And i <= UBound(strPathParts)
If i > 0 Then
strReturn = strPathParts(UBound(strPathParts) - i) & "\" & strReturn
Else
strReturn = strPathParts(UBound(strPathParts))
End If
i = i + 1
Loop
GetFileAndBasePath = strReturn
End Function

How to Remove Specific Special Characters

I have a string like X5BC8373XXX. Where X = a special character equals a Square.
I also have some special characters like \n but I remove them, but I can't remove the squares...
I'd like to know how to remove it.
I Found this method:
Dim Test As String
Test = Replace(Mscomm1.Input, Chr(160), Chr(64) 'Here I remove some of the special characters like \n
Test = Left$(Test, Len(Test) -2)
Test = Right$(Test, Len(Test) -2)
This method DOES remove those special characters, but it's also removing my first character 5.
I realize that this method just remove 2 characters from the left and the right,
but how could I work around this to remove these special characters ?
Also I saw something with vblF, CtrlF something like this, but I couldn't work with this ;\
You can use regular expressions. If you want to remove everything that's not a number or letter, you can use the code below. If there are other characters you want to keep, regular expressions are highly customizable, but can get a little confusing.
This also has the benefit of doing the whole string at once, instead of character by character.
You'll need to reference Microsoft VBScript Regular Expressions in your project.
Function AlphaNum(OldString As String)
Dim RE As New RegExp
RE.Pattern = "[^A-Za-z0-9]"
RE.Global = True
AlphaNum = RE.Replace(OldString, "")
End Function
Cleaning out non-printable characters is easy enough. One brute-force but easily customizable method might be:
Private Function Printable(ByVal Text As String) As String
Dim I As Long
Dim Char As String
Dim Count As Long
Printable = Text 'Allocate space, same width as original.
For I = 1 To Len(Text)
Char = Mid$(Text, I, 1)
If Char Like "[ -~]" Then
'Char was in the range " " through "~" so keep it.
Count = Count + 1
Mid$(Printable, Count, 1) = Char
End If
Next
Printable = Left$(Printable, Count)
End Function
Private Sub Test()
Dim S As String
S = vbVerticalTab & "ABC" & vbFormFeed & vbBack
Text1.Text = S 'Shows "boxes" or "?" depending on the font.
Text2.Text = Printable(S)
End Sub
This will remove control characters (below CHR(32))
Function CleanString(strBefore As String) As String
CleanString = ""
Dim strAfter As String
Dim intAscii As Integer
Dim strTest As String
Dim dblX As Double
Dim dblLen As Double
intLen = Len(strBefore)
For dblX = 1 To dblLen
strTest = Mid(strBefore, dblX, 1)
If Asc(strTest) < 32 Then
strTest = " "
End If
strAfter = strAfter & strTest
Next dblX
CleanString = strAfter
End Function

I want to read the last 400 lines from a txt file

I know how to do it in VB.Net but not an idea in vb6.
What I what to achieve is to avoid reading the whole file.
Is that possible?
You could open the file using Random access. Work your way backward a byte at a time, counting the number of carriage return line feed character pairs. Store each line in an array, or something similar, and when you've read your 400 lines, stop.
Cometbill has a good answer.
To open file for Random access:
Open filename For Random Access Read As #filenumber Len = reclength
To get the length of the file in Bytes:
FileLen(ByVal PathName As String) As Long
To read from Random access file:
Get [#]filenumber,<[recnumber]>,<varname>
IMPORTANT: the <varname> from the Get function must be a fixed length string Dim varname as String * 1, otherwise it will error out with Bad record length (Error 59) if the variable is declared as a variable length string like this Dim varname as String
EDIT:
Just wanted to point out that in Dim varname as String * 1 you are defining a fixed length string and the length is 1. This is if you wish to use the read-1-byte-backwards approach. If your file has fixed length records, there is no need to go 1 byte at a time, you can read a record at a time (don't forget to add 2 bytes for carriage return and new line feed). In the latter case, you would define Dim varname as String * X where X is the record length + 2. Then a simple loop going backwards 400 times or untill reaching the beginning of the file.
The following is my take on this. This is more efficient than the previous two answers if you have a very large file, since we don't have to store the entire file in memory.
Option Explicit
Private Sub Command_Click()
Dim asLines() As String
asLines() = LoadLastLinesInFile("C:\Program Files (x86)\VMware\VMware Workstation\open_source_licenses.txt", 400)
End Sub
Private Function LoadLastLinesInFile(ByRef the_sFileName As String, ByVal the_nLineCount As Long) As String()
Dim nFileNo As Integer
Dim asLines() As String
Dim asLinesCopy() As String
Dim bBufferWrapped As Boolean
Dim nLineNo As Long
Dim nLastLineNo As Long
Dim nNewLineNo As Long
Dim nErrNumber As Long
Dim sErrSource As String
Dim sErrDescription As String
On Error GoTo ErrorHandler
nFileNo = FreeFile
Open the_sFileName For Input As #nFileNo
On Error GoTo ErrorHandler_FileOpened
' Size our buffer to the number of specified lines.
ReDim asLines(0 To the_nLineCount - 1)
nLineNo = 0
' Read all lines until the end of the file.
Do Until EOF(nFileNo)
Line Input #nFileNo, asLines(nLineNo)
nLineNo = nLineNo + 1
' Check to see whether we have got to the end of the string array.
If nLineNo = the_nLineCount Then
' In which case, flag that we did so, and wrap back to the beginning.
bBufferWrapped = True
nLineNo = 0
End If
Loop
Close nFileNo
On Error GoTo ErrorHandler
' Were there more lines than we had array space?
If bBufferWrapped Then
' Create a new string array, and copy the bottom section of the previous array into it, followed
' by the top of the previous array.
ReDim asLinesCopy(0 To the_nLineCount - 1)
nLastLineNo = nLineNo
nNewLineNo = 0
For nLineNo = nLastLineNo + 1 To the_nLineCount - 1
asLinesCopy(nNewLineNo) = asLines(nLineNo)
nNewLineNo = nNewLineNo + 1
Next nLineNo
For nLineNo = 0 To nLastLineNo
asLinesCopy(nNewLineNo) = asLines(nLineNo)
nNewLineNo = nNewLineNo + 1
Next nLineNo
' Return the new array.
LoadLastLinesInFile = asLinesCopy()
Else
' Simply resize down the array, and return it.
ReDim Preserve asLines(0 To nLineNo)
LoadLastLinesInFile = asLines()
End If
Exit Function
ErrorHandler_FileOpened:
' If an error occurred whilst reading the file, we must ensure that the file is closed
' before reraising the error. We have to backup and restore the error object.
nErrNumber = Err.Number
sErrSource = Err.Source
sErrDescription = Err.Description
Close #nFileNo
Err.Raise nErrNumber, sErrSource, sErrDescription
ErrorHandler:
Err.Raise Err.Number, Err.Source, Err.Description
End Function

How to get only a filename?

Using VB6
Code.
Dim posn As Integer, i As Integer
Dim fName As String
posn = 0
For i = 1 To Len(flname)
If (Mid(flname, i, 1) = "\") Then posn = i
Next i
fName = Right(flname, Len(flname) - posn)
posn = InStr(fName, ".")
If posn <> 0 Then
fName = Left(fName, posn - 1)
End If
GetFileName = fName
FileName: Clockings8.mis06042009 120442.fin
But it is showing a filename is “Clockings8”. It should show “Clockings8.mis06042009 120442”
How to modify a code?
Need vb6 code Help
It is a bit cleaner to use the Scripting.FileSystemObject component. Try:
Dim fso as New Scripting.FileSystemObject
GetFileName = fso.GetBaseName(fname)
The reason why your code stops short is that InStr works from the beginning of the string to the end and stops wherever it finds a match. The filename "Clockings8.mis06042009 120442.fin" contains two periods. For this reason, you should use InStrRev instead to start the search from the end of the string.
Going with FileSystemObject's GetBaseName like David suggests is a good idea. If you can't or don't want to (and there are reasons why you might not want to) work with the FileSystemObject there's a simple solution: Remove all characters from a filename string starting with the last dot in the name.
Here's what I mean:
Dim fn As String
fn = "Clockings8.mis06042009 120442.fin"
Dim idx As Integer
idx = InStrRev(fn, ".")
GetFileName = Mid(fn, 1, idx - 1)
If your filename does not have an extenstion but has a dot somewhere in the filename string, then this method will return bad results.

Resources