JD Roberson
JD Roberson

Reputation: 599

How to call a function between two WinForm applications over the network?

I have a video kiosk setup in my lobby, it lets people check in and print a badge with their picture, name, etc. There is also a remote support tool that unfortunately crashes sometimes. I have a function on the kiosk that fixes this issue but you must go to the kiosk to trigger it right now.

I have also written a management tool that uses WMI to monitor and manage some other aspects of the kiosk. I would like to be able to trigger this repair function via this application. I have spent countless hours on google trying to figure this out with no luck. Maybe I am not searching for the right things.

My question is this. In C# how can I call the repair function in my kiosk application from the admin application over the network?

Upvotes: 3

Views: 1092

Answers (1)

user153923
user153923

Reputation:

OK, on my Server form, I have a BackgroundWorker that runs a TcpListener. You will want to put this TcpListener in a BackgroundWorker, otherwise you will never be able to stop it from executing until it accepts a TcpClient.

Also, you will want to process any data you receive from this background thread in the main thread of execution to prevent cross thread exceptions:

private TcpListener _listener;
private const int port = 8000;

private void Worker_TcpListener(object sender, DoWorkEventArgs e) {
  BackgroundWorker worker = sender as BackgroundWorker;
  do {
    try {
      _listener = new TcpListener(IPAddress.Any, port);
      _listener.Start();
      TcpClient client = _listener.AcceptTcpClient(); // waits until data is avaiable
      int MAX = client.ReceiveBufferSize;
      NetworkStream stream = client.GetStream();
      Byte[] buffer = new Byte[MAX];
      int len = stream.Read(buffer, 0, MAX);
      if (0 < len) {
        string data = Encoding.UTF8.GetString(buffer);
        worker.ReportProgress(len, data.Substring(0, len));
      }
      stream.Close();
      client.Close();
    } catch (SocketException) {
      // See MSDN: Windows Sockets V2 API Error Code Doc for details of error code
    } catch (ThreadAbortException) { // If I have to call Abort on this thread
      return;
    } finally {
      _listener.Stop();
    }
  } while (!worker.CancellationPending);
}

This would not be good for large messages (like JPEG files and such), but works great for short strings where I have coded in special data to look for.

This data is sent back to my main thread of execution (using the ReportProcess method) where the data is processed:

private void Worker_TcpListener(object sender, ProgressChangedEventArgs e) {
  if (e.UserState != null) {
    int len = e.ProgressPercentage;
    string data = e.UserState.ToString();
    if (!String.IsNullOrEmpty(data) && (3 < len)) {
      string head = data.Substring(0, 3);
      string item = data.Substring(3);
      if (!String.IsNullOrEmpty(item)) {
        if (head == "BP:") {
          string[] split = data.Split(';');
          if (2 < split.Length) {
            string box = split[0].Substring(3); // Box Number
            string qty = split[1].Substring(2); // Quantity
            string customer = split[2].Substring(2); // Customer Name
            MyRoutine(box, qty, customer);
          }
        }
      }
    }
  }
}

The code above just sits and runs all day long.

Meanwhile, I have about 10 Pocket PC devices in our plant that could send data at any time. The code for them is written in VB, and I really hope I have time to finish my C# version one of these days, but here it is:

Private Sub SendToServer(string serialNum, int qty, string customer)
  Cursor.Current = Cursors.WaitCursor
  Try
    Dim strPacket As String = String.Format("BP:{0};Q:{1};C:{2};", serialNum, qty, customer)
    Dim colon As Integer = p7_txtIPAddress.Text.IndexOf(":")
    Dim host As String = p7_txtIPAddress.Text.Substring(0, colon)
    Dim port As Integer = CInt(p7_txtIPAddress.Text.Substring(colon + 1))
    Dim dataPacket As [Byte]() = Encoding.ASCII.GetBytes(strPacket)
    Using client As New TcpClient(host, port)
      Dim stream As NetworkStream = client.GetStream()
      stream.Write(dataPacket, 0, dataPacket.Length)
    End Using
  Catch err As Exception
    MessageBox.Show(err.Message, "Print To Server TCP Error")
  Finally
    Cursor.Current = Cursors.Default
  End Try
End Function

I don't know if that is what you are trying to do, but it works and is reliable.

Obviously, the code I have in production is larger and includes other things (i.e. employee validation, error loggers, etc.) that you would not find useful. I have cut a lot of those out, and I hope I did not cut out anything necessary.

This should give you an idea of how to move forward, at least.

Upvotes: 2

Related Questions