PDA

View Full Version : COM Objects on Windows 7 with 4.7.2



kwire
15th March 2011, 16:40
Good morning all. I've been using QT off and on for several years and have always been able to find answers to
my problems here on the forum. So thanks for that... But I am stumpped this time.

In my application I am printing Labels on a Dymo LabelWriter 400. I used the type library and opened a
command box and ran "dumpcpp DYMO.DLS.SDK.tlb -o dymosdk". That generated the dymosdk.h and
dymosdk.cpp files which I link into my application.

I have been using Creator 2.0.1 and Qt 4.7.1 on a laptop running Vista (32bit) and it has been working fine.
Then last weekend I set up an new desktop machine running Windows 7 (64bit) and installed Qt 4.7.2 and Creator 2.1.0.

I installed the same DYMO software (& SDK) as on the Vista machine.

Here is the code:

dymoAddIn = new DYMO_DLS_SDK::ISDKDymoAddin();
// dymoAddIn->setControl("{09DAFAE2-8EB0-11D2-8E5D-00A02415E90F}");
dymoAddIn->setControl("Dymo.DymoAddIn");
dymoAddIn->Open("d:/abe/catalog/abe_catalog/BinLabelKAWDIB-New.label");

dymoLabels = new DYMO_DLS_SDK::ISDKDymoLabels;
// dymoLabels->setControl("{3AAD7661-8F83-11D2-8E5D-00A02415E90F}");
dymoLabels->setControl("Dymo.DymoLabels");

When I run the application it chokes with

CoCreateInstance failure (Class not registered)
QAxBase::setControl: requested control Dymo.DymoAddIn could not be instantiated

on first setControl() method, and

CoCreateInstance failure (Not enough storage is available to complete this operation.)
QAxBase::setControl: requested control Dymo.DymoLabels could not be instantiated

on the second setControl() method.

I have verified in the registry that the Guid is correct for both objects. The Dymo Label Software works just fine.
I believe it uses the same COM objects I am trying to use. And as I said the same code works on my laptop running
Vista using either the Guid or the name of the object.

Can anybody think of anything else I can check? I thought about installing 4.7.1 (which is what is on the laptop)
on the new machine, but thought I'd ask for help first...

Thanks, Keith

schnitzel
15th March 2011, 17:34
It has been a while since I've used COM but I remember that the COM registration instructions have to be followed to the dot.

Are you sure you don't need some sort of license string or file in the control's constructor?
Also, is this perhaps due to your new OS being 64 bit and the control isn't?

Other than that, I can only suggest to contact dymo sdk support.

kwire
15th March 2011, 18:08
Thanks schnitzel,

Since it works on the Vista machine I don't think I need anything in the constructor. As I said I believe the COM is being used by DYMO's own software. The FAQ for the DYMO software says it is compatible with Win-7 (32 & 64).

I have contacted DYMO support, so I guess I'll keep my fingers crossed. I really want to do this in the "new and faster" machine :).

Keith

schnitzel
15th March 2011, 19:42
have you tried using the control in a .NET app?
Do they provide sample code?

kwire
15th March 2011, 23:18
Shnitzel,

I discovered something a minute ago...

If I take the constructor for my "DymoPrinter" (code below) out of the constructor for the form and put it in the "clicked"
slot of my "Post" button where I print labels for each record that was changed it works. To test it out I just dropped a
new button on the form and put these two lines in the "clicked" slot and it works just fine.

dPrinter = new DymoPrinter();
dPrinter->printOneLabel("000346050493");

That makes no sense to me at all...

I tried stepping through the debugger and I get lost in all the "Ax" code.

Can you see anything wrong with my "DymoPrinter" object? Is there a reason I can't instantiate COM object in the
constructor of a form?

BTW, no I haven't tried to use the control in .NET... Thanks for all your ideas.

Keith

dymoPrinter.h
---------------------------------
#ifndef DYMOPRINTER_H
#define DYMOPRINTER_H

#include <QString>
#include <QSqlQuery>

#include "dymosdk.h"

class DymoPrinter
{
public:
DymoPrinter();
~DymoPrinter();
bool printOneLabel(const QString productId) const;
private:
QSqlQuery *rockQuery;

DYMO_DLS_SDK::ISDKDymoAddin *dymoAddIn;
DYMO_DLS_SDK::ISDKDymoLabels *dymoLabels;

};
#endif // DYMOPRINTER_H



dymoPrinter.cpp
-----------------------------
#include <QMessageBox>
#include <QSqlDatabase>

#include "dymoPrinter.h"
#include "dymosdk.h"

DymoPrinter::DymoPrinter()
{
dymoAddIn = new DYMO_DLS_SDK::ISDKDymoAddin();
dymoAddIn->setControl("{09DAFAE2-8EB0-11D2-8E5D-00A02415E90F}");
dymoAddIn->Open("d:/abe/catalog/abe_catalog/BinLabelKAWDIB-New.label");

dymoLabels = new DYMO_DLS_SDK::ISDKDymoLabels;
dymoLabels->setControl("{3AAD7661-8F83-11D2-8E5D-00A02415E90F}");

if (QSqlDatabase::database("rock").isValid())
rockQuery = new QSqlQuery(QSqlDatabase::database("rock"));
else
QMessageBox::critical( 0, "Error!", "Unable to connect to database! Are you sure you set up the correct paths?" );
}

DymoPrinter::~DymoPrinter()
{
QSqlDatabase::database().close();
delete rockQuery;
}

bool DymoPrinter::printOneLabel(const QString productId) const
{
bool result = false;
rockQuery->clear();
rockQuery->exec("SELECT p.cdeProduct, " \
"p.cdeV1SKU, " \
"p.dscDescription, " \
"uom.dscUOM, " \
"p.curStnd_price, " \
"p.numORD_MULT1, " \
"p.numORD_MULT2, " \
"p.numORD_MULT3, " \
"p.cdeMSKU " \
"FROM tProducts AS p INNER JOIN tUOM AS uom ON p.cdeUOM = uom.cdeUOM " \
"WHERE cdeProduct = '" + productId + "';");

if (rockQuery->isActive())
{
if (rockQuery->next())
{
dymoLabels->SetField("Vendor 1 SKU", rockQuery->value(1).toString());
dymoLabels->SetField("Description", rockQuery->value(2).toString());
dymoLabels->SetField("UOM", rockQuery->value(3).toString());
dymoLabels->SetField("Product Code", productId);
dymoLabels->SetField("Standard Retail Price", "$" + rockQuery->value(4).toString());
dymoLabels->SetField("OrdMult", rockQuery->value(5).toString() + "-" +
rockQuery->value(6).toString() + "-" +
rockQuery->value(7).toString());
dymoLabels->SetField("cdeMSKU", rockQuery->value(8).toString());

if( dymoAddIn->Print(1,true) )
result = true;
else
result = false;
}
}
return result;
}

schnitzel
15th March 2011, 23:40
How exactly did you register this COM object on the new machine? Did you use regsvr32?

btw: looking at the info on DYMO website regarding COM class factory...

http://developers.dymo.com/2010/06/25/error-80040154-retreiving-com-class-factory/

they also have .NET samples - I suggest you try that first as I believe your troubles are not related to Qt at all but I have to agree that it is weird if you get it working by taking it out of the constructor. :confused:

kwire
16th March 2011, 14:30
schnitzel

I didn't need to use regsvr32 because there was an install program.

The COM objects work because their software, a label designing application, works and prints using the same objects.

It works in my application too, if I take the constructor out of the form constructor. Now that is strange....

I saw those notes on the DYMO support site too, thanks for looking.

Have I tried it on .NET? No I was a Clipper programmer back in the days of DOS, then moved to Delphi for years. I used .NET and C# on one project, but never really got comfortable with it.

I like Qt a lot, but there is a learning curve with any software and the older I get the longer it takes me to get around the corner... ;)

Thanks, Keith

high_flyer
16th March 2011, 14:52
Just a small comment:
I don't see where you are deleting 'dymoAddIn' and 'dymoLabels'?


I tried stepping through the debugger and I get lost in all the "Ax" code.
try setting a break point in the constructor, and just let it run, see if the break point gets caught.
It looks like this code is not getting called (for what ever reason) where it is.

schnitzel
16th March 2011, 15:55
Taking one of their samples to try it on .NET shouldn't be too hard. You could try VB express (for free) which is very similar to Delphi. Anyway, the point is not to push you away from Qt, but to quickly try something that will show whether or not *their* stuff works.
If they have examples for C++, then I would try to follow that as closely as possible.
The fact that their software works might be because they do things programmatically - such as the registering a dll.

The link I sent had a lot of posts below the article where people were having tons of trouble with registration - that didn't look good :(

kwire
16th March 2011, 23:14
schnitzel,

I downloaded and installed VB express. Tried it on the DYMO .NET VB example included in the SDK. After it converted the project it compiled it and ran just fine. I was able to open the label, fill in the data fields and it printed my labels including the barcode. So I guess the COM objects are registered and working OK.

I still can't think of a good reason I have to take the COM object instantiation out of the constructor. This project has a Main Form where I call each job from the menu by creating another form where I do the work and print my labels. Something in Qt must need to be done in the constructor before I can create these two COM objects.

I hate it when I don't know what is going on...

Keith

high_flyer,

I may be wrong, but I thought COM objects were reference counted and didn't need to be manually deleted. At least that is the way they always worked in Delphi and C#. When the last variable went out of scope that referenced the COM object the object was automatically deleted.

Is that not true for Qt?

Keith

schnitzel
16th March 2011, 23:30
Do they provide a C++ example? If so, are they also allocating the objects using new in the constructor?

kwire
17th March 2011, 13:13
schnitzel,

They have a Visual C++ example but they use CreateDispatch().

I took my inspiration for my code from the Qt dumpcpp documentation I found here (http://doc.qt.nokia.com/4.7-snapshot/activeqt-dumpcpp.html).

I have tried lots of things and read lots and I think my usage is correct, it just won't work in the constructor of the form...

Keith

high_flyer
17th March 2011, 13:21
I may be wrong, but I thought COM objects were reference counted and didn't need to be manually deleted. At least that is the way they always worked in Delphi and C#. When the last variable went out of scope that referenced the COM object the object was automatically deleted.

Is that not true for Qt?
It has nothing to do with Qt.
Regarding the reference count on COM objects, I think it depends on what kind of pointer container they are held.
CComXXX<T> pointer does ref counts, but a plain pointer does not.
I can't see the declaration of the pointer variable so I don't know for your case.

You should run you application through a leak detection tool, which can also detect COM leakages to be sure.
I'd recommend that you ask that on a COM oriented forum, where the people know these issues in more detail.

kwire
17th March 2011, 14:17
high_flier, can you recommend a good "leak detection tool" that works on Windows 7?

high_flyer
17th March 2011, 15:21
You need more the just a leak detection tool, you need one that can also detect COM leaks (which (can be)/is trickier).
For "regular" leak detection you can use the CRT leak detection tool:
http://msdn.microsoft.com/en-us/library/e5ewb1h3%28v=vs.71%29.aspx
In my company we use our own brewed leak detection (which basically intercepts ALL (external as well) allocations/frees before the kernel) since we didn't find anything that could handle our large code base.
Again, you should ask that on forums that specialize with COM.