Converting AcDbObjectIdArray to IAcadSelectionSet

By Madhukar Moogala

Recently I have received a request from an ADN partner how to pass set of Object Ids to Export COM API, the problem here is working on cross technologies i.e. passing data from C++ to COM

The signature of Export  API in COM is :

Export (        /[in]/ BSTR FileName,        /[in]/ BSTR Extension,        /[in]/ struct IAcadSelectionSet * SelectionSet ) = 0;

It takes a filename, extension and IAcadSelectionSet, now all we have is set of ids.

For better understanding we will pursue an example, the objective of problem is to “Export set of selected objects to BMP format”

 

To tackle such requirement our workflow would be:

  • From list retrieve ObjectIds, get associated IAcadEntity using Global function AcAxGetIUnknownOfObject.
    – Append IAcadEntity to AcadSelectionSet.AddItems
    – Use the selectionset in Export API

Sample Code:

void TestExport()
{
    ads_name ss;
    AcDbObjectIdArray* pIdArray = new AcDbObjectIdArray();
    // get the selectionset
    int res = acedSSGet (NULL, NULL, NULL, NULL, ss);
    if (res == RTNORM)
    {
        //get the length of the selection set
        long length = 0l;
        acedSSLength (ss, &length);

 //now loop round 

        for (long i=0l; iappend(objId);
        }
    }
    /*Export the collection of Objects to BMP format*/
    ExportToFile(pIdArray);
    //free the selection set after use
    acedSSFree (ss);
    delete pIdArray;
}
Utility Functions:
/*Puts AcadEntity to given selectionset*/
HRESULT addToSelSet(AutoCAD::IAcadSelectionSet* pSelSet, AutoCAD::IAcadEntity* pEntity)
{
HRESULT hr;
 
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = 1;
SAFEARRAY* psa = SafeArrayCreateVector(VT_DISPATCH, rgsabound->lLbound, rgsabound->cElements);
if( ! psa )
return E_OUTOFMEMORY;
long i = 0;
LPDISPATCH pDisp = pEntity;
pEntity->Release();
 
/*
This function assigns a single element to the array.
*/
/*NOTE: Void pointer to the data to assign to the array. 
The variant types VT_DISPATCH, VT_UNKNOWN, and VT_BSTR are pointers, and do not require another level of indirection.*/
hr = SafeArrayPutElement(psa, &i,pDisp);
if( FAILED(hr) )
{
SafeArrayDestroy(psa);
return hr;
}
VARIANT v;
 
VariantInit(&v);
v.vt = VT_DISPATCH|VT_ARRAY;
v.parray = psa;
 
return pSelSet->AddItems(v);
}
 
/*Get me a Selection set or create one if not present*/
AutoCAD::IAcadSelectionSet *GiveMeSelectionSet(AutoCAD::IAcadSelectionSets *pSelSets, BSTR Name)
{
try {
AutoCAD::IAcadSelectionSet *pSet = NULL;
if (pSelSets->Add(Name,&pSet) == S_OK) {
return pSet;
} else if (pSelSets->Item(_variant_t(Name),&pSet) == S_OK) {
return pSet;
} else return NULL;
} catch(...) {
return NULL;
}
return NULL;
}
 
 
void ExportToFile(AcDbObjectIdArray*&  pIdArray)
{
HRESULT hr;
try
{
 
AutoCAD::IAcadApplication *pAcad =NULL;
AutoCAD::IAcadDocument *pDoc =NULL;
AutoCAD::IAcadModelSpace *pMSpace = NULL;
AutoCAD::IAcadSelectionSets *pSelSets = NULL;
AutoCAD::IAcadSelectionSet *pSet= NULL;
 
hr = NOERROR;
LPUNKNOWN pUnk = NULL;
LPDISPATCH pAcadDisp = acedGetIDispatch(TRUE);
if(pAcadDisp==NULL)
return ;
 
hr = pAcadDisp->QueryInterface(AutoCAD::IID_IAcadApplication,(void**)&pAcad);
pAcadDisp->Release();
if (FAILED(hr))
return;
 
if (pAcad)
{
 
if (pAcad->get_ActiveDocument(&pDoc) == S_OK)
{
 
if (pDoc->get_SelectionSets(&pSelSets) == S_OK) {
/*Gets or Creates a set*/
if ((pSet = GiveMeSelectionSet(pSelSets,_bstr_t("TestSet"))) != NULL)
{
    pSet->Clear();
    for (int i = 0; i < pIdArray->length(); i++)
    {
        AcDbObjectId id = pIdArray->at(i);
        //get the COM wrapper associated with the entity
        if(FAILED(hr =AcAxGetIUnknownOfObject(&pUnk, id, pAcadDisp)))
            throw (_com_error(hr));
        //get the AutoCAD::IAcadEntity
        AutoCAD::IAcadEntity *pEnt = NULL;
        if(FAILED(hr= pUnk->QueryInterface(AutoCAD::IID_IAcadEntity, (void **)&pEnt)))
            throw (_com_error(hr));
 
        /*Add acad entities to Selection set*/
        if (FAILED(hr = addToSelSet(pSet,pEnt)))
            throw(_com_error(hr)) ;
    }
 
    if (FAILED(hr = pDoc->Export(_bstr_t("c:\temp\test"),_bstr_t("BMP"),pSet)))
        throw(_com_error(hr)) ;
    pSet->Release();
}
else
    return ;
pSelSets->Release();
}
pDoc->Release();
}
pAcad->Release();
}
pUnk->Release();
}
catch (...)
{
return ;
}
return ;
}

Comments

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading