I have a clickonce application, and I have set up several file handlers for this application (for the sake of this example, I want to handle files with either the .aaa or .bbb extensions).
If I select a single file with one of these extensions, my application starts up as expected, everything is good. But if I select multiple files and open them (either by hitting Enter or by right clicking and selecting Open), then multiple instances of my aopplication are started up - one instance per file that was selected.
This is not the behavior I expected, I want just one instance to start with multiple file entries in the AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData. Can this be achieved, or is my expectation incorrect?
Edit:
Just to elaborate: we have followed the single instance approach as mentioned by #Matthias, the first instance to start up creates a named server pipe. Subsequent instances then start up, detect that they are secondary, communicate their command line arguments (filename) through to the main instance via the named pipe, then quit. The main instance receives the filename via the named pipe, and does its thing (starts up a file import wizard).
The issue comes when a user selects several files (i.e. 5 files), then selects to open those files in the application. Instead of getting one secondary instance starting with 5 file names supplied on the command line, I'm getting 5 secondary instances of the application starting, each with a single filename on the command line. Each of these then creates a client named pipe and communicates that filename to the main instance - so the server named pipe receives 5 separate messages.
Follow up thoughts:
after chatting about this it occurs to me that maybe this is just the way registered file handlers work, maybe it is not related to clickonce. Maybe the solution is for the server named pipe to pause after receiving each message and to attempt to queue messages before actioning them?
You can achieve this by implementing a single instance application. If the application is already running (second call), you can use named pipes to inform the application (first call) of a file open event.
EDIT
Found a code snippet from an earlier project. I want to underline that the code definitely needs improvements, but it should be a good point where you can start from.
In your static main:
const string pipeName = "auDeo.Server";
var ownCmd = string.Join(" ", args);
try
{
using (var ipc = new IPC(pipeName))
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form = new ServerForm();
ipc.MessageReceived += m =>
{
var remoteCmd = Encoding.UTF8.GetString(m);
form.Invoke(remoteCmd);
};
if (!string.IsNullOrEmpty(ownCmd))
form.Invoke(ownCmd);
Application.Run(form);
}
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
if (string.IsNullOrEmpty(ownCmd))
return;
var msg = Encoding.UTF8.GetBytes(ownCmd);
IPC.SendMessage(pipeName, msg);
}
The IPC class:
public class IPC : IDisposable
{
public IPC(string pipeName)
{
Stream = new NamedPipeServerStream(pipeName,
PipeDirection.InOut,
1,
PipeTransmissionMode.Byte,
PipeOptions.Asynchronous);
AsyncCallback callback = null;
callback = delegate(IAsyncResult ar)
{
try
{
Stream.EndWaitForConnection(ar);
}
catch (ObjectDisposedException)
{
return;
}
var buffer = new byte[2000];
var length = Stream.Read(buffer, 0, buffer.Length);
var message = new byte[length];
Array.Copy(buffer, message, length);
if (MessageReceived != null)
MessageReceived(message);
Stream.Disconnect();
// ReSharper disable AccessToModifiedClosure
Stream.BeginWaitForConnection(callback, null);
// ReSharper restore AccessToModifiedClosure
};
Stream.BeginWaitForConnection(callback, null);
}
private NamedPipeServerStream Stream
{
get;
set;
}
#region IDisposable Members
public void Dispose()
{
if (Stream != null)
Stream.Dispose();
}
#endregion
public static void SendMessage(string pipeName, byte[] message)
{
using (var client = new NamedPipeClientStream(".", pipeName))
{
client.Connect();
client.Write(message, 0, message.Length);
client.Close();
}
}
~IPC()
{
Dispose();
}
public event MessageHandler MessageReceived;
}
The answer to the problem was to have a small delay at the server end of the pipe. In summary:
the first started instance of the app is the owner of the server end of the pipe, subsequent instances of the app are a client
When receiving a message from a client, a timer was started, if the timer was already started then it was reset. The passed file name is added to a list.
The timer delay was set to 2 seconds, once the tick event occurred (so it had been 2 seconds since the last client communication) the single instance server would take the appropriate action with the list of file names
This is not the behavior I expected, I want just one instance to start with multiple file entries in the AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData. Can this be achieved, or is my expectation incorrect?
My expectation was incorrect - you can only pass through a single file name to a registered file handler, each file name starts a separate instance of the handler.
Related
I have a Node.Js server running on localhost listening to some API requests.
These requests are transferred to my console application via TCP/IP. Here's my c# code which receives data from Node server (hosted at localhost:9999) via GetData() and pass it to another function SendData().
namespace Datatransfer
{
/* global variable declaration*/
class Global
{
public static string receive_data;
}
class Program
{
static string HOST = "localhost";
static int PORT = 9999;
static TcpClient client;
/*Function to receive data*/
static string GetData()
{
while (true)
{
NetworkStream nwStream = client.GetStream();
byte[] bytesToRead = new byte[client.ReceiveBufferSize];
int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
Global.receive_data= Encoding.ASCII.GetString(bytesToRead, 0, bytesRead);
Console.WriteLine("Received data : " + Global.receive_data);
SendData(Global.receive_data)
}
}
/*Function to send data*/
static void SendData(string val)
{
/*Code to process recevied_data..*/
Console.WriteLine("Data to Send : " + Global.receive_data);
/*some codes....*/
}
static void Main(string[] args)
{
client = new TcpClient();
client.Connect(HOST, PORT);
GetData();
}
}
}
I have declared the receive_data as global so as to use it across the application. The code works and I am getting output. Everytime I make an API request to port 9999 am getting output as :
Connection Successfull...
Received data : somestring
Data to Send : somestring
I was wondering if this is an efficient way or not ?
Is there another way by which the receive_data can be passed to other functions 'without' using the function ( ie;SendData() ) inside the while loop.? Or to put it simply, pass data from an infinite while loop to main or other functions.
Any suggestions?
You basically have two options for further processing the data you receive:
Store it somewhere like you did (from a design perspective it doesn't matter how you implement this). Just one thing to think about would be if you want to store a list of received data-"messages", and what happens if you receive another message.
Call a method an pass the received data. This would be the better approach, because you abstract away the implementation and are free to change it (e.g. from storing global to a message-sink mechanism or whatever) without changing your receiving-code.
Approach 2) has more information and more context, because you trigger the method at the point you receive data. In option 1) you have no information about how old the information is, or even if the same information was sent multiple times. So more information is (always) better, if you don't need it in the method call, you are free to condense it again to say a global variable.
For approach 2) you should keep in mind, that the method is running "inside" your loop, so all long-running operations would block the loop. But still you are free to implement it in a way, that allows the message to be processed in another thread (asynchronous).
I am making a program that starts a child process and communicates via anonymous pipes. When I read from a pipe, the program hangs at the first ReadLine() call as seen in the following code method:
// Reads messages sent from module's process via anonymous pipe
internal string[] ReadPipe() {
try {
Log.Verbose("Checking read pipe");
// Check for sync message and return null if there is no message to receive
string pipeMessage = _pipeInReader.ReadLine(); // HANGS ON THIS LINE
if(pipeMessage == null || !pipeMessage.StartsWith("SYNC")) {
Log.Verbose("No message found in pipe");
return null;
}
// Return array of message lines
Log.Verbose("Received message from module {ModuleName}", _fileInfo.Name);
List<string> pipeMessageLines = new();
do {
pipeMessage = _pipeInReader.ReadLine();
pipeMessageLines.Add(pipeMessage);
Log.Debug(pipeMessage);
} while(pipeMessage != null && !pipeMessage.StartsWith("END"));
return pipeMessageLines.ToArray();
} catch(Exception e) {
Log.Error(e.ToString());
return null;
}
}
The code I am using to write to the pipe is the following:
// Sends a message to module's process via anonymous pipe
public static void WritePipe(string message) {
try {
Log.Verbose("Sending \"{Message}\" to kit pipe", message);
// Send sync message and wait for module process to receive it
Log.Verbose("Waiting for pipe drain");
_pipeOutWriter.Write("SYNC");
_pipeOut.WaitForPipeDrain();
// Send the specified message
Log.Verbose("Pipe drained. Sending message");
_pipeOutWriter.Write(message);
_pipeOutWriter.Write("END");
} catch(Exception e) {
Log.Error(e.ToString());
}
}
Why does it hang at that ReadLine() line?
Thanks in advance!
Without a proper minimal, reproducible example, it's impossible to say for sure. However, one glaring problem with your code is that when you write to the _pipeOutWriter object, you don't call Flush(). Assuming that's a TextWriter, by default it's going to buffer the data until the internal buffer is full, and not send anything to the underlying Stream until then.
By calling Flush(), you force it to flush its internal buffer and send the data right away.
If that does not address your question, please edit the question to improve it, making sure to provide a minimal, reproducible example, and any additional details about what you've tried so far to fix the problem and what specifically you need help with.
I have two console apps written with C#. I'm trying to exchange messages between them. In an attempt to do this, I'm using non-persisted memory-mapped files. In my scenario, one console app is the parent and the other is the child. Sometimes, the parent will send a message to the child. Other times, the child will send a message to the parent.
I can't figure out how to do this though. It's like each process is either listening or speaking. It's not actively doing both. At this time, I'm trying to exchange messages between the two processes using a struct that's defined as this:
public struct Message
{
public string Source { get; set; }
public string Text { get; set; }
}
My parent console app has a method that looks like this:
private void SendMessageToChild(string text, int childHandle)
{
Console.WriteLine("Sending message to child...");
var messageChannelFileName = childHandle.ToString() + ".msgs";
using (var messageChannelFile = MemoryMappedFile.CreateOrOpen(messageChannelFileName, 10240))
{
using (var memoryMappedAccessor = messageChannelFile.CreateViewAccessor())
{
var message = new Message();
message.Text = text;
message.Source = "Parent";
memoryMappedAccessor.Write<Message>(0, ref message);
}
}
Console.ReadKey(); // This is to keep the memory mapped file open for the child to be able to read it
Console.WriteLine("Successfully sent message to child.");
}
My child console app (process) has a method that looks like this:
private void StartListening()
{
Task.Run(() =>
{
var messageChannelFileName = Process.GetCurrentProcess().Id + ".msgs";
using (var messageChannelFile = MemoryMappedFile.OpenExisting(messageChannelFileName, MemoryMappedFileRights.Read))
{
var message = new Message();
using (var messageAccessor = messageChannelFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read))
{
messageAccessor.Read<Message>(0, out message);
Console.WriteLine(message.Text);
}
}
Console.ReadKey(); // This is to keep the memory mapped file
});
}
This approach isn't working. I never see the message printed to the console window. At the same time, I do not see a way to send messages back-and-forth. In my opinion, the Console.ReadKey required in both sides locks the file.
Am I misunderstanding something? Am I using the wrong thing to exchange messages between two processes? I know I can't use Pipes for my scenario, which is why I went with memory mapped files.
Its really easy to communicate between 2 processes
For example Parent process do that :
// create EventWaitHandle, MemoryMapped and accessor
ewh = new EventWaitHandle(false, EventResetMode.AutoReset, "ewhFreePIE");
memory = MemoryMappedFile.CreateOrOpen("hookFreePIE", 68, MemoryMappedFileAccess.ReadWrite);
accessor = memory.CreateViewAccessor();
:
:
// Send message with accessor.write
ewh.Set();//say to other process, there is something to read
Example of Child Process:
memory = MemoryMappedFile.CreateOrOpen("hookFreePIE", 68, MemoryMappedFileAccess.ReadWrite);
accessor = memory.CreateViewAccessor();
ewh = EventWaitHandle.OpenExisting("ewhFreePIE");
:
:
// sample of loop
public void StartLoop()
{
while (running)
{
ewh.WaitOne();// wait Set() of another or same process
if (cmdtostop) //you could create cmdstop inside memorymapped file (set first byte to 1 for example
{
running = false;
}
else
{
//do something with data , using accessor.Read
}
}
if you want child send to parent you create another EventWaithandle and do the same thing from child to Parent
Dont forget to dispose resource when process finish
I read a couple of related questions which had an issue with accessing nency from a remote computer. However, I am unable to access nancy from my own pc.
Here is my code:
class Program
{
static void Main(string[] args)
{
HostConfiguration hostConfigs = new HostConfiguration();
//hostConfigs.RewriteLocalhost = true;
hostConfigs.UrlReservations.CreateAutomatically = true;
using (var host = new NancyHost(hostConfigs, new Uri("http://localhost:1234")))
{
host.Start();
Console.WriteLine("Running on http://+:1234");
Console.WriteLine(host.ToString());
}
Console.ReadKey();
}
}
public class HelloModule : NancyModule
{
public HelloModule()
{
Get["/"] = parameters => Response.AsJson("Success");
Get["/nancy"] = parameters => Response.AsJson("Success");
}
}
}
I am administrator on my PC and I do not get any exception. If I type http://localhost:1234 or http://127.0.0.1:1234 to my browser (with /nancy and without) I would expect a response. However, I do net get any reponse. Further, in the list produced with netstat -ano I do not see any process listing on port 1234. I downloaded the latest version of nancy via nuget.
Do you have any idea?
The following line should work as expected:
var host = new NancyHost(hostConfigs, new Uri("http://localhost:1234"))
But what happens with a using statement, is that anything specified between ( and ) (simply put) is disposed after the closing brace (}) of the same using statement. So what is actually happening is, the host gets created, is started, and is disposed right after it printed some lines to the console.
Simply put, move the ReadKey call inside the using statement. There it will wait until a key is pressed, and the host will be disposed after that event has occurred.
I am using Pcap.Net take Pcap File and transmit all it's packet through my machine Network Adapter.
So in order to do that i am using the code example Sending packets using Send Buffer:
class Program
{
static void Main(string[] args)
{
string file = #"C:\file_1.pcap";
string file2 = #"C:\file_2.pcap";
// Retrieve the device list from the local machine
IList<LivePacketDevice> allDevices = LivePacketDevice.AllLocalMachine;
// Take the selected adapter
PacketDevice selectedOutputDevice = allDevices[1];
SendPackets(selectedOutputDevice, file);
SendPackets(selectedOutputDevice, file2);
}
static void SendPackets(PacketDevice selectedOutputDevice, string file)
{
// Retrieve the length of the capture file
long capLength = new FileInfo(file).Length;
// Chek if the timestamps must be respected
bool isSync = false;
// Open the capture file
OfflinePacketDevice selectedInputDevice = new OfflinePacketDevice(file);
using (PacketCommunicator inputCommunicator = selectedInputDevice.Open(65536, PacketDeviceOpenAttributes.Promiscuous, 1000))
{
using (PacketCommunicator outputCommunicator = selectedOutputDevice.Open(100, PacketDeviceOpenAttributes.Promiscuous, 1000))
{
// Allocate a send buffer
using (PacketSendBuffer sendBuffer = new PacketSendBuffer((uint)capLength))
{
// Fill the buffer with the packets from the file
Packet packet;
while (inputCommunicator.ReceivePacket(out packet) == PacketCommunicatorReceiveResult.Ok)
{
//outputCommunicator.SendPacket(packet);
sendBuffer.Enqueue(packet);
}
// Transmit the queue
outputCommunicator.Transmit(sendBuffer, isSync);
inputCommunicator.Dispose();
}
outputCommunicator.Dispose();
}
//inputCommunicator.Dispose();
}
}
}
In order to send packet Pcap.Net offers 2 ways:
Send buffer.
Send each packet using SendPacket().
Now after finish to send my 2 files (like in my example) i want to use the Dispose() to free resources.
when using the first option all works fine and this finish to handle my 2 Pcap files.
When using the second option SendPacket() (currently in my code example this is as a comments) after the first file finish my application is closing and not reach to the second file.
I try it also in Console Application and in WPF and in both cases same result.
With UI (WPF) my application GUI just close without any error.
Any suggestions what could cause this ?
When you use the using keyword it means you implicitly call Dispose() at the end of the scope.
If you call Dispose() explicitly as well, it means you call Dispose() twice on the same instance, which is likely to crash your program.