❔ Passing data from a web page to a ""singleton"" C# desktop application

So, let's say I have a web page that has a button that opens my C# application (through a url protocol in the registry), through which it might receive some parameters. However, I also want it so that if I have an instance of my C# application open, clicking the button will instead send those parameters to the already-open application, rather than starting a new instance of it. How would I go about doing this? ------ Currently, I have it so that my program maintains a named mutex, and if that named mutex is owned by another process, then there is a previous instance of my program running, and the current instance aborts.
20 Replies
sibber
sibber15mo ago
you could use a named pipe to pass whatever you want to the running instance
PracticalPotato
PracticalPotato15mo ago
ok so this is the first time I've encountered pipes so let me know if I'm getting anything wrong in my first instance, when I establish that my program is the first instance, I create a NamedPipeServerStream, with PipeDirection.In in my second instance, I create a NamedPipeServerClient, with PipeDirection.Out and connect from the client to the server how do I get the info out of the pipe and usable by the rest of the application? and how would I do other stuff while waiting for info to come out of the pipe? Do I spin up a thread to handle the pipeServer?
sibber
sibber15mo ago
yes start a task, use a cancellation token to loop until cancelled and just await pipeServer.WaitForConnectionAsync(); until a client connects. then read the message, disconnect, and continue the loop
PracticalPotato
PracticalPotato15mo ago
sorry, I'm.. not quite sure how this works. So I have
Task waitConnection = Task.Run(() = > {PipeServer();})
Task waitConnection = Task.Run(() = > {PipeServer();})
and
static void PipeServer()
{
NamedPipeServerStream _incomingPipeStream = new NamedPipeServerStream("Test", PipeDirection.In);
await _incomingPipeStream.WaitForConnectionAsync();
}
static void PipeServer()
{
NamedPipeServerStream _incomingPipeStream = new NamedPipeServerStream("Test", PipeDirection.In);
await _incomingPipeStream.WaitForConnectionAsync();
}
and in the client I have
NamedPipeClientStream _outgoingPipeStream = new NamedPipeClientStream("Test")
_outgoingPipeStream.Connect();
NamedPipeClientStream _outgoingPipeStream = new NamedPipeClientStream("Test")
_outgoingPipeStream.Connect();
Where do I go from here?
sibber
sibber15mo ago
why is it static id make a service that just handles the pipe
PracticalPotato
PracticalPotato15mo ago
well, currently it's just placed under
internal static class Program
internal static class Program
which contains
static void Main()
static void Main()
sibber
sibber15mo ago
oh is the desktop app not a gui app? anyway this is a simple example of a server:
sealed class NamedPipeMessageServer : IDisposable
{
private readonly NamedPipeServerStream _pipeServer;

private readonly StreamReader _reader;

public NamedPipeMessageServer()
{
_pipeServer = new("blablaMessagePipe", PipeDirection.In, 1, default, PipeOptions.Asynchronous);
_reader = new(_pipeServer);
}

public void Run(CancellationToken cancellationToken)
{
Task.Run(async () =>
{
while (!cancellationToken.IsCancellationRequested)
{
await _pipeServer.WaitForConnectionAsync();

var message = await _reader.ReadToEndAsync();
// raise an event or something

_pipeServer.Disconnect();
}
}, cancellationToken);
}

// implement disposing
}
sealed class NamedPipeMessageServer : IDisposable
{
private readonly NamedPipeServerStream _pipeServer;

private readonly StreamReader _reader;

public NamedPipeMessageServer()
{
_pipeServer = new("blablaMessagePipe", PipeDirection.In, 1, default, PipeOptions.Asynchronous);
_reader = new(_pipeServer);
}

public void Run(CancellationToken cancellationToken)
{
Task.Run(async () =>
{
while (!cancellationToken.IsCancellationRequested)
{
await _pipeServer.WaitForConnectionAsync();

var message = await _reader.ReadToEndAsync();
// raise an event or something

_pipeServer.Disconnect();
}
}, cancellationToken);
}

// implement disposing
}
PracticalPotato
PracticalPotato15mo ago
I'm trying to use windows forms for UI, this is Program.cs which calls Application.Run(new MainForm())
sibber
sibber15mo ago
ah winforms so i assume youre not using mvvm anyway thats not relevant
PracticalPotato
PracticalPotato15mo ago
lol
sibber
sibber15mo ago
so here you just run the server and to send a message you just create a client stream, connect, write to it, then dispose it simple as that
PracticalPotato
PracticalPotato15mo ago
mmkay lemme give it a shot OK so, I have no issues with the server, but when I connect I get a "access to the path is denied" error.
var pipeClient = new NamedPipeClientStream("blablaMessagePipe");
pipeClient.Connect() // <- access to the path is denied
var pipeClient = new NamedPipeClientStream("blablaMessagePipe");
pipeClient.Connect() // <- access to the path is denied
sibber
sibber15mo ago
thats not how you should create the client stream
new NamedPipeClientStream(".", "blablaMessagePipe", PipeDirection.Out)
new NamedPipeClientStream(".", "blablaMessagePipe", PipeDirection.Out)
also, use the async versions
PracticalPotato
PracticalPotato15mo ago
oh I see. what's the "just a string" constructor for? and uh do I need the client to be async?
sibber
sibber15mo ago
well it doesnt have to be
PracticalPotato
PracticalPotato15mo ago
cuz for my purposes it seems like I can just leave it mmkay
sibber
sibber15mo ago
but its better to use async actually youre probably only doing this on startup then closing the process in this case its fine to leave it sync
PracticalPotato
PracticalPotato15mo ago
yeah
sibber
sibber15mo ago
you use it if you want the default values for all other params
Accord
Accord15mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.