Click here to Skip to main content
Click here to Skip to main content
Go to top

Control Your PC App With Your Cell-Phone

, 8 Apr 2012
Rate this:
Please Sign up or sign in to vote.
Ultralight Remote Control for Your PC App using your Cell-phone's Browser

Introduction

Control your .NET PC app with your cell-phone. Without loading an app on the cellphone, you can control your PC App from a cell-phone, android, iPhone, iPad—anything with a browser by serving an HTML page with the controls and handling the input. On the way, this article shows most of the code needed to write your own web server too.

Background

There are many ways for a cellphone to control a PC app and I think this one is the easiest. I call it “Ultralight” because it only does a few things...get button presses and text input from the remote device. But if that's all you need for your app, this is straightforward.

Instead of installing an app on the remote control device (there are quite a few available), this control works entirely from the PC side. It opens a “micro-web-server” on the PC which can serve a simple HTML page to the remote device showing the controls. When the remote browser submits user input back to the PC, the control decodes it and raises an event.

Some advantages for this approach

  • It works with any device—iPhone, iPad, Android, even another PC.

  • It is reasonably secure—serving a web page is fairly safe.

  • There is no download/install needed on the remote device.

  • You can customize to display just the controls needed for your app. The UI on the remote device is simply an HTML page and is easy to customize.

  • On the remote, you can create a desktop short-cut which goes directly to the remote-control page so it is as easy as starting a phone-app.

  • As a developer, you don't have to download a bunch of tools and learn the java libraries for Android development or buy a MAC for iPhone development.

Some limitations

  • You can't do drags or other touch/mouse inputs (as written).

  • The user must key in a URL on the remote device—the remote cannot search the network automatically for your app.

  • As written, you cannot change the controls displayed on the remote device because they are served to the remote before the action is decoded by the UI event. As such, the remote also has no way of behaving properly if the app has stopped.

  • The program must have administrator privileges if Windows Account Control is enabled.

  • The firewall may block access. Although I have used this with Norton 360 with no issues on my Vista laptop, on my Windows 7 machine, the app could be controlled from a local browser but not from the remote until I edited the firewall settings to allow World Wide Web (HTTP) services.

Using the code

Download, compile and try the demo program: You can press one of the three buttons to change the window's background color—just to demonstrate some functionality. When the program is started, it also displays the URL you need to enter on your remote device browser. For testing convenience, you can try it out with a browser on your local machine first.

You should see a window like this:

Clicking the buttons will change the window background on the PC App.

Then, on your remote device, open a web-browser and enter in the URL shown in the app.

You should see screens like this:

Have fun!

To adapt the control to use in your own app: Add the control to the window which will handle the commands coming from the remote and add an event handler to handle the control's RemoteInputReceived event. This handler is called whenever input is received from the remote device. Add your own code to the event handler—usually, the various remote control events will map to controls which already exist in your window.

The demo event handler looks like this:

private void remoteControl11_RemoteControl(object sender, RoutedEventArgs e1)
{
     var e = e1 as RemoteControl1.RemoteControlEventArgs;
     if (e.pageParams.ContainsKey("red"))
                buttonRed_Click(null, null);
     if (e.pageParams.ContainsKey("blue"))
                buttonBlue_Click(null, null);
     if (e.pageParams.ContainsKey("green"))
                buttonGreen_Click(null, null);
     if (e.pageParams.ContainsKey("name") && e.pageParams["name"] != "")
                textBlockHello.Text = "Hello " + e.pageParams["name"] + "!";
     else
                textBlockHello.Text = "";

}

Edit the HTML page (RemoteControl.htm) to include the controls relevant to your app. In theory, you can make the page as complex as you like but in practice, writing device-independent HTML means things should stay simple.

When the window loads (or is initialized) call “StartServer” to start the remote functionality. Call StopServer to end the remote functionality.

Under the Hood

The HttpListener is the key. In a small amount of code, I could create a rudimentary web server which can serve up an HTML page. Here's all the code needed to serve up a page and get a response:

void BackgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    // Create a listener.
    listener = new HttpListener();
    // Add the prefixes.
    listener.Prefixes.Add("http://*:" + portNumber.ToString() + "/");
    try
    {
        listener.Start();
        //read in the html page to serve
        TextReader tr = new StreamReader("RemoteControlPage.htm");
        string pageString = tr.ReadToEnd();
        while (!worker.CancellationPending)
        {
            // Note: The GetContext method blocks while waiting for a request. 
            HttpListenerContext context = listener.GetContext();
            if (context.Request.HttpMethod == "POST")
            {
                //this is a POST, handle the input parameters
                var body = new StreamReader(context.Request.InputStream).ReadToEnd();
                ParsePostParameters(body);
                worker.ReportProgress(1); //raise the event
            }
            // Set up the response object to serve the page
            byte[] buffer = System.Text.Encoding.UTF8.GetBytes(pageString);
            context.Response.ContentLength64 = buffer.Length;
            context.Response.OutputStream.Write(buffer, 0, buffer.Length);
            context.Response.Close();
        }
        listener.Stop();
    }
    catch (Exception e1)
    {
        if (!cancelling)
            MessageBox.Show("Remote Listener failed. " + e1.Message);
    }
}

The HttpListener has a few inconveniences for the developer:

  • It is a blocking function so it needs to be put in its own thread. I put it in a BackGroundWorker thread because it was easy. I use the ReportProgess functionality of the BackgGroundWorker whenever a message is received from the remote device, this way, the result ends up back in the UI thread where it can be used to control the other actions.

  • The HttpListener leaves the developer on your own to parse any parameters. I parse them into a Dictionary (static) and pass it back to the UI thread in the event. Determining the user input from the Dictionary is just a matter of asking if it Contains a certain key or getting the value associated with a key. The key is the “name” of the control in the HTML and is case sensitive. Here is the input parser:

private static void ParsePostParameters(string body)
{
    //format:  name1=value1&name2=value2&name3=value3
    string[] stringParams = body.Split('&');
    pageParams.Clear();
    foreach (string s in stringParams)
    {
        int index = s.IndexOf('=');
        if (index > -1)
        {
            string key = s.Substring(0, index);
            string value = s.Substring(index + 1);
            value = System.Uri.UnescapeDataString(value); //removes all the 'secret' character encoding
            pageParams.Add(key, value);
        }
    }
}
  • If User Account Control (UAC) is enabled, HttpListener requires administrator privileges. To cope with this, I added a manifest file to the demo application with the line:
<requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />

Points of Interest

Here's an interesting browser quirk: Unlike IE, the android browser on my phone ignores port numbers entered into its address bar. If I key in http://myPC:9999, the browser actually goes to http://myPC:80 instead. That's the reason I use port 80 for the remote. Since I am running a web server on my development machine, I have to shut it down (Command Prompt: “net stop was”) whenever I want to run the remote control program and restart it (Command Prompt: “net start w3svc”) when I'm done.

Here's another browser quirk: If I touch buttons on the web page, there is a noticeable delay before the PC program responds. If I hold the button for a moment, the response time is essentially instant when I release the button. I speculate that there may be a Javascript way to eliminate the delay if it is a problem for your app. I tried using 'onmousedown' on the buttons and this worked when I tried it on IE but not on the Android. Suggestions are welcome.

NOTE: this is the kind of little app/control which is intended to be cross-platform is exceedingly difficult for a lone developer to test because many external factors could make it not work. I would appreciate feedback on the platforms/configurations where it works (or not) to help make it more useful.

History

Initial submission 4/6/12

Fixed some typos 4/8/12

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

CharlieSimon

United States United States
An avid sailor, I combine writing useful programs with travel, sailing, diving, sailing...did I mention sailing?
 
I also used to work at Microsoft.
 
Try out my latest free sail racing management app, "Committee Boat Suite," here.
 
Most of my code posts are extracted from the app.
Follow on   Google+

Comments and Discussions

 
GeneralExcelent,.... Pinmembercoolerfire25-Jul-14 1:19 
QuestionImage are not showing in the html page Pinmembersitharamax12315-Jan-14 2:50 
QuestionHow to use remote device as a other hardware device. PinmemberVerma.No.19-Aug-13 1:24 
Questionproblem PinmemberRamiro Madriaga13-Mar-13 9:32 
AnswerRe: problem PinmemberJibesh13-Mar-13 9:49 
GeneralRe: problem PinmemberRamiro Madriaga13-Mar-13 9:57 
GeneralRe: problem PinmemberJibesh13-Mar-13 10:00 
GeneralRe: problem PinmemberCharlieSimon13-Mar-13 10:16 
Questionexe file of the project PinmemberMember 77979678-Jan-13 3:37 
GeneralMy vote of 4 PinmemberMember 77979676-Jan-13 0:59 
Questionbar code scanning PinmemberMember 931878528-Jul-12 4:13 
AnswerRe: bar code scanning PinmemberCharlieSimon28-Jul-12 12:24 
GeneralRe: bar code scanning PinmemberMember 931878529-Jul-12 5:38 
GeneralRe: bar code scanning PinmemberMember 931878530-Jul-12 1:53 
GeneralRe: bar code scanning PinmemberCharlieSimon31-Jul-12 1:32 
QuestionChange the controls on the htm page Pinmemberdiogocc15-May-12 0:55 
AnswerRe: Change the controls on the htm page PinmemberCharlieSimon15-May-12 2:04 
GeneralRe: Change the controls on the htm page Pinmemberdiogocc16-May-12 3:20 
GeneralRe: Change the controls on the htm page PinmemberCharlieSimon16-May-12 5:18 
GeneralRe: Change the controls on the htm page Pinmemberdiogocc16-May-12 11:47 
GeneralRe: Change the controls on the htm page PinmemberCharlieSimon31-Jul-12 8:02 
QuestionClick Once Deployment [modified] PinmemberTed Goulden16-Apr-12 13:04 
AnswerRe: Click Once Deployment PinmemberCharlieSimon16-Apr-12 17:57 
GeneralRe: Click Once Deployment PinmemberTed Goulden16-Apr-12 21:05 
GeneralRe: Click Once Deployment PinmemberCharlieSimon17-Apr-12 4:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 9 Apr 2012
Article Copyright 2012 by CharlieSimon
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid