Windows COM automation Qt and AutoCAD
-
Hi,
I have ran into the problem with Qt AutoCAD COM automation
I'm using MinGw compiler. Additionally in my qt application I'm using header and cpp file generated with dumpcpp from tlb files.
I can start and stop AutoCAD,
I'm able to add new layer, get existing object copy it or delete it for example
I'm starting to run into a problem when I need to add new object such as point for example.
According to autocad documentation it requires double[3] object to pass coordinates.
Ofcourse Im using QVariant. Precisely speaking QList<QVariant> to pass three coordinates
When I'm trying to add point with appropriate method I'm getting such message.
QAxBase: Error calling IDispatch member AddPoint: Exception thrown by server
Code : -2147024809
Source :
Description:
Help :
Connect to the exception(int,QString,QString,QString) signal to catch this exceptionApplication is not crashing but new point is not appearing into Autocad model space
Any suggestions from you people? Where can I get information about this exception code?
Thank you in advance for your help
Regards
Adam -
@nadamus said in Windows COM automation Qt and AutoCAd:
OK
My research shows that code most probably means : 2147024809 ERROR_INVALID_PARAMENTER - E_INVALIDARG
So most probably it connects with sending these coordinates with list of Qvariants. Anyone can point me a direction where look for solution?
Regards
Adam -
Hi, I think if you're using the dynamicCall function, you should be able to do something simpler, perhaps like:
myLayer->dynamicCall("AddPoint(double,double,double)",1.0,2.0,3.0);
Note: I don't know anything about AutoCad, this is just a guess :-)
Edit: googled a bit, maybe this works better:
QList<QVariant> v3; v3.append(1.0); v3.append(2.0); v3.append(3.0); myLayer->dynamicCall("AddPoint(QList<QVariant>&)",v3);
-
@hskoglund said in Windows COM automation Qt and AutoCAd:
myLayer->dynamicCall
Thanks for your replay.
AddPoint requires only one argument to pass. Second approach is similar to what I tried to do.
Orginal AutoCAD documentation:Signature
VBA:
RetVal = object.AddPoint(Point)
object
Type: Block, ModelSpace, PaperSpace
The objects this method applies to.
Point
Access: Input-only
Type: Variant (three-element array of doubles)
The coordinates of the point to be created.
Return Value (RetVal)Type: Point
The newly created Point object.
and this is what was generated in header file from tlb file with dumpcpp
inline AutoCAD::IAcadPoint* IAcadPaperSpace::AddPoint(const QVariant& Point)
{
AutoCAD::IAcadPoint* qax_result = 0; qRegisterMetaType<AutoCAD::IAcadPoint*>("IAcadPoint*", &qax_result); qRegisterMetaType<AutoCAD::IAcadPoint>("IAcadPoint", qax_result); void *_a[] = {(void*)&qax_result, (void*)&Point}; qt_metacall(QMetaObject::InvokeMetaMethod, 43, _a); return qax_result;
}
Regards
Adam -
I see, should be good using the dumpcpp tool, so perhaps try something like:
QList<QVariant> v3; v3.append(1.0); v3.append(2.0); v3.append(3.0); QVariant point = QVariant::fromValue(v3); myPaperSpaceClass->AddPoint(point);
Or is this what you've tried already?
-
Ok time to bring out the big guns, i.e. go native and try with the old style SAFEARRAY, say like this:
SAFEARRAYBOUND rgsabound[1]; rgsabound[0].lLbound = 0; rgsabound[0].cElements = 3; SAFEARRAY* psa = SafeArrayCreate(VT_R8, 1, rgsabound); LONG rgIndex = 0; double x = 1.0; double y = 2.0; double z = 3.0; SafeArrayPutElement(psa, &rgIndex, &x); rgIndex++; SafeArrayPutElement(psa, &rgIndex, &y); rgIndex++; SafeArrayPutElement(psa, &rgIndex, &z); QVariant point = QVariant::fromValue(psa); myPaperSpaceClass->AddPoint(point);
Note: if the QVariant::fromValue fails to compile, consider brute-forcing by changing the void *_a[] declaration inside that function AddPoint() that dumpcpp generated for you, to:
void *_a[] = {(void*)&qax_result, (void*)&psa};
Also need a way to make psa variable visible in there, perhaps declare it as a global (quick and dirty :-)
-
What I did:
I changed my compiler from MinGW to MSVC and prepared tlh and tli files from the same tlb libraries.
Then I used SAFEARRAY* wrapped with variant_t
Now it works, but sill I wonder why it is not working with QList and QVariant. According to documentation it should, as far as I understand it. Maybe I'm missing something? Hard to say.
Anyway. Thanks for your support. I appreciate it :)
Code looks like this:
variant_t AcadCom::SetVariant(SAFEARRAY** wektor, double* koordynaty,unsigned long wymiar){
if(wymiar>0) { SAFEARRAYBOUND granice; granice.lLbound=0; granice.cElements=wymiar; *wektor=SafeArrayCreate(VT_R8,1,&granice); double HUGEP* pdFreq; SafeArrayAccessData(*wektor,(void HUGEP* FAR*)&pdFreq); for(DWORD i=0;i<wymiar;i++) { *pdFreq++=koordynaty[i]*skala; } SafeArrayUnaccessData(*wektor); variant_t vKoordynaty; vKoordynaty.vt=VT_ARRAY|VT_R8; vKoordynaty.parray=*wektor; return vKoordynaty; } else { return 0; }
}
bool AcadCom::SetPunkt(double *koordynaty, QString identyfikator)
{
bool sukces=false; SAFEARRAY *wektor; IAcadPointPtr pktPtr; IAcadTextPtr idText; if(czyPolaczony) { variant_t vKoordynaty=SetVariant(&wektor,koordynaty); pktPtr=autoCadAppPtr->ActiveDocument->ModelSpace->AddPoint(vKoordynaty); if(pktPtr->GetApplication()) { idText=autoCadAppPtr->ActiveDocument->ModelSpace->AddText(identyfikator.toStdString().c_str(),vKoordynaty,0.005*skala); if(idText->GetApplication()) sukces=true; DopasujWidok(); } SafeArrayUnlock(wektor); SafeArrayDestroy(wektor); vKoordynaty.Clear(); wektor=NULL; } return sukces;
Regards
Adam -
@nadamus said in Windows COM automation Qt and AutoCAD:
..
Now it works, but sill I wonder why it is not working with QList and QVariant.I think the culprit is this line:
*wektor=SafeArrayCreate(VT_R8,1,&granice);
had it instead been
*wektor=SafeArrayCreate(VT_VARIANT,1,&granice);
then a QList<QVariant> should've worked.Qt's COM support is kind of stuck between a rock (everything is a VARIANT, the Visual Basic COM flavor, functions are called 100% through the IDispatch interface) and a hard place (you can pass native data types like int, doubles etc through COM, the C/C++ COM flavor, functions are called through specialized interfaces based on IUnknown). I remember doing a lot COM coding around the turn of the century, it was really hot then. Nowadays not so much :-)
-
This is the modified part,
variant_t Form::SetVariant(SAFEARRAY **wektor, double *koordynaty, unsigned long wymiar)
{
if(wymiar>0)
{
SAFEARRAYBOUND granice;
granice.lLbound=0;
granice.cElements=wymiar;
*wektor=SafeArrayCreate(VT_R8,1,&granice);double HUGEP* pdFreq; SafeArrayAccessData(*wektor,(void HUGEP* FAR*)&pdFreq); for(DWORD i=0;i<wymiar;i++) { *pdFreq++=koordynaty[i]*skala; } SafeArrayUnaccessData(*wektor); variant_t vKoordynaty; vKoordynaty.vt=VT_ARRAY|VT_R8; vKoordynaty.parray=*wektor; return vKoordynaty; } else { return 0; }
}
inline AutoCAD::IAcadPoint* IAcadModelSpace::AddPoint(const variant_t & Point)
{
AutoCAD::IAcadPoint* qax_result = 0;
qRegisterMetaTypeAutoCAD::IAcadPoint*("IAcadPoint*", &qax_result);
qRegisterMetaTypeAutoCAD::IAcadPoint("IAcadPoint", qax_result);
void _a[] = {(void)&qax_result, (void*)&Point};
qt_metacall(QMetaObject::InvokeMetaMethod, 42, _a);
return qax_result;
}call:
double ptV[3];
ptV[0] = 1000.0;
ptV[1] = 1000.0;
ptV[2] = 0.0;
SAFEARRAY *wektor;
variant_t vKoordynaty=SetVariant(&wektor,ptV,3);
ModelSpace->AddPoint(vKoordynaty);But it's still wrong:Error calling IDispatch member AddPoint: Exception thrown by server
Code : -2147024809
Source :
Description:
Help :
Connect to the exception(int,QString,QString,QString) signal to catch this exception -
This post is deleted!