I latched onto the Catia using:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim boolCatAlive As Boolean
boolCatAlive = False
Try
Dim myCatia As INFITF.Application
myCatia = Interaction.GetObject(vbNullString, "CATIA.Application")
boolCatAlive = True
Catch ex As Exception
boolCatAlive = False
End Try
Select Case boolCatAlive
Case True
'continue loading app, do my stuff
Case Else
'end this now
MsgBox("No running CATIA instance detected, please start a new CATIA instance and re-run this program.", MsgBoxStyle.Critical, "Error")
End
End Select
End Sub
So that is a simple boolean switch at the form loading that decides whether the app is going to load or not.
This works ok, but is doing the check only once when the app is started. Is there a way to continually detect CATIA status, so that - if a user exits CATIA in the middle of my app running - app gets notified and realises that the CATIA COM link is no longer alive?
I could also use that to detect selection changes for example?
You can Check it All the time by using a timer.Add a timer and specify the same code in its TICK event.sorry to Post this as an answer.I don't have enough reputation to post comment.
http://vb.net-informations.com/gui/timer-vb.htm
This link will be helpfull to you.
Thanks, it works fine.
I put this code inside Tick event, set timer to enabled, and use 1000ms interval to check every 1 second for CATIA link.
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Dim boolCatAlive As Boolean
boolCatAlive = False
Try
Dim myCatia As INFITF.Application
myCatia = Interaction.GetObject(vbNullString, "CATIA.Application")
boolCatAlive = True
Catch ex As Exception
boolCatAlive = False
End Try
End Sub
I would recommend to ask the actual Catia Object in timer instead of getting new object. Assuming you have Global CatiaApp variable
Put in the timer something like this
Try
If CatiaApp.Name.Length > 0 Then
'catia is alive
End If
Catch ex As Exception
'catia is down
CatiaApp = Nothing
End Try
You get an exception if Name.Length fails which signal that catia is down
Related
I’ve got this issue with stopping a thread cleanly. I’ve tried to simplify it into a more basic version of the code below and I’m wondering if my approach is completely wrong here.
I have Form1 with a bunch of UI elements which need updating as BackgroundCode runs (I run it here so it’s a separate thread and it doesn’t hold up the UI) I then update the UI by invoking a sub
(Me.Invoke(Sub()
something.property=something
End Sub))
I’m also trying to handle some errors handed to the application by an external file. I’ve used a timer to check for the file and if it exists I grab the contents and pass it to my ErrorHandler. This Writes the Error out to a log file, displays it on screen and then aborts the background worker so that the program doesn’t continue to run. The trouble I’m getting is that by executing BackgroundThread.Abort() that action itself is triggering the ErrorHandler. Is there a way to ask the BackgroundThread to stop cleanly? I want BackgroundThread to trigger the ErrorHandler if something else goes wrong in that code.
I’m wondering about using a global boolean like “ErrorIsRunning” to restrict the ErrorHandler sub so that it can only ever run once, but this is starting to feel more and more hacky and I’m wondering if I’ve gone completely off track here and if there might be a better way to approach the entire thing.
Public Class Form1
Dim BackgroundThread As New Thread(AddressOf BackgroundCode)
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
‘Hide Error Page
ErrorPage.Visible = False
ErrorLabel.Visible = False
‘Start Background Code
BackgroundThread.Start()
End Sub
Private Sub BackgroundCode()
Try
‘<Background code which runs over a number of minutes>
Catch.ex as Exception
ErrorHandler(“Error with BackgroundCode: “ + ex.Message)
End Try
End Sub
Private Sub Timer_Tick(sender As Object, e As EventArgs) Handles Timer.Tick
Dim ErrorFile As String = “C:\MyErrorFile.Err”
Dim ErrorContents As String
If File.Exists(ErrorFile) Then
Timer.Enabled = False
ErrorContents = File.ReadAllText(ErrorFile).Trim()
ErrorHandler(ErrorContents)
End If
End Sub
Public Sub ErrorHandler(ErrorText As String)
WriteLog(“ERROR” + ErrorText)
Me.Invoke(Sub()
Me.ErrorPage.Visible = True
Me.ErrorLabel.Text = ErrorText
End Sub)
BackgroundThread.Abort()
End Sub
End Class
Never abort threads.
This uses a Task and a ManualResetEvent. Without seeing the code inside of the background task it is hard to know how many stop checks might be needed.
Public Class Form1
Private BackgroundTask As Task
Private BackgroundTaskRunning As New Threading.ManualResetEvent(True)
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Hide Error Page
ErrorPage.Visible = False
ErrorLabel.Visible = False
'Start Background Code
BackgroundTask = Task.Run(Sub() BackgroundCode())
End Sub
Private Sub BackgroundCode()
Try
'<Background code which runs over a number of minutes>
'put stop checks periodically
' e.g.
If Not BackgroundTaskRunning.WaitOne(0) Then Exit Sub 'stop check
Catch ex As Exception
ErrorHandler("Error with BackgroundCode: " + ex.Message)
End Try
End Sub
Private Sub Timer_Tick(sender As Object, e As EventArgs) Handles Timer.Tick
Dim ErrorFile As String = "C:\MyErrorFile.Err"
Dim ErrorContents As String
If File.Exists(ErrorFile) Then
Timer.Enabled = False
ErrorContents = File.ReadAllText(ErrorFile).Trim()
ErrorHandler(ErrorContents)
End If
End Sub
Public Sub ErrorHandler(ErrorText As String)
WriteLog("ERROR" + ErrorText)
Me.Invoke(Sub()
Me.ErrorPage.Visible = True
Me.ErrorLabel.Text = ErrorText
End Sub)
BackgroundTaskRunning.Reset() 'stop task <<<<<<<<<<<<<<<<<<<<<<<<<<<
End Sub
End Class
I've been racking my brain for days over this code and I just can't seem to get it working. I've researched and researched with no luck. I have four textboxes on my form. Two textboxes is a folder location and the other two textboxes are file locations. I'm trying to use a function that will return true or false telling if the files in the two textboxes exist or not. I don't see anything at all wrong with this code and it just won't work! I'm sure it's something simple I'm overlooking. Maybe someone else can spot it!
Private Function doesFileExist(folderPath, fileName) As Boolean
If IO.File.Exists(folderPath & "\" & fileName) Then
Return True
Else
Return False
End If
End Function
Private Sub chkStart_CheckedChanged(sender As Object, e As EventArgs) Handles chkStart.CheckedChanged
If doesFileExist(txtCPU.Text, txtFileCPU.Text) And
doesFileExist(txtGPU.Text, txtFileGPU.Text) Then
If chkStart.Checked Then
chkStart.Text = "Stop Monitor"
Else
chkStart.Checked = False
chkStart.Text = "Start Monitor"
End If
Else
chkStart.Checked = False
MessageBox.Show("Please check directory & file locations!", "Error!", MessageBoxButtons.OK)
End if
End Sub
I want to mention that before I tried nested if statements on this I also tried to separate them both like so..
Private Sub chkStart_CheckedChanged(sender As Object, e As EventArgs) Handles chkStart.CheckedChanged
If Not doesFileExist(txtCPU.Text, txtFileCPU.Text) And
Not doesFileExist(txtGPU.Text, txtFileGPU.Text) Then
chkStart.Checked = False
MessageBox.Show("Please check directory & file locations!", "Error!", MessageBoxButtons.OK)
Exit Sub
End If
If chkStart.Checked Then
chkStart.Text = "Stop Monitor"
Else
chkStart.Checked = False
chkStart.Text = "Start Monitor"
End If
End Sub
Both of these ways will show the messagebox if the application is ran with the checkbox checked on start up. Not only will it show the messagebox it also shows the messagebox twice! I've yet to figure that one out!
Your check file exists can be simplified... (It's been a while since I used VB so apologies for any syntax errors, I don't have an IDE to hand)
Function DoesFileExist(Folder as String, Filename As String) As Boolean
Return IO.File.Exists(IO.Path.Combine(Folder, Filename))
End Function
Re: Changing whether the "check" checkbox is set shouldn't perform the check itself - otherwise you only check when people click. (Incidentally, I'm guessing you're getting a message twice as code elsewhere ticks/unticks this checkbox, but it's only a guess).
Private Sub chkStart_CheckedChanged(sender As Object, e As EventArgs) Handles chkStart.CheckedChanged
If chkStart.Checked Then
chkStart.Text = "Stop Monitor"
PollTimer.Start()
Else
chkStart.Text = "Start Monitor"
PollTimer.Stop()
End if
End Sub
Finally... You need to define when your check will happen. Ideally, you'd want to use a FileSystemWatcher which will give you events when the file system changes, but you can also poll using a timer...
Private PollTimer As System.Timers.Timer
Then in your Form Main, do some initial timer setup...
...
PollTimer = New System.Timers.Timer()
PollTimer.Interval = 30000 ' Seconds
AddHandler PollTimer.Elapsed, AddressOf CheckExistsNow
PollTimer.Start()
...
And finally the code to run every time we want to make the check....
Sub CheckExistsNow(sender As Object, e As System.Timers.ElapsedEventArgs)
If Not DoesFileExist(txtGPU.Text, txtFileGPU.Text) Then
' Handle the missing file.
End if
End Sub
In my project im using inputsimulator and it works great when visual studio is ran as an administrator, but when i build it into a .exe it doesn't work even when i run it as administrator. here's my code
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
AutoSaveTimer.Enabled = True
Try
System.Threading.Thread.Sleep(50)
GameConnection.SendKeyTo(Keys.OemSemicolon)
System.Threading.Thread.Sleep(2000)
GameConnection.SendKeyTo(Keys.K)
System.Threading.Thread.Sleep(50)
GameConnection.SendKeyTo(Keys.Enter)
Catch AutoSaveExeption As GameException
If AutoSaveExeption.GameErrorCode = GameError.GAME_ERR_SENDMSG Then
' Send message error - connection to Game lost.
'
MessageBox.Show("cant make a connection.... can't autosave sadly", AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
SimConnectionBar.BackColor = Color.Red
End If
End Try
End Sub
it does send focus to the window i specify but it doesn't send the keystrokes
Try using SetForegroundWindow before sending any input to ensure your game does in fact have focus.The call to SetForegroundWindow should be made in your method just before sending the input.
<DllImport("user32.dll")> _
Public Shared Function SetForegroundWindow(hWnd As IntPtr) As Boolean
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click `
AutoSaveTimer.Enabled = True
Try
'Find the handle to the game. This can do it by searching for the process.
Dim p As System.Diagnostics.Process() = System.Diagnostics.Process.GetProcessesByName("notepad")
'search for process notepad
If p.Length > 0 Then
'check if window was found
'bring notepad to foreground
SetForegroundWindow(p(0).MainWindowHandle)
End If
System.Threading.Thread.Sleep(50)
GameConnection.SendKeyTo(Keys.OemSemicolon)
System.Threading.Thread.Sleep(2000)
GameConnection.SendKeyTo(Keys.K)
System.Threading.Thread.Sleep(50)
GameConnection.SendKeyTo(Keys.Enter)
Catch AutoSaveExeption As GameException
If AutoSaveExeption.GameErrorCode = GameError.GAME_ERR_SENDMSG Then
' Send message error - connection to Game lost.
'
MessageBox.Show("cant make a connection.... can't autosave sadly", AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
SimConnectionBar.BackColor = Color.Red
End If
End Try
end sub
I am trying a simple code in Silk4Net using VB.Net. I have automated launching of a calculator. Before the numbers can be typed, a message box appears. I am unable to find a way to dismiss the message box automatically. I want to be able to recognize the message box and either push it to the back or dismiss it totally.
The code is as below:
<TestMethod()>
Public Sub TestMethod1()
With _desktop.Window("Calculator")
.SetActive()
generateMsg()
.PushButton("Clear").Select()
.PushButton("3").Select()
.PushButton("5").Select()
End With
End Sub
Public Sub generateMsg()
Thread.Sleep(2000)
With _desktop.Window(MsgBox("Test", MsgBoxStyle.Critical, "Test"))
For Each p As Process In Process.GetProcesses
If p.MainWindowTitle.Contains("Test") Then
p.Kill()
End If
Next
'With .Dialog("Test")
' '.PushButton("OK").Select()
'End With
' .Close()
End With
End Sub
Any help would be much appreciated. Thanks.
Updated answer
You could add a timer to the code that uses SendKeys.SendWait - like this - adapting it a little for your test environment as I'm not sure about Silk4Net tbh
Dim WithEvents timer1 As New System.Timers.Timer
timer1.Interval = 5000
timer1.Enabled = True
MsgBox("Hello. I will go bye-bye in 5 seconds.")
timer1.Enabled = False
And as a separate sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles timer1.Elapsed
SendKeys.SendWait("{ENTER}")
End Sub
I'm working on an application to read something from a serial port (COMM-port).
In short, it works like this: when you work in a bar or restaurant, before you can enter something in the register, you have to scan a sort of card. If this card returns a good number, you can enter something.
So, there has to be a form that listens to the serial port and checks whether someone scans a card and if it's a card with good rights.
If the person has the good rights, the form can be closed and another form is called.
Now, in code:
Here, the MenuForm is loaded (the form that has to be accesible after the correct code was read). I call the frmWaiterKey to show up.
Private Sub frmMenu_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim oForm As frmWaiterKey = New frmWaiterKey()
oForm.ShowDialog()
End Sub
The code of the class frmWaiterKey:
Private Sub frmWaiterKey_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
nameArray = SerialPort.GetPortNames
OpenComPort()
AddHandler myComPort.DataReceived, SerialDataReceivedEventHandler1
End Sub
Sub OpenComPort()
Try
' Get the selected COM port's name
' from the combo box.
If Not myComPort.IsOpen Then
myComPort.PortName = _
nameArray(0).ToString()
' Get the selected bit rate from the combo box.
myComPort.BaudRate = CInt(9600)
' Set other port parameters.
myComPort.Parity = Parity.None
myComPort.DataBits = 8
myComPort.StopBits = StopBits.One
myComPort.Handshake = Handshake.None
'myComPort.ReadTimeout = 3000
'myComPort.WriteTimeout = 5000
' Open the port.
myComPort.Open()
End If
Catch ex As InvalidOperationException
MessageBox.Show(ex.Message)
Catch ex As UnauthorizedAccessException
MessageBox.Show(ex.Message)
Catch ex As System.IO.IOException
MessageBox.Show(ex.Message)
End Try
End Sub
Sub CloseComPort()
Using myComPort
If (Not (myComPort Is Nothing)) Then
' The COM port exists.
If myComPort.IsOpen Then
' Wait for the transmit buffer to empty.
Do While (myComPort.BytesToWrite > 0)
Loop
End If
End If
End Using
End Sub
Private SerialDataReceivedEventHandler1 As New SerialDataReceivedEventHandler(AddressOf DataReceived)
' Specify the routine that runs when
' a DataReceived event occurs at myComPort.
' This routine runs when data arrives at myComPort.
Friend Sub DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
Dim newReceivedData As String
' Get data from the COM port.
newReceivedData = myComPort.ReadExisting
newReceivedData = newReceivedData.Trim()
MsgBox(newReceivedData)
If newReceivedData.Equals("00150324294764") Then
CloseComPort()
Me.Close()
End If
End Sub
I get an error in the last line: Me.Close()
I get the point: I call the form frmWaiterKey from the frmMenu and can't close it here...
But I have no idea how to solve this problem.
I hope someone can help me or tell me what I'm doing wrong.
First, you need to make a method like this:
Private Sub CloseMe()
If Me.InvokeRequired Then
Me.Invoke(New MethodInvoker(AddressOf CloseMe))
Exit Sub
End If
Me.Close()
End Sub
Then, close your form by calling that method, like this:
If newReceivedData.Equals("00150324294764") Then
CloseComPort()
CloseMe()
End If
The reason this is necessary is because all UI activity in WinForms must be performed from the same thread. Since the DataReceived method is being called from another thread, it must get back onto the UI thread before it can close the form. The InvokeRequired property returns true if you are on any thread other than the UI thread, and the Invoke method invokes the given method from the UI thread.