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. How to call Registeration-Free COM dll?
Forum Updated to NodeBB v4.3 + New Features

How to call Registeration-Free COM dll?

Scheduled Pinned Locked Moved Solved General and Desktop
36 Posts 4 Posters 6.7k Views
  • 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.
  • Bruce.ZhangB Offline
    Bruce.ZhangB Offline
    Bruce.Zhang
    wrote on last edited by
    #1

    Hi guys, As the topic mentioned, how to call the registration-free COM DLLs from QT?

    In C# I see we can use the manifest files, so what if in QT?

    C 1 Reply Last reply
    0
    • hskoglundH Offline
      hskoglundH Offline
      hskoglund
      wrote on last edited by
      #27

      Hi, I had written a post above where I more or less gave up, but I made another effort!

      It turns out that that ancient Qt enhancement suggestion speaking about manifest files wasn't completely science-fiction. I found this MSDN article and of course some StackOverflow posts helped a lot.

      Thanks to your ProcMon trace above we can see it haplessly looking for DataTypesLibrary.dll's type library in the registry. By adding manifest files we can provide a path to that type library.

      Actually we need two manifest files. The first you'll add to your TestRegFreeCOM.exe. I'm assuming you're using MSVC 64-bits compiler and ..pro file (not CMake).
      Qt already adds an .rc file to your .exe so we also need to remove that (there can only be one manifest). Add this to your TestRegFreeCOM.pro:

      CONFIG -= embed_manifest_exe
      QMAKE_MANIFEST = $$PWD/TestRegFreeCOM.exe.manifest
      

      then create a text file TestRegFreeCOM.exe.manifest in your project dir with this:

      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
        <dependency>
          <dependentAssembly>
            <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" 
             version="6.0.0.0" 
      	publicKeyToken="6595b64144ccf1df"
      	language="*"
      	processorArchitecture="*" />
          </dependentAssembly>
        </dependency>
        <dependency>
          <dependentAssembly>
            <assemblyIdentity 
              name="DataTypesLibrary.X" 
              version="1.0.0.0" 
              type="win32" 
      	language="*"
             processorArchitecture="*" />
      </dependentAssembly>
        </dependency>
        <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
          <security>
            <requestedPrivileges>
              <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
            </requestedPrivileges>
          </security>
        </trustInfo>
      </assembly>
      

      most of the contents is because we're replacing the Qt standard manifest with our own. The relevant part is where we add a dependentAssembly for the DataTypesLibrary. I think the old MSDN article I mentioned above started this trend of suffixing an .X, don't worry it works :-)

      The second manifest file is for the DataTypesLibrary.dll, create a text file called DataTypesLibrary.X.manifest with this:

      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
       <assemblyIdentity 
          name="DataTypesLibrary.X" 
          version="1.0.0.0" 
          type="win32"
         processorArchitecture="AMD64" />
      
        <file name="DataTypesLibrary.dll">
        <comClass
          progid="EventData"
          clsid="{0405e972-093d-4f16-9b4f-f9071cc8f9b2}"
          threadingModel = "Apartment" />
      
         <typelib tlbid="{A9D4AEA1-46D8-4E98-B9AA-BE93A21A58AD}"
          version="1.0" 
          helpdir="" />
      
        </file>
      </assembly>
      

      then put the DataTypesLibrary.X.manifest and DataTypesLibrary.dll both in the same directory as TestRegFreeCOM.exe.

      To test, try something like:

      auto comObject = new QAxObject("EventData");
      qDebug() << comObject->generateDocumentation();
      

      If it fails, you can trace the manifest fiddling with the SXSTrace.exe tool, step 1, start the trace in a separate CMD window:
      sxstrace trace -logfile:sxstrace
      irun TestRegFreeCOM.exe and press Enter to stop the trace
      step 2: decode the trace
      sxxtrace parse -logfile:sxstrace -outfile:trace.txt
      then you can type trace.txt

      If this works for you, you owe me a beer :-))

      Bruce.ZhangB 2 Replies Last reply
      1
      • hskoglundH Offline
        hskoglundH Offline
        hskoglund
        wrote on last edited by
        #2

        Hi, as far as I know Qt has no built-in support for calling Registration-Free COM dlls, i.e. reading the manifest file :-(
        Some more info on this here.

        But you can always do it the hard way by calling DllGetClassObject() in your .dll and then CoCreateInstance() etc.

        Christian EhrlicherC 1 Reply Last reply
        0
        • hskoglundH hskoglund

          Hi, as far as I know Qt has no built-in support for calling Registration-Free COM dlls, i.e. reading the manifest file :-(
          Some more info on this here.

          But you can always do it the hard way by calling DllGetClassObject() in your .dll and then CoCreateInstance() etc.

          Christian EhrlicherC Offline
          Christian EhrlicherC Offline
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on last edited by
          #3

          @hskoglund said in How to call Registeration-Free COM dll?:

          , as far as I know Qt has no built-in support

          Why should Qt has something for this? It's a c++ problem. You need a header file somehow.

          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
          Visit the Qt Academy at https://academy.qt.io/catalog

          1 Reply Last reply
          0
          • Bruce.ZhangB Bruce.Zhang

            Hi guys, As the topic mentioned, how to call the registration-free COM DLLs from QT?

            In C# I see we can use the manifest files, so what if in QT?

            C Offline
            C Offline
            ChrisW67
            wrote on last edited by ChrisW67
            #4

            @Bruce-Zhang As far as I can see: You use the manifest file to get the COM object into the application's execution context at start up (Windows does this for you). Then you can use the ActiveQt classes exactly the same way you would for a registered COM object.

            You would have to craft the manifest file and include it in your application binary though the Windows (not Qt) resource system. You may already have a Windows RC file if you have a included a range of application icons or some UAC escalation magic.

            You can see an example manifest file in an ancient Qt enhancement suggestion.

            hskoglundH 1 Reply Last reply
            0
            • C ChrisW67

              @Bruce-Zhang As far as I can see: You use the manifest file to get the COM object into the application's execution context at start up (Windows does this for you). Then you can use the ActiveQt classes exactly the same way you would for a registered COM object.

              You would have to craft the manifest file and include it in your application binary though the Windows (not Qt) resource system. You may already have a Windows RC file if you have a included a range of application icons or some UAC escalation magic.

              You can see an example manifest file in an ancient Qt enhancement suggestion.

              hskoglundH Offline
              hskoglundH Offline
              hskoglund
              wrote on last edited by hskoglund
              #5

              @ChrisW67 said in How to call Registeration-Free COM dll?:

              @Bruce-Zhang As far as I can see: You use the manifest file to get the COM object into the application's execution context at start up (Windows does this for you). Then you can use the ActiveQt classes exactly the same way you would for a registered COM object.

              That's a great idea! One of QAxObject's constructors takes an IUnknown ptr so one way to do it would be to LoadLibrarying the dll, call DllGetClassObject() and CreateInstance() on the returned IClassFactory. Then construct a QAxObject from the IUnknown you got from CreateInstance() and Bob's your uncle.

              P.S. I don't think that code in that ancient QtBug suggestion actually works, it's more of "how it could be written" once ActiveQt starts supporting .manifest files...

              Bruce.ZhangB 2 Replies Last reply
              0
              • hskoglundH hskoglund

                @ChrisW67 said in How to call Registeration-Free COM dll?:

                @Bruce-Zhang As far as I can see: You use the manifest file to get the COM object into the application's execution context at start up (Windows does this for you). Then you can use the ActiveQt classes exactly the same way you would for a registered COM object.

                That's a great idea! One of QAxObject's constructors takes an IUnknown ptr so one way to do it would be to LoadLibrarying the dll, call DllGetClassObject() and CreateInstance() on the returned IClassFactory. Then construct a QAxObject from the IUnknown you got from CreateInstance() and Bob's your uncle.

                P.S. I don't think that code in that ancient QtBug suggestion actually works, it's more of "how it could be written" once ActiveQt starts supporting .manifest files...

                Bruce.ZhangB Offline
                Bruce.ZhangB Offline
                Bruce.Zhang
                wrote on last edited by
                #6

                @hskoglund @ChrisW67 @Christian-Ehrlicher
                Thanks for replies, I will have a try.

                1 Reply Last reply
                0
                • hskoglundH hskoglund

                  @ChrisW67 said in How to call Registeration-Free COM dll?:

                  @Bruce-Zhang As far as I can see: You use the manifest file to get the COM object into the application's execution context at start up (Windows does this for you). Then you can use the ActiveQt classes exactly the same way you would for a registered COM object.

                  That's a great idea! One of QAxObject's constructors takes an IUnknown ptr so one way to do it would be to LoadLibrarying the dll, call DllGetClassObject() and CreateInstance() on the returned IClassFactory. Then construct a QAxObject from the IUnknown you got from CreateInstance() and Bob's your uncle.

                  P.S. I don't think that code in that ancient QtBug suggestion actually works, it's more of "how it could be written" once ActiveQt starts supporting .manifest files...

                  Bruce.ZhangB Offline
                  Bruce.ZhangB Offline
                  Bruce.Zhang
                  wrote on last edited by
                  #7

                  Thank you for responding, @hskoglund. Can you please provide a straightforward demonstration of this? I would greatly appreciate it.

                  1 Reply Last reply
                  0
                  • hskoglundH Offline
                    hskoglundH Offline
                    hskoglund
                    wrote on last edited by
                    #8

                    Hi, here's a demo for you, first you need a COM dll to test on, I built the ActiveQt Wrapper Example using Qt 6.5.2 and MSVC 2019 64-bits (got an linker error when building so that regsvr32 failed, but it doesn't matter, it's not needed since we're working registry-free :-)

                    Then create a console app (Untitled), I used the same Qt 6.5.2 and MSVC 2019 64-bits compiler. Note: I created the app with qmake (not CMake).
                    Change untitled.pro to look like this:

                    QT       = core axcontainer
                    CONFIG  += c++17 cmdline
                    SOURCES += main.cpp
                    

                    and change main.cpp to look like this:

                    #include <QCoreApplication>
                    
                    #include "qaxobject.h"
                    #include "quuid.h"
                    #include "qlibrary.h"
                    #include "qdebug.h"
                    #include "atlbase.h"
                    int main(int argc, char *argv[])
                    {
                        Q_UNUSED(argc) Q_UNUSED(argv)
                    
                    // load a COM flavored DLL without using the registry (here we use the Wrapper example)
                        QLibrary regFreeLib("C:/Qt/Examples/Qt-6.5.2/activeqt/build-wrapper-Desktop_Qt_6_5_2_MSVC2019_64bit-Release/wrapperax.dll");
                    
                    // wire up the DllGetClassObject function so we can call it
                        auto regFreeGetDllClassObject = reinterpret_cast<HRESULT (__stdcall *)(REFCLSID,REFIID,LPVOID*)> (regFreeLib.resolve("DllGetClassObject"));
                        if (nullptr == regFreeGetDllClassObject)
                            qFatal("wiring up DLLGetClassObject() failed");
                    
                    // try to call it
                        CComPtr<IClassFactory> pClassFactory;
                        HRESULT hr = regFreeGetDllClassObject(QUuid("{6E795DE9-872D-43CF-A831-496EF9D86C68}"),IID_IClassFactory,(LPVOID*) &pClassFactory);
                        if (FAILED(hr))
                            qFatal("calling DLLGetClassObject() failed");
                    
                    // and then obtain the IUnknown ptr
                        CComPtr<IUnknown> pUnknown;
                        hr = pClassFactory->CreateInstance(nullptr,IID_IUnknown,(LPVOID*) &pUnknown);
                        if (FAILED(hr))
                            qFatal("createInstance() failed");
                    
                    // if we get this far Bob's your uncle, let Qt take it from here
                        auto comObject = new QAxObject(pUnknown);
                        if (nullptr == comObject)
                            qFatal("QAxObject creation failed");
                    
                    // as a test, fiddle with checked property of the QCheckBox
                        comObject->setProperty("checked",true);
                        qDebug() << comObject->property("checked");
                        comObject->setProperty("checked",false);
                        qDebug() << comObject->property("checked");
                    }
                    

                    P.S. If you get a compiler error: "cannot find qaxobject.h" then you might have forgotten to add the "Active Qt" component to your Qt (can be found inside "Additional Libraries" in the Qt Maintainer).

                    Bruce.ZhangB 1 Reply Last reply
                    1
                    • hskoglundH hskoglund

                      Hi, here's a demo for you, first you need a COM dll to test on, I built the ActiveQt Wrapper Example using Qt 6.5.2 and MSVC 2019 64-bits (got an linker error when building so that regsvr32 failed, but it doesn't matter, it's not needed since we're working registry-free :-)

                      Then create a console app (Untitled), I used the same Qt 6.5.2 and MSVC 2019 64-bits compiler. Note: I created the app with qmake (not CMake).
                      Change untitled.pro to look like this:

                      QT       = core axcontainer
                      CONFIG  += c++17 cmdline
                      SOURCES += main.cpp
                      

                      and change main.cpp to look like this:

                      #include <QCoreApplication>
                      
                      #include "qaxobject.h"
                      #include "quuid.h"
                      #include "qlibrary.h"
                      #include "qdebug.h"
                      #include "atlbase.h"
                      int main(int argc, char *argv[])
                      {
                          Q_UNUSED(argc) Q_UNUSED(argv)
                      
                      // load a COM flavored DLL without using the registry (here we use the Wrapper example)
                          QLibrary regFreeLib("C:/Qt/Examples/Qt-6.5.2/activeqt/build-wrapper-Desktop_Qt_6_5_2_MSVC2019_64bit-Release/wrapperax.dll");
                      
                      // wire up the DllGetClassObject function so we can call it
                          auto regFreeGetDllClassObject = reinterpret_cast<HRESULT (__stdcall *)(REFCLSID,REFIID,LPVOID*)> (regFreeLib.resolve("DllGetClassObject"));
                          if (nullptr == regFreeGetDllClassObject)
                              qFatal("wiring up DLLGetClassObject() failed");
                      
                      // try to call it
                          CComPtr<IClassFactory> pClassFactory;
                          HRESULT hr = regFreeGetDllClassObject(QUuid("{6E795DE9-872D-43CF-A831-496EF9D86C68}"),IID_IClassFactory,(LPVOID*) &pClassFactory);
                          if (FAILED(hr))
                              qFatal("calling DLLGetClassObject() failed");
                      
                      // and then obtain the IUnknown ptr
                          CComPtr<IUnknown> pUnknown;
                          hr = pClassFactory->CreateInstance(nullptr,IID_IUnknown,(LPVOID*) &pUnknown);
                          if (FAILED(hr))
                              qFatal("createInstance() failed");
                      
                      // if we get this far Bob's your uncle, let Qt take it from here
                          auto comObject = new QAxObject(pUnknown);
                          if (nullptr == comObject)
                              qFatal("QAxObject creation failed");
                      
                      // as a test, fiddle with checked property of the QCheckBox
                          comObject->setProperty("checked",true);
                          qDebug() << comObject->property("checked");
                          comObject->setProperty("checked",false);
                          qDebug() << comObject->property("checked");
                      }
                      

                      P.S. If you get a compiler error: "cannot find qaxobject.h" then you might have forgotten to add the "Active Qt" component to your Qt (can be found inside "Additional Libraries" in the Qt Maintainer).

                      Bruce.ZhangB Offline
                      Bruce.ZhangB Offline
                      Bruce.Zhang
                      wrote on last edited by
                      #9

                      @hskoglund Thanks very much.

                      1 Reply Last reply
                      0
                      • hskoglundH Offline
                        hskoglundH Offline
                        hskoglund
                        wrote on last edited by
                        #10

                        Hi forgot to mention: how did I find that GUID QUuid("{6E795DE9-872D-43CF-A831-496EF9D86C68}")? It's from line 68 in main.cpp in the Wrapperax example, it's one of the 3 classIDs listed (you can use any one of the 3).

                        For your dll, you need to find the relevant CLSID, in the manifest file look for the comclass line.
                        For example, the manifest file shown in that ancient QtBug suggestion shows:

                        ...
                        <comClass clsid="{6BF52A52-394A-11D3-B153-00C04F79FAA6}" 
                        ...
                        

                        If you want to use that and open the Windows Media Player dll (wmp.dll) instead, change my demo code above to:

                        // load a COM flavored DLL without using the registry (here we use wmp.dll)
                            QLibrary regFreeLib("wmp.dll");
                        
                        // wire up the DllGetClassObject function so we can call it
                            auto regFreeGetDllClassObject = reinterpret_cast<HRESULT (__stdcall *)(REFCLSID,REFIID,LPVOID*)> (regFreeLib.resolve("DllGetClassObject"));
                            if (nullptr == regFreeGetDllClassObject)
                                qFatal("wiring up DLLGetClassObject() failed");
                        
                        // try to open the Windows Media Player:
                            CComPtr<IClassFactory> pClassFactory;
                            HRESULT hr = regFreeGetDllClassObject(QUuid("{6BF52A52-394A-11D3-B153-00C04F79FAA6}"),IID_IClassFactory,(LPVOID*) &pClassFactory);
                            if (FAILED(hr))
                                qFatal("calling DLLGetClassObject() failed");
                        

                        To check that you managed to open the dll correctly, one way is to add a call generateDocumentation at the end, like this:

                        ,,,
                        
                        // if we get this far we're in business, let Qt take it from here
                            auto comObject = new QAxObject(pUnknown);
                            if (nullptr == comObject)
                                qFatal("QAxObject creation failed");
                        
                        // check that we have something live
                            qDebug() << comObject->generateDocumentation();
                        

                        the output (if it works) should have some HTML code (save it to a HTML file to view it properly).

                        Finally, you need to match the bitness of your dll (it it's 32-bits you need to compile a 32-bits Qt app and the other way around). Normally the COM infrastructure allows 32-bit/64-bit crossplaying by loading the .dll out-of-process, but since you're doing LoadLbrary() you are closer to the metal.

                        Bruce.ZhangB 1 Reply Last reply
                        0
                        • hskoglundH hskoglund

                          Hi forgot to mention: how did I find that GUID QUuid("{6E795DE9-872D-43CF-A831-496EF9D86C68}")? It's from line 68 in main.cpp in the Wrapperax example, it's one of the 3 classIDs listed (you can use any one of the 3).

                          For your dll, you need to find the relevant CLSID, in the manifest file look for the comclass line.
                          For example, the manifest file shown in that ancient QtBug suggestion shows:

                          ...
                          <comClass clsid="{6BF52A52-394A-11D3-B153-00C04F79FAA6}" 
                          ...
                          

                          If you want to use that and open the Windows Media Player dll (wmp.dll) instead, change my demo code above to:

                          // load a COM flavored DLL without using the registry (here we use wmp.dll)
                              QLibrary regFreeLib("wmp.dll");
                          
                          // wire up the DllGetClassObject function so we can call it
                              auto regFreeGetDllClassObject = reinterpret_cast<HRESULT (__stdcall *)(REFCLSID,REFIID,LPVOID*)> (regFreeLib.resolve("DllGetClassObject"));
                              if (nullptr == regFreeGetDllClassObject)
                                  qFatal("wiring up DLLGetClassObject() failed");
                          
                          // try to open the Windows Media Player:
                              CComPtr<IClassFactory> pClassFactory;
                              HRESULT hr = regFreeGetDllClassObject(QUuid("{6BF52A52-394A-11D3-B153-00C04F79FAA6}"),IID_IClassFactory,(LPVOID*) &pClassFactory);
                              if (FAILED(hr))
                                  qFatal("calling DLLGetClassObject() failed");
                          

                          To check that you managed to open the dll correctly, one way is to add a call generateDocumentation at the end, like this:

                          ,,,
                          
                          // if we get this far we're in business, let Qt take it from here
                              auto comObject = new QAxObject(pUnknown);
                              if (nullptr == comObject)
                                  qFatal("QAxObject creation failed");
                          
                          // check that we have something live
                              qDebug() << comObject->generateDocumentation();
                          

                          the output (if it works) should have some HTML code (save it to a HTML file to view it properly).

                          Finally, you need to match the bitness of your dll (it it's 32-bits you need to compile a 32-bits Qt app and the other way around). Normally the COM infrastructure allows 32-bit/64-bit crossplaying by loading the .dll out-of-process, but since you're doing LoadLbrary() you are closer to the metal.

                          Bruce.ZhangB Offline
                          Bruce.ZhangB Offline
                          Bruce.Zhang
                          wrote on last edited by
                          #11

                          @hskoglund I works for wmp.dll, but don't know why failed on my dll at bellow line:

                          if (nullptr == regFreeGetDllClassObject)
                                  qFatal("wiring up DLLGetClassObject() failed");
                          

                          And GetLastError code is 126, which is cannot find the DLL, maybe the DLL is invalid? but I can use it in my msvc project.

                          1 Reply Last reply
                          0
                          • hskoglundH Offline
                            hskoglundH Offline
                            hskoglund
                            wrote on last edited by
                            #12

                            If you get an error 126: if you didn't specify a path to the .dll check that it's placed together with the .exe (or one directory level above if you're running from inside Qt Creator).
                            To make sure add a qDebug on an explicit .load(), say like this:

                            ...
                                QLibrary regFreeLib("wmp.dll");
                                qDebug() << "dll loaded ok: " << regFreeLib.load();
                            ...
                            

                            Also make sure all the other .dlls that your .dll is dependent on are loaded ok (i.e. another reason for error 126).
                            If you're stuck, fire up ProcessMonitor :-)

                            Bruce.ZhangB 1 Reply Last reply
                            0
                            • hskoglundH hskoglund

                              If you get an error 126: if you didn't specify a path to the .dll check that it's placed together with the .exe (or one directory level above if you're running from inside Qt Creator).
                              To make sure add a qDebug on an explicit .load(), say like this:

                              ...
                                  QLibrary regFreeLib("wmp.dll");
                                  qDebug() << "dll loaded ok: " << regFreeLib.load();
                              ...
                              

                              Also make sure all the other .dlls that your .dll is dependent on are loaded ok (i.e. another reason for error 126).
                              If you're stuck, fire up ProcessMonitor :-)

                              Bruce.ZhangB Offline
                              Bruce.ZhangB Offline
                              Bruce.Zhang
                              wrote on last edited by Bruce.Zhang
                              #13

                              @hskoglund Thanks for reminder, I copied all dlls and can load now, but failed at bellow:

                              CComPtr<IClassFactory> pClassFactory;
                                  HRESULT hr = regFreeGetDllClassObject(QUuid("{A9D4AEA1-46D8-4E98-B9AA-BE93A21A58AD}"), IID_IClassFactory, (LPVOID*) &pClassFactory);
                                  if (FAILED(hr))
                                  {
                                      auto err = GetLastError();
                                      QString str = QString("GetLastError():%1").arg(err);
                                      qFatal("calling DLLGetClassObject() failed");
                                  }
                              

                              GetLastError() Error Number is 3.

                              Part of my .idl file like this:

                              [
                                  uuid(A9D4AEA1-46D8-4E98-B9AA-BE93A21A58AD),
                                  version(1.0),
                              ]
                              library DataTypesLibraryLib
                              {
                                  importlib("stdole2.tlb");
                              
                                  typedef
                                  [
                                      uuid(C15BA150-A8BA-4A10-8C5C-0D65F97A9840),
                                      version(1.0)
                                  ]
                              
                                  enum EventTypes
                                  {
                                      EVENT_UNKNOWN = 0,
                                      EVENT_FROM_RECIPE = 10000,
                                      EVENT_START_HISTORICAL_JOB = 10001,
                                      EVENT_WEB_POSITION_AND_SPEED = 10005,
                                      EVENT_BLOB_OVERRUN = 10009,
                                      EVENT_CUT_SIGNAL = 10019,
                                      EVENT_START_JOB = 10023,
                                      EVENT_STOP_JOB = 10024,
                                      EVENT_START_INSPECTION = 10025,
                                      EVENT_STOP_INSPECTION = 10026,
                                      EVENT_WEB_EDGE = 10036,
                                      EVENT_PAUSE_INSPECTION = 10045,
                                      EVENT_RESTART_INSPECTION = 10046,
                                      EVENT_JOB_PASSED = 10049,
                                      EVENT_JOB_FAILED = 10050,
                                      EVENT_DOFF_PASSED = 10051,
                                      EVENT_DOFF_FAILED = 10052,
                                      EVENT_ROLL_PASSED = 10053,
                                      EVENT_ROLL_FAILED = 10054,
                                      EVENT_EXTERNAL_RUNNEXTJOB = 10055,
                                      EVENT_DENSITY_EVENT = 10079,
                                      EVENT_WET_CAMERA_STATUS = 10180,
                                      EVENT_WET_START_CALIBRATION = 10181,
                                      EVENT_WET_STOP_CALIBRATION = 10182
                                  } EventTypes;
                              
                                  enum CommandTypes
                                  {
                                      COMMAND_UNINITIALIZED = -1,
                                      COMMAND_START_JOB = 1,
                                      COMMAND_STOP_JOB,
                                      COMMAND_LINEPROFILE_START,
                                      COMMAND_LINEPROFILE_STOP,
                                      COMMAND_SNAPIMAGE
                                  };
                              
                                  [
                                      uuid(0405e972-093d-4f16-9b4f-f9071cc8f9b2)
                                  ]
                                  coclass EventData
                                  {
                                      [default] interface IEventData;
                                  };
                              }
                              
                              1 Reply Last reply
                              0
                              • hskoglundH Offline
                                hskoglundH Offline
                                hskoglund
                                wrote on last edited by
                                #14

                                Once you're in the COM world, GetLastError() is less interesting.
                                You need the qdebug dump the hr (HResult) that GetDllClassObjet returned. Preferable in hex, something like 0x80040154 will be shown...

                                Bruce.ZhangB 1 Reply Last reply
                                0
                                • hskoglundH hskoglund

                                  Once you're in the COM world, GetLastError() is less interesting.
                                  You need the qdebug dump the hr (HResult) that GetDllClassObjet returned. Preferable in hex, something like 0x80040154 will be shown...

                                  Bruce.ZhangB Offline
                                  Bruce.ZhangB Offline
                                  Bruce.Zhang
                                  wrote on last edited by
                                  #15

                                  @hskoglund said in How to call Registeration-Free COM dll?:

                                  Once you're in the COM world, GetLastError() is less interesting.
                                  You need the qdebug dump the hr (HResult) that GetDllClassObjet returned. Preferable in hex, something like 0x80040154 will be shown...

                                  I've got the error code 0x80040111:In this specific case, the error code "80040111" translates to "CLASS_E_CLASSNOTAVAILABLE" Seems the specified class is not correct. I don't know why got this error, the GUID was wrong?

                                  1 Reply Last reply
                                  0
                                  • hskoglundH Offline
                                    hskoglundH Offline
                                    hskoglund
                                    wrote on last edited by
                                    #16

                                    Yeah you got bad luck and selected the wrong GUID :-( That one at the top is the library UUID, but we're only interested in coclass-flavored UUIDs (i.e. that is what DllGetClassObject wants).
                                    They're usually found at the end of an .idl file, in your case:

                                    ...
                                     [
                                         uuid(0405e972-093d-4f16-9b4f-f9071cc8f9b2)
                                    // try this one ^
                                    ]
                                    coclass EventData
                                    {
                                        [default] interface IEventData;
                                    };
                                    
                                    
                                    Bruce.ZhangB 1 Reply Last reply
                                    0
                                    • hskoglundH hskoglund

                                      Yeah you got bad luck and selected the wrong GUID :-( That one at the top is the library UUID, but we're only interested in coclass-flavored UUIDs (i.e. that is what DllGetClassObject wants).
                                      They're usually found at the end of an .idl file, in your case:

                                      ...
                                       [
                                           uuid(0405e972-093d-4f16-9b4f-f9071cc8f9b2)
                                      // try this one ^
                                      ]
                                      coclass EventData
                                      {
                                          [default] interface IEventData;
                                      };
                                      
                                      
                                      Bruce.ZhangB Offline
                                      Bruce.ZhangB Offline
                                      Bruce.Zhang
                                      wrote on last edited by Bruce.Zhang
                                      #17

                                      @hskoglund Finally, I can run it now, but with some error output.
                                      bellow is my code snippet:

                                       LPVOID rev = nullptr;
                                          CoInitialize(rev);// Add this line because there will be  another output  of missing the CoInitialize. 
                                      
                                          // load a COM flavored DLL without using the registry (here we use the Wrapper example)
                                          QLibrary regFreeLib("DataTypesLibrary.dll");
                                          qDebug() << "dll loaded ok: " << regFreeLib.load();
                                      
                                          // wire up the DllGetClassObject function so we can call it
                                          auto regFreeGetDllClassObject = reinterpret_cast<HRESULT(__stdcall*)(REFCLSID, REFIID, LPVOID*)> (regFreeLib.resolve("DllGetClassObject"));
                                      
                                          if (nullptr == regFreeGetDllClassObject)
                                          {
                                              auto err = GetLastError();
                                              QString str = QString("GetLastError():%1").arg(err);
                                              qFatal("wiring up DLLGetClassObject() failed");
                                          }
                                      
                                          // try to call it
                                          CComPtr<IClassFactory> pClassFactory;
                                          HRESULT hr = regFreeGetDllClassObject(QUuid("{0b4be3c3-f304-4f98-a870-e2933dee5b7e}"), IID_IClassFactory, (LPVOID*) &pClassFactory);
                                      
                                          if (FAILED(hr))
                                          {
                                              auto err = GetLastError();
                                              QString str = QString("DLLGetClassObject GetLastError():%1 HRESULT:%2").arg(err).arg(hr, 8,  16, QLatin1Char('0'));
                                              qFatal(str.toStdString().c_str());
                                          }
                                      
                                          for (int i = 0; i < 1000000; i++)
                                          {
                                              // and then obtain the IUnknown ptr
                                              CComPtr<IUnknown> pUnknown;
                                              hr = pClassFactory->CreateInstance(nullptr, IID_IUnknown, (LPVOID*) &pUnknown);
                                      
                                              if (FAILED(hr))
                                                  qFatal("createInstance() failed");
                                      
                                              // if we get this far we're in business, let Qt take it from here
                                              auto comObject = new QAxObject(pUnknown);
                                              auto pEventData = reinterpret_cast<DataTypesLibraryLib::IEventData*>(comObject);
                                              pEventData->SetCD(20.22);
                                              qDebug() << "CD:" << pEventData->CD();
                                              delete pEventData;
                                      
                                          }
                                      
                                          qDebug() << "This is the End";
                                      

                                      And bellow is the output when exec "pEventData->SetCD(20.22);" each loop.

                                      mincore\com\oleaut32\typelib\tlibapi.cpp(2279)\OLEAUT32.dll!00007FF8FE894743: (caller: 00007FF8FE87847B) ReturnHr(239969) tid(5a8c) 8002801D Library not registered.
                                      void __cdecl MetaObjectGenerator::readClassInfo(void): IDispatch 0x28bf7aa0040 does not provide interface information
                                      CD: 20.22
                                      

                                      BTW: I generated the .h & .cpp using "dumpcpp DataTypesLibrary.dll". And DataTypesLibraryLib::IEventData is from the .h file.

                                      1 Reply Last reply
                                      0
                                      • hskoglundH Offline
                                        hskoglundH Offline
                                        hskoglund
                                        wrote on last edited by
                                        #18

                                        Hi, dumpcpp can be a useful tool but it does not support RegistrationFree COM dlls. Usually the .cpp code generated (in DataTypesLibrarylib.cpp) will, in the constructor, include a call to QAxWidget->setControl(), and that call relies on the registry to work :-(
                                        And that's probably why you get that error "Library not registered".

                                        Once you've started using a QAxObject, best is to avoid stunts like ... reinterpret_cast<DataTypesLibraryLib::IEventData*>(comObject); it will only come back to haunt you :-)

                                        I see you're not using the UUID i suggested but another one?

                                        Once you gotten a QAxObject up and running, start by checking it's validity by calling generateDocumentation: (i.e. from my code earlier in this topic):

                                        / check that we have something live
                                            qDebug() << comObject->generateDocumentation();
                                        

                                        If that works, then try using your comObject say like this:

                                        comObject->setProperty("CD",20.22);
                                        qDebug() << "CD:" << comObject->property("CD");
                                        
                                        Bruce.ZhangB 1 Reply Last reply
                                        0
                                        • hskoglundH hskoglund

                                          Hi, dumpcpp can be a useful tool but it does not support RegistrationFree COM dlls. Usually the .cpp code generated (in DataTypesLibrarylib.cpp) will, in the constructor, include a call to QAxWidget->setControl(), and that call relies on the registry to work :-(
                                          And that's probably why you get that error "Library not registered".

                                          Once you've started using a QAxObject, best is to avoid stunts like ... reinterpret_cast<DataTypesLibraryLib::IEventData*>(comObject); it will only come back to haunt you :-)

                                          I see you're not using the UUID i suggested but another one?

                                          Once you gotten a QAxObject up and running, start by checking it's validity by calling generateDocumentation: (i.e. from my code earlier in this topic):

                                          / check that we have something live
                                              qDebug() << comObject->generateDocumentation();
                                          

                                          If that works, then try using your comObject say like this:

                                          comObject->setProperty("CD",20.22);
                                          qDebug() << "CD:" << comObject->property("CD");
                                          
                                          Bruce.ZhangB Offline
                                          Bruce.ZhangB Offline
                                          Bruce.Zhang
                                          wrote on last edited by Bruce.Zhang
                                          #19

                                          @hskoglund Actually the last GUID is what I pasted. I tried the comObject->generateDocumentation();
                                          The output also contains .... Library not registered.

                                          
                                          mincore\com\oleaut32\typelib\tlibapi.cpp(2279)\OLEAUT32.dll!00007FFCB00B4743: (caller: 00007FFCB009847B) ReturnHr(1) tid(3864) 8002801D Library not registered.
                                          void __cdecl MetaObjectGenerator::readClassInfo(void): IDispatch 0x22af47e0000 does not provide interface information
                                          mincore\com\oleaut32\typelib\tlibapi.cpp(2279)\OLEAUT32.dll!00007FFCB00B4743: (caller: 00007FFCB009847B) ReturnHr(2) tid(3864) 8002801D Library not registered.
                                          mincore\com\oleaut32\typelib\tlibapi.cpp(2279)\OLEAUT32.dll!00007FFCB00B4743: (caller: 00007FFCB009847B) ReturnHr(3) tid(3864) 8002801D Library not registered.
                                          "<h1 align=center> Reference</h1>\n<p>The  COM object is a QAxObject with the CLSID .</p>\n<h3>Interfaces</h3>\n<ul>\n</ul>\n<h3>Event Interfaces</h3>\n<ul>\n</ul>\n<h2>Public Slots:</h2>\n<ul>\n</ul>\n<h2>Signals:</h2>\n<ul>\n<li>void <a href=\"#exception\"><b>exception</b></a>(int code, QString source, QString disc, QString help);</li>\n<li>void <a href=\"#propertyChanged\"><b>propertyChanged</b></a>(QString name);</li>\n<li>void <a href=\"#signal\"><b>signal</b></a>(QString name, int argc, void* argv);</li>\n</ul>\n<h2>Properties:</h2>\n<ul>\n<li>QString <a href=\"#objectName\"><b>objectName</b></a>;</li>\n<li>QString <a href=\"#control\"><b>control</b></a>;</li>\n</ul>\n<hr><h2>Member Function Documentation</h2>\n<h3><a name=exception></a>void exception (int code, QString source, QString disc, QString help)<tt> [signal]</tt></h3>\n<p>Connect a slot to this signal:<pre>\n\tQObject::connect(object, SIGNAL(exception(int, QString, QString, QString)), receiver, SLOT(someSlot(int, QString, QString, QString)));</pre>\n\n<h3><a name=propertyChanged></a>void propertyChanged (QString name)<tt> [signal]</tt></h3>\n<p>Connect a slot to this signal:<pre>\n\tQObject::connect(object, SIGNAL(propertyChanged(QString)), receiver, SLOT(someSlot(QString)));</pre>\n\n<h3><a name=signal></a>void signal (QString name, int argc, void* argv)<tt> [signal]</tt></h3>\n<p>Connect a slot to this signal:<pre>\n\tQObject::connect(object, SIGNAL(signal(QString, int, void*)), receiver, SLOT(someSlot(QString, int, void*)));</pre>\n\n<hr><h2>Property Documentation</h2>\n<h3><a name=objectName></a>QString objectName</h3>\n<p>\n<p>Read this property's value using QObject::property:<pre>\n\tQString val = object->property(\"objectName\").toString();\n</pre>\nSet this property' value using QObject::setProperty:<pre>\n\tQString newValue = ...\n\tobject->setProperty(\"objectName\", newValue);\n</pre>\nOr using the <a href=\"#setObjectName\">setObjectName</a> slot.\n\n<h3><a name=control></a>QString control</h3>\n<p>\n<p>Read this property's value using QObject::property:<pre>\n\tQString val = object->property(\"control\").toString();\n</pre>\nSet this property' value using QObject::setProperty:<pre>\n\tQString newValue = ...\n\tobject->setProperty(\"control\", newValue);\n</pre>\nOr using the <a href=\"#setControl\">setControl</a> slot.\n\n"
                                          

                                          The messages outputs when execute "comObject->generateDocumentation();"

                                          1 Reply Last reply
                                          0
                                          • hskoglundH Offline
                                            hskoglundH Offline
                                            hskoglund
                                            wrote on last edited by
                                            #20

                                            Hmm if you're testing on a pretty old Windows 10, you might have been bitten by this bug:
                                            https://bugreports.qt.io/browse/QTBUG-63789

                                            Also I dug up some old code for debugging COM, try these lines:

                                            ...
                                            // try to call it
                                                CComPtr<IClassFactory> pClassFactory;
                                                HRESULT hr = regFreeGetDllClassObject(QUuid("{0405e972-093d-4f16-9b4f-f9071cc8f9b2}"),IID_IClassFactory,(LPVOID*) &pClassFactory);
                                                if (FAILED(hr))
                                                    qFatal("calling DLLGetClassObject() failed");
                                            
                                            // and then obtain the IUnknown ptr
                                                CComPtr<IUnknown> pUnknown;
                                                hr = pClassFactory->CreateInstance(nullptr,IID_IUnknown,(LPVOID*) &pUnknown);
                                                if (FAILED(hr))
                                                    qFatal("createInstance() failed");
                                            
                                            // if we get this far we're in business, let Qt take it from here
                                                auto comObject = new QAxObject(pUnknown);
                                                if (nullptr == comObject)
                                                    qFatal("QAxObject creation failed");
                                            
                                            // *** some debugging code
                                            // try to obtain a IDispatch ptr
                                                CComPtr<IDispatch> pDispatch;
                                                comObject->queryInterface(QUuid(IID_IDispatch),(void**) &pDispatch);
                                                if (nullptr == pDispatch)
                                                    qFatal("Error: an IDispatch interface was not found.");
                                            
                                            // get the ITypeInfo ptr
                                                UINT uTypeInfo;
                                                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");
                                            
                                            // if you get this far you comObject is most likely ok (never mind generateDocumentation) so try your dll
                                                comObject->setProperty("CD",20.22);
                                                qDebug() << "CD:" << comObject->property("CD");
                                            
                                            Bruce.ZhangB 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