Windows COM automation Qt and AutoCAD
-
@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!