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 exception

    Application 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?



  • This approach is not working neither. Same exception is thrown.
    Regards
    Adam



  • 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 :-)



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.