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. Accessing OCX APIs using QAxContainer
Forum Updated to NodeBB v4.3 + New Features

Accessing OCX APIs using QAxContainer

Scheduled Pinned Locked Moved Unsolved General and Desktop
7 Posts 2 Posters 559 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.
  • K Offline
    K Offline
    Ketan
    wrote on 21 May 2019, 08:28 last edited by
    #1

    Is there any way to get the list of the registered OCX's APIs using QAxContainer?

    1 Reply Last reply
    0
    • H Offline
      H Offline
      hskoglund
      wrote on 21 May 2019, 19:10 last edited by
      #2

      Hi, I have an old example for listing the API's of an application (Excel). see below (note: the output is more than 10000 lines).

      It should work the same for an OCX loaded into your QAxContainer, you only need an IDispatch pointer to the OCX, which this program uses to obtain the ITypeInfo pointer and then list the API of the COM object.

      #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);
              }
          }
      }
      
      void main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
      
      // launch Excel and try to obtain an IDispatch ptr
          auto excel = new QAxObject("Excel.Application");
          CComPtr<IDispatch> pDispatch;
          excel->queryInterface(QUuid(IID_IDispatch),(void**) &pDispatch);
      
          if (nullptr == pDispatch)
              return qDebug("Error: an IDispatch interface to \"Excel.Application\" was not found.");
      
      // get the ITypeInfo ptr
          UINT uTypeInfo;
          HRESULT hr = pDispatch->GetTypeInfoCount(&uTypeInfo);
          if (FAILED(hr) || (uTypeInfo < 1))
              return qDebug("Sorry, could not locate any type information");
          if (1 != uTypeInfo)
              return qDebug("Expected GetTypeInfoCount() to return 1 but alas");
      
          CComPtr<ITypeInfo> pTypeInfo;
          if FAILED(pDispatch->GetTypeInfo(0,LOCALE_SYSTEM_DEFAULT,&pTypeInfo))
              return qDebug("Error: GetTypeInfo() failed");
      
      // ok have ITypeInfo, use it to get the ITypeLib
          CComPtr<ITypeLib> pTypeLib;
          UINT uTypeInfoIndex;
          if FAILED(pTypeInfo->GetContainingTypeLib(&pTypeLib,&uTypeInfoIndex))
              return qDebug("Error: GetContainingTypeLib() failed");
      
      // party on this type library
          partyOnTypeLibrary(pTypeLib);
      
      // sayonara
          excel->dynamicCall("Quit()");
      }
      
      K 1 Reply Last reply 30 May 2019, 04:56
      1
      • K Offline
        K Offline
        Ketan
        wrote on 22 May 2019, 04:06 last edited by
        #3

        @hskoglund said in Accessing OCX APIs using QAxContainer:

        TypeLib(&p

        Thank you!

        1 Reply Last reply
        0
        • H hskoglund
          21 May 2019, 19:10

          Hi, I have an old example for listing the API's of an application (Excel). see below (note: the output is more than 10000 lines).

          It should work the same for an OCX loaded into your QAxContainer, you only need an IDispatch pointer to the OCX, which this program uses to obtain the ITypeInfo pointer and then list the API of the COM object.

          #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);
                  }
              }
          }
          
          void main(int argc, char *argv[])
          {
              QApplication a(argc, argv);
          
          // launch Excel and try to obtain an IDispatch ptr
              auto excel = new QAxObject("Excel.Application");
              CComPtr<IDispatch> pDispatch;
              excel->queryInterface(QUuid(IID_IDispatch),(void**) &pDispatch);
          
              if (nullptr == pDispatch)
                  return qDebug("Error: an IDispatch interface to \"Excel.Application\" was not found.");
          
          // get the ITypeInfo ptr
              UINT uTypeInfo;
              HRESULT hr = pDispatch->GetTypeInfoCount(&uTypeInfo);
              if (FAILED(hr) || (uTypeInfo < 1))
                  return qDebug("Sorry, could not locate any type information");
              if (1 != uTypeInfo)
                  return qDebug("Expected GetTypeInfoCount() to return 1 but alas");
          
              CComPtr<ITypeInfo> pTypeInfo;
              if FAILED(pDispatch->GetTypeInfo(0,LOCALE_SYSTEM_DEFAULT,&pTypeInfo))
                  return qDebug("Error: GetTypeInfo() failed");
          
          // ok have ITypeInfo, use it to get the ITypeLib
              CComPtr<ITypeLib> pTypeLib;
              UINT uTypeInfoIndex;
              if FAILED(pTypeInfo->GetContainingTypeLib(&pTypeLib,&uTypeInfoIndex))
                  return qDebug("Error: GetContainingTypeLib() failed");
          
          // party on this type library
              partyOnTypeLibrary(pTypeLib);
          
          // sayonara
              excel->dynamicCall("Quit()");
          }
          
          K Offline
          K Offline
          Ketan
          wrote on 30 May 2019, 04:56 last edited by
          #4

          @hskoglund Any workaround to get the datatype of the interface arguments?

          H 1 Reply Last reply 30 May 2019, 12:35
          0
          • K Ketan
            30 May 2019, 04:56

            @hskoglund Any workaround to get the datatype of the interface arguments?

            H Offline
            H Offline
            hskoglund
            wrote on 30 May 2019, 12:35 last edited by
            #5

            @Ketan The type discovery (reflection is the more modern term) in my example is via the OLE Automation API:s (VARIANTS, SAFEARRAY and IDispatch-based interfaces) so the datatypes are expected to be Automation-compatible, i.e. callable from Visual Basic or VBScript.

            But there's no rule saying an .OCX has to restrict itself to just using VARIANT-based datatypes, from C++ you can use any type of struct or class in an .OCX.

            If your .OCX has those type flavors, have you tried the dumpcpp.exe tool in Qt's bin directory? (That tool will generate .h and .cpp files which you #include in your project).

            K 1 Reply Last reply 31 May 2019, 08:36
            1
            • H hskoglund
              30 May 2019, 12:35

              @Ketan The type discovery (reflection is the more modern term) in my example is via the OLE Automation API:s (VARIANTS, SAFEARRAY and IDispatch-based interfaces) so the datatypes are expected to be Automation-compatible, i.e. callable from Visual Basic or VBScript.

              But there's no rule saying an .OCX has to restrict itself to just using VARIANT-based datatypes, from C++ you can use any type of struct or class in an .OCX.

              If your .OCX has those type flavors, have you tried the dumpcpp.exe tool in Qt's bin directory? (That tool will generate .h and .cpp files which you #include in your project).

              K Offline
              K Offline
              Ketan
              wrote on 31 May 2019, 08:36 last edited by
              #6

              @hskoglund Using dumpcpp.exe and including header file everytime isn't much convenient.
              The above code works, but the problem is type discovery. Ex: Using dynamicCall I can open a pdf file in Adobe Reader. i.e. dynamicCall("LoadFile(QString&)","FileName"). But to end user, the question is about which interface is to use to open a file (in this case "LoadFile"). Now, I can get the API through the code above, but the problem still persists with the arguments (in this case "QString&") . Also, the ActiveX control is not limited to WMP, end user decides which one to use. So, I'm stuck in between displaying API's(either through code or using dumpcpp.exe) along with it's arguments.

              1 Reply Last reply
              0
              • H Offline
                H Offline
                hskoglund
                wrote on 31 May 2019, 09:27 last edited by
                #7

                Ok I know you can dig deeper with those Automation APIs. That example you gave, Adobe Reader, are you using an .OCX? Could you give me the path on your machine so I can download a similar one and test. Also do you have another example of an .OCX I can test on?

                1 Reply Last reply
                0

                • Login

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