[2005] Single Instance Application
I don't ask too many questions on here these days, but I figured I would ask about this and try to see if anyone maybe has some insight.
What I am looking to do, is prevent multiple instances of my application from running. Yes I know you are probably saying "Just click the single instance application" checkbox, but unfortunatly, it is not that simple.
There is a little known, but nasty bug in VBs application framework (which is what single instance application is part of). It is detailed here by yours truly, and is still waiting for resolution by Microsoft.
If you don't feel like reading the bug submission, basically the problem is this:
the Single Instance Application feature uses .NET remoting to setup a channel to listen for, detect, and handle additional instances of a given application. .NET remoting relies on TCP/IP, and certain firewalls break this functionality (mcafee and comodo to name 2, but there are more, windows onecare/windows firewall does not cause the bug, and it has all to do with how the given firewall product handles a request before access is granted)
So anyway, since all this code wireup happens prior to the global application exception handler being hooked up, there is absolutely NO WAY to capture the socket exception that gets thrown when one of the offending firewalls blocks the remoting call. This causes a hard crash of the application. (you know the "do you want to send an error report" crash.)
A really great VBer by the name of Bill McCarthy came up with a nice solution after seeing my bug report, however it uses features only available in .NET 3.5, and I need to resolve this for apps in .NET 2.0.
So basically I need to try to find a workaround that simulates the single instance application framework, but does not use remoting to accomplish this. I have a feeling this issue will never be fixed by MS in .NET 2.0, and eventually fixed in a SP to 3.5 or perhaps not until whatever the next framework version is.
The workaround needs to
1) check for an already running instance of the app when a new instance is started up
2) shut down the new instance in the event a first instance exists
3) focus the already running instance (ie bring to front or maximize, etc)
4) send any command line params from the second instance back to the first already running instance.
So if you haven't already guessed, the thing I am stuck on at the moment is #4. All the rest are pretty simple using a few different methods.
Does anyone have a solid way to pass data between the 2 exes without remoting?
My application has file associations, so when a user double clicks a file that is associated with my app, it launches my app. This is why I need to handle this multiple instance thing, because if they double click a file, and my app is already open, I need to send that filename over to the already open instance so it can open that file as well.
If you are still reading this, sorry for the long post, but I wanted to be as descriptive as possible to try to come up with a solution.
Re: [2005] Single Instance Application
Quote:
Originally Posted by kleinma
Does anyone have a solid way to pass data between the 2 exes without remoting?
How about message queueing?
Re: [2005] Single Instance Application
I suppose anything is possible. However I guess my logical question there would be
What are the requirements of Message Queuing (IE additional redist files?, requirement on end user system?, certain OS requirement?)
It would have to be a solution that I could always guarantee to be present on an end users computer.
Re: [2005] Single Instance Application
I'm pretty sure Windows doesn't require message queueing, so I guess that would be a problem. Maybe you could create a custom event log for your applications to communicate.
Re: [2005] Single Instance Application
I recently had to do something very similar to this. I was able to accomplish it by using the StartupNextInstance event under Application Events. This allows you to read incoming parameters in an already running instance. I'm not sure if this will help you or not, I just thought I'd throw it out there...
Re: [2005] Single Instance Application
nbrege, that only works when you checkoff the "Single Instance Application" checkbox in the project, which is exactly what I can not do because of the mentioned bug. StartupNextInstance is a product of TCP remoting and the single instance application framework.
Re: [2005] Single Instance Application
How about this? In your Sub Main, get the current list of processes running on that machine, if your application is in there then bring that app to the forefront and call the close on the current instance.
Untested, but my random thought for the day.....and you help me so much I figure I should at least throw my 2 cents at ya!!!
Good Luck!
D
Re: [2005] Single Instance Application
I think you could use SendMessage Api method to send a message to the app instance main window.
To send message to the window you need its handle so you could use Process.MainWindowHandle. It is possible that there might be more than one process with the same name since there might be more than one app instance therefore you might want to loop through the all processes and send the same message to the windows that corresponds to your app.
The message can be custom message and let say Lparam or W param contains the message you want to pass.
This is not tested but worth to try.
Re: [2005] Single Instance Application
Quote:
Originally Posted by dminder
How about this? In your Sub Main, get the current list of processes running on that machine, if your application is in there then bring that app to the forefront and call the close on the current instance.
Untested, but my random thought for the day.....and you help me so much I figure I should at least throw my 2 cents at ya!!!
Good Luck!
D
Sure, but if you check my post again, the problem I am stuck on is #4, what you are talking about is #1-3 which I already have resolved.
Re: [2005] Single Instance Application
Quote:
Originally Posted by VBDT
I think you could use
SendMessage Api method to send a message to the app instance main window.
To send message to the window you need its handle so you could use Process.MainWindowHandle. It is possible that there might be more than one process with the same name since there might be more than one app instance therefore you might want to loop through the all processes and send the same message to the windows that corresponds to your app.
The message can be custom message and let say Lparam or W param contains the message you want to pass.
This is not tested but worth to try.
I have thought about using custom messages too. I actually have a few possible solutions on the table that I am currently testing, so I will post back with the proceedure and result of each of these methods once I have tested them all. Hopefully one of them is a perfect resolution to the issue.
Re: [2005] Single Instance Application
Remoting isn't tied to TCP. Perhaps there's no way to change the protocol used by the VB application framework but if you set up your own Remoting then you can use a different protocol. I'm no networking or remoting guru but maybe IPC wouldn't get interfered with by firewalls the way TCP does.
Re: [2005] Single Instance Application
John, I am actually testing an IPC solution right now after someone on another list mentioned it, I am converting one I found from C# to VB and I will post back with the results of that test.
I was actually unaware it was in .NET 2.0, I thought it was added in .NET 3.5 along with the managed named pipe classes.
I also did find an example of using unmanaged win32 apis to accomplish named pipes as well so I wouldn't need .NET 3.5 for that.
So I am sure one of these will come to resolution. Also if I find IPC works, I am going to start wondering why TCP was used for the application frameworks single instance capabilities versus IPC.
1 Attachment(s)
Re: [2005] Single Instance Application
There is a workaround using the clipboard. Here is the code that is tested and works. The only limitation is that since it uses the clipboard it will erase what ever is in there but won’t have other permission or firewall problems.
Code:
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("user32", CharSet:=CharSet.Auto)> _
Private Shared Function SendMessage( _
ByVal hwnd As IntPtr, _
ByVal wMsg As UInt32, _
ByVal wParam As IntPtr, _
ByVal lParam As IntPtr) As IntPtr
End Function
Private Const WM_CUSTOMMSG As UInt32 = 2000
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim msg As String = CStr(Date.Now.Ticks)
Me.Label2.Text = "My Tiks: " & msg
Me.Label3.Text = "My Handle: " & Me.Handle.ToString
For Each p As Process In Process.GetProcesses
If p.MainWindowTitle = Me.Text Then
My.Computer.Clipboard.SetText(msg)
SendMessage(p.MainWindowHandle, WM_CUSTOMMSG, IntPtr.Zero, IntPtr.Zero)
End If
Next
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_CUSTOMMSG Then
If My.Computer.Clipboard.ContainsText Then
Me.Label1.Text = "Message:" & Environment.NewLine _
& My.Computer.Clipboard.GetText & Environment.NewLine _
& "Target window handle: " & m.HWnd.ToString
End If
End If
MyBase.WndProc(m)
End Sub
End Class
Re: [2005] Single Instance Application
VBDT, it is a clever method of doing things, but this application goes out to hundreds of users, and I couldn't do something like that because that creates non standard behavior in Windows.
If I had an app that kept erasing whatever I might have copied to clipboard, it would drive me mad.
Re: [2005] Single Instance Application
I apologize kleinma for not taking in the part where you only need help with the last one. I was thinking on it though.....could you maybe have an external .ini type file that your program keeps a systemfilewatcher on for changes - then when your app tries to start again with variances from the currently running on you can pick them up and incorporate them via the .ini file. Maybe this is a bit far-fetched and definitely outside the box.....just a thought though :o
If/When you figure it out can you post the solution, I for one would be most interested in how this is handled.
Thanks and good luck my friend!! :wave:
D
Re: [2005] Single Instance Application
Someone else (not here) made that same suggestion about the filesystemwatcher, and while it would likely work, it does somewhat feel like a cheap hack. That's not to say its a bad idea, but if there is a better fool proof way to handle things, then that is what I am after.
So anyways, I spent pretty much ALL DAY working on this stupid issue, which annoys me because it is all because of a bug that should not exist in the first place. However, I was able to make a successful working demo that does infact do exactly what I need, and still uses remoting, just ICP remoting instead of TCP remoting. This means a firewall won't get in the way.
You can download the source code here
Please note the following things:
1) It is a VS 2008 project, however it targets .NET 2.0 framework. If you don't have VS 2008, sorry. (Or go download it. its way better)
2) I have todo comments in the exception handlers for setting up the remoting because I am not quite sure what the best course of action is in the event remoting fails for any reason and I am not sure how I want it to act yet.
3) The ZIP file doesn't contain the BIN or OBJ folders, so you need to build the project after opening it
4) After you build the project, test it OUTSIDE the IDE. This is because when you run inside the IDE, it tacks ".vshost.exe" to the end of your assemblies name, which causes the name matching not to work so it doesn't see the second instance as the same program.
There may be some revisions over the next few days as I continute to test, so I will update this thread if that happens.
Re: [2005] Single Instance Application
Quote:
Originally Posted by kleinma
VBDT, it is a clever method of doing things, but this application goes out to hundreds of users, and I couldn't do something like that because that creates non standard behavior in Windows.
If I had an app that kept erasing whatever I might have copied to clipboard, it would drive me mad.
I agree, I would not use it also but I though it might help you with some new ideas. :)