简体   繁体   中英

Calling a Windows Forms Application via C# API

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)]");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM