views:

411

answers:

6

A similar question has been asked before here

... but mine differs in the fact that I just need to control a winforms app from a web page (not bi-directional). I just need to tell the winforms app to open windows, etc. when the user clicks links inside the web app.

This is all in a secure, corporate environment, so no real worries about security.

I see 2 possible solutions:

1) create an ActiveX "shim" which can easily be embedded in the web page

2) host a WCF service in the WinForms app that listens for (REST-ful type) commands

is there a dead simple solution I am missing? Any other alternatives?

+1  A: 

Depending on the complexity of the "commands" that can be issued from the webpage to the WinForms application, you could simply register a custom URI scheme with the web browser which invokes your application. Like, for example, mailto: invokes your e-mail program, or itms: invokes the iTunes Music Store.

Your application would then recognize that an instance of it is already running and pass the arguments to the running instance.

dtb
A: 

I would register a extension for the program. You know, when you klick a xls-file, it starts excel with the url to the xls-file as a parameter, and if you klick on a play-list-file it starts your mediaplayer.

You can register an extension for (exemple) ".fro"-files that opens your program with the .fro-file as an parameter.

If your program is allready running, it gets the parameter, or else it starts the program and passes the parameter. Your program reads the file and follow the commands in the file.

So, for example, if you have a link in your web-app that should make your winform-program to open up a customer and show the customer detail, you make your web app have a link <a href="opencustomer.fro">Open customer</a>, the file opencustomer.fro could be dynamically created or static.

  1. Register the file extension ".fro" to open your .Net program. (example following)

  2. Make web site create .fro-files with commands in them.

  3. Make your .Net program to single-instance application following this tutorial ( http://visualstudiomagazine.com/articles/2007/11/01/simplify-application-instancing.aspx ) . So if a second instance is started, it sends the command$ to the first instance via named pipes.

  4. Make your .Net program download the .fro-file and interpret the command in the file. That could be as simple as just containing a customernumber to open.

I found this vb.net example about register filetypes, it should not be hard to convert or google C#-version of it: http://bytes.com/topic/net/answers/519230-vb-net-associate-file-program

Public Class Example 

    Public Sub RegisterType() 
        Dim fileReg As New FileTypeRegistrar 

        With fileReg 
            .FullPath = Path_To_Executable 
            .FileExtension = Extension_To_Register 
            .ContentType = "application/" & Your_Description 
            .IconIndex = Icon_Index_In_Application 
            .IconPath = Path_To_Executable 
            .ProperName = Name_Of_Executable 
            .CreateType() 
        End With 

    End Sub 

End Class 

Public Class FileTypeRegistrar 

#Region "Properties & Property Variables" 
    Private _ProperName As String 
    Public Property ProperName() As String 
        Get 
            Return _ProperName 
        End Get 
        Set(ByVal Value As String) 
            _ProperName = Value 
        End Set 
    End Property 

    Private _ContentType As String 
    Public Property ContentType() As String 
        Get 
            Return _ContentType 
        End Get 
        Set(ByVal Value As String) 
            _ContentType = Value 
        End Set 
    End Property 

    Private _FullPath As String 
    Public Property FullPath() As String 
        Get 
            Return _FullPath 
        End Get 
        Set(ByVal Value As String) 
            _FullPath = Value 
        End Set 
    End Property 

    Private _FileExtension As String 
    Public Property FileExtension() As String 
        Get 
            Return _FileExtension 
        End Get 
        Set(ByVal Value As String) 
            _FileExtension = Value.Replace(".", "") 
        End Set 
    End Property 

    Private _IconPath As String 
    Public Property IconPath() As String 
        Get 
            Return _IconPath 
        End Get 
        Set(ByVal Value As String) 
            _IconPath = Value 
        End Set 
    End Property 

    Private _IconIndex As Integer 
    Public Property IconIndex() As Integer 
        Get 
            Return _IconIndex 
        End Get 
        Set(ByVal Value As Integer) 
            _IconIndex = Value 
        End Set 
    End Property 
#End Region 

#Region "Public Methods" 
    Public Sub CreateType() 
        Dim fileName As String = Path.GetFileNameWithoutExtension(FullPath) 
        Dim Ext As String = "." & FileExtension.ToLower 
        Dim extKey As RegistryKey = Registry.ClassesRoot.CreateSubKey(Ext) 

        extKey.SetValue("", fileName) 
        extKey.SetValue("Content Type", ContentType) 
        extKey.Close() 

        Dim mainKey As RegistryKey = Registry.ClassesRoot.CreateSubKey(fileName) 
        Dim defIconKey As RegistryKey = mainKey.CreateSubKey("DefaultIcon") 

        defIconKey.SetValue("", IconPath & ", " & IconIndex) 
        defIconKey.Close() 

        Dim shellKey As RegistryKey = mainKey.CreateSubKey("shell") 
        Dim OpenKey As RegistryKey = shellKey.CreateSubKey("Open") 
        Dim cmdKey As RegistryKey = OpenKey.CreateSubKey("command") 

        cmdKey.SetValue("", """" & FullPath & " %1""") 
        cmdKey.Close() 
        OpenKey.Close() 
        shellKey.Close() 
        mainKey.Close() 

    End Sub 

    Public Sub DeleteType() 
        Dim fileName As String = Path.GetFileNameWithoutExtension(FullPath) 
        Dim Ext As String = "." & FileExtension.ToLower 

        Registry.ClassesRoot.DeleteSubKey(Ext) 
        Registry.ClassesRoot.DeleteSubKey(fileName) 

    End Sub 
#End Region 

End Class
Stefan
A: 

Another way to controll winformclients would be to add a webservice on the website, and let your clients poll the webservice every 2-4 seconds to see if a waiting command exists for the particularry client to execute.

Add a table to the database clientid, command, ClientDone

And when a logged in user clicks a link in the web app that should controll the winformclient, add a row in the table with the clientid and the commmand.

If the client is logged in in the winform program the winform program will poll the webservice for newly stored commands for that client. When the client has performed the command its marked as done (or just delete the row from the database)

This will assume that a user logged in on the website has same clientid/userid when logged in at the winform program.

Stefan
A: 

Since you're in a corporate environment there's probably a very close range of browsers in use. Have you thought about writing a slim Firefox add-on that interfaces with your website and forwards all commands to your WinForms app?

dtb
A: 

2) host a WCF service in the WinForms app that listens for (REST-ful type) commands

this is dead-simple... I'd opt for this

Marc Wittke
A: 

I'm looking to do something similar. In my case I want a WinForm app that hosts a WCF service. Another app on the desktop will call the WCF service (e.g. OpenCustomer(string customerId)) and the WinForm will do stuff (e.g. navigate the embedded web browser control). Did you ever find a good solution?

I'm thinking: - Invisible Singleton form "Coordinator", which is the one Program.cs starts (Application.Run(Coordinator.Instance)) - Singleton class "Service" that hosts WCF service - Form with web browser controller "WebForm". Coordinator owns the instance of WebForm.

  • calling the OpenCustomer method of Service will cause it to direct Coordinator to direct WebForm to do stuff
James McLachlan
We have not gotten around to doing the project yet that needed this solution - probably sometime in the near future though. Our approach would be similar except I dont think we'd need the invisible window part. Our .NET WinForms app would just host the WCF service ( could be a component on its main MDI form ) and respond to commands from there.
HokieMike