0

We are trying to setup a SysTray application which can be activated from elsewhere. To be more specific the activation will come from a third party app which we cannot modify but allows us to activate our own app via its path (plus a parameter/argument).

When it gets activated we want to put up a BalloonText, there are to be no forms involved.

Therefore we have two problems to solve:

  1. Make our SysTray application single instance (since it's no good generating multiple instances).

  2. Allow this other app to activate our application with arguments

Lots of help out there to help learners create simple SysTray applications (and indeed we've done it ourselves as part of a solution to an unconnected project). However we've never tried to make it single instance before.

Lots of help out there to help learners create single instance Winforms applications (again we've done this as part of other projects) but always simple applications with conventional forms (not SysTray). We use the VisualBasic WindowsFormsApplicationBase method.

Can't seem to combine these two approaches into a single solution.

Update:
Hans answer below nails it (and especially his comment):

This is already taken care of with a NotifyIcon, drop it on the form. And the "Make single instance application" checkbox. And the StartupNextInstance event. You'll need to stop assuming there's anything special about this

hawbsl
  • 15,313
  • 25
  • 73
  • 114
  • Have you tried selecting `Make single instance application` in the Project's properties application tab ? – Mark Hall Jul 15 '12 at 20:43
  • @MarkHall that would be too easy. If you do that, you're required to specify a conventional form as the startup. As I said, we're not using a form, just a SysTray with balloon text. – hawbsl Jul 15 '12 at 20:46
  • just asking.. I figured as much – Mark Hall Jul 15 '12 at 20:47

2 Answers2

2

As far as your first question about checking for other instances this seems to work. I used the CodeProject example as a baseline. In your Sub Main routine you can check for other instances by using the GetProcessesByName Method of the Process class. Something like this:

Public Sub Main()
    'Turn visual styles back on
    Application.EnableVisualStyles()

    'Run the application using AppContext
    Dim p() As Process
    p = Process.GetProcessesByName("TrayApp") 'Your application name here
    If UBound(p) >= 0 Then
        End
    End If
    Application.Run(New AppContext)

End Sub

For the second question if your SysTray application is already running you might want to give this article on .Net Interprocess Communication a try. Otherwise parse the CommandLine arguments in yourSub Main as it is created.

From above article:

The XDMessaging library provides an easy-to-use, zero-configuration solution to same-box cross-AppDomain communications. It provides a simple API for sending and receiving targeted string messages across application boundaries. The library allows the use of user-defined pseudo 'channels' through which messages may be sent and received. Any application can send a message to any channel, but it must register as a listener with the channel in order to receive. In this way, developers can quickly and programmatically devise how best their applications can communicate with each other and work in harmony.

Mark Hall
  • 53,938
  • 9
  • 94
  • 111
1

Everything becomes trivial when you actually do use a form. It is simple to put your app together with the designer, simple to get your app to terminate, simple to avoid a ghost icon in the tray, simple to create a context menu, simple to add popups if you ever need them.

The only un-simple thing is getting the form to not display. Paste this code in the form's class:

Protected Overrides Sub SetVisibleCore(ByVal value As Boolean)
    If Not Me.IsHandleCreated Then
        Me.CreateHandle()
        value = False
    End If
    MyBase.SetVisibleCore(value)
End Sub

The "Exit" command in the context menu is now simply:

Private Sub ExitToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExitToolStripMenuItem.Click
    Me.Close()
End Sub
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • thanks ... so is this dummy form our project's startup form or is it just ... hanging around in the background somwhere? – hawbsl Jul 16 '12 at 17:13
  • It is simply hidden, just as you would call Hide() on a visible form. You can call Show() and you'd see it. – Hans Passant Jul 16 '12 at 17:15
  • do you see it as the startup form? i ask because whether or not you have a startup form (at all) ... appears to affect whether or not you can do funky stuff with WndProc (to receive messages from other processes) and whether or not (in VB at least) you can "Enable application framework" and use the built in "Make single instance application" versus rolling your own – hawbsl Jul 16 '12 at 17:21
  • It is an entirely normal VB.NET app, no "funky stuff" needed. Why don't you just try it, takes a minute to copy/paste the code. – Hans Passant Jul 16 '12 at 17:24
  • as for trying it, your code sure hides the form, no doubt about that. i'm just trying to work in our other requirements, the systray, the single instance, the communication from an external source – hawbsl Jul 16 '12 at 17:28
  • 1
    This is already taken care of with a NotifyIcon, drop it on the form. And the "Make single instance application" checkbox. And the StartupNextInstance event. You'll need to stop assuming there's anything special about this. – Hans Passant Jul 16 '12 at 17:37
  • Hans you're absolutely right. I've just built a lightweight version from scratch this morning in a few minutes. Yes, the whole thing is taken care of by built in features. As you say, it's so much simpler than I had originally envisaged it. – hawbsl Jul 18 '12 at 09:01