10 Replies Latest reply on Dec 19, 2014 3:24 PM by gregor

    Need help getting the type for each ProcessBook symbol in display (ActiveX)

    Asle Frantzen



      I'm creating a docking window add-in to ProcessBook, and I'm foreach'ing my way through all the symbols in the active display to locate the ones I'm going to work with. All the trends and value symbols are easily identifiable, but I'm going to work on an ActiveX component and I can't seem to get the type/class for these controls. All I get when I debug is the name (which could be "HistogramControl1") and a lot of System.___COMobject stuff, but I'd like to get the class name ("HistogramControl") so that I can be sure I'm working on the correct items. (Of course I could use the name of the object, since they are named "HistogramControl1/2/3" etc. but end users might rename them to something else so I'd like to avoid that).


      I'm also able to filter on ActiveX / COM controls in general, in the display symbols collection:


      foreach (PBObjLib.Symbol s in currentDisplay.Symbols)
      if ((PBObjLib.pbSYMBOLTYPE)s.Type == PBObjLib.pbSYMBOLTYPE.pbSymbolControl)
           //Do work


      But I just can't seem to get more information out from my Symbol s.




      When I look at the Properties dialog for each Symbol in ProcessBook I see the name of the object + the class (in the dropdown list on top of the dialog), so the class information should be available. I'm thinking it's just a matter of casting it to the right type, but so far I haven't been successful with that. Any idea on how to extract the type/class info for these controls?


      Another part of my add-in is to add new controls to the active display, and here I've successfully been able to add new instances of my ActiveX control by sending the ProgID into the Symbols.Add function:


      PBObjLib.Symbol aControl = currentDisplay.Symbols.Add(PBObjLib.pbSYMBOLTYPE.pbSymbolControl, "Amitec.Amitec_Histogram_Component.HistogramControl");


      But it seems that once I "send" that ProgID into the Add function it's gone, and there's no way to retrieve it. What am I doing wrong?

        • Re: Need help getting the type for each ProcessBook symbol in display (ActiveX)

          Hi Asle,


          A long while ago I have created some code to change colors in a display, and I had the same concern I needed to identify the right object.  So how do we do that?

          Well, there is an instruction called TypeOf that can be used to compare an object to its type,  and I think that is what interests you.


          Here is an example:

          ' Procedure : ChangeColors
          ' Purpose   : Change colors of the display
          Public Sub ChangeColors()
              Dim o As Object
              Dim LiteBlue As Long
              Dim LiteBlue2 As Long
              Dim LiteYellow As Long
              LiteBlue = RGB(128, 152, 217)
              LiteYellow = RGB(231, 239, 199)
              LiteBlue2 = RGB(158, 177, 226)
              For Each o In ThisDisplay.Symbols
                  If TypeOf o Is Value Then
                      o.BackgroundColor = -1    ' set transparency
                  End If
                  If TypeOf o Is Rectangle Then
                      If o.Height > 100 Then
                          o.FillColor = LiteBlue
                          o.FillColor = LiteYellow
                      End If
                  End If
                  If TypeOf o Is Button Or TypeOf o Is Trend Then
                      o.BackgroundColor = LiteBlue
                  End If
              ThisDisplay.BackgroundColor = LiteBlue2
          End Sub


          Let us know if this helps.

            • Re: Need help getting the type for each ProcessBook symbol in display (ActiveX)
              Asle Frantzen



              I'm mainly a C# guy so I can't tell if you intended a VB.net or VBA example here (I'm leaning towards the latter), but this isn't helping me in any way. As I mentioned in my post I can distinguish between objects of the different types defined in the enum PBObjLib.pbSYMBOLTYPE (which includes pbSymbolValue, pbSymbolTrend, pbSymbolControl, etc.) but once I've found objects of the pbSymbolControl type I'm not finding more details. It could be my HistogramControl or it could be MSFlexGrid or another control.

            • Re: Need help getting the type for each ProcessBook symbol in display (ActiveX)
              Rhys Kirk

              Cast the Symbol to a PBControl, then get the type of the PBControl.Object property.

                • Re: Need help getting the type for each ProcessBook symbol in display (ActiveX)
                  Asle Frantzen

                  Hi Rhys


                  Unfortunately I can't seem to be able to cast it to anything. I get System.InvalidCastException: Can't use object type PBObjLib.SymbolClass as PBSymLib.PBControl when trying that.


                  I've tested the code with other controls (such as MSFlexGrid) as well, with no luck

                    • Re: Need help getting the type for each ProcessBook symbol in display (ActiveX)
                      Rhys Kirk

                      Ah, right, I did it in VBA of the display so C# is a bit more tircky.


                      You need to cast to an object first then to the PBControl:

                      PBSymLib.PBControl pbc = (PBSymLib.PBControl)(object)sym;


                      Now the real tricky part, the Object property of the PBControl is likely going to come back as a Com Object. You'll have to use an IDispatch approach to get the actual wrapped type name in C#. I quickly did the following code, but I wanted to find a better way...


                      using System;
                      using System.Collections.Generic;
                      using System.Linq;
                      using System.Text;
                      using System.Threading.Tasks;
                      using System.Reflection;
                      using System.ComponentModel;
                      using System.Runtime.InteropServices;
                      using ComTypes = System.Runtime.InteropServices.ComTypes;
                          interface IDispatch
                              int GetTypeInfoCount(out int Count);
                              int GetTypeInfo
                                      [MarshalAs(UnmanagedType.U4)] int iTInfo,
                                      [MarshalAs(UnmanagedType.U4)] int lcid,
                                      out ComTypes.ITypeInfo typeInfo
                              int GetIDsOfNames
                                      ref Guid riid,
                                      [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgsNames,
                                      int cNames,
                                      int lcid,
                                      [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId
                              int Invoke
                                      int dispIdMember,
                                      ref Guid riid,
                                      uint lcid,
                                      ushort wFlags,
                                      ref ComTypes.DISPPARAMS pDispParams,
                                      out object pVarResult,
                                      ref ComTypes.EXCEPINFO pExcepInfo,
                                      IntPtr[] pArgErr


                      Then you need to do something like...

                                      IDispatch dispatch = o as IDispatch;
                                      ComTypes.ITypeInfo typeInfo = null;
                                      dispatch.GetTypeInfo(0, 0, out typeInfo);
                                      string typeName = "";
                                      string documentation, helpFile;
                                      int helpContext = -1;
                                      typeInfo.GetDocumentation(-1, out typeName, out documentation, out helpContext, out helpFile);


                      Not as simple as in VBA unfortunately. I'll take another look shortly to see if there is an easier way.

                      • Re: Need help getting the type for each ProcessBook symbol in display (ActiveX)
                        Rhys Kirk

                        Here you go, much simpler...


                        static extern int ProgIDFromCLSID([In] ref Guid clsid, [MarshalAs(UnmanagedType.LPWStr)] out string lplpszProgID);
                        [ComImport, Guid("0000010c-0000-0000-c000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
                        public interface IPersist
                             void GetClassID(out Guid pClassID);
                        Guid controlGUID;
                        ((IPersist)pbc.Object).GetClassID(out controlGUID);
                        string controlProgId;
                        ProgIDFromCLSID(ref controlGUID, out controlProgId);
                    • Re: Need help getting the type for each ProcessBook symbol in display (ActiveX)
                      Asle Frantzen

                      So Rhys's solution works, but not all the time. Sometimes there's still a problem casting the symbol to a PBControl, but it seems it's only in rare cases so I'm going this way anyways.


                      I still haven't found the solution to why the ProcessBook Application object can't find and identify my controls until I've switched Run/Build mode back and forth, but my workaround for now is to do this every time the ActiveDisplay has changed:


                      ProcBookApp.RunMode = !ProcBookApp.RunMode;
                      ProcBookApp.RunMode = !ProcBookApp.RunMode;


                      If anyone would happen to know how to avoid this please let me know!