How to send bytes through RS-232C serial? - vb.net

Because vb.net no longer accepts ChrB for communication via RS-232C. In older days (vb6), one can use code (assuming we paste comRs MSComm control on the form) like the below:
Public Sub M__RsSb(Sb As Integer)
Dim b() As Byte
b = ChrB(Sb)
comRs.Output = b
End Sub
I think that one must try to send bytes instead of Sb above in the case of the new Visual Basic (vb.net). First, one must know the corresponding hex value for Sb. For example, let us assume this is &HFE. So, the migration (from vb6 to vb.net) will be like the below:
Public Sub M__RsSb(ByVal Sb As Byte())
Dim b As Byte() = {&HFE}
SerialPort.Write(b,0,b.Length)
End Sub
But, I think it is correct. Do you have any advice on that?

Related

Visual Basic - newbie question - unable to assign user input to a class property

I am trying to take the user input and assign it to a property defined in a class. When I run the program, it asks for user input as expected, but displays a different result. Can someone point out where my mistake is ?
I was trying to base my simple program on this tutorial
https://learn.microsoft.com/en-us/dotnet/core/tutorials/vb-with-visual-studio
but trying to extend it to classes.
I am using the latest version of Visual Studio and Visual Basic. It's a visual basic Console App
Module Module1
Sub Main()
Dim ClassInstance As New Class1()
Console.WriteLine("Input Property 1: ")
ClassInstance.Property1 = Console.Read()
Console.Write(ClassInstance.Property1)
Console.ReadKey(True)
End Sub
Public Class Class1
Public Property1 As Integer
Public Property2 As Integer
End Class
End Module
Expected output:
"Input Property 1:" |
User input 50 |
Output 50
Console.Read reads the next character from the input, and gives you that character's code. If, for instance, you typed 5 at the prompt1, Console.Read would return 53. Why? Because that's the ASCII/Unicode code for that character (in Unicode terms, it's U+0035, which is the same number represented in hexadecimal).
If you want to read multiple characters and interpret them as an integer, you should a) be using something other than Console.Read to take the input and b) use Int32.TryParse to try to turn it into a number (because users don't always give us the input we expect).
Something like:
Module Module1
Sub Main()
Dim ClassInstance As New Class1()
Console.WriteLine("Input Property 1: ")
Dim inp = Console.ReadLine()
Dim value as Int32
If Int32.TryParse(inp, value) Then
ClassInstance.Property1 = value
Console.Write(ClassInstance.Property1)
Console.ReadKey(True)
End If
End Sub
Public Class Class1
Public Property1 As Integer
Public Property2 As Integer
End Class
End Module
(With apologies if I've made syntax errors - my VB's quite rusty)
In reality, you'd probably want to write some form of loop that prompts for user input and doesn't terminate until it successfully parses. I think Do/While would fit there - but if you're going to prompt the user more than once, you probably would want to extract the "Loop until valid input received" code into a function that takes the prompt as a parameter.
More reading - ASCII/Unicode. For characters in the "7-bit ASCII" range, basic latin characters without accents, it doesn't make much difference which references you check
1And it doesn't matter if you carried on and typed any more characters, your program only asks for/gets one of them

read event log detail in vb.net

I'm writing a application at the moment, part of it will be scraping some information from the windows event log, it mostly works....
Dim strValue As String
Dim objLogs() As EventLog
Dim Logname As String = "Application"
Dim objEntry As EventLogEntry
Dim objLogEntry As EventLogEntry
Dim objLog As EventLog
objLogs = EventLog.GetEventLogs()
For Each objLog In objLogs
If objLog.LogDisplayName = Logname Then
For Each objLogEntry In objLog.Entries
WriteLine("EventID")
WriteLine("Machinename")
WriteLine("message")
Next
Exit For
End If
Next
This will happily write out the EventID, machine name and event message.
details tab in event viewer
What I can't figure out is how to output the "details" tab in event viewer ideal into strings or similar.
MSDN isn't being helpful, could anyone point me in the right direction please?
Thanks in advance,
Looks like the details in the EventLogEntry is represented by the Data property that is stored as a byte array. You would have you would have to then converted to something readable. But the format of the data seems to vary on the Windows OS version.
Here an alternative way to do it. Code copied from answer to from the following question and converted to VB.Net.
Serializing a .NET EventLogEntry instance to XML
Imports System.Diagnostics.Eventing.Reader
Sub Main()
Dim query As New EventLogQuery("System", PathType.LogName)
Dim watcher As New EventLogWatcher(query)
AddHandler watcher.EventRecordWritten, AddressOf watcher_EventRecordWritten
watcher.Enabled = True
Console.ReadLine()
End Sub
Public Sub watcher_EventRecordWritten(sender As Object, e As EventRecordWrittenEventArgs)
Console.WriteLine(e.EventRecord.ToXml())
End Sub
Put in the main module of a simple console application and an watches for system events. Writing out the event data converted to XML as one long string.
Worked using 4.5 framework on a Windows 7 machine.

Visual Basic.NET - Add two numbers (I/O from file)

Following code should sum two numbers from file "input.txt" and write the sum to "output.txt". Compilation is succesfull, but "output.txt" is still empty after running program. What am I doing wrong?
Imports System.IO
Public Class test
Public Shared Sub Main()
Dim scan as StreamReader = new StreamReader("input.txt")
Dim writer as StreamWriter = new StreamWriter("output.txt", True)
Dim input as String
input = scan.ReadLine()
Dim ab() as String = Split(input)
Dim res as Integer = Val(ab(0))+Val(ab(1))
writer.writeLine(res)
writer.close()
End sub
End class
Your code works properly for me, so as long as your input file is formatted properly (i.e. a single line with two numbers separated by spaces, like "1 2") and you have the necessary OS permissions to read and write to those files, then it should work for you too. However, it's worth mentioning that there are several issues with your code that would be good to correct, since the fly in the face of typical best-practices.
First, you should, as much as possible, turn Option Strict On. I know that you have it Off because your code won't compile with it On. The following line is technically misleading, and therefore fails with Option Strict On:
Dim res As Integer = Val(ab(0)) + Val(ab(1))
The reason if fails is because the Val function returns a Double, not an integer, so, technically, depending on the contents of the file, the result could be fractional or could be too large to fit in an Integer. With Option Strict Off, the compiler is essentially automatically fixing your code for you, like this:
Dim res As Integer = CInt(Val(ab(0)) + Val(ab(1)))
In order to set the res variable equal to the result of the calculation, the more capable Double value must be converted down to an Integer. When you are forced to put the CInt in the code yourself, you are fully aware that the conversion is taking place and what the consequences of it might be. When you have Option Strict Off and it inserts the conversion behind-the-scenes, then you may very well miss a potential bug.
Secondly, the Val function is old-school VB6 syntax. While it technically works fine, it's provided mainly for backwards compatibility. The new .NET equivalent would be to use Integer.Parse, Integer.TryParse or Convert.ToInt32.
Thirdly, you never close the scan stream reader. You could just add scan.Close() to the end of your method, but is better, when possible, to create Using blocks for any disposable object, like this:
Using scan As StreamReader = New StreamReader("test.txt")
Using writer As StreamWriter = New StreamWriter("output.txt", True)
Dim input As String
input = scan.ReadLine()
Dim ab() As String = Split(input)
Dim res As Integer = Integer.Parse(ab(0)) + Integer.Parse(ab(1))
writer.WriteLine(res)
End Using
End Using
Lastly, as Hans pointed out, it's not good to rely on the current directory. It's always best to specify full paths for your files. There are different methods in the framework for getting various folder paths, such as the user's desktop folder, or the download folder, or the temp folder, or the application folder, or the current application's folder, or the folder of the current running assembly. You can use any such method to get your desired folder path, and then use Path.Combine to add the file name to get the full file path. For instance:
Dim desktopFolderPath As String = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
Dim inputFilePath As String = Path.Combine(desktopFolderPath, "input.txt")
Dim outputFilePath As String = Path.Combine(desktopFolderPath, "output.txt")

VB.net Passing a structure to unmanaged dll

I'm migrating some VB6 code to VB.net,
the code contains a structure that contains 1d arrays, 2d arrays, and few other variables.
The general outline of the Vb.net structure is as under
Public Structure Test
Dim a As Single
Dim b As Single
Dim c As Single
<VBFixedArray(2)> Dim arr1() As Single
<VBFixedArray(2, 2)> Dim mdarr1(,) As Single
<VBFixedArray(4)> Dim arr2() As Byte
<VBFixedArray(4)> Dim arr3() As Short
<VBFixedArray(3, 2)> Dim mdarr2(,) As Integer
Dim d As Integer
Dim e As Decimal
End Structure
The call to the dll is declared as under
Public Declare Sub getState Lib "val.dll" (ByRef state As Test)
Elsewhere on this site I realized that we have to "marshal" the structure to allow it to be compatible with the unmanaged code that is about to accept it.
However I still receiving runtime errors when running the code, I don't have any clue of how to use the System.Runtime.InteropServices.Marshal class.
What would be the correct way to pass this structure to the dll?
EDIT:
The original VB6 data type is
Public Type Test
a As Single
b As Single
c As Single
arr1(0 To 2) As Single
mdarr1(0 To 2, 0 To 2) As Single
arr2(0 To 4) As Byte
arr3(0 To 4) As Integer
mdarr2(0 To 3, 0 To 2) As Long
d As Long
e As Currency
End Type
Do you have the source code for getState in the val.dll? If it's written in C or C++, and you have the source code or even just the headers, you could use the P/Invoke Assistant to automatically generate your VB.Net code.
Alternatively... (and please do post the original VB6 structure!)
You might need to allocate the arrays before calling getState, e.g. state.arr1 = {0.0, 0.0} etc.
The Decimal variable e could cause you a problem. In VB6 this was probably a Currency variable, and Decimal is not an exact equivalent as far as I can remember. There will be a way to tell VB.Net to marshal it like a Currency. Perhaps adding an attribute like this...
Sample code:
Imports System.Runtime
Public Structure Test
''blah blah
<InteropServices.MarshalAs(InteropServices.UnmanagedType.Currency)> _
Dim e As Decimal
''blah blah

Weird problem with List(Of T) declaration and .add

I have this really weird problem in my code (.Net Framework 3.5). So, in a normal VB.NET program, I would do something like this :
Dim MyList As New List(Of Integer)
MyList.Add(3)
MyList.Add(5)
MyList.Add(9)
MyList.Add(17)
And if I put a "break" rigth after
Dim MyList As New List(Of Integer)
and put the mouse over "MyList" while code is paused, I should get : Count=0. However, I have a sub where I create a list just that way and get (when I break after it) : "Count = Property evaluation failed".
It seems like if my list has not enough space to hold the data... Here's the complete code I use to try out everything (by the way, the code itself doesn't really make sense since it's a part of my project). With it I can create the "weird" behavior and anyone can test this. Here's the code (sorry the Code Block button isn't working) :
Structure lPossibilitiesOutputStruct
Dim Pinion As GearOutputStruct
Dim Gear As GearOutputStruct
Dim Forces As ForcesStruct
Dim CenterDistance As Double
Dim Pitch As Double
Dim lStagePossibilities As List(Of lPossibilitiesOutputStruct)
End Structure
Structure GearOutputStruct
Dim TeethNbr As Integer
Dim RPM As Double
Dim FaceWidth As Double
Dim OutsideDiameter As Double
Dim Addendum As Double
Dim WholeDepth As Double
Dim OperatingPitchDiameter As Double
Dim OverPinData As OverPinOutputStruct
Dim SpanData As SpanOutputStruct
Dim AllowableBendingPower As Double
Dim AllowablePittingPower As Double
End Structure
Structure OverPinOutputStruct
Dim PinDiameter As Double
Dim OverpinMeasurement As Double
End Structure
Structure SpanOutputStruct
Dim TeethNbr As Integer
Dim SpanMeasurement As Double
End Structure
Structure ForcesStruct
Dim GearSetAxialForce As Double
Dim GearSetRadialForce As Double
Dim GearSetTangentialForce As Double
End Structure
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim lStagePossibilities As New List(Of lPossibilitiesOutputStruct)
Dim MyList As New List(Of Integer)
MyList.Add(3)
MyList.Add(5)
MyList.Add(9)
MyList.Add(17)
lStagePossibilities = lGeneratePossibilities(Nothing, Nothing, 3, 1)
End Sub
Private Function lGeneratePossibilities(ByVal ActualStage As lPossibilitiesOutputStruct, ByVal CSL As List(Of Integer), ByVal MaxStage As Integer, ByVal CumulatedRatio As Double) As List(Of lPossibilitiesOutputStruct)
Return Nothing
End Function
All I did is create a new project with a form and created that code. There's nothing else in the project. I played with the "targeted CPU" and that's all...
If I run that program with compile option to use x86 CPU, and put a break on the "lStagePossibilities = ..." I get the "Count = Property evaluation failed" when i put my mouse over MyList. If I run it with the x64 CPU, then everything is working fine... ("Count = 4"). If I go back with the x86 CPU, I get back the error. Even worst, if I comment the line "Dim Pinion as GearOutputStruct" or the line "Dim Gear as GearOutputStruct" or the line "Dim Forces as ForcesStruct" in the lPossibilitiesOutPutStruct structure declaration, then everything works fine with x86 CPU...
Could it be related to a kind of maximum size of a list ???
Thank you !
Jean
I bet if you changed some of the Strucures into Classes the problem will go away. It is a well known bug in Visual Studio that when Structures get large and try to allocate a lot of local memory things go bad in the debugger. Some of the structures contain other structures and the memory adds up. I bet in x64 the size of the structs gets bigger, due to packing.
To quote some MSDN blogs
Just so others know too. This issue was because of a large struct in my code as well. I converted it to a class and I could read the values of variables hovering over the objects. It worked in some functions and classes, but the error message where the large struct was contained had the error "Cannot evaluate expression because a thread is stopped at a point where garbage collection is impossible, possibly because the code is optimized." and it went away upon making the change. Hope it helps and confirms the solution.
To clarify, what is too big. My Struct has (rather had) ...
55 public variables
A constructor with 6 parameters
Two public functions (one of those was small and one was large, about 200 lines of code)
I believe structs are intended to be used as small containers of straight forward, simple, cohesive data and functionality, and I would agree that this one got too far out of hand. It started out small, of course, and the needs ballooned. Now that it's in a class where the cohesive data and functionality is now contained there, I can sleep at night. =)
It took me all of 5 minutes to convert it to a class. Easy enough.