I imported the Winsock feature in my vb.net application, so I can make a Chat System. I just have one little problem with my program. In the GetData method of my program,
CLIENT SIDE:
*Dim strData As String*
AxWinsock1.GetData(strData, vbString)
TextBox1.Text = TextBox1.Text & _
strData & vbCrLf
It will underline the whole first line, unless have an maxLen as Object in. So I plugged in Nothing, since I thought it was optional. Now when I debug, and I send a message from the server, it won't display anything. I put in vbByte as the maxLen object, and now it only shows part of the message. Can anyone tell me how to fix this. This works in VB6...
PS: I am not going to use the System.Namespaces function of VB.NET since, I find the Winsock feature much easier.
Thanks
vbByte is a constant with a value of 17, so you actually send a max length of 17 ;-)
You will want to send a bigger number as the max length. If what you want to send as a max length is the upper bound of the Byte data type you could send Byte.MaxValue (which is 255).
Edit:
I don't know what is the upper bound, but you can try Integer.MaxValue, or some arbitrary big value like 1000000...
Looking at the documentation, I noticed two things:
maxLen should be optional, I don't know why it would flag an error when you don't specify it, what kind of error is it?
It's mentioned that it's common to use GetData with a DataArrival event, is that your case? If it is, you could pass the totalBytes argument as the maxLen.
Related
I have a barcodescanner hooked up to a serialport. I read the Serialport via DataReceived-Event
Now there is some weird timing issue occurring on repetitive scans that I try to explain in the following. So can you explain to me what is causing this difference?
I use this barcode: 01513511220001.
I scan it twice with both examples
Example1:
Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SP1.DataReceived
If SP1.BytesToRead > 0 Then
Threading.Thread.Sleep(1) '!!!
Dim str As String = SP1.ReadExisting
Debug.WriteLine(str)
End If
End Sub
'Output Scan 1:
'01513511220001
'Output Scan 2!!!:
'01513511220001
Example2:
Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SP1.DataReceived
If SP1.BytesToRead > 0 Then
Dim str As String = SP1.ReadExisting
Debug.WriteLine(str)
End If
End Sub
'Output Scan 1:
'01513511220001
'Output Scan 2!!!:
'015135112
'20001
Note sometimes it cuts after the 9th digit sometimes it cuts after the 8th digit.
Understanding ReadExisting
You are using the ReadExisting function, which as per the documentation
Reads all immediately available bytes, based on the encoding, in both the stream and the input buffer of the SerialPort object.
As it says it immediately reads and gives you the data, even though it's not fully complete. A barcode scanner does not know how long the code is so it continuously reads it, it is up-to the software to make sense of it.
Understanding DataReceived
Similarly DataReceived method is called anytime there is data received via the port as per documentation (regardless of partial or full data, which depends on barcode scanner, internal buffers, etc.)
Indicates that data has been received through a port represented by the SerialPort object.
Again it is upto the software to make sense of the data being received.
Understanding your examples
The reason why your example 1 always works is because you add a delay before reading the actual data, giving a chance for the internal buffers to be full and hence you captured the full data upon calling ReadExisting
Note: If you have to add a delay to the code, it's always the wrong way to do it (extreme exceptions exist, but this isn't it)
Possible Solutions
I would suggest using ReadLine method but it has its challenges
Simply put a logic to wait till all 14 characters are read before moving to next step of processing (given you have a fixed size code, even not this can still be done but logic becomes more complex).
Crude Example for Solution 2
Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SP1.DataReceived
If SP1.BytesToRead >= 14 Then 'Basically wait for the bytes to fill upto the length of the code
Dim str As String = SP1.ReadExisting
Debug.WriteLine(str)
End If
End Sub
Note: I have not ran the above example, it's just indicative to what needs to be done
Specifically for Honeywell 1911i
As per its manual, you need to ensure the Programming Interface for the device is set to RS232 Serial Port to do this refer to page 2-1 (page 27) of the manual under the heading Programing the Interface > RS232 Serial Port.
In this interface it automatically adds the suffix of Carriage Return and Line Feed, basically the NewLine character. Excerpt from the manual
The RS232 Interface bar code is used when connecting to the serial port of a PC or terminal. The following RS232 Interface bar code also programs a carriage return (CR) and line feed (LF) suffix, baud rate, and data format as indicated below. It also changes the trigger mode to manual.
This should allow you to use the ReadLine method to fetch the barcode without complexity.
You can set this interface by simply scanning the RS232 Interface Bar Code from the manual.
While looking for a way to test when a user cancels an InputBox, I stumbled across the StrPtr function. I believe it checks if a variable was ever assigned a value and returns zero if it was never assigned and some cryptic number if it was.
It seems like a useful function! I started with this code:
Dim myVar as string
myVar = InputBox("Enter something.")
MsgBox StrPtr(myVar)
The message box shows a zero if the user cancelled.
Fantastic! But then why do some insist that StrPtr never be used? I read it's unsupported. Why does that matter?
A good answer will explain benefits (beyond my example above) and risks of using the StrPtr function, possibly how you use (or don't use) it without giving an opinion as to whether everyone or no one should use it.
tldr; There's no real risk to using StrPtr like that, but there's not really a benefit either.
While it might look like you get a null pointer back from the InputBox call, you actually don't. Compare the result of StrPtr to VarPtr:
Sub Test()
Dim result As String
result = InputBox("Enter something.") 'Hit cancel
Debug.Print StrPtr(result) '0
Debug.Print VarPtr(result) 'Not 0.
End Sub
That's because InputBox is returning a Variant with a sub-type of VT_BSTR. This code demonstrates (note that I've declared result as a Variant so it doesn't get implicitly cast - more on this below):
Sub OtherTest()
Dim result As Variant
result = InputBox("Enter something.") 'Hit cancel
Debug.Print StrPtr(result) '0
Debug.Print VarPtr(result) 'Not 0.
Debug.Print VarType(result) '8 (VT_BSTR)
Debug.Print TypeName(result) 'String
End Sub
The reason why StrPtr returns 0 is because the return value of InputBox is actually malformed (I consider this a bug in the implementation). A BSTR is an automation type that prefixes the actual character array with the length of the string. This avoids one problem that a C-style null terminated string presents automation - you either have to pass the length of the string as a separate parameter or the caller won't know how large to size a buffer to receive it. The problem with the return value of InputBox is that the Variant that it's wrapped in contains a null pointer in the data area. Normally, this would contain the string pointer - the caller would dereference the pointer in the data area, get the size, create a buffer for it, and then read the N bytes following the length header. By passing a null pointer in the data area, InputBox relies on the calling code to check that the data type (VT_BSTR) actually matches what is in the data area (VT_EMPTY or VT_NULL).
Checking the result as a StrPtr is actually relying on that quirk of the function. When it's called on a Variant, it returns the pointer to the underlying string stored in the data area, and it offsets itself by the length prefix to make it compatible with library functions that require a C-string. That means the StrPtr has to perform a null pointer check on the data area, because it's not returning a pointer to the start of the actual data. Also, like any other VARTYPE that stores a pointer in the data area, it has to dereference twice. The reason VarPtr actually gives you a memory address is that it gives you the raw pointer to whatever variable you pass it (with the exception of arrays, but that's not really in scope here).
So... it's really no different than using Len. Len just returns the value in the header of the BSTR (no, it doesn't count characters at all), and it also needs a null test for the similar reason that StrPtr does. It makes the logical conclusion that a null pointer has zero length - this is because vbNullstring is a null pointer:
Debug.Print StrPtr(vbNullString) '<-- 0
That said, you're relying on buggy behavior in InputBox. If Microsoft were to fix the implementation (they won't), it would break your code (which is why they won't). But in general, it's a better idea to not rely on dodgy behavior like that. Unless you're looking to treat the user hitting "Cancel" differently than the user not typing anything and hitting "Enter", there really isn't much point in using StrPtr(result) = 0 in favor of the much clearer Len(result) = 0 or result = vbNullString. I'd assert that if you need to make that distinction, you should throw together your own UserForm and explicitly handle cancellation and data validation in your own dialog.
I find the accepted answer to be rather misleading, so I was compelled to post another one.
A good answer will explain benefits (beyond my example above) and risks of using the StrPtr function, possibly how you use (or don't use) it without giving an opinion as to whether everyone or no one should use it.
There are three "hidden" functions: VarPtr, StrPtr and ObjPtr.
VarPtr is used when you need to get the address of a variable (that is, the pointer to the variable).
StrPtr is used when you need to get the address of the text data of a string (that is, the BSTR, a pointer to the first Unicode character of the string).
ObjPtr is used when you need to get the address of an object (that is, the pointer to the object).
They are hidden because it may be unsafe to mess around with pointers.
But you cannot go completely without them.
So, when do you use them?
You use them when you need to do what they do.
You use VarPtr when your problem in hand is "I need to know the address of that variable" (e.g. because you want to pass that address to CopyMemory).
You use StrPtr when your problem in hand is "I need to know the address of the first character of my BSTR string" (e.g. because you want to pass it to an API function that accepts wide strings only, but if you simply declare the parameter As String, VB will convert the string into ANSI for you, so you have to pass StrPtr).
You use ObjPtrwhen your problem in hand is "I need to know the address of that object" (e.g. because you want to examine its vtable or manually check if the object address does or does not equal some value you knew previously).
These functions correctly do what they are supposed to do, and you should not be afraid to use them for their intended purpose.
If your task in hand is different, you probably should not be using them, but not out of fear that they will return a wrong value - they will not.
In a perfect world, you would stop at that conclusion. That is not always possible, unfortunately, and the InputBox situation you mention is one of the examples.
From what is outlined above, it would appear that you should not be using StrPtr to determine if Cancel was pressed in an InputBox. Realistically though, you don't have a choice.
VBA.InputBox returns a String. (This fact is incorrectly omitted from the current documentation making it look like it returns a Variant.) It is perfectly okay to pass a string to StrPtr.
However, it is not documented that InputBox returns a null pointer on a cancel. It is merely an observation. Even though realistically that behaviour will never change, theoretically it may in a future version of Office. But that observation is all you have; there is no documented return value for a cancel.
With this in mind, you make a decision on whether or not you are comfortable with using StrPtr on the InputBox result. If you are happy to take the very small risk of this behaviour changing in future and your app therefore breaking, you do use StrPtr, otherwise you switch to Application.InputBox that returns a Variant and is documented to return a False on a cancel.
But that decision will not be based on whether StrPtr is correct in what it tells you. It is. It is always safe to pass the String result of VBA.InputBox to it.
Fantastic! But then why do some insist that StrPtr never be used? I read it's unsupported. Why does that matter?
When someone insists that something should never be used, it's almost always wrong. Even GoTo has its correct uses.
I tired both using StrPtr and without using StrPtr. I tested my Sub with several examples. I got same results except in one occasion - When User inputs null value (nothing) and presses OK.
Precisely I tried these two:
Using StrPtr. "Invalid Number" was the result here
ElseIf StrPtr(Max_hours_string) = 0
MsgBox "Cancelled"
Else
MsgBox "Invalid Number"
Without Using StrPtr. "Cancelled" was the result here
ElseIf Max_hours_string = "" Then
MsgBox "Cancelled"
Else
MsgBox "Invalid Number"
This is my code.
Sub Input_Max_Hours_From_The_User()
'Two Common Error Cases are Covered:
'1. When using InputBox, you of course have no control over whether the user enters valid input.
' You should store user input into a string, and then make sure you have the right value.
'2. If the user clicks Cancel in the inputbox, the empty string is returned.
'Since the empty string can't be implicitly coerced to a double, an error is generated.
'It is the same thing that would happen if the user entered "Haughey" in the InputBox.
Dim Max_hours_string As String, Max_hours_double As Double
Max_hours_string = InputBox("Enter Maximum hours of any Shift")
If IsNumeric(Max_hours_string) Then
Max_hours_double = CDbl(Max_hours_string) 'CDbl converts an expression to double
Range("L6").Value = Max_hours_double
Range("L6").Interior.ColorIndex = 37
ElseIf StrPtr(Max_hours_string) = 0 Then 'ElseIf Max_hours_string = "" Then MsgBox "Cancelled" also works !
MsgBox "Cancelled"
Else
MsgBox "Invalid Number"
End If
End Sub
So I think it depends how important it is to handle the null value for you. All other test cases, including pressing Cancel, non-numerical inputs etc. give the same results. Hope this helps.
Read through this thread and ultimately ended up doing the following... which does exactly what I want.... If the user deletes the previous entry which is the default... and clicks ok.. it moves forward and deletes the back end data ( not shown ). If the user click's cancel, it exists the sub without doing anything. This is the ultimate objective and... this allows it to work as intended... Move forward unless cancel is clicked.
hth,
..bob
Dim str As String
If IsNull(Me.Note) = False Then
str = Me.Note
Else
str = "Enter Note Here"
End If
Dim cd As Integer
cd = Me.ContractDetailsID
str = InputBox("Please Enter Note", "NOTE", str)
If StrPtr(str) = 0 Then
Exit Sub 'user hit cancel
End If
In my opinion: Using StrPtr in order to identify if a value converts to 0 is extra code to write. if you use the following function like your example above
Sub woohoo()
Dim myVar As String
myVar = "hello"
myVar = InputBox("Enter something.")
'if Cancel is hit myVar will = "" instead of hello.
'MsgBox StrPtr(myVar) not needed
MsgBox myVar 'will show ""
End Sub
Now is this the only reason to not use StrPtr no not at all. The other issue you run into with using unsupported functions is that eventually they can break the application. Whether its a library issue or another programmer looking through your code and trying to find that function it just is not a good idea. This may not seem like a big deal if your script is only 100 lines long. But what about when it is thousands of lines long. If you have to look at this code 2 years down the road because something broke it would not be very fun to have to find this magical function that just does not work anymore and try to figure out what it did. Lastly especially in VBA you can get overflow errors. If StrPtr is used and it goes past the allocated space of your data type that you declared it's another unnecessary error.
Just my 2 cents but due to being able to use less code and the function being more stable without it I would not use it.
10+ years Excel Programmer.
So.
I am making a bruteforcer in visual basic.
It has a charset as shown below:
Dim charset as string
charset = "abcdefghijklmnopqrstuvwxyz1234567890."
There is 37 different chars right? The program is made to search for all the different combinations made with this charset, with a maximum of 3 different letters. For example
This is a combination that can be made: ac6
So since there is 37 letters and 3 slots the possible combinations are 37^3
But I wanted my program not to try the same combination twice.
So it saves every single combination tried in this location (Desktop)
Dim filex As System.IO.StreamWriter
filex = My.Computer.FileSystem.OpenTextFileWriter("c:\Users\" + Environment.UserName + "\desktop\alreadytested.txt", True)
filex.WriteLine(combination)
filex.Close()
And, at the start of the Sub that checks for new combinations, I have this
text = File.ReadAllText("c:\Users\" + Environment.UserName + "\desktop\alreadytested.txt")
index = text.IndexOf(combination) 'checks if it has been generated already
If index >= 0 Then
keyword() 'The sub
End If
But after some combinations (in this case the max 37^3 ~= 50.000 and I the program tried around 5200 times) I get this error
An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll
And this error points in this line of code
filex = My.Computer.FileSystem.OpenTextFileWriter("c:\Users\" + Environment.UserName + "\desktop\alreadytested.txt", True)
But why? at 5200 there is still 44800 possible random combinations, why do I get an overflow?
It would make sense if I got it when I had 50000 combinations out of 50000 possible tested, but now I have 10% only, so why do I get an overflow?
You keep on recursively calling the keyword() method. Every time you call a method its return address and possibly its arguments is/are added to the call stack. The callstack can only take a certain amount of calls before it overflows, and for your computer and that specific method of yours, that amount seems to be about 5200.
You should switch to using for example a While-loop instead, and whenever you want to block the rest of the execution and go back to the beginning of the loop you'd just call Continue While.
A little side note is also that you shouldn't open and close the file every time you read/write to it. Store the contents of the file in a long string (or even better, in a HashSet(Of T)) instead and check that every time you need to, then at the end of the loop you may write all the contents to a file.
If you still wish to write to the file during the process then do so. But instead open a stream before your loop which you keep writing to until the loop is finished, then close the stream.
I want to make a program, which generate the same string each time, and it must be different on any each pc. So like HWID. After I have the string I send it into a php file on a remote host, the php handle it, and store it in the database.
On the first run it will make a new row in the table, but after 2nd run, it will select the row where the POST-ed hash = the hash in the table, and it has banned - not banned function. So if I give back 0 the pc is not banned, so program start to run, if I give back 1 the program close.
This is all made, my problem is, I generate hwid from processorid, and send it to the php. the processorid can be the same on different computers sometimes. So if I give fake ban, the users will be angry for me...
The question is:
How to generate a hash, which will be always the same on the pc which run the application, but different on each pc?
I know I can make it if I store a special id on the pc for example in the registry, but if somebody reinstall the pc, he can use again the service. If I generate hwid, it will takes him more time to find out how to access again to the service.
I dont think this really has anything to do with PHP, but entirely about the client side steps.
To do what it sounds like you want, you want to use a hardware signature made up of several things so that if one or two are unavailable, the result is still valid. This will use a form of the WMI polling procedure from the answer on your last question:
Private Shared Function GetHardwareItemInfo(item As String, wmiclass As String) As String
Dim data As String = ""
Dim query As String = String.Format("Select {0} From {1}", item, wmiclass)
Using mbs As ManagementObjectSearcher = New ManagementObjectSearcher(query)
For Each mo As ManagementObject In mbs.Get
For Each pd As PropertyData In mo.Properties
' should be only one
If String.Compare(pd.Name, item, StringComparison.InvariantCultureIgnoreCase) = 0 Then
' value is object, test for Nothing
If pd.Value IsNot Nothing Then
data = pd.Value.ToString
End If
Exit For
End If
Next
Next
End Using
Return data
End Function
This allows you to poll for different items in different wmi classes using the same code. Example:
' get the serialnumber item from the baseboard class:
answer = GetHardwareItemInfo("serialNumber", "Win32_BaseBoard")
For a hardware signature:
Get and store the info for each item
Combine them into one string
Convert the string to a byte array
Use crypto to hash the byte array
convert the result to a base64 string
There are other ways. For instance you could encode the result as a Hex string, but the above is what the code shows. First, these are the namespaces you need:
Imports System.Security.Cryptography
Imports System.Management
Imports System.Text
Then the procedure to get the stuff using the GetHardwareItemInfo method above:
' place to store bits of data
Dim HWStuff As New List(Of String)
Dim answer As String
' get and store some info
answer = GetHardwareItemInfo("serialNumber", "Win32_BaseBoard")
HWStuff.Add(answer)
answer = GetHardwareItemInfo("uuid", "win32_ComputerSystemProduct")
HWStuff.Add(answer)
answer = GetHardwareItemInfo("serialNumber", "Win32_OperatingSystem")
HWStuff.Add(answer)
'...etc
' glue the bits together into one string
Dim HWSig = String.Join("", HWStuff)
Dim byteHash As Byte()
' create crypto hasher
Using hasher = New SHA1Managed()
' convert the string to bytes
Dim tmpBytes = Encoding.UTF8.GetBytes(HWSig)
'hash the bytes
byteHash = hasher.ComputeHash(tmpBytes)
End Using
' encode as B64 string.
Dim HWHash = Convert.ToBase64String(byteHash)
Console.WriteLine(HWHash)
Result:
MUjeLeZtbTQ3Rc8zgFquBkOwFzA=
You could glue the string together as you get answers. But during development it helps to see the candidate info before you decide to use it or not.
Notes:
There are many many things to choose from. See WMI Win32 Classes.
Not everything needs to come from WMI. the LocalMachine name might be a good one (I have no idea of the context for this) as is the Windows Activation Key.
Other crypto hashers will produce longer hashes
This is far from foolproof.
Some things can be spoofed - the Win OS Serial number can be changed in the registry. You dont really care if the values are right, just that they do not change.
This is not copy protection. Someone could sniff out the token(s) sent from a legitimate system(s), then patch your app to send that token only.
if I store a special id...
No. Do not write anything down. Its impossible to keep a secret from the user on their own PC. Dont store the hash either - generate it every time. If you write it down it is easier to copy that value to a different machine.
I give fake ban, the users will be angry for me...
Since it sounds like you are working from a blacklist rather than a whitelist, you dont have to worry about the hash failing. The worst that will happen is that a system which should be denied access will get access. If you want to further reduce the chance of a match, use SHA512Managed; it will produce a longer hash though.
If a user changes one of the parts you are polling, they will still get in - it is quite unlikely that the hash from 2 systems will match (one white, one black).
I am writing a program in Visual Basic that writes and reads to and from a Microsoft Access Database. When reading from the database, one of the functions that I am trying to perform is to determine the number of lines in a multi-line string that was written to the database and then subsequently read from the database. Here's what I have tried so far with no luck.
Dim stringLines() As String = databaseReader("multilineString").ToString.Split(CChar("Environment.NewLine"))
Dim stringLinesCount As Integer = stringLines.Length
For some reason, this always results in stringLinesCount being equal to one, regardless of how many lines the string has. In this example, I am using Environment.NewLine, but I have tried \n, \r, vbCr, vbLf, and vbCrLf as well, and they all result in a value of one. Since none of these seem to be working, what can I use instead to determine the number of lines?
Edit:
Dim splitCharacters() As Char = {CChar(vbCrLf), CChar(vbCr), CChar(vbLf), CChar(Environment.NewLine), CChar("\n"), CChar("\r")}
Dim stringLines() As String = databaseReader("multilineString").ToString.Split(splitCharacters)
Dim stringLinesCount As Integer = stringLines.Length
Since Chris Dunaway provided the answer that I view as helpful but posted it as a comment, here's what he said:
VB cannot use C# style escape sequences, so CChar("\n") and CChar("\r") is meaningless in VB. Also, calling CChar("Environment.NewLine") is wrong because you are trying to convert the actual string "Environment.NewLine" to a single character, which obviously won't work. You can just use Environment.Newline directly in the call to String.Split.
If Chris decides to post his comment as an answer, please let me know so that I may remove this.