I'm trying to compare 2 strings (KeyCode and SerialN)
I've tried a bunch of diferente aproaches... but as you can see in my print screen neither = or Equals work.
Can you tell me what is wrong?
Private Function VerificaKeyCode(SerialN As String) As Boolean
Dim snEsq As Integer
Dim snDir As Integer
Dim KeyCode As String
Dim buffer As String
Dim ind As Short
VerificaKeyCode = False
buffer = Space(255)
For ind = 1 To 5
'UPGRADE_WARNING: App property App.EXEName has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="6BA9B8D2-2A32-4B6E-8D36-44949974A5B4"'
GetPrivateProfileString(My.Application.Info.AssemblyName, "HD" & ind, "", buffer, Len(buffer), My.Application.Info.DirectoryPath & "\ServerHD.ini")
KeyCode = Trim(buffer)
If KeyCode <> "" Then
VerificaKeyCode = KeyCode.Equals(SerialN)
VerificaKeyCode = CBool(KeyCode = SerialN)
If VerificaKeyCode Then Exit Function
End If
Next ind
End Function
Edit
Aparently there is an empty char in the string, I need to remove it somehow
The expressions in your watch window are stale as indicated by the disabled color and the presence of the Refresh/Recycle icon. Click the icon and the expression will be re-evaluated and the result updated:
Mimicking what you have, notice the first expression is stale and wrong. The second has been refresh/reevaluated and reports the correct result. As soon as you execute a line of code, the watch expressions will be marked as stale/not updated.
A better way to return a function with NET is to use a local variable and Return it. The local var allow you to easily view the result by hovering the mouse:
A variable can go out of scope, but it can't be stale.
Edit 4 or 5 reveals that while the watch expressions are stale, so what we see in the pic neither proves nor disproves that the strings do not match, this is apparently a VB6 -> .NET refurb (notice the 102 warnings).
We cant see the declaration for GetPrivateProfileString but the usage is at least suboptimal.
<DllImport("kernel32.dll", SetLastError:=True)>
Shared Function GetPrivateProfileString(appname As String,
keyname As String, def As String,
sbuffer As StringBuilder,
nSize As Int32,
strFile As String) As Integer
End Function
Note that it is a Function; it returns the number of chars read into the buffer. Rather than Trim which will not remove NUL, the return should be used (if not a stringbuilder) to get the number of characters specified. If you use a string buffer, trim to the number of characters read:
Dim n As Int32 = GetPrivateProfileString(...)
KeyCode = buffer.Substring(0, n)
StringBuilder should do that for you:
Dim buffer As New StringBuilder(255)
...
Dim n As Int32 = GetPrivateProfileString(..., buffer, buffer.Capacity)
KeyCode = buffer.ToString()
You can still check the function return against the size of the string.
You could skip GetPrivateProfileString entirely and read the file yourself with a stream reader. It should be faster than PInvoke, but at the least, less convoluted to use.
Related
I need to allow the user to select an icon, so I've implemented the PickIconDlg function from shell32. The problem is that if the user selects a path that is longer than the initial path I declare, the resultant value is the user-selected path truncated to length of the initial path.
For instance, if I set the initial path to "C:\Windows\System32\shell32.dll" and the user selects "C:\Users\Public\Documents\TheIcons\Library.dll", the updated string value comes back as "C:\Users\Public\Documents\TheIc" (i.e. the first 31 characters of the user-selected path, because the initial path is 31 characters long).
I have tried adjusting the 'nMaxFile' value I pass to PickIconDlg, which I understand is supposed to set the max length of the path variable. This doesn't seem to make a difference.
Declare Unicode Function PickIconDlg Lib "Shell32" Alias "PickIconDlg" (ByVal hwndOwner As IntPtr, ByVal lpstrFile As String, ByVal nMaxFile As Integer, ByRef lpdwIconIndex As Integer) As Integer
Public Function GetIconLoc(frmform As Form) As Object()
Dim iconfile As String = Environment.GetFolderPath(Environment.SpecialFolder.System) + "\shell32.dll"
Dim iconindex As Integer ' Will store the index of the selected icon
If PickIconDlg(frmform.Handle, iconfile, 50, iconindex) = 1 Then
MessageBox.Show(iconfile)
Return {iconfile, iconindex}
Else
Return Nothing
End If
End Function
I expect the string variable iconfile to contain the full user-selected path, as its length is less than the defined max of 50 characters. Instead, only a portion of the path is returned, as described above.
Append a Null character plus empty space after the original file name to create a string buffer large enough to contain the result.
Dim iconfile As String = _
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "shell32.dll") & _
vbNullChar & Space(256)
Then pass the total length when calling the function
PickIconDlg(frmform.Handle, iconfile, Len(iconfile), iconindex)
And finally cut the extra space from the result
iconfile = Left(iconfile, InStr(iconfile, vbNullChar) - 1)
Also, use Path.Combine instead of concatenating the path yourself. Path.Combine adds missing or removes extra backslashes (\) automatically.
I have looked on the web and I cannot find anything that helps me, all I can find is changing the characters into ASCII or Hexadecimal. However I would like to do it a different way. For example, say the string that got passed in was abcdef, I would like to have a key which changes these characters into another string such as qwpolz. Is there an easier way than declaring each character in the alphabet to be another character like:
Dim sText As String = "Hello"
Dim sEncode As String = ""
Dim iLength As Integer
Dim i As Integer
iLength = Len(sText)
For i = 1 To iLength
sEncode = sEncode ????
Next
Return sEncode
And then have a very lengthy loop which checks for these loops? There must be a much simpler way. Can anybody help by pointing me in the right direction?
Edit: Why downvote? Seriously, it's a legitimate question. Instead of downvoting for no reason, just move onto another question.
Well actually, this sounds like a Caesar sipher
Private Overloads Shared Function Encrypt(ByVal ch As Char, ByVal code As Integer) As Char
If Not Char.IsLetter(ch) Then
Return ch
End If
Dim offset As Char = IIf(Char.IsUpper(ch), "A", "a")
Return CType((((ch + (code - offset)) Mod 26) + offset),Char)
End Function
Private Overloads Shared Function Encrypt(ByVal input As String, ByVal code As Integer) As String
Return New String(input.ToCharArray.Select(() => { }, Encrypt(ch, code)).ToArray)
End Function
Private Shared Function Decrypt(ByVal input As String, ByVal code As Integer) As String
Return Encrypt(input, (26 - code))
End Function
Note that this assumes, that you use English alphabet. In general case where for example you have 'ä', 'ö', 'š', 'ž', 'ß', 'õ', 'ü' etc. this would not work. In that case it is simpler to just create a list/dictionary of your ordered alphabet and use it.
Example use:
encrypted = Encrypt(sText, 5)
decypted = Decrypt(encrypted, 5)
Sounds as if you want to modify a string by replacing each character with a different character according to a mapping table. An efficient approach is to use a Dictionary(Of Char, Char). But easier to write and maintain is something like this:
Shared ReadOnly replaceChars As String = "abcdef"
Shared ReadOnly withChars As String = "qwpolz"
Public Shared Function ReplaceAll(input As String) As String
Dim newChars = From c In input
Let index = replaceChars.IndexOf(c)
Select If(index >= 0, withChars(index), c)
Return String.Concat(newChars)
End Function
So the first string contains the chars that you want to replace and the second the replacement characters. Both strings must have the same length.
If you want to support case insensitivity:
Public Shared Function ReplaceAll(input As String, comparison As StringComparison) As String
Dim newChars = From c In input
Let index = replaceChars.IndexOf(c.ToString(), comparison)
Select If(index >= 0, withChars(index), c)
Return String.Concat(newChars)
End Function
Note that this is also a loop. There is no way to avoid some kind of loops if you want to replace multiple characters or strings.
Hi Guys, I have searched for different methods for this thing but couldn't get it right. Used AutoEllipses Property, Set the MaximumSize too but to no avail. How can i get a label to show the name of the file being scanned like in the pic i attached? I mean, the label should show some part from the beginning of full path of the file then some dots and then the file name with extension.
You might consider a few things; however, the range of possibilities is too large to cover, here.
There are three (3) things you need to know in order to code this properly: the actual measured size of the filepath string you are sending to the label; the measured size of the label; and the length (in characters) of your file name. There may be a fancy function that reduces the number of things you need to do and know; however, I am not about to read oodles of documentation.
All of the above things need to be dynamic so that your label can take different String objects and render them, properly.
Dim filePath As String = ""
Dim FileDirectory As String = ""
Dim fileName As String = ""
Dim filePathLength As SizeF = 0.0
Dim labelLength As Double = 0.0
Dim fileNameLength As Integer = 0.0
' Come up with a way for measuring your string:
Dim _GraphicsUnit As Graphics = Me.CreateGraphics()
' Receive your file path, here:
' and work with your file path-related Strings:
filePath = ' SOMETHING
fileDirectory = Path.GetDirectoryName(filePath)
fileName = Path.GetFileName(filePath)
fileNameLength = fileName.Length()
' Measure the length of you path
filePathLength = _GraphicsUnit.MeasureString(filePath, INSERTFONT) * _GraphicsUnit.Inches 'or other usable unit
If filePathLength > SIZEOFLABEL Then
While filePathLength > SIZEOFLABEL
' Grab a substring of the the fileDirecory, append the "...", and keep measuring until shorter
' than SIZEOFLABEL.
' Your algorithm will need to figure out how and when to re-append the fileName
End While
End If
The above is pseudo-code and is rife with errors. The above is means to demonstrate some of the tools .Net can provide you, here namely the GraphicsUnit stuff and the Path. stuff. Both of those are helpful. You will essentially be juggling those two 'things' and the SubString() method.
My attempt is to show you how to begin to think about the problem you have in front of you so that you can begin to tackle the problem (because as the comments above state, there isn't much out there that will do what you need). Your initial question does not provide any original code on which to base the above pseudo-code; in other words, I don't feel like coding your whole project but at least want to get the answers ball rolling.
An Additional Thought: .MaxLength
The above approach is quite memory intensive - requiring a lot of repetition that may not be be necessary. Simply knowing the size - in this case the MaxLength property - might be helpful. Setting the .MaxLength property of the TextBox will allow you to know how many characters can fit in the box (you'd need to consider a few other elements, e.g. font, size, etc.).
Knowing this number, you could avoid looping altogether:
SubString of fileDirectory equal to the length of .MaxLength property, remove number of characters equating to size of fileName and "..." and append the latter two.
I got an answer to this problem here Shorten The File Path and it's a very short solution as far as code is concerned.
You can use the PathCompactPathExW pInvoke method to accomplish this:
Imports System.Runtime.InteropServices
Imports System.Text
Public Class Program
<DllImport("shlwapi.dll", EntryPoint:="PathCompactPathExW", SetLastError:=True, CharSet:=CharSet.Unicode)> _
Public Shared Function PathCompactPathEx(<MarshalAs(UnmanagedType.LPTStr)> pszOut As System.Text.StringBuilder, _
<MarshalAs(UnmanagedType.LPTStr)> pszSrc As String, _
cchMax As UInteger, _
reserved As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
Public Shared Sub Main()
Dim longPath As String = "c:\a\very\very\long\path\that\needs\to\be\shortened\by\calling\the\PathCompactpathEx.ext"
Dim length As Integer = 40
Dim result As String = CompactPath(longPath, length)
'Prints c:\a\very\very\...\PathCompactpathEx.ext
Console.WriteLine(result)
Console.ReadLine()
End Sub
Public Shared Function CompactPath(longPathName As String, wantedLength As Integer) As String
'NOTE: You need to create the builder with the required capacity before calling function.
'See http://msdn.microsoft.com/en-us/library/aa446536.aspx
Dim sb As New StringBuilder(wantedLength + 1)
PathCompactPathEx(sb, longPathName, CUInt(wantedLength + 1), 0)
Return sb.ToString()
End Function
End Class
I realize this is a very specific question, and not very helpful outside of this scenario, although I am sure it applies to other questions with the same problem. I have a function to recursively search through windows (and their child windows) to find specific ones, it works exactly as expected, however it causes "function doesn't return a value on all paths" warning. This is the only warning in my entire program, and although it might be silly, I'm interested in knowing if there is a way to stop this error from occurring, but still allowing the function to work properly.
Public Function FindQWidgetWindows() As Integer
Dim hWndStart As Integer = 0
Dim WindowText As String = "*"
Dim Classname As String = "QWidget"
Dim hwnd As Integer
Dim sWindowText As String
Dim sClassname As String
Dim r As Integer
Static level As Integer
If level = 0 Then
If hWndStart = 0 Then hWndStart = GetDesktopWindow()
End If
level = level + 1
hwnd = GetWindow(hWndStart, GW_CHILD)
Do Until hwnd = 0
Call FindQWidgetWindows()
'Get the window text and class name'
sWindowText = Space$(255)
r = GetWindowText(hwnd, sWindowText, 255)
sWindowText = Microsoft.VisualBasic.Left(sWindowText, r)
sClassname = Space$(255)
r = GetClassName(hwnd, sClassname, 255)
sClassname = Microsoft.VisualBasic.Left(sClassname, r)
If (sWindowText Like WindowText) And (sClassname Like Classname) Then
Dim aRECT As RECT
Dim hwndInt As Int32 = hwnd
GetWindowRect(hwndInt, aRECT)
FindQWidgetWindows = hwnd
'uncommenting the next line causes the routine to'
'only return the first matching window.'
'Exit Do'
End If
hwnd = GetWindow(hwnd, GW_HWNDNEXT)
Loop
level = level - 1
End Function
You rely on the fact, that VB automatically declares a return variable with the name of your function. This variable can be used as any other variable in your function. So it also can get a default initialization.
As already mentioned, you only assign a value in a very nested If statement.
You should simply initialize your variable outside and before of your Do-loop with something like
FindQWidgetWindows = Nothing
Yes, you can get rid of this error by ensuring every path returns a value.
This can be done by simply initialising the return value at the top of the function:
FindQWidgetWindows = Nothing
But you have another problem that you're probably not seeing because your desired window is at the top level. If you recurse into your function, the hWndStart will once again be set to the desktop, not the child window.
In your code the below code will be executed only if the If condition is satisfied.
FindQWidgetWindows = hwnd
Which also means if the If condition is not satisfied nothing will be returned.
You have declared the function (Public Function FindQWidgetWindows() As Integer) as returning a integer but the function doesn't return anything. Just ensure that you return an integer using the Return statement.
Is there a way to give a value to multiple variables (integers in this case), instead of all at once?
For instance, I have Dim aceVal, twoVal, threeVal, fourVal, fiveVal, sixVal, sevenVal, eightVal, nineVal, tenVal As Integer and, pending listbox selection, I'd like to assign threeVal fourVal and sixVal all values of -1.
How can I do this? Thanks.
There is no way in vb.net to assign them all on one line like threeVal=fourVal=SixVal.
If you need all these variables then one line at a time is the way. I would suggest if -1 is going to be used a lot then create a constant for it and assign the var's to the constant.
I would also consider using an array or collection to store all your values if possible and work with them in order for setting / retrieving their values. You then won't have to have 60 variables littered all in your code. Array and/or collection would be a little cleaner.
I really don't mean to be a jerk, but is there any reason why you can't just do:
threeVal = -1
fourVal = -1
sixVal = -1
If you want to keep it on one line then you can do it like this
Dim m1 As String = "false", m2 As String = "false", m3 As String = "false"
'etc..
You could use an array/dictionary like so:
Dictionary myValues = new Dictionary();
myValues.Add("FirstVal", 1);
myValues.Add("SecondVal", -1);
myValues.Add("ThirdVal", 1);
You could then write a simple function:
public updateMyValues(string[] myKeys, int myValue)
{
foreach (string s in myKeys)
{
myValues[s] = myValue;
}
}
And finally when your list box changes you could just call the function to update the variables you want like so:
upDateMyValues({"FirstVal", "ThirdVal"}, -1);
Hope this helps.
*Edit: I know it's in C#, but it's easily portable to VB.
You can declare and asign the value using the constructor:
Dim str1, str2, str3, str4 As New String("asdf")
Dim int1, int2, int3, int4 As New Integer
I know this is an old thread, however I've just run into a similar issue myself - here's how I did it (I am only dealing with 4 values
Private Sub SetFalse(ByRef first As Boolean, Optional ByRef second As Boolean = False, Optional ByRef third As Boolean = False, Optional ByRef fourth As Boolean = False)
first = False
second = False
third = False
fourth = False
End Sub
this can be easily adapted, by making the first variable the required value (this code also looks a bit daft because I have to provide a default which can only be true or false, but obviously with integers or something it looks more meaningful.)
I thought the multiple assignment feature was so cool in C# that I wrote a VB extension method (Assign) to do the same thing. The semantics are pretty easy to follow; you just call Assign on any value to assign it to multiple other variables
i.e.
Call True.Assign(b1, b2, b3)
Call 4.1.Assign(d1, d2, d3)
etc...
Here's the code:
Imports System.Runtime.CompilerServices
Namespace Utility
Public Module MultiAssignExtensionMethod
' Multiply assign the same value to 1 (required) or more variables
<Extension()> _
Public Function Assign(Of T)(this As T, ByRef first As T, Optional ByRef second As T = Nothing, Optional ByRef third As T = Nothing,
Optional ByRef forth As T = Nothing, Optional ByRef fifth As T = Nothing, Optional ByRef sixth As T = Nothing,
Optional ByRef seventh As T = Nothing, Optional ByRef eighth As T = Nothing, Optional ByRef nineth As T = Nothing,
Optional ByRef tenth As T = Nothing) As T
' I would LIKE to do this as a ParamArray, but it doesn't allow references for basic types....grrr
first = this
second = this
third = this
forth = this
fifth = this
sixth = this
seventh = this
eighth = this
nineth = this
tenth = this
Return this ' For use as assignment and evaluation as Function parameter
End Function
End Module
End Namespace
You can try like this:
Dim aceVal, twoVal,fourVal,sevenVal, eightVal, nineVal, tenVal As Integer
Dim threeVal As Integer =-1,fiveVal=-1,sixVal=-1
alternatively follow this post: http://www.informit.com/library/content.aspx?b=Net_2003_21days&seqNum=95
you can put it in List and use For Each method
here is the code
Dim aceVal, twoVal, threeVal, fourVal, fiveVal, sixVal, sevenVal, eightVal, nineVal, tenVal As Integer
Dim var As New List(Of Integer) From {threeVal, fiveVal, sixVal} 'you can add more variable here
For Each n As Integer In var
n = -1
Next