VB: Encapsulating an Application Object with a Process - vb.net

I am starting an external application from Visual Basic to perform CPU and memory intensive computations. The code more or less looks like the following:
gApp = New CANoe.ApplicationgApp = New CANoe.Application
While gApp Is Nothing 'wait until CANoe started
Threading.Thread.Sleep(100)
End While
gApp.Open(canoeConfigFile, False, False)
gApp.Configuration.OfflineSetup.Source = dataFile
gMeasurement.Start()
While (gMeasurement.Running)
Threading.Thread.Sleep(1000)
End While
gApp.Quit()
Would it be possible to encapsulate the above code into a process? I am ultematelly looking for something like:
Dim canoeProcess As New Process
canoeProcess.StartInfo.FileName = "C:\Program Files (x86)\Vector CANoe 8.1\Exec32\CANoe32.exe"
canoeProcess.Start()
gApp = canoeProcess.Application
...
' (the code continues as the above)
...
The reason why I want to encapusalte the application into the process is that (i) I want to run muliple instances of the executable with different dataFiles as jobs and (ii) in case the canoe software hangs or does something weird I'd like to be able to kill the process from the VB application.
Is it possible to achieve the reverse? I.e., giving gApp Application object (that is running) to get its Process ID?
Any comments?

I believe the answer is that it is not possible. I am requesting the resources through the Windows COM interface and encapsulating it into a process might be even impossible (maybe a process does not exist at all)

Related

Starting app with Process.Start does not show in Task Manager until main application exits

I start a small application from my main application using process.start. Here is an abstract of my code: (I removed all the error-checking just for clarity...)
Dim proc as New Process
Dim si As New ProcessStartInfo
si.FileName = "SourceMonitor.exe"
si.Arguments = "guid=" & GUID & " name=" & Name & " timeout=0"
si.UseShellExecute = True
si.CreateNoWindow = True
Proc.StartInfo = si
Proc.EnableRaisingEvents = True
AddHandler Proc.Exited, AddressOf procExitEventHandler
Proc.Start()
What happens is that the new app SourceMonitor will not show up in Task Manager - but I want it to. However, it Does show up as soon as the program that launched it (using process.start) exits. This seems odd to me!
I've tried setting UseShellExecute to False, and even tried a different approach using si (my ProcessStartInfo) to
WindowStyle = ProcessWindowStyle.Hidden
si.UseShellExecute = False 'this is required when using processWindowStyle.hidden
In every case the app does not show up in Task Manager until the main program exits.
Does anyone know of a way to make sure my app does show up in Task Manager? It helps when I need to diagnose a customer issue - because I need to see if the SourceMonitor is running.
Ok - found the "issue" - and it was rather obvious...
The second process is owned by the first. It doesn't show up in the list as an independent process, rather it shows up as a child of the main process. The Task Manager has a drop-down arrow on the main application.
v MainApplication
- SourceMonitor
Clicking the dropdown shows the SourceMonitor it shelled. If I stop the main application the SourceMonitor does become an independent app and then shows up on the regular list. This actually works better than I had hoped.

Monitor Executable Use

My goal is to set up a service to watch a network folder containing about 200 .exe files. What I'd like is to have the service update a log each time one of the .exes is launched. Basically I'd like to log usage of each application by recording every time one one of them is used.
I've tried using the FileSystemWatcher class to accomplish this, code below, figuring that the LastAccess filter would do the trick, but it seems it won't. When I run this code no event is raised when the applications are opened.
Is there some way of using the FileSysteWatcher class to do this kind of monitoring? Is there any way to do what I'm attempting?
Private Sub StartWatch()
Dim exeWatcher As New FileSystemWatcher
exeWatcher.Path = "<path>"
exeWatcher.Filter = "*.exe"
exeWatcher.IncludeSubdirectories = True
exeWatcher.NotifyFilter = (NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.FileName Or NotifyFilters.DirectoryName Or NotifyFilters.Attributes)
AddHandler exeWatcher.Changed, AddressOf ExeChanged
exeWatcher.EnableRaisingEvents = True
End Sub
Private Sub ExeChanged(source As Object, e As FileSystemEventArgs)
Console.WriteLine("File: " & e.FullPath & " " & DateTime.Now.ToString())
End Sub
Take a look at this Stack Overflow answer, which involves monitoring WMI Win32_Process instance creation events (basically, when WMI registers that a new process has been created). This is probably the most effective way outside of a C++ kernel hook to find out when a process has started.
At that point, you just need to use a regular expression to test the file path against to see if it's originating from that folder, and respond appropriately if it is.
The file system watcher cannot be used to accomplish this because it doesn't know why the file is being accessed. It could be accessed to show the properties of the executable or someone copied it to their local hard drive.
If your goal is to see what machines are running your executable, you can use Windows Management Instrumentation (WMI) to remotely query a machine for Win32_Process and determine if your process is running there.

An issue with reading DB when program runs at startup in vb.net

I'm new here and to vb.net and I'm stuck on something that I feel SHOULD be simple to resolve. I setup my program to let the user decide if he or she wants to have the program run at windows start. It actually works fine as it is assigning the registry value to CurrentUser instead of Local Machine because of admin rights needing to be bypassed. However, when I restart my computer the program comes up like normal, but it will not read my access db that is located in the same folder as the program; it tries to read the DB from Windows\System32.
Is there a way to force it to read from the executablepath instead of System32?
Here is my simple code:
Private Sub startup()
If cbStartup.Checked = True Then
My.Computer.Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("Microsoft").OpenSubKey("Windows").OpenSubKey("CurrentVersion").OpenSubKey("Run", True).SetValue("CC_List", System.Windows.Forms.Application.ExecutablePath)
ElseIf cbStartup.Checked = False Then
My.Computer.Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("Microsoft").OpenSubKey("Windows").OpenSubKey("CurrentVersion").OpenSubKey("Run", True).DeleteValue("CC_List", False)
End If
End Sub
So when the O/S starts your program the Current Directory is %windir%\System32.
You need to either adjust all your existing paths to be explicitly relative to Application.ExecutablePath, or put
My.Computer.FileSystem.CurrentDirectory = My.Application.Info.DirectoryPath
at the start of your program (which is the modern version of ChDir ...).

How to kill an instance of an application

I am having a text file in this path "C:\Test\test.txt" when this was openeed I need to close this.
When I am trying to use the below code all the instances of notepad are closing and I don't want that to be happened and I want to close only the ".txt" file:
Any help would be appreciated!
Here is my code:
Dim Process() As Process = System.Diagnostics.Process.GetProcessesByName("notepad")
For Each p As Process In Process
p.Kill()
Next
You can look at the
Process.MainWindowTitle
property of p.
Notepad's title will be Filename.txt - Notepad
If you started the process yourself, you can kill it using the Process.Kill() method.
Note that in many (most?) circumstances, killing all instances of a process isn't really a good user experience since the user may have started instances of that process on their own in addition to the instance your program launched / is attempting to close.
You could do something as mentioned about using an if statement. Assuming you opened the file called test.
Dim Process() As Process = System.Diagnostics.Process.GetProcessesByName("notepad")
For Each p As Process In Process
If p.MainWindowTitle.Contains("test") Then
p.Kill()
End If
Next
EDIT:
To check for multiple files
simply add or to the .Contains line
If p.MainWindowTitle.Contains("test") Or ("blahblah") Then
p.kill()

How to find 64-bit process info using a 32-bit process

I have a 32 bit application that shells a second application that can be 32 or 64-bit depending upon the computer it's running on.
I only want one instance of the second application to run at a time, and I need the first application to prevent the second from being launched more than once.
I want to be able to use GetProcessesByName to obtain the running processes. This seems to work fine. It's when I attempt to obtain the module data to find out what folder the second application was run from that things fall apart.
Does anyone have a suggestion for identifying 64-bit processes and their folder of origin from a 32-bit application?
Thank you,
SH
You can use the WMI API (System.Management namespace) for this, specifically the ManagementObjectSearcher. The example below shows to get the process id and full command line from all running notepad instances.
Imports System.Management
Module Module1
Sub Main()
Dim wmi = New ManagementObjectSearcher("SELECT ProcessId, CommandLine FROM Win32_Process WHERE CommandLine LIKE ""%notepad%""")
Dim result = wmi.Get().OfType(Of ManagementObject)()
For Each r In result
Console.WriteLine("Process ID: {0}, Command Line: {1}" r("ProcessId"), r("CommandLine"))
Next
End Sub
End Module
I think it could be easier if you set a Mutex when launching second app.
In main app you could do this: if Mutex doesn't exist you run second app (which creates Mutex when run and release it when closing), otherwise you skip...
EDITED:
You can't edit second app to insert the creation of a mutex, ok.
But you can do this in main app:
Create a background worker BackgroudWorker wrk
Set a private bool to true: bool running = false
Execute wrk when you want the new app run: if (running) return; running = true;
wrk creates a Process and waits for its end
when wrk ends running = false
Just an idea...
EDITED AGAIN:
If you close first app and reopen it, user is able to run second app again.
So you could do this:
Create a background worker BackgroudWorker wrk
Write a tmp file (on NTFS it can be empty)
Execute wrk when you want the new app run:
if your tmp file exists then exit;
wrk creates a Process and waits for its end
when wrk ends deletes tmp file
With this method, even if user quits your first app, tmp file remains on hdd; so when user runs first app again, second app will not be executed.
Remeber that if user is smart enough to undestand this, he could manully delete file and the trick is done.
Finally: are you sure user cannot run directly second app?