Is there a clean way to access the commandline arguments passed as part of an AppDomain.ExecuteAssembly call that starts a WPF application?
I'm spinning up a WPF application in a separate app domain and passing arguments to the application like so:
AppDomain moduleDomain = AppDomain.CreateDomain("Friendly Name");
moduleDomain.ExecuteAssembly(path, new[] { "arg1", "arg2" });
There's a work-around to access these arguments, since both Environment.GetCommandLineArgs() and StartupEventArgs return the commandline arguments for the original application, not the one spun up with ExecuteAssembly().
I would like to access the arguments passed to the WPF application without having to manually define a Main method, preferably using StartupEventArgs. Is there a way to do so?
Starting the WPF application in a separate process works, but has performance penalties and complicates debugging.
Tigran's comment lead me to a solution that I'm happy with, using AppDomain.SetData instead of using command line arguments. The basic outline looks like this:
AppDomain moduleDomain = AppDomain.CreateDomain("Friendly Name");
moduleDomain.SetData("arg1", "arg1Value");
moduleDomain.SetData("arg2", "arg2Value");
moduleDomain.ExecuteAssembly(path);
Then, to access the 'arguments' in the WPF app:
string arg1Value = AppDomain.CurrentDomain.GetData("arg1");
string arg2Value = AppDomain.CurrentDomain.GetData("arg2");
This works well for my use case.
Related
I have problem passing arguments from one WPF application to another.
I'm trying to start it as a new process with arguments (string) but nothing is passed.
Here is what I tried:
AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData is null.
ApplicationDevelopment.CurrentDevelopment.ActivationUri.Query is null
Environment.GetCommandLineArguments is giving me the path of the application
I'm starting the app like this:
System.Diagnostics.Process.Start(filepath, "argumentTest");
Both applications are deployed as click once, and in the second one in publish options I checked "Allow URL parameters to be passed to application"
I'm starting the app like this: System.Diagnostics.Process.Start(filepath, "argumentTest");
filePath should refer to the shortcut as suggested here:
StringBuilder sb = new StringBuilder();
sb.Append(Environment.GetFolderPath(Environment.SpecialFolder.Programs));
sb.Append("\\");
sb.Append("WpfApplicationClickOnce"); //pubslisher name
sb.Append("\\");
sb.Append("WpfApplicationClickOnce.appref-ms "); //application name
string shortcutPath = sb.ToString();
Process.Start(shortcutPath, "argumentTest");
You should then be able to retrieve the data using AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData.
I have a windows form application written in C# that allows me to point to a folder of images and parse those images into a easily view able format for a user. This is a stand alone application and it works fine. I want to extend this application so that instead of it parsing a folder of images, I can hand it a prebuilt data set, with all of the images and meta data preset by an external application via an API.
I have been able to compile the application into a class library and access the classes and structs to actually build the data set without issue, the problem I am having now is launching the application externally with the data set I have built.
For context, I am writing a tool that will allow the user to call this windows form application from Spotfire. Inside of spotfire I am parsing a DataTable object and building the data set from the information I have. Once this data set is built I need to be able to launch the application as a stand-alone process instead of calling the forms explicitly inside of Spotfire. (This is due to a limitation of GUI threads in Spotfire and we can't call a multi threaded process in a single threaded application as well as we want to keep the Spotfire GUI responsive which can't be done if we call the forms directly)
I know I can launch the exe standalone using Process.Start(), however this doesn't let me pass my information to teh application. How can I build this application to allow me to pass information to it? I've been trying to google examples of how to do this and keep coming up empty handed as people will reference ASP.net or things that are over my head.
Thank you in advance!
EDIT: An example of an application that handles this really well is below. We use DPlot Jr to create graphs externally. The dplot.dll exposes the following function:
[System.Runtime.InteropServices.DllImport("dplotlib64.dll")]
public static extern int DPlot_Plot8(
ref DPLOT d, double[] x, double[] y, string cmds);
which I can then use in my code
docNum = dplot.DPlot_Plot8(ref dPlot, X, Y, cmds);
docNums.Add(docNum);
calling this function in this way actually launches the dplot application and passes the object I've built "dPlot" along with the X and Y data in order to plot the information. I would like to build something like this in my windows form application in order to be able to launch it easily from an external application. Unfortunately I don't know how this function works inside the .dll
EDIT2: I have been able to modify the runtime via the commandline as suggested by Aybe. In my desktop application I have created a conditonal in the main program like so.
if (args.Length == 0 && false)
{
Application.Run(new frmWaveFormViewer());
}
else
{
DataSet dataSet = new DataSet();
//dataSet.LoadMetaData(args[0]);
dataSet.LoadMetaData(#"C:\Users\a0273881\AppData\Local\Temp\tmp1141.tmp");
Application.Run(new frmWaveFormViewer(dataSet));
}
the user can then call the forms externally by using the following...
DataSet dataSet = new DataSet(dpList);
dataSet.PrintDatasetMetadataToFile(String.Format(#"C:\Spotfire\DataSetTesting_{0}.csv", DateTime.Now.ToString("yyyyMMdd_HHmmss")));
string args = dataSet.GetMetaData();
ProcessStartInfo starter = new ProcessStartInfo();
starter.FileName = #"C:\Users\a0273881\Desktop\WaveFormViewer.exe";
starter.Arguments = args;
Process.Start(starter);
However, this is not easy to use for other developers.
I am starting to look into WCF, can anyone provide good resources on WCF for dummies? I'm currently reading through: http://www.codemag.com/article/0705041
I have been able to spawn a NamedPipeServer on the application when it is launched. The named pipeserver names itself tagged with the name of the application + the process id that it spawns with. The process number is logged to a ini file in the users appdata folder. The process can be started with an optional command line argument to effect the value of the "callingApplication" which is the INI Header. This way, we can create multiple instances of the application from different callers without interfering and ensuring connection to the correct named pipe.
static void Main(string[] args)
{
string callingApplication = "None";
if (args.Length != 0)
{
callingApplication = args[0];
}
int pId = Process.GetCurrentProcess().Id;
PipeServer.StartPipeServer(pId, callingApplication);
// do things
PipeServer.StopPipeServer();
}
The PipeClient side is accessed through public functions available in a API static class. Functions that connect through the pipe are all housed in a seperate PipeClient class. These functions require a spawned process id in order to connect to the correct pipe. These are api functions to either launch or return the needed pipe from an api
public static class API
{
public static int SendCommand(int aKey, ...)
{
try
{
PipeClient.StartCommandSendClient(input, aKey);
}
catch (TimeoutException)
{
// returns error codes based on exceptions
}
return 0;
}
}
So with this I've managed to create a link between two applications. All that is really required past this is custom implementation of methods exposed through the API class which have custom client methods to call as well. All of this together is pretty simple to call from my calling app...
int aKey = API.GetKey("callingAppName");
API.SendCommand(aKey, "[Reset()][AddPoint(arg1, arg2, arg3)]");
I wrote a Console Application that I start with parameters in the following way
ABC.exe -oldParam
Inside the application I elaborate the parameters and then want to start the same application with different parameters:
string parms = "-newParam";
System.Diagnostics.Process proc = System.Diagnostics.Process.Start("ABC.exe", parms);
proc.WaitForExit();
The weird thing is, that the new process starts always with the "-oldParam" (the parameters of the 'parent' proccess) instead of "-newParam", regardless what I write into string parms.
Am I missing something?
I've managed to create my own file extension following this tutorial: http://www.codeproject.com/Articles/17023/System-File-Association
So far, it works perfectly. I've got only one thing that I can't solve.
When I double-click on a file with that extension, my program opens up. Now, I'd want to perform an action in my program. I made my way through some threads here and read that the file path is automatically passed to the startup arguments.
The problem is that no single argument is passed, also Process.GetCurrentProcess().StartInfo.FileName returned an empty string. I think this is consecutively because I don't pass any arguments when double-clicking my file.
This is my code:
var fai = new FileAssociationInfo(".extension");
if (!fai.Exists)
{
try
{
fai.Create("My Extension Program");
var pai = new ProgramAssociationInfo(fai.ProgId);
if (!pai.Exists)
{
pai.Create("My Program File",
new ProgramVerb("Open", Application.ExecutablePath);
pai.DefaultIcon = new ProgramIcon(Application.ExecutablePath);
}
}
}
As you can see I only pass the application's path to open it up. But how can I pass the file path as argument now? I've seen that e.g. the author of the article passes "%1" as argument, I tried that, too, but nothing changed.
Thanks in advance.
ProcessStartInfo.FileName usually gives you the path to your program executable itself, not the file which was clicked in Windows Explorer, so this seems the wrong thing to check in your case.
If you want to get the arguments using the current Process, then Process.GetCurrentProcess().StartInfo.Arguments should give you a string containing all the arguments passed to the program. If there are multiple arguments, you would need to parse these into separate values yourself.
But the standard, simpler way to get the arguments is to make sure the Main() method of your program has signature static void Main(string[] args){}. args is already processed into separate values for you, so it is easier to handle it here, even if you only pass it off to another class or store them in a static variable.
The %1 should ensure the clicked file is passed as the first argument (args[0]) to your program.
Well, I got it. What I had to do was creating a subkey in ClassesRoot: "ProgramName\shell\open\command". Then set a value containing the application's path and attach "%1" to it and you're done.
I am currently developing a system that will allow for an external piece of software to click a button and his will then execute some c#.net code that plans to call the Dynamics NAV RTC by using the following code.
Process.Start("Microsoft.Dynamics.Nav.Client.exe");
The external application contains variables that I would like to pass through to the NAV CRM.
Is there a way that i could do this by Passing the parameters like what you would with a web address similar to the way below:
Process.Start("Microsoft.Dynamics.Nav.Client.exe", "DynamicsNAV://localhost:7046/DynamicsNAV70/CRONUS%20UK%20Ltd./RunPage?Page=50000&No=10");
The above line doesn't work. I receive the followowing error:
Priming dictionary contains a key 'no' which is not allowed
Parameter name: primingDictionary
Does anyone in the community know how I could produce this functionality in a similar way?
you can use it like that:
ProcessStartInfo psi = new ProcessStartInfo("Microsoft.Dynamics.Nav.Client.exe",
"DynamicsNAV://localhost:7046/DynamicsNAV70/CRONUS%20UK%20Ltd./RunPage?Page=50000&No=10");
Process.Start(psi);
the first argument is the process itself, the secomd is the argument.
you can change them as you'd like
you can learn on the argument NAV accept here
Yes, just call the overload of Process.Start() that takes input arguments:
Process.Start("Microsoft.Dynamics.Nav.Client.exe", "DynamicsNAV://localhost:7046/DynamicsNAV70/CRONUS%20UK%20Ltd./RunPage?Page=50000&No=10");