Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. ActiveQt / dumpcpp type library - skipping event interface
Forum Updated to NodeBB v4.3 + New Features

ActiveQt / dumpcpp type library - skipping event interface

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 2 Posters 724 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G Offline
    G Offline
    gkeller
    wrote on 12 Oct 2020, 12:47 last edited by
    #1

    Hello,
    I want to use a com component with ActiveQt.
    For this, I created a type library with the dumpcpp utility.

    Unfortunately, there are a lot of "// skipping event interface..." remarks inside the header file which was created from the dumpcpp utility.

    I have also seen an unsolved bug report https://bugreports.qt.io/browse/QTBUG-28383?page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel&showAll=true about this topic.

    Does anybody know a workaround for the skipped event interfaces?

    or

    a better approach (without the dumpcpp utility) to use com components with mingw/Qt?

    1 Reply Last reply
    0
    • H Offline
      H Offline
      hskoglund
      wrote on 12 Oct 2020, 13:29 last edited by
      #2

      Hi, while dumpcpp is helpful, it's not really necessary if you have some documentation for the com component you want to use with ActiveQt, like the names of the callable functions and what arguments they expect.

      For example, when ActiveQt is used for Excel or Word, usually dumpcpp fails for those programs, but ActiveQt works anyway, just google and you'll see.

      1 Reply Last reply
      4
      • G Offline
        G Offline
        gkeller
        wrote on 12 Oct 2020, 14:19 last edited by
        #3

        Hi,
        The whole com component topic is new to me. I have no documentation, only a .tlb file.
        Oleview has no search functionality and also fails when I try to load a .tlb file. But there is a tool called Olewoo which can load the .tlb file and shows some information about the com interface.

        The created classes from the dumpbin utility have no signals (maybe? because of the "skipping event interface" warnings): I do not know how to catch the com events.

        Can you give me a short example how to catch com events without dumpcpp?
        How can I list the available events of Qaxobject?

        1 Reply Last reply
        0
        • H Offline
          H Offline
          hskoglund
          wrote on 12 Oct 2020, 15:39 last edited by
          #4

          Re. short example: I have not, but examples show be easy to find (but probably just vanilla C++ and not using Qt)

          Re. list the available events, first thing you can try is to query your com component's type info and type library using your own C++ code. All well-behaved com components should implement those 2 interfaces, they're called ITypeInfo and ITypeLib.

          I have some old code, to test it, create an empty, vanilla widget in Qt Creator, and then change your main.cpp to this:

          #include "mainwindow.h"
          #include <QApplication>
          
          #include "qaxobject.h"
          #include "quuid.h"
          #include "qdebug.h"
          #include <atlbase.h>
          
          void partyOnTypeLibrary(CComPtr<ITypeLib> pTypeLib)
          {
          // BSTR to QString converter
              auto bstr2QString = [](BSTR bstr) { return QString::fromUtf16((ushort*) bstr); };
          
          // show type library's doc strings
              CComBSTR bstrName,bstrDocString;
              pTypeLib->GetDocumentation(-1,&bstrName,&bstrDocString,NULL,NULL);
              qDebug() << bstr2QString(bstrName) << bstr2QString(bstrDocString) << ":\n";
          
          // step thru all the type info
              for (UINT u = 0; (u < pTypeLib->GetTypeInfoCount()); ++u)
              {
              // get the iTypeInfo ptr
                  CComPtr<ITypeInfo> pTypeInfo;
                  if FAILED(pTypeLib->GetTypeInfo(u,&pTypeInfo))
                      continue;
          
              // get type flavor and name
                  TYPEKIND typeKind;
                  if FAILED(pTypeLib->GetTypeInfoType(u,&typeKind))
                      continue;
          
                  CComBSTR bstrName;
                  if FAILED(pTypeInfo->GetDocumentation(-1,&bstrName,NULL,NULL,NULL))
                      continue;
                  QString sName = bstr2QString(bstrName);
          
              // get the type attribute
                  TYPEATTR* pTypeAttr;
                  if FAILED(pTypeInfo->GetTypeAttr(&pTypeAttr))
                      continue;
          
              // check the type flavor, we support enums, interfaces and coclasses
                  if (TKIND_ENUM == typeKind)
                  {
                      QString sEnums;
                      for (int v = 0; (v < pTypeAttr->cVars); ++v)
                      {
                          VARDESC* pVarDesc;
                          if FAILED(pTypeInfo->GetVarDesc(v,&pVarDesc))
                              break;
          
                          if (v > 0)
                              sEnums += " ";
                          if (VAR_CONST == pVarDesc->varkind)
                              sEnums += QString::number(pVarDesc->lpvarValue->lVal);
          
                          pTypeInfo->ReleaseVarDesc(pVarDesc);
                      }
          
                      qDebug() << "Enum type:" << sName << sEnums;
                  }
          
                  if (TKIND_INTERFACE == typeKind)
                      qDebug() << "Interface type:" << sName;
          
                  if (TKIND_DISPATCH == typeKind)
                      qDebug() << "IDispatch callable type:" << sName;
          
              // any function descriptors? they usually exist for interfaces and IDispatch
                  for (int f = 0; (f < pTypeAttr->cFuncs); ++f)
                  {
                      FUNCDESC* pFuncDesc;
                      if FAILED(pTypeInfo->GetFuncDesc(f,&pFuncDesc))
                          break;
          
                      if (pFuncDesc->wFuncFlags > 0)
                          continue;   // skip these chaps (boring)
          
                      if (pFuncDesc->invkind > INVOKE_PROPERTYGET)
                          continue;   // skip put and putref properties
          
                  // get the prop/func name and all the arg names
                      QStringList slNames;
                      BSTR aBS[1000];     // 1000 should suffice
                      UINT uNames = 0;
                      if FAILED(pTypeInfo->GetNames(pFuncDesc->memid,aBS,1000,&uNames))
                          break;
          
                      for (uint u = 0; (u < uNames); ++u)
                          slNames.append(bstr2QString(aBS[u]));
          
                      QString sKind = "Property";
                      if (pFuncDesc->invkind == INVOKE_FUNC)
                          sKind = "Function";
                      QString sPropOrFuncName = slNames.first();
                      slNames.removeFirst();
          
                      qDebug() << sKind << sPropOrFuncName << slNames;
                  }
                  qDebug() << "";
          
              // we only care about coclasses at this point
                  if (TKIND_COCLASS != typeKind)
                      continue;
          
                  qDebug() << "CoClass:" << bstr2QString(bstrName) << ":";
          
              // step through the implemented types for this coclass
                  for (int i = 0; (i < pTypeAttr->cImplTypes); ++i)
                  {
                      HREFTYPE hRefType;
                      if FAILED(pTypeInfo->GetRefTypeOfImplType(i,&hRefType))
                          continue;
          
                      CComPtr<ITypeInfo> pRefTypeInfo;
                      if FAILED(pTypeInfo->GetRefTypeInfo(hRefType,&pRefTypeInfo))
                          continue;
          
                      CComBSTR bstrInterfaceName;
                      if FAILED(pRefTypeInfo->GetDocumentation(-1,&bstrInterfaceName,NULL,NULL,NULL))
                          continue;
          
                      qDebug() << "        " << bstr2QString(bstrInterfaceName);
                  }
              }
          }
          
          int main(int argc, char *argv[])
          {
              QApplication a(argc, argv);
          
              QString sCOMName = "Excel.Application"; // replace with your component's name
          
          // try to obtain an IDispatch ptr
              auto obj = new QAxObject(sCOMName);
          
              CComPtr<IDispatch> pDispatch;
              obj->queryInterface(QUuid(IID_IDispatch),(void**) &pDispatch);
          
              if (nullptr == pDispatch)
                  qFatal("Error: an IDispatch interface was not found.");
          
          // get the ITypeInfo ptr
              UINT uTypeInfo;
              HRESULT hr = pDispatch->GetTypeInfoCount(&uTypeInfo);
              if (FAILED(hr) || (uTypeInfo < 1))
                  qFatal("Sorry, could not locate any type information");
              if (1 != uTypeInfo)
                  qFatal("Expected GetTypeInfoCount() to return 1 but alas");
          
              CComPtr<ITypeInfo> pTypeInfo;
              if FAILED(pDispatch->GetTypeInfo(0,LOCALE_SYSTEM_DEFAULT,&pTypeInfo))
                  qFatal("Error: GetTypeInfo() failed");
          
          // ok have ITypeInfo, use it to get the ITypeLib
              CComPtr<ITypeLib> pTypeLib;
              UINT uTypeInfoIndex;
              if FAILED(pTypeInfo->GetContainingTypeLib(&pTypeLib,&uTypeInfoIndex))
                  qFatal("Error: GetContainingTypeLib() failed");
          
          // party on this type library
              partyOnTypeLibrary(pTypeLib);
          
          // that's all folks
          }
          

          In theory it should be possible to compile using MinGW, but I recommend using Visual Studio for compiling this example :-)

          Note: this example does not explicitly list the available COM events, but if it lists anything at all it's a good start :-)

          1 Reply Last reply
          1
          • G Offline
            G Offline
            gkeller
            wrote on 13 Oct 2020, 15:41 last edited by
            #5

            Thanks for your code.
            I have no Qt/VC++ toolchain (only mingw) so I had to do some modifications to your code, but got it finally running.

            The interesting part of the output which I get is that it seems as all interfaces skipped by dumpcpp are IDispatch types

            for example:
            The Wrapper created by dumcpp utility has this line. And for ITubeInterfaceEvents there is no wrapper class created.

            // skipping event interface ITubeInterfaceEvents
            

            The output of your code is:

            CoClass: "TubeInterfaceCOM" :
                     "_Object"
                     "ITubeInterface"
                     "ITubeInterfaceEvents"
            IDispatch callable type: "ITubeInterfaceEventArgsCOM"
            "Property" "ToString" ()
            "Property" "Code" ()
            "Property" "Help" ()
            "Property" "Info" ()
            "Property" "Text" ()
            "Property" "Type" ()
            "Property" "Ip" ()
            
            CoClass: "TubeFlagCOM" :
                     "_Object"
                     "IAccessibleBaseCOM"
                     "ITubeFlagCOM"
                     "ITubeFlagCOMEvents"
                     "IAccessibleBaseCOMEvents"
            IDispatch callable type: "ITubeInterfaceEvents"
            "Function" "Initialized" ()
            "Function" "TubeStateChanged" ()
            "Function" "TubeInterfaceError" ("tubeErrorCode")
            "Function" "ConfigurationChanged" ()
            "Function" "RefreshLimitableChanged" ()
            

            Do you know how to use such IDispatch interface types? Even creating an instance like this is not working for me...

            auto obj = new QAxObject(UUID_TubeInterfaceCOM);
            boost::intrusive_ptr<IUnknown> pITubeInterfaceEvents;
            obj->queryInterface(QUuid(UUID_ITubeInterfaceEvents),(void**) &pITubeInterfaceEvents);
            if (nullptr == pITubeInterfaceEvents) qFatal("Error: the interface for UUID_ITubeInterfaceEvents was not found.");
            
            1 Reply Last reply
            0
            • H Offline
              H Offline
              hskoglund
              wrote on 13 Oct 2020, 18:09 last edited by
              #6

              Hi, that's good news, your com component has some iDispatch interfaces (most but not all com components have them), that means you have a foothold into the API.

              Using boost::intrusive_ptr looks dangerously modern, though. All of the COM technology is from last century, so my advice is to stick with those vintage types and macros. For an example of using IDispatch, you can use a pattern similar to my code in the main() function:

              auto obj = new QAxObject(UUID_TubeInterfaceCOM);
              CComPtr<IDispatch> pDispatch;
              obj->queryInterface(QUuid(IID_IDispatch),(void**) &pDispatch);
               if (nullptr == pDispatch)
                      qFatal("Error: an IDispatch interface was not found.");
              
              1 Reply Last reply
              0
              • G Offline
                G Offline
                gkeller
                wrote on 18 Oct 2020, 12:29 last edited by
                #7

                I use the boost::intrusive_ptr because the VC com smart pointer CComPtr ist not available in mingw (at least I did not find a header, but maybe missed it) and a sort of smart pointer seems to be needed with com. I choose intrusive_ptr because COM already counts the references internally.

                Here you will find some explanation:
                https://dieboostcppbibliotheken.de/boost.smartpointers-spezielle-smartpointer
                -> it is german, but maybe you can translate it.

                Do you know where I can find CComPtr in mingw?

                //-----------------------------------------------------------------

                Here is my workaround/solution for the initial topic (The skipped event interface) for others who have this problem.

                I recognized that I can connect a generic signal handler to the com component (QAxObject) which contains the skipped event interface and can catch the events there. Something like this:

                connect( m_qaxobject, SIGNAL(signal(const QString&, int, void*)),
                                 this, SLOT(eventSink(const QString&, int, void*)) );
                
                void AClass::eventSink( const QString & name, int argc, void * argv )
                {
                  // See what events fired
                  qDebug() << "Event: " << name << "argc:" << argc;
                  
                  if( name == "EventInterfaceEvent()" )
                  {
                  ...
                  }
                }
                

                I have another issue with the wrapper which the dumpp utility created, therefore I will open another topic.

                1 Reply Last reply
                0

                1/7

                12 Oct 2020, 12:47

                • Login

                • Login or register to search.
                1 out of 7
                • First post
                  1/7
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved