hexagon logo

Got Visual Studio and the Interop.PCDLRN.dll... Now what?

As I upgraded one CMM to Windows 7 64-bit, my small VBS helpers died in the process (still kickin' butt on XP though).
So, I have begun re-coding them in Visual Studio 2010 (I think). I have gotten so far in the coding where I need to connect to PC-DMIS and start interfacing with it. Now, I managed to find the DLL that is supposed to expose some interfaces and methods and I have successfully added it to my project.

Then what? How do I use the DLL to connect to PC-DMIS and expose the PartPrograms collection for instance?

Oh, I am using C# for this...

Any and all input, examples or suggestions are VERY welcome!

TIA!
  • Did you add a reference to the PC-DMIS object library, or did you just add the DLL itself into your solution (in the solution explorer tree display, by default in the top-right corner of the VS IDE)?

    Check out this thread where I walk someone through their first foray into Visual Studio: http://www.pcdmisforum.com/showthread.php?26953-Script-to-make-a-change-in-all-programs. At some point, I explain how to add a reference to a COM object library.

    Everything I program for work is in VB, so I don't have any examples calling PC-DMIS through C#; I can throw some together for you later tonight or tomorrow.
  • Yep, I added the DLL through "Add reference" in the top-right corner.

    This is the snippet where I try to connect to PC-DMIS, but it gives me the "PC-DMIS needs to be started" no matter what...
    It doesn't matter if the DLL is present or not...

    if (openfiledialog1.ShowDialog() == DialogResult.OK)
                        {
                            try
                            {
                                PCDLRN.IApplication PCDApp = new PCDLRN.Application(); // fetch the PC-DMIS application
                                PCDLRN.IPartPrograms PCDPartPrograms = PCDApp.PartPrograms; // set up partprograms
                                PCDPartPrograms.Open(openfiledialog1.FileName, "CMM1"); // have PC-DMIS open the PRG
                                //PCDPartPrograms = null;
                                //PCDApp = null;
                            }
                            catch (Exception)
                            {
                                MessageBox.Show("PC-DMIS needs to be started!"); // PC-DMIS needs to be started!
                                Application.Exit(); // Exit
                            }
                        }
  • It might be useful for you to show the actual error from the Exception object, instead of just showing a text of your own.

    Note that your problem can still be that PCDLRN.Application in the Registry has not been updated (as I mentioned in other threads) and points to an older version of PC-DMIS. It is not clear from your post if PC-DMIS is already running when you try the script, or if you expect the script to start PC-DMIS.
  • It is a clean slate installation - no other versions are installed or have been installed, 2013 MR1 SP1 only.

    I have tried with PC-DMIS started and with it not started, but it doesn't matter.

    I probably don't have to mention that C# is a totally new environment for me, I feel like a hurt antelope on the C# + PC-DMIS plain, the lions are many and I am seriously limping...

    ...to make matters worse, I cannot do a live debug on the PC-DMIS CMM (IT restrictions).
  • I think what Anders is trying to say is you are getting an exception when you start PC-DMIS, but all you ever give yourself for feedback is your own generic message.

    Instead of this:

    MessageBox.Show("PC-DMIS needs to be started!");


    Try something like this:

    MessageBox.Show("ConnectPCDMIS : " & Exception.Message);


    You can change "ConnectPCDMIS" to whatever the name of the method you are making this call from (gives you a bit of a trace as to where exceptions are happening as your program gets bigger.) The main thing is, you'll be passing the message from the exception so your message box will tell you more about what's going on.
  • Run regedit.exe, look in HKEY_CLASSES_ROOT for PCDLRN.Application and PCDLRN.Application.8.1 - do they both have a CLSID, and the same?

    If they are the same, search the registry for that CLSID (it looks something like {AC5C0EBD-E5E6-4AFB-95CB-1861FDCF785F}) and see what the LocalServer32 key says (something like "C:\Program Files\WAI\PC-DMIS 2013 MR1 (Release) 64-bit\PCDLRN.exe" (NOTE: Quotes should be included). Verify that this is the actual path to your PC-DMIS.

    And if you don't understand these instructions, leave the regedit running to someone else...Stuck out tongue closed eyes

    The following VBA for Excel code works on my Win7/64, PC-DMIS/64 (opens a connection to an already running PC-DMIS)

      Dim app As PCDLRN.Application
      Dim cmds As PCDLRN.Commands
      Dim part As PCDLRN.PartProgram
      
      Set app = CreateObject("PCDLRN.Application")
      Set part = app.ActivePartProgram
      Set cmds = part.Commands
    
  • This seems to work for me:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
    
            static Type PCDLRN_Application = null;
            static dynamic PCDApp = null;
            static dynamic PCDParts = null;
            static dynamic PCDPart = null;
    
            static void Main(string[] args)
            {
    
                try
                {
                    PCDLRN_Application = Type.GetTypeFromProgID("PCDLRN.Application");
                    PCDApp = System.Activator.CreateInstance(PCDLRN_Application);
                    PCDApp.WaitUntilReady(60);
                    System.Threading.Thread.Sleep(2000);
                    PCDApp.OperatorMode = false;
                    PCDApp.Visible = true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    Console.ReadLine();
                }
                Console.ReadLine();
            }
        }
    }


    To connect to an existing instance, you would need to use System.Runtime.InteropServices.Marshal.GetActiveObject instead of System.Activator.CreateInstance. I don't believe there is a simple way to do both from one call in C# (VB takes care of this in the background for you.)

    You may find it easier to reference to use VB for your resource management calls:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
    
            static Type PCDLRN_Application = null;
            static PCDLRN.Application PCDApp = null;
            static PCDLRN.PartPrograms PCDParts = null;
            static PCDLRN.PartProgram PCDPart = null;
    
            static void Main(string[] args)
            {
    
                try
                {
                    //PCDLRN_Application = Type.GetTypeFromProgID("PCDLRN.Application");
                    PCDApp = (PCDLRN.Application)Microsoft.VisualBasic.Interaction.CreateObject("PCDLRN.Application","");
                    PCDApp.WaitUntilReady(60);
                    System.Threading.Thread.Sleep(2000);
                    PCDApp.OperatorMode = false;
                    PCDApp.Visible = true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    Console.ReadLine();
                }
    
                Console.ReadLine();
            }
        }
    }
  • Thanks for all your input, I checked the GUIDS and they all checked out, they existed and the path is correct.

    What I haven't done is trying the VB-path as I want to create this as a learning experience for me in C#.
    Who knows, I might have to do that if this doesn't work out (thanks ewe0006).

    As I explained, the C# arena is new to me and I have no previous experience, but I feel like this could be a bug as I can't connect to PC-DMIS at all using the Marshal.GetActiveObject in C#... I have a little tester app that checks for the instance in the ROT (Running Object Table) and PC-DMIS does not seem to be available there. Start Word (and PC-DMIS), then run my app (run it in a command window) and it will look for both an instance of Word and PC-DMIS through Marshal.GetActiveObject. Here, it finds Word when started and reports the opposite when Word isn't started. PC-DMIS on the other hand, displays as not available no matter what. I have tried running it elevated and not elevated to no avail. I want to connect to a running instance of PC-DMIS - not start a new one.

    The app is available here:
    http://www.datafilehost.com/d/6d40852b

    As always, any and all input is welcome!
  • Well, something you will learn pretty quickly is that C# is not particularly conducive to working with COM, just like C++, Objective C, and all the other "C" based languages. Unfortunately, it just wasn't a particularly high concern at the time of the design. VB, however, is pretty specifically designed with COM in mind for non-programmers to script automation of simple tasks in applications with an API. Whenever you hear hardcore C# programmers talking (or rather, complaining) about having to work with COM, they will generally mention the massive wrapper classes they have to write.

    In my spare time, I am (or should say 'was' since I don't know what spare time is anymore) developing a machine/robotic vision application, the interface to which is actually through COM. To make life easier, the camera manufacturer includes a utility that will generate a wrapper class for my specific model of camera and in my choice of a few different languages. Since I'm currently developing that application in C# (in Mono on a MacBook), that utility has been a Godsend.

    Edit: Here's a little PC-DMIS wrapper class for C# I picked up somewhere along the way: https://www.dropbox.com/s/o91x6gqkfwkuok7/H_Pcdmis.zip