Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / QT

Using COM Binary Interface with C++

4.58/5 (7 votes)
28 Mar 2014CPOL4 min read 25.1K  
A presentation on how to extract data from a Type Library (.tlb) and access COM Binary Interface from C++ using Qt

Introduction

Using COM Binary interface from VB.NET or VBS is easy thanks to Visual Studio, but getting this to work in C++ has been a bit trickier.

Quite a few software provide COM objects as an inter communication mechanism and I recently had to interact with one from a C++ project.

The software is written using the Qt framework, so in this tip, I will talk about how to use the TLB file and interact it with COM from a Qt Application. Most of the resources I read on using a Type Library File (.tlb) in C++ were dependent upon VC++. I hope this tip will provide you with basics on how to interact with a COM using a Type Library File from C++.

Requirements

This solution is done under Windows 7 using Qt 5.2.0, compiling with MinGW 4.8 (32b) and the software providing the .tlb file is E3.Series.

Extract Data from the Type Library

The first step is to generate the required files we will need for our project to be able to interact with COM. Fortunately, Qt comes with great software that will ease this process, and save us quite some time. It is called dumpcpp. This is how it is done:

Opening the Qt Console from the Windows Menu:

Image 1

Opening the Qt Console from the Windows Search:

C:\Windows\System32\cmd.exe /A /Q /K C:\Qt\Qt5.2.0\5.2.0\mingw48_32\bin\qtenv2.bat

This is what Qt Console looks like when it is just opened:

Image 2

Now it is time to run dumpcpp on the .tlb file to generate the C++ namespace:

dumpcpp "C:\Program Files (x86)\CIM-Team\E3.series_2009\e3.tlb" 

This will create two files based on our .tlb file: our namespace in e3.h and our metadata in e3.cpp.

Just to make sure that our namespace is correct, we can open our e3.h file and we should see that the namespace extracted from the e3.tlb is named "e3".

Preparing the Qt Project

Next, we will take the two generated files and integrate them in our Qt project. To use those, we will use Qt's AtiveX Framework (ActiveQt) we should edit the .pro file and add the following line to enable ActiveQt usage:

QT       += axcontainer 

At this stage, Qt Creator should look something as follows:

Image 3

Right now, you should be able to compile the project without issues. This means it is time to dive into coding.

How to Code

There are three things you should consider while trying to use this method to use COM. First, use the auto-completion functionality of the IDE you will be working with, like this:

Image 4

Second, use the software's scripting manual if one is provided. In my case, e3.Series provides a really extensive one, which helps save time.

Alternatively, you can also try to guess what functions you can use by digging into the e3.h file. This can take some time, since the generated e3.h file is 70000 lines long. For instance, in the file we can find the following class:

C++
// Actual coclasses
class E3_EXPORT e3Application : public QAxObject 

We can also find the methods we want to use, for example printing a message looks as follows:

C++
inline int PutInfo(int ok, const QString& text);

It can be a bit harder for more complex functions, since you have to guess how to get the data back, and more importantly, the type of the returned data. For instance, if you want to get all signals, you can look into the e3Job class and

C++
inline int GetSignalIds(QVariant& ids); 

The function itself does not provide much information. However, we can guess two things from its signature. Since the return type is an integer, it gives us either the count of signal Ids, or tells us if everything went well. After a bit of testing, you understand that it was the former and that ids is an array of integers.

Coding

To use the COM, I have made a simple class that serves two purposes. First is to show our proof of concept. Second is to show how to use the library correctly. The code is as follows:

C++
#include <QObject>
#include "e3.h"

class intwe3 : public QObject {
     Q_OBJECT
private:
     e3::e3Application App;  // Entry Point 
     e3::e3Job Job;
     e3::e3Signal Signals;
     e3::e3Device Devices;
     e3::e3Connection Connection;

public:
     intwe3();
     void test();
};

As I said, this is a simple class that contains several variables coming from the generated e3 files. A constructor, that will let us test the communication, and the test method that will hold anything I want to try before starting to work with it.

In the Constructor, I will do two things, test if App exists (COM enabled) and try to write a message in the software's output.

C++
intwe3::intwe3() {
     if (App.isNull()){ 
          qDebug() << "Issue with e3";
     }else{
          App.ClearOutputWindow();
          App.PutInfo(0, "Text wrote from Qt");
     }
} 

After creating the object in the main function and running the software, we can see our message in the output of the software, meaning that the library is working correctly.

Image 5

Calling Methods that Use QVariant

For other functions, like the aforementioned GetSignalIds, you have to pass a QVariant pointer that will hold the list of Signal Ids.

You can read the Qt-project reference page about QVariants, available at:

For now, our code will be held in our test() function with the following contents:

C++
void
intwe3::test(){
     QList<QVariant> liste; // creates a list of QVariants
     QVariant *ConnectionIds = new QVariant(liste); // creates a QVariant from the Qlist of QVariants
     int number = 0;

     number = Job.GetSignalIds(*SignalIds);
     qDebug() << "Number of signals returned : " << number;

     if (SignalIds->canConvert<QVariantList>()) {
          QSequentialIterable iterable = SignalIds->value<QSequentialIterable>();

          foreach (const QVariant &v, iterable) {
               if (v.isValid()){
                    qDebug() << "QVariant content : " << v;
                    // Here is how you could use what we got from the GetSignalIds call.
                    int SignalId = v.toInt(); // Get the Id as an integer
                    sig.SetId(SignalId); // Sets this signal as the working signal
                    qDebug() << "Signal Name :" << sig.GetSignalName; // gets its name
               }
          }
     }
}

Conclusion

I hope this will help you start working with third party software's COM from Qt. Have a good day.

History

  • 28th March, 2014: Initial post
  • 28th March, 2014: Content update

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)