9

I'm trying to create a connection to multiple instances of an open application (WRQ Reflection). Connecting to the first instance that was opened is fine using this:

Session appInstance = (Marshal.GetActiveObject("Reflection4.Session.8") as Session);

But I'd like to be able to connect to multiple instances. I've been doing alot of research and found some helpful links such as this, but that solution wont work in this situation as all the open instances have the same progId.

I've also tried looking at the window handles, which are obviously different for each instance. Using this:

Process[] processes = Process.GetProcessesByName("r4win");
foreach (Process p in processes)
{
    IntPtr windowHandle = p.MainWindowHandle;
    string handle = windowHandle.ToString();

    MessageBox.Show(handle);
}

But I haven't been able to figure out how to create a connection to the window via the window handle.

Any assistance is appreciated.

Additional Code:

void TestROT()
{
    // Look for open instances
    string[] progIds = {"Reflection4.Session.8"};

    List<object> instances = GetRunningInstances(progIds);

    foreach (object refleObjs in instances)
    {
        Session session = refleObjs as Session;
        session.Transmit("12345");
    }
}

For this scenario, I have 2 instances of the target application running. In the above code, it will send the string 12345 to the same instance of the application, twice.

I need it to send 12345 to the first instance, and then 12345 to the second instance.

Kieran Quinn
  • 1,085
  • 2
  • 22
  • 49
  • 1
    What do you mean connect? To do what? The code you posted is about COM Automation, not any kind of connection. It's about eg. driving Word using Interop. What are you trying to do? Connection implies things like sockets, services, WCF etc, not automation – Panagiotis Kanavos Nov 06 '15 at 09:12
  • PS even in COM, CreateObject will create a new object or use an existing, while GetActiveObject will create a new one. In .NET though people use COM Interop instead of the raw COM methods – Panagiotis Kanavos Nov 06 '15 at 09:15
  • Apologies, not sure of the correct terminology. By connect, I mean the ability to send text, and commands to the application, and read information from the screen. – Kieran Quinn Nov 06 '15 at 09:18
  • *What are you trying to do?* Even Automation will expose what the application wants to expose. Reading the screen though is used by accessibility utilities and use the Accessibility SDK. Test utilities and libraries actually use the Accessibility APIs to drive UIs – Panagiotis Kanavos Nov 06 '15 at 09:22
  • Using `Marshal.GetActiveObject` I can create a **Reflection** object of the open application. Then I can call the methods included in the reflection api such as `appInstance.GetText()` or `appInstance.Transmit()`. I want to be able to do the same thing, but for multiple running instances of the appliction – Kieran Quinn Nov 06 '15 at 09:28
  • Which duplicate, links back to *your* linked article that actually does answer the question. Identical prog ids are *not* a problem, they identify the target class. Obviously, all Autocad instances will have the same ProgID. You need (and the code shows) how to retrieve all active instances for a single ProgID – Panagiotis Kanavos Nov 06 '15 at 09:36
  • Are you are confusing **Reflection** with [this](https://msdn.microsoft.com/en-us/library/ms173183.aspx)? `appInstance` above IS an object of type `Session`. When I use the code from that article to retrieve all active instances, it returns one. Even when there are multiple instances open, I believe it is because they all have the same target class – Kieran Quinn Nov 06 '15 at 09:44
  • I'm not confusing Reflection with ... Reflection. That *is* what reflection means in .NET. What you describe is COM and the methods you use are from the Interop namespace. And I *have* worked with COM, COM+ and interfaces in the 90s so I know what a ROT is what is or isn't an AppInstance etc. – Panagiotis Kanavos Nov 06 '15 at 09:52
  • The short answer is - you already have a link to an article with the way to retrieve all instances of an application, and an explanation on how this works. Do you have a question beyond that? – Panagiotis Kanavos Nov 06 '15 at 09:52
  • Like I already mentioned in the last comment, when I use the code from that article to retrieve all active instances, it returns one. I don't know why but maybe because all instances are using the same classID's. My question is, is there a way around that, or another way to identify open applications other than `GetActiveObject`, perhaps identifying them via whandle. – Kieran Quinn Nov 06 '15 at 09:56
  • Of course they are, they *are* instances of the same type. The ROT will contain *multiple* entries for a single CLSID, one for each active application instance. The last `while` goes through the table to find all of them – Panagiotis Kanavos Nov 06 '15 at 10:00
  • I've added some additional code based on the article. – Kieran Quinn Nov 06 '15 at 10:06
  • @PanagiotisKanavos please unmark as duplicate. I've shown that the accepted solution on that question does not work in this scenario. – Kieran Quinn Nov 06 '15 at 10:25
  • As for me you are trying to do some kind of IPC but in some strange way. Why don't you use common tools for that? – Ilia Maskov Jan 26 '16 at 16:40
  • It may very well be possible that this specific COM application does not support accessing multiple instances. For example, that's how Visual Studio does (it's based on "monikers" that are processId-specific) it: http://blogs.msdn.com/b/kirillosenkov/archive/2011/08/10/how-to-get-dte-from-visual-studio-process-id.aspx, but not every COM server supports that kind of moniker syntax. If when you run the sample code, no interesting moniker shows up, then it's bad news (make sure you try it under admin/non admin account). Or try to contact this application support. – Simon Mourier Jan 26 '16 at 22:10
  • Have you looked at [this link](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365574(v=vs.85).aspx)? It's a documentation from Microsoft on IPC (Interprocess communication). They list a variety of ways to establish communication between different applications. However, You need to be able to change both the sender and the recipient applications code. – ATC Jan 27 '16 at 08:30
  • 1
    did you see this ? http://stackoverflow.com/questions/13432057/how-to-use-marshal-getactiveobject-to-get-2-instance-of-of-a-running-process-t – Ilia Maskov Jan 29 '16 at 11:18

2 Answers2

5

You can use the classes NamedPipeClientStream and NamedPipeServerStream in the System.IO.Pipes-namespace to send data from your application to another one. In your first application implement a NamedPipeServerStream like this:

NamedPipeServerStream pipeServer = new NamedPipeServerStream("MyApp1");
pipeServer.WaitForConnection();//wait for connection of client

Place an instance of NamedPipeClientStream in your second application:

NamedPipeClientStream clientStream = new NamedPipeClientStream("MyApp1");
clientStream.Connect();

After connecting the client to the server you can send the data by using the methode Write:

Sending data from your server:

byte[] test = Encoding.UTF8.GetBytes("Hello World");
pipeServer.Write(test, 0, test.Length);

Sending data from the client:

byte[] test = Encoding.UTF8.GetBytes("Hello World");
clientStream.Write(test, 0, test.Length);

You can use Read to get the received bytes. This method exists in both classes.

You also can use more than one server and one client at the same time to communicate with more applications.

daniel59
  • 906
  • 2
  • 14
  • 31
  • I'm not familiar with Named Pipes, but it sounds like I need the ability to add code to the application I'm trying to automate, which isn't possible in this case. – Kieran Quinn Jan 29 '16 at 11:01
0

From the description in your question, perhaps what you want to do is get all instances of a running COM object.

Community
  • 1
  • 1
Joe
  • 122,218
  • 32
  • 205
  • 338
  • Ok so using the blog post in the answer to that question, the code requires some modification and is missing the list types but it does return a list of items in the ROT. I'm returning them as `List` which works fine but I cant convert the items I want from the list to the application type I'm using - `Session`. Getting _Cannot convert type 'Form2.RunningObject' to 'Reflection4.Session' via a reference conversion etc_ – Kieran Quinn Jan 29 '16 at 11:58
  • Does the following help? http://stackoverflow.com/questions/24612691/cannot-get-interface-from-different-process-via-rot – Joe Jan 29 '16 at 12:26