Handling URL Protocol without application restarts - c#

My question is all about URL Protocols.
I have registered a URL Protocol called mcm, but I noticed that everytime I run it from any web browser, t creates a new instance of the application. Is there any way to handle the protocol request in an already running instance?
For example, when uTorrent is using the torrent protocol It handles the request immediately without running the app again. I couldn't really find anything interesting about it, so I am asking here...
Here is the code I use to register the protocol:
private static void RegisterUrlProtocol()
{
UnregisterUrlProtocol();
RegistryKey rKey = Registry.ClassesRoot.OpenSubKey(UrlProtocol, true);
if (rKey == null)
{
rKey = Registry.ClassesRoot.CreateSubKey(UrlProtocol);
rKey.SetValue("", "URL: MazCraft Protocol");
rKey.SetValue("URL Protocol", "");
rKey = rKey.CreateSubKey(#"shell\open\command");
rKey.SetValue("", "\"" + Application.ExecutablePath + "\" %1");
}
if (rKey != null)
{
rKey.Close();
}
}
And the code to read the arguments:
private static bool CheckForProtocolMessage()
{
string[] arguments = Environment.GetCommandLineArgs();
if (arguments.Length > 1)
{
string[] args = arguments[1].Split(':');
args[1] = args[1].Replace("//", "");
if (args[0].Trim().ToUpper() == "MCM" && args.Length > 1)
{
string[] actionDetail = args[1].Split('=');
if (actionDetail[0].Trim().ToUpper() == "INSTALL" && actionDetail.Length > 1)
{
string id = actionDetail[1].Trim().Replace("/", "");
Funcs.ID = id;
return true;
}
}
}
return false;
}
Any help would be greatly appreciated :)
Greetings.

You could use a Mutex to detect an instance of the application that is already running and send the data over to the existing instance via Named Pipes.
Hope the following example helps.
you can swap out the named pipes object (in this case string) for whatever serializable object you like.
NamedPipe.cs
namespace SingleInstanceNP
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using System.IO;
public class NamedPipe<T> : IDisposable
{
#region Attribute and Properties
private string _pipeName;
private NamedPipeServerStream _pipeServer;
private bool _disposed;
private Thread _thread;
private bool _started;
#endregion
#region Constructors
public NamedPipe(NameTypes pipeType)
{
_disposed = false;
_started = false;
_pipeName = pipeType.ToString();
_thread = new Thread(Main);
_thread.SetApartmentState(ApartmentState.STA);
_thread.Name = "NamePipe: " + pipeType.ToString() + " Thread";
_thread.IsBackground = true;
}
~NamedPipe()
{
Dispose();
}
#endregion
#region Events
public delegate void Request(T t);
public event Request OnRequest;
#endregion
#region Public Methods
public static void Send(NameTypes pipeType, T t)
{
using (var npc = new NamedPipeClientStream(".", pipeType.ToString(), PipeDirection.Out))
{
var bf = new BinaryFormatter();
npc.Connect();
bf.Serialize(npc, t);
}
}
public static T Recieve(NameTypes pipeType)
{
using (var nps = new NamedPipeServerStream(pipeType.ToString(), PipeDirection.In))
{
return Recieve(nps);
}
}
public void Start()
{
if (!_disposed && !_started)
{
_started = true;
_thread.Start();
}
}
public void Stop()
{
_started = false;
if (_pipeServer != null)
{
_pipeServer.Close();
// disposing will occur on thread
}
}
public void Dispose()
{
_disposed = true;
Stop();
if (OnRequest != null)
OnRequest = null;
}
#endregion
private void Main()
{
while (_started && !_disposed)
{
try
{
using (_pipeServer = new NamedPipeServerStream(_pipeName))
{
T t = Recieve(_pipeServer);
if (OnRequest != null && _started)
OnRequest(t);
}
}
catch (ThreadAbortException)
{ }
catch (System.IO.IOException iox)
{
Console.WriteLine("ERROR: {0}", iox.Message);
Thread.Sleep(TimeSpan.FromSeconds(30));
}
catch (Exception ex)
{
Console.WriteLine("ERROR: {0}", ex.Message);
return;
}
}
}
private static T Recieve(NamedPipeServerStream nps)
{
var bf = new BinaryFormatter();
try
{
nps.WaitForConnection();
var obj = bf.Deserialize(nps);
if (obj is T)
return (T)obj;
}
// Catch the IOException that is raised if the pipe is
// broken or disconnected.
catch (IOException e)
{
Console.WriteLine("ERROR: {0}", e.Message);
}
return default(T);
}
#region Enums
public enum NameTypes
{
PipeType1
}
#endregion
}
}
Program.cs
Please give credit for the APP GUID to What is a good pattern for using a Global Mutex in C#?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Threading;
namespace SingleInstanceNP
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// get application GUID as defined in AssemblyInfo.cs
string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();
// unique id for global mutex - Global prefix means it is global to the machine
string mutexId = string.Format("Global\\{{{0}}}", appGuid);
using (var mutex = new Mutex(false, mutexId))
{
try
{
if (!mutex.WaitOne(0, false))
{
//signal existing app via named pipes
NamedPipe<string>.Send(NamedPipe<string>.NameTypes.PipeType1, "test");
Environment.Exit(0);
}
else
{
// handle protocol with this instance
Application.Run(new Form1());
}
}
finally
{
mutex.ReleaseMutex();
}
}
}
}
}
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SingleInstanceNP
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// start listening for named pipe connections
var namedPipeString = new NamedPipe<string>(NamedPipe<string>.NameTypes.PipeType1);
namedPipeString.OnRequest += new NamedPipe<string>.Request(namedPipeString_OnRequest);
namedPipeString.Start();
}
void namedPipeString_OnRequest(string t)
{
MessageBox.Show(t);
}
}
}

Related

Visual Studio Thread Statement gives Error?

I decompiled a .NET Application to write my own Injection Software. A Thread Error don't want to get removed. I tried everything but it keeps telling me that something is wrong...
Code (Screenshot)
{
using System;
using System.IO;
using System.IO.Pipes;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
internal class NamedPipes
{
public static string luapipename = "IDUNNOPIPE123";
public static void LuaPipe(string script)
{
if (NamedPipeExist(luapipename))
{
new Thread (delegate {
try
{
using (NamedPipeClientStream stream = new NamedPipeClientStream(".", luapipename, PipeDirection.Out))
{
stream.Connect();
using (StreamWriter writer = new StreamWriter(stream, Encoding.Default, 0xf423f))
{
writer.Write(script);
writer.Dispose();
}
stream.Dispose();
}
}
catch (IOException)
{
MessageBox.Show("Error occured connecting to the pipe.", "Connection Failed!", MessageBoxButtons.OK, MessageBoxIcon.Hand);
}
catch (Exception exception1)
{
MessageBox.Show(exception1.Message.ToString());
}
}).Start();
}
else
{
MessageBox.Show("Please Inject " + Functions.exploitdllname + " before Using this!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
public static bool NamedPipeExist(string pipeName)
{
bool flag;
try
{
int timeout = 0;
if (!WaitNamedPipe(Path.GetFullPath($"\\\\.\\pipe\\{pipeName}"), timeout))
{
bool flag4;
int num2 = Marshal.GetLastWin32Error();
if (num2 != 0)
{
if (num2 != 2)
{
goto TR_0005;
}
else
{
flag4 = false;
}
}
else
{
flag4 = false;
}
return flag4;
}
TR_0005:
flag = true;
}
catch (Exception)
{
flag = false;
}
return flag;
}
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool WaitNamedPipe(string name, int timeout);
}
}
I think you are getting the The call is ambiguous between the following methods or properties: 'Thread.Thread(ThreadStart)' and 'Thread.Thread(ParameterizedThreadStart)' error with this.
As you correctly noted, the compiler can't distinguish what type the Thread constructor parameter is. ParameterizedThreadStart is used if you pass a parameter to your delegate when calling the Thread.Start method. Your code does not do this. Thus, you need a ThreadStart delegate here. Its syntax is
public delegate void ThreadStart();
I.e. it does not accept any parameter and does not return a value. So, you can just pass a lambda function that does the same.
new Thread(() => {
// ...
}).Start();

Windows service webs server cannot connect to other machines

I am attempting to design a windows service that contains a web server to do basic get request handling. Requests from the localhost work just find but I am unable to process requests from other machines. On python, setting the IP address to 0.0.0.0 allows the server to process requests from any IP on the network. I have found examples that use http://*:port/ or http://+:port/ to obtain this functionality in C# but these have not worked for me.
I am currently starting a HttpListener (WebServer.cs) when the windows service (UsherService.cs) receives its start command. If there is a better way to do this, I'd appreciate that answer as well.
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
namespace UsherService
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new UsherService()
};
ServiceBase.Run(ServicesToRun);
}
}
}
UsherService.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
namespace UsherService
{
public partial class UsherService : ServiceBase
{
WebServer ws;
public UsherService()
{
InitializeComponent();
}
public static string SendResponse(HttpListenerRequest request)
{
return string.Format("<HTML><BODY>My web page.<br>{0}</BODY></HTML>", DateTime.Now);
}
protected override void OnStart(string[] args)
{
try
{
ws = new WebServer(SendResponse, "http://*:5000/");
ws.Run();
System.IO.File.AppendAllText(#"C:\Users\kburd\Desktop\WriteText.txt", "Started Successfully");
}
catch(Exception e)
{
System.IO.File.AppendAllText(#"C:\Users\kburd\Desktop\WriteText.txt", e.Message);
}
}
protected override void OnStop()
{
System.IO.File.AppendAllText(#"C:\Users\kburd\Desktop\WriteText.txt", "Stopped Successfully");
}
}
}
WebServer.cs
using System;
using System.Net;
using System.Text;
using System.Threading;
public class WebServer
{
private readonly HttpListener _listener = new HttpListener();
private readonly Func<HttpListenerRequest, string> _responderMethod;
public WebServer(string[] prefixes, Func<HttpListenerRequest, string> method)
{
if (!HttpListener.IsSupported)
throw new NotSupportedException(
"Needs Windows XP SP2, Server 2003 or later.");
// URI prefixes are required
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
// A responder method is required
if (method == null)
throw new ArgumentException("method");
foreach (string s in prefixes)
{
_listener.Prefixes.Add(s);
System.IO.File.AppendAllText(#"C:\Users\kburd\Desktop\WriteText2.txt", s);
}
_responderMethod = method;
_listener.Start();
}
public WebServer(Func<HttpListenerRequest, string> method, params string[] prefixes)
: this(prefixes, method) { }
public void Run()
{
ThreadPool.QueueUserWorkItem((o) =>
{
Console.WriteLine("Webserver running...");
try
{
while (_listener.IsListening)
{
ThreadPool.QueueUserWorkItem((c) =>
{
var ctx = c as HttpListenerContext;
try
{
string rstr = _responderMethod(ctx.Request);
byte[] buf = Encoding.UTF8.GetBytes(rstr);
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
}
catch { } // suppress any exceptions
finally
{
// always close the stream
ctx.Response.OutputStream.Close();
}
}, _listener.GetContext());
}
}
catch { } // suppress any exceptions
});
}
public void Stop()
{
_listener.Stop();
_listener.Close();
}
}
The firewall was blocking the localhost from communicating to other devices on the network. I had to allow for communication over that port

UWP Bluetooth Low Energy Application Disconnects Early

So I am designing an application for windows laptops to connect to a custom designed pressure sensor. The application pairs to the device and then receives notifications from the device every 10 ms. Then for some reason the communication stops. I know it is a problem with my application and not with the device, because when I connect to my phone, I do not have this problem.
Here is the main page where I create the devicewatcher and discover the device:
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.Devices.Bluetooth;
using Windows.Devices.Enumeration;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace BLEInterfaceTest
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
private DeviceWatcher deviceWatcher;
private ObservableCollection<DeviceInformation> deviceList = new ObservableCollection<DeviceInformation>();
public MainPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.DataContext = deviceList;
deviceListView.ItemsSource = deviceList;
deviceWatcher = DeviceInformation.CreateWatcher(
"System.ItemNameDisplay:~~\"Button\"",
new string[] {
"System.Devices.Aep.DeviceAddress",
"System.Devices.Aep.IsConnected" },
DeviceInformationKind.AssociationEndpoint);
deviceWatcher.Added += DeviceWatcher_Added;
deviceWatcher.Removed += DeviceWatcher_Removed;
deviceWatcher.Start();
base.OnNavigatedTo(e);
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
AppViewBackButtonVisibility.Collapsed;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
deviceWatcher.Stop();
base.OnNavigatedFrom(e);
}
private async void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
{
var toRemove = (from a in deviceList where a.Id == args.Id select a).FirstOrDefault();
if (toRemove != null)
{
await this.Dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
() => { deviceList.Remove(toRemove); });
}
}
private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
{
await this.Dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
() => { deviceList.Add(args); });
}
private void deviceListView_ItemClick(object sender, ItemClickEventArgs e)
{
this.Frame.Navigate(typeof(DevicePage), e.ClickedItem);
}
}
}'
This next code is the page where the pressure sensor is connected to and where data is read from the device.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Popups;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Bluetooth;
using Windows.Devices.Enumeration;
using Windows.Storage.Pickers;
using Windows.Storage;
using Windows.Storage.Streams;
using System.Threading.Tasks;
using Windows.ApplicationModel.Background;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
namespace BLEInterfaceTest
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class DevicePage : Page
{
private DeviceInformation device { get; set; }
private PressureSensor pSensor { get; set; }
public static DateTime startTime { get; set; }
public ObservableCollection<DataPoint> PressureData = new ObservableCollection<DataPoint>();
public static ObservableCollection<DataPoint> inbetween;
private static TextBox txtP;
private BluetoothLEDevice leDevice;
private DispatcherTimer timer = new DispatcherTimer();
private int packetNum = 0;
public DevicePage()
{
this.InitializeComponent();
SystemNavigationManager.GetForCurrentView().BackRequested += DevicePage_BackRequested;
txtP = txtValue1;
inbetween = PressureData;
}
public static void ChangeText(string text)
{
txtP.Text = text;
}
private async void InitializePressureSensor(GattDeviceService service)
{
pSensor = new PressureSensor(service, SensorUUIDs.PressureSensorUuid);
await pSensor.EnableNotifications();
btnStart.IsEnabled = true;
}
private async void StartRecievingData()
{
try
{
leDevice = await BluetoothLEDevice.FromIdAsync(device.Id);
string selector = "(System.DeviceInterface.Bluetooth.DeviceAddress:=\"" +
leDevice.BluetoothAddress.ToString("X") + "\")";
var services = await leDevice.GetGattServicesAsync(BluetoothCacheMode.Uncached);
foreach (var service in services.Services)
{
if (service.Uuid.ToString() == SensorUUIDs.ButtonSensorServiceUuid)
{
InitializePressureSensor(service);
}
}
timer.Interval = new TimeSpan(0, 0, 0, 0, 1);
timer.Tick += Timer_Tick1;
startTime = DateTime.Now;
timer.Start();
}
catch (Exception ex)
{
var messageDialog = new MessageDialog("An error has occured Please try again. \n" + ex.Message, "Error!");
}
}
public async void UpdateAllData()
{
while (pSensor != null && pSensor.MorePacketsAvailable)
{
int[] values = await pSensor.GetPressure();
int packetNumber = values[0];
if (packetNumber > packetNum)
{
packetNum = packetNumber;
txtValue1.Text = Convert.ToString(values[1]);
txtValue2.Text = Convert.ToString(values[5]);
for (int i = 1; i < 5; i++)
{
PressureData.Add(new DataPoint(DateTime.Now - startTime, packetNumber, ((i-1)*2.5 + 10*packetNumber), values[i], values[i + 4]));
}
}
}
}
private void Timer_Tick1(object sender, object e)
{
UpdateAllData();
}
private async void PairToDevice()
{
if (device.Pairing.CanPair)
{
var customPairing = device.Pairing.Custom;
customPairing.PairingRequested += CustomPairing_PairingRequested;
var result = await customPairing.PairAsync(DevicePairingKinds.ConfirmOnly);
customPairing.PairingRequested -= CustomPairing_PairingRequested;
if ((result.Status == DevicePairingResultStatus.Paired) || (result.Status == DevicePairingResultStatus.AlreadyPaired))
{
/*while (device.Pairing.IsPaired == false)
{
device = await DeviceInformation.CreateFromIdAsync(device.Id);
}*/
StartRecievingData();
}
}
else if (device.Pairing.IsPaired)
{
StartRecievingData();
}
}
private void CustomPairing_PairingRequested(DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args)
{
args.Accept();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
btnSave.Content = "Save";
btnStop.IsEnabled = false;
btnStart.IsEnabled = false;
this.DataContext = PressureData;
device = (DeviceInformation)e.Parameter;
PairToDevice();
//StartRecievingData();
base.OnNavigatedTo(e);
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoBack)
{
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
AppViewBackButtonVisibility.Visible;
}
}
private void DevicePage_BackRequested(object sender, BackRequestedEventArgs eventArgs)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
return;
}
// Navigate back if possible, and if the event has already been handled
if (rootFrame.CanGoBack && eventArgs.Handled ==false)
{
eventArgs.Handled = true;
rootFrame.GoBack();
}
}
private async void btnSave_Click(object sender, RoutedEventArgs e)
{
timer.Stop();
var picker = new FileSavePicker();
picker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
picker.FileTypeChoices.Add("CSV", new List<string>() { ".csv" });
StorageFile file = await picker.PickSaveFileAsync();
if (file != null)
{
var stream = await file.OpenAsync(FileAccessMode.ReadWrite);
using (IOutputStream outputStream = stream.GetOutputStreamAt(0))
{
using (var writer = new DataWriter(outputStream))
{
foreach (DataPoint p in PressureData)
{
string text = p.TimeStamp.ToString() + "," + p.PacketNumber.ToString() + "," + p.InternalTimestamp.ToString() + "," + p.PressureValue1.ToString() + "," + p.PressureValue2.ToString() + "\n";
writer.WriteString(text);
}
await writer.StoreAsync();
await writer.FlushAsync();
}
}
stream.Dispose();
}
}
private async void btnStart_Click(object sender, RoutedEventArgs e)
{
if (pSensor != null)
{
btnStop.IsEnabled = true;
btnStart.IsEnabled = false;
startTime = DateTime.Now;
if (pSensor != null)
{
await pSensor.BeginCollecting();
}
}
}
private async void btnStop_Click(object sender, RoutedEventArgs e)
{
btnStart.IsEnabled = true;
btnStop.IsEnabled = false;
if (pSensor != null)
{
await pSensor.StopCollecting();
}
}
}
}
Here is where I define my SensorBase and PressureSensor class that handles the device connection:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Storage.Streams;
using Windows.Devices.Enumeration;
namespace BLEInterfaceTest
{
public static class SensorUUIDs
{
private static readonly string _packetUuid = "0000a043-0000-1000-8000-00805f9b34fb";
private static readonly string _buttonSensorServiceUuid = "0000a042-0000-1000-8000-00805f9b34fb";
private static readonly string _sensorStateUuid = "0000a044-0000-1000-8000-00805f9b34fb";
public static string PressureSensorUuid
{
get { return _packetUuid; }
}
public static string ButtonSensorServiceUuid
{
get { return _buttonSensorServiceUuid; }
}
public static string SensorStateUuid
{
get { return _sensorStateUuid; }
}
}
public class SensorBase : IDisposable
{
protected GattDeviceService deviceService;
protected string sensorDataUuid;
protected Queue<byte[]> fifoBuffer;
protected bool isNotificationSupported = false;
public bool newData = false;
private GattCharacteristic dataCharacteristic;
public SensorBase(GattDeviceService dataService, string sensorDataUuid)
{
this.deviceService = dataService;
this.sensorDataUuid = sensorDataUuid;
fifoBuffer = new Queue<byte[]>(20);
}
public bool MorePacketsAvailable
{
get
{
if (fifoBuffer.Count > 0)
{
return true;
}
else
{
return false;
}
}
}
public virtual async Task EnableNotifications()
{
GattCharacteristicsResult result = await deviceService.GetCharacteristicsAsync();
foreach (var test in result.Characteristics)
{
string t = test.Uuid.ToString();
}
isNotificationSupported = true;
dataCharacteristic = (await deviceService.GetCharacteristicsForUuidAsync(
new Guid(sensorDataUuid))).Characteristics[0];
dataCharacteristic.ValueChanged += dataCharacteristic_ValueChanged;
GattCommunicationStatus status = await dataCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
GattClientCharacteristicConfigurationDescriptorValue.Notify);
var currentDescriptorValue = await dataCharacteristic.ReadClientCharacteristicConfigurationDescriptorAsync();
if (currentDescriptorValue.Status != GattCommunicationStatus.Success
|| currentDescriptorValue.ClientCharacteristicConfigurationDescriptor != GattClientCharacteristicConfigurationDescriptorValue.Notify)
{
GattCommunicationStatus status2 = await dataCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
GattClientCharacteristicConfigurationDescriptorValue.Notify);
}
}
public virtual async Task DisableNotifications()
{
newData = false;
isNotificationSupported = false;
dataCharacteristic = (await deviceService.GetCharacteristicsForUuidAsync(
new Guid(sensorDataUuid))).Characteristics[0];
dataCharacteristic.ValueChanged -= dataCharacteristic_ValueChanged;
GattCommunicationStatus status = await dataCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.None);
}
protected async Task<byte[]> ReadValue()
{
if (!isNotificationSupported)
{
if (dataCharacteristic == null)
{
dataCharacteristic = (await deviceService.GetCharacteristicsForUuidAsync(
new Guid(sensorDataUuid))).Characteristics[0];
}
GattReadResult readResult = await dataCharacteristic.ReadValueAsync();
byte[] data = new byte[readResult.Value.Length];
DataReader.FromBuffer(readResult.Value).ReadBytes(data);
fifoBuffer.Enqueue(data);
}
return fifoBuffer.Dequeue();
}
protected async Task WriteByteArray(string characteristicUuid, byte[] value)
{
GattCharacteristic writeCharacteristic = (await deviceService.GetCharacteristicsForUuidAsync(
new Guid(characteristicUuid))).Characteristics[0];
var writer = new DataWriter();
writer.WriteBytes(value);
var res = await writeCharacteristic.WriteValueAsync(writer.DetachBuffer(), GattWriteOption.WriteWithoutResponse);
}
private void dataCharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
byte[] data = new byte[args.CharacteristicValue.Length];
DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(data);
fifoBuffer.Enqueue(data);
newData = true;
}
public async void Dispose()
{
await DisableNotifications();
}
}
public class PressureSensor: SensorBase
{
public PressureSensor(GattDeviceService dataService, string sensorDataUuid)
: base(dataService, sensorDataUuid)
{
}
public async Task BeginCollecting()
{
await WriteByteArray(SensorUUIDs.SensorStateUuid, new byte[] { 0x01 });
}
public async Task<int[]> GetPressure()
{
byte[] data = await ReadValue();
if (data != null)
{
int[] values = new int[9];
values[0] = (int)BitConverter.ToInt32(data, 0);
for (int i = 1; i < values.Length; i++)
{
values[i] = (int)BitConverter.ToInt16(data, 2 * i + 2);
}
return values;
}
else
{
return new int[] { 0 };
}
}
public async Task StopCollecting()
{
await WriteByteArray(SensorUUIDs.SensorStateUuid, new byte[] { 0x00 });
}
}
}
Here is the DataPoint Class that I use to organize the data received from the pressure sensor:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace BLEInterfaceTest
{
public class DataPoint : INotifyPropertyChanged
{
private TimeSpan _timestamp;
private int _packetNumber;
private double _internalTimestamp;
private int _pressure1;
private int _pressure2;
public event PropertyChangedEventHandler PropertyChanged;
public TimeSpan TimeStamp
{
get { return _timestamp; }
set
{
_timestamp = value;
this.NotifyPropertyChanged();
}
}
public int PacketNumber
{
get { return _packetNumber; }
set
{
_packetNumber = value;
this.NotifyPropertyChanged();
}
}
public double InternalTimestamp
{
get { return _internalTimestamp; }
set
{
_internalTimestamp = value;
this.NotifyPropertyChanged();
}
}
public int PressureValue1
{
get { return _pressure1; }
set
{
_pressure1 = value;
this.NotifyPropertyChanged();
}
}
public int PressureValue2
{
get { return _pressure2; }
set
{
_pressure2 = value;
this.NotifyPropertyChanged();
}
}
public DataPoint(TimeSpan time,int packetNumber, double internalTimestamp, int pressure1, int pressure2)
{
_timestamp = time;
_packetNumber = packetNumber;
_internalTimestamp = internalTimestamp;
_pressure1 = pressure1;
_pressure2 = pressure2;
}
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
if (!string.IsNullOrEmpty(propertyName))
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
I have researched this extensively, and all I could find was help on how to initiate a disconnection. I have the opposite problem. One page I found stated that the problem might be caused by the device not properly storing the bonding state, but I have checked that and I did initialize the device to save the bonding state.
Interestingly if I do not pair the device to the computer before trying to read information from it then I do not have the problem. The connection never randomly stops. But when I do this, the computer does not receive every packet of data sent from the sensor device. It will receive one or two packets and then skip five or six packets. If I pair the device then I will receive every packet but the connection will randomly cut off.
So my question is two fold, I guess. How do I stop the connection from cutting off when the device is paired? Or alternatively, is there a way to allow the application to receive every packet of data when it is not paired?
UPDATE
I realized I should include more information on my sensor peripheral in case the error is in that code. I am currently designing a rapid prototyping of this sensor before I move on to designing the embedded version. To do this, I am using the BLE Nano 1 from RedBearLabs as a user friendly prototype. I am programing this device with the online MBED compiler. I have included the nRF51822 and BLE_API libraries to handle the bluetooth low energy communication.
UPDATE 2
So after more research into what is causing the problem, I have found that the disconnection occurs when a connection interval and a generation 2 garbage collection occur at the same time. In UWP the garbage collector can pause the UI Thread for generation 2 collections. (see here)
My thought is that if the thread is paused at the beginning of a connection interval, then the central is not able to initiate the connection with the peripheral and the peripheral therefore thinks the client is no longer listening (see more about how BLE connections work).
I discovered this by finding out exactly what is necessary to get the connection back once it has randomly stopped. I started with the entire connection process and reduced it down to this:
public async Task ReconnectDevice()
{
GattCommunicationStatus status = await dataCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
GattClientCharacteristicConfigurationDescriptorValue.Notify);
await WriteByteArray(SensorUUIDs.SensorStateUuid, new byte[] { 0x01 });
}
Because my BluetoothLEDevice, GattService, and GattCharacteristic objects are not disposed, all I need to do is resubscribe to notifications and write a 1 to the device so that it begins collecting data again.
I have reduced my memory allocations in my application significantly since discovering this, and the time for a gen2 collection has decreased to an average of 5 ms. Also, the amount of time before the connection disconnects has increased to around 4-5 sec.
UWP has a GattCharacteristicNotificationTrigger for receiving notifications in a BackgroundTask, but I have never had much success at incorporating background tasks in UWP.
I think I will try next to incorporate the windows.devices into a WPF application where I think I will have a better chance at getting it working.
So, after a while of trying different ideas I have finally stumbled across a solution to my problem. I had to make 2 changes:
Used the unpaired connection instead of the paired connection. This solved the problem of the connection dropping suddenly.
Increased the connection interval to 40 ms. For some reason when I did this, I received all of the data and no longer had any problems. Anything below 40 ms causes information to be lost when communicating to a Windows device (I had to make this change on the C code running on my sensors.)
I have used the devices for about 2 months now after making this change and have had no problems at all.
I seems to me that these problems are related to the BluetoothCacheMode Enum.
This indicates whether certain Bluetooth API methods should operate on values cached in the system or
retrieve those values from the Bluetooth device.
Using BluetoothCacheMode.Uncached attribute allows the service to update the attributes when needed.
If the device is paired then the BluetoothCacheMode is not needed(I think BluetoothCacheMode.Cached is default).
In your code the line:
var services = await leDevice.GetGattServicesAsync(BluetoothCacheMode.Uncached);
Can be the cause of the connection lost if paired.
GetGattServicesAsync(), GetCharacteristicsAsync() and ReadValueAsync()
must have the attribute BluetoothCacheMode.Uncached when not paired, when paired default or BluetoothCacheMode.Cached.
See https://msdn.microsoft.com/en-us/library/windows/apps/dn263758.aspx.

C# .net Remoting Client/Server multithreading Chatroom

I am trying to get my Chat system to work. I have a Client/Server launch per an app. I have Client1 talking to Server 2 and Client2 to Server1 but I cannot figure out how to print the information being sent to the servers to the chat windows of their corresponding Clients.
ChatRoom
using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;
namespace ChatRoom
{
public class Class1:MarshalByRefObject
{
// initialize Arraylist to store users signed into chat room
private static ArrayList userNames = new ArrayList();
private static string chatWindow; // fuck u, now ye be a static var
public void sendMessage(string message)
{
Console.WriteLine(message);
//if (message != null)
// {
//add to chat window
chatWindow += message + Environment.NewLine;
//}
}
//public void test()
//{
// Console.WriteLine("pizza");
//}
public void addUserName(string UserName)
{
String test = UserName;
Console.WriteLine(test);
userNames.Add(test);
Console.WriteLine("0");
}
public void deleteUserName(string userName)
{
if (userName != null)
{
userNames.Remove(userName);
}
}
public ArrayList userList()
{
return userNames; // userNames
}
public string OutputWindow()
{
return chatWindow;
}
}
}
SERVER
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using ChatRoom;
using System.Runtime.Remoting.Channels.Http;
using RemoteServer;
namespace RemoteServer
{
public partial class Form1 : Form
{
private int channelNum;
private static string temp;
public Form1()
{
InitializeComponent();
}
private void buttonConfirm_Click(object sender, EventArgs e)
{
temp = textBoxPort.Text;
channelNum = Convert.ToInt32(temp);
HttpChannel ServerChannel = new HttpChannel(channelNum);
Console.WriteLine("httpChannel Set");
this.Close(); // close GUI
ChannelServices.RegisterChannel(ServerChannel, false);
Console.WriteLine("channel registered");
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Class1), "ChatRoom",
WellKnownObjectMode.SingleCall);
Console.WriteLine("working");
Console.WriteLine("Port number is " + channelNum);
Console.ReadKey();
}
}
}
CLIENT
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ChatRoom;
using RemoteServer;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Threading;
using System.Diagnostics;
using System.Timers;
namespace ClientServerGui
{
public partial class Form1 : Form
{
private Class1 server;
private Thread thread;
//private Thread thread2;
//private HttpChannel ClientHttpChannel;
private string UserName;
public Form1()
{
InitializeComponent();
}
public static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private void logoutToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Close();
}
private void ConfigureServer(string port)
{
HttpClientChannel ClientChannel = new HttpClientChannel();
ChannelServices.RegisterChannel(ClientChannel, false);
RemotingConfiguration.RegisterWellKnownClientType(typeof(Class1), "http://localhost:"
+ textBoxPort.Text + "/ChatRoom");
}
private void buttonSend_Click(object sender, EventArgs e)
{
//ArrayList displayUsers = server.userList();
//string send = textBoxSend.Text;
//textBoxChatWindowDisplay.Text += send;
//combine User's name with input text
string send = UserName + ": " + textBoxSend.Text;
while( textBoxSend.Text != "")
{
//send message
server.sendMessage(send);
//Clear and focus to start new message
textBoxSend.Clear();
buttonSend.Focus();
}
textBoxChatWindowDisplay.Text += send;
textBoxChatWindowDisplay.Text = server.OutputWindow();
//textBoxChatWindowDisplay.Text += "\n";
//listBoxUserList.Items.Clear();
// foreach (string x in displayUsers)
// {
// listBoxUserList.Items.Add(displayUsers);
// }
}
public void chatReloadTimer_Tick(object sender, EventArgs e)
{
textBoxChatWindowDisplay.Text = server.OutputWindow();
StartServer();
}
private void buttonConnect_Click(object sender, EventArgs e)
{
//RemoteServer.Form1 port = new RemoteServer.Form1();
//string Serverport = port.ServerPort();
if (textBoxUserName.Text != "")
{
UserName = textBoxUserName.Text;
//ClientHttpChannel = new HttpChannel();
//ChannelServices.RegisterChannel(ClientHttpChannel, false);
if (textBoxPort.Text == "")
{
textBoxPort.Text = "9000";
}
//server1
ConfigureServer(textBoxPort.Text);
//server2
// ConfigureServer(Serverport);
server = new Class1();
//add user
server.addUserName(UserName);
//server.test();
//new thread
thread = new Thread(new ThreadStart(StartServer));
//start thread
thread.Start();
//new thread
//thread2 = new Thread(new ThreadStart(StartServer2));
//start thread
//thread2.Start();
buttonSend.Focus();
System.Windows.Forms.Timer chatReloadTimer = new System.Windows.Forms.Timer();
chatReloadTimer.Interval = (100); // .1 seconds refresh
chatReloadTimer.Tick += new EventHandler(chatReloadTimer_Tick);
chatReloadTimer.Start();
}
}
private void StartServer()
{
string currentChatWindow;
//set array list to capture people joining server
ArrayList usersArrayList = server.userList();
//** BAD FOR CHATROOM STYLE****
//if (listBoxUserList.ItemHeight > 0)//if not enmpy kill all
//{
// //empty listbox
this.Invoke(new MethodInvoker(delegate() { listBoxUserList.Items.Clear(); }));
//}
// Add all users to listbox
//while (usersAL != null)
//{
foreach (string x in usersArrayList)
{
//listBoxUserList.Items.Add(UserName);
this.Invoke(new MethodInvoker(delegate() { listBoxUserList.Items.Add(x); }));
}
//}
//display data to user
currentChatWindow = server.OutputWindow();
//textBoxChatWindowDisplay.Text = currentChatWindow;
this.Invoke(new MethodInvoker(delegate() { textBoxChatWindowDisplay.Text = currentChatWindow; }));
//listBoxUserList.Items.Add(
}
private void Form1_Load(object sender, EventArgs e)
{
//Boolean on = true;
Process start = new Process();
start.StartInfo.FileName = "RemoteServer";
start.Start();
MessageBox.Show("Continue?", "Continue", MessageBoxButtons.OKCancel);
//while (on == true)
//{
// Thread.Sleep(1);
// textBoxChatWindowDisplay.Text = server.OutputWindow();
//}
buttonSend.Focus();
}
}
}

Emulating console in winforms, the hard way how to make it better

Im trying to emulate the console in a windows forms applicaton. I have made it possible by using two extra threads and a delegate to be able to interact with my multiline textbox.
This somehow seems like I complicate things to much. So my questions.
Is there a better way of doing this?
When i press enter the command does not get sent, first if i press again it get sent? WHy is that? I ahve treid to debug it but failed to find the solution.
EDIT! Im using CsharpSSH, to do the SSH connection. Also I have included my full code now!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Tamir.SharpSsh;
using System.IO;
using System.Threading;
using System.Timers;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public string mHost;
SshShell mShell;
public string mInput;
string pattern = "";
bool mInputHolder = false;
string mPattern = "";
int mValue = 0;
bool mStatus = false;
private Thread thrdtwo = null;
private Thread thrdone = null;
public string mKorv;
string mString = "";
delegate void SetTextCallback(string text);
bool clientopen = true;
public Form1()
{
InitializeComponent();
txthost.Text = "sdf.org";
txtuser.Text = "kalle82";
txtpass.Text = "kattsand";
string pattern = "sdf:";
mPattern = pattern;
}
public void button1_Click(object sender, EventArgs e)
{
mShell = new SshShell(Host, User);
mShell.Password = Pass;
//WRITING USER MESSAGE
txtOutput.AppendText("Connecting...");
mShell.Connect();
txtOutput.AppendText("OK");
mShell.ExpectPattern = mPattern;
mShell.RemoveTerminalEmulationCharacters = true;
this.SetText(mShell.Expect(pattern));
txtInput.Focus();
thrdone = new Thread(new ThreadStart(appengine));
thrdone.Start();
}
private void appengine()
{
this.txtInput.KeyPress += new System.Windows.Forms.KeyPressEventHandler(checkforenter);
// MessageBox.Show("Appengine started");
while (mShell.ShellOpened)
{
thrdtwo = new Thread(new ThreadStart(startthread2));
thrdtwo.Start();
thrdtwo.Join();
// this.SetText(mShell.Expect(pattern));
if (clientopen == false) break;
}
// MessageBox.Show("Appengine stopped");
}
private void startthread2()
{
//Wait for answer
while (mStatus == false)
{
}
}
//Recieves keypressevent
public void checkforenter(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if (e.KeyChar == (char)13)
{
mStatus = true;
mString = txtInput.Text;
mShell.WriteLine(mString);
this.SetText(mShell.Expect(pattern));
txtOutput.AppendText(txtInput.Text + "\n");
}
mStatus = false;
}
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.txtOutput.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.txtOutput.Text = text.ToString();
}
}
public int checkfortrue()
{
if (mInputHolder != true)
{
mValue = 0;
}
if (mInputHolder == false)
{
mValue = -1;
}
return mValue;
}
public string userInput()
{
while (mInputHolder == true)
{
}
mInputHolder = true;
return txtInput.Text;
}
//Properties
public string Host
{
get
{
return txthost.Text;
}
set
{
txthost.Text = value;
}
}
public string User
{
get
{
return txtuser.Text;
}
set
{
txtuser.Text = value;
}
}
public string Pass
{
get
{
return txtpass.Text;
}
set
{
txtpass.Text = value;
}
}
public string Pattern
{
get
{
return pattern;
}
set
{
pattern = value;
}
}
private void button2_Click(object sender, EventArgs e)
{
clientopen = false;
}
}
}

Categories