5 Replies Latest reply on Jan 28, 2010 5:04 AM by john_dube

    Attach to a specific instance of MGCPCB (with C#)

    janpieter.deruiter

      Hi all,

       

      since I can't find any thread of anyone using C# with MGCPCB Automation, I doubt anyone can help me, but here's my shot:

       

      Well, as I said, I'm using a C# application with Automation, and until now I figured out how to get it working (if anyone is interested, I can provide a basic setup how to do it).

      One of the features I included is that it is possible to start my application from Expedition PCB, through a menu item.

      The problem is that the only way I found to open a PCB in C# was by calling the "OpenDocument" function from a ExpeditionPCBApplication object.

      This will create a new instance of Expedition, and because it is already opened, I get a "Read only" warning.

      That's not realy a problem, but the user might have changed the design already without saving, and thus my C# application will get an "outdated" design.

       

      So I start looking, and found that in VBScript you can attach to a running instance with a GetObject call.

      Though C# doesn't have this function, I found that you can use Marshal.GetActiveObject.

      But the problem is that when more designs are opened at the same time, GetActiveObject will always attach to the design which was opened first.

      So when I first open one design, and then open a second design, and start my application from the second design, the application will be attached to the first design.

      (I guess the same will happen when using GetObject from a VBScript...)

      But when I want to attach to a specific instance by enumerating all running Monikers, and then selecting the moniker with the PCB design file as display name, I get an "Invalid interface" error.

       

      Does anyone know how I can solve this, or at least if it is possible in VBScript to attach to a specific instance?

       

      Thanks in advance.

       

      JP de Ruiter

        • 1. Re: Attach to a specific instance of MGCPCB (with C#)
          janpieter.deruiter

          Hi all,

           

          after looking into it a little more, I found that two Monikers where running for one design, one with the PCBFile name as DisplayName, and the other with the ProcessID as DisplayName.

          I tried to get the Interface from the first Moniker, but you should use the second for it.

          It's working now :-)

           

          Here's the C# class I use to do it (based on http://www.experts-exchange.com/Programming/Languages/.NET/Q_24115864.html)

           

           

          [CODE]

          using System;

          using System.Runtime.InteropServices;

          using System.Collections;

          using System.Runtime.InteropServices.ComTypes;

          using System.Diagnostics;

           

          namespace TestSpecificInstance

          {

              class RunningExpeditionPCBInstances

              {

                  [DllImport("ole32.dll")]

                  private static extern int GetRunningObjectTable(int reserved,

                      out IRunningObjectTable prot);

           

                  [DllImport("ole32.dll")]

                  private static extern int CreateBindCtx(int reserved,

                      out IBindCtx ppbc);

           

                  public static MGCPCB.ExpeditionPCBApplication GetSpecificInstance(string PCBFile)

                  {

                      // Convert the prog id into a class id

                      MGCPCB.ExpeditionPCBApplication ReturnPCB = null;

                      Process[] processes = Process.GetProcessesByName("EXPEDITIONPCB");

                      foreach (Process proc in processes)

                      {

                          if (proc.MainWindowTitle.IndexOf(PCBFile) != -1)

                          {

                              IRunningObjectTable prot = null;

                              IEnumMoniker pMonkEnum = null;

                              try

                              {

                                  IntPtr Fetched = IntPtr.Zero;

                                  // Open the running objects table.

                                  GetRunningObjectTable(0, out prot);

                                  prot.EnumRunning(out pMonkEnum);

                                  pMonkEnum.Reset();

                                  IMoniker[] pmon = new IMoniker[1];

           

                                  // Iterate through the results

                                  while (pMonkEnum.Next(1, pmon, Fetched) == 0)

                                  {

                                      IBindCtx pCtx;

           

                                      CreateBindCtx(0, out pCtx);

           

                                      string displayName;

                                      pmon[0].GetDisplayName(pCtx, null, out displayName);

                                      Marshal.ReleaseComObject(pCtx);

                                      if (displayName.IndexOf(proc.Id.ToString("D")) != -1)

                                      {

                                          // Return the matching object

                                          object objReturnObject;

                                          prot.GetObject(pmon[0], out objReturnObject);

                                          ReturnPCB = (MGCPCB.ExpeditionPCBApplication)objReturnObject;

                                      }

                                  }

                              }

                              finally

                              {

                                  // Free resources

                                  if (prot != null)

                                      Marshal.ReleaseComObject(prot);

                                  if (pMonkEnum != null)

                                      Marshal.ReleaseComObject(pMonkEnum);

                              }

                              break;

                          }

                      }

                      return ReturnPCB;

                  }

              }

          }

          [/CODE]
          • 2. Re: Attach to a specific instance of MGCPCB (with C#)
            yu.yanfeng

            Much thanks!

            Last year, I try to migrate some VB scripts to C# scripts, I encounted this problem.

            Yanfeng

            • 3. Re: Attach to a specific instance of MGCPCB (with C#)
              john_dube

              Why not just the Utility.FindApplication method?

               

                          ExpeditionPCBApplication pcbApp = (ExpeditionPCBApplication)Marshal.GetActiveObject("MGCPCB.ExpeditionPCBApplication");

                          int cnt = 0;

                          pcbApp = (ExpeditionPCBApplication)pcbApp.Utility.FindApplication(cnt);

                          while (pcbApp != null)

                          {

                              MessageBox.Show(pcbApp.ActiveDocument.FullName);

                              cnt += 1;

                              pcbApp = (ExpeditionPCBApplication)pcbApp.Utility.FindApplication(cnt);

                          }

              John

              • 4. Re: Attach to a specific instance of MGCPCB (with C#)
                janpieter.deruiter

                I thought I had been through the documentation completely, but appearently missed that one.

                 

                Thanks a lot.

                I suppose it's doing the same as the function I wrote, but it would have saved me a lot of time.

                Next time I'll search the docs better ;-)

                • 5. Re: Attach to a specific instance of MGCPCB (with C#)
                  john_dube

                  It's good to have the running object table code anyway, in case someone wants to connect to a specific instance of DxDesigner, which does not have a FindApplication method.

                   

                  John