Issue with a recursive function to get list of leaf components.

94 views
Skip to first unread message

Brendan L

unread,
May 9, 2008, 1:29:13 PM5/9/08
to SolidWorks-API
Hello All:

I’m attempting to gather all of the leaf nodes from the component tree
for any given assembly model.

My code is written as a C++ ATL COM object, which is acting as a
SolidWorks add-in. The recursive function at the end of this post
works fine when making the call from the add-in’s menu in SolidWorks.
However, I also use the COM object as a backend interface to
SolidWorks from other programs, such as Matlab…

When making the same function call via the COM object in Matlab, the
return from IGetChildrenCount is the same consistently, but the return
from IGetChildren is different! I’m completely baffled at how the
call could be different at all, especially when the model itself has
never changed.

If anyone has some insight, or a different method for getting the leaf
nodes of the component tree, then please let me know. I’d be more
than willing to send a sample of the COM object, and any necessary
code needed for debugging.

Thanks In Advance,



void CMDO::getLeafComponents(IComponent2 *recComp,
vector<IComponent2*> *swVectorComp){
int count,i;
typedef IComponent2 *LPCOMPONENT2;
CComBSTR name;
LPCOMPONENT2* swComponent;

CHECKPT
fprintf(m_DebugFile,"////////////////////////////////////////%p\n",
recComp);
fflush(m_DebugFile);

//The recComp sould never be NULL!
if(recComp == NULL) {
CHECKPT
fprintf(m_DebugFile, "ERROR in getLeafComponents!\n");
fflush(m_DebugFile);
return; // There is a problem!
} else {
if(recComp->IGetChildrenCount(&count) == S_OK) {
CHECKPT
//Determined how many children this node has
fprintf(m_DebugFile,"COUNT: %i\n",count);
fflush(m_DebugFile);

//Stoping condition
if(count == 0) {
CHECKPT
//This means that the recComp is a leaf node. Save it and return!
//Only save the leaf nodes of the component tree
swVectorComp->push_back(recComp);
return;
}
else
{
CHECKPT

//Create a new list of components.
swComponent = new LPCOMPONENT2[count];

//Initialize all of these component pointers
//to NULL to avoid random assingment problems.
for(i = 0; i < count; i++)
{
swComponent[i] = NULL;
}

//Save all of the children into the swComponent array.
if(recComp->IGetChildren(swComponent) == S_OK) {
CHECKPT

//For each component, get it's children.
for(i = 0; i < count; i++) {
if(swComponent[i] != NULL)
{
getLeafComponents(swComponent[i],swVectorComp);
}
}
}else{
CHECKPT
//get children failed
}
}
}else{
CHECKPT
//get children count failed.
}
}
}//end function

Andrey Dankevich

unread,
May 12, 2008, 4:03:27 AM5/12/08
to SolidWorks-API, ble...@aerotonomy.com
Hi Brendan,
 
Could you clarify what is exactly different in the return of IGetChildren?
 
May be this quotation form API Help will help you "Because Component2::IGetChildren returns an array, this code must be used in an in-process DLL. Otherwise, use the method Component2::GetChildren, which returns a VARIANT.".
 
Regards
Andrey

Brendan L

unread,
May 13, 2008, 2:35:53 PM5/13/08
to SolidWorks-API
When I call the recursive function from the SolidWorks add-in, the
return from IGetChildren is an array of legitimate pointers to the
Components, as it should be. When I make the function call from
MATLAB, I get an array containing a legitimate pointer to the first
Component accessed followed by a series of NULL pointers. I have
tried the recursive functions on multiple different assembly file
configurations and this seems to be the trend. I have also finagled a
version of the function to run iteratively through the component tree
(or at least no recursive call) and it also shows the same trend.

Regards,
Brendan

Andrey Dankevich

unread,
May 14, 2008, 9:50:51 AM5/14/08
to ble...@aerotonomy.com, SolidWorks-API
Hi Brendan,
 
See the code below.
 
As I supposed the issue is that you have to use Component2::GetChildren() instead of Component2::IGetChildren().
 
Regards
Andrey

void TraverseComponents( IComponent2 *recComp, int level)
{
 
    typedef IComponent2 *LPCOMPONENT2;
    CComBSTR name, cfg;
    int count = 0;
 
    recComp->IGetChildrenCount(&count);
 
    if ( !count )
        return;
 
    LPDISPATCH* componentChildrenArray;
    VARIANT vChildren;
    HRESULT hres = recComp->GetChildren( &vChildren );
    SAFEARRAY* psa = V_ARRAY(&vChildren);
    HRESULT res = SafeArrayAccessData(psa, (void **)&componentChildrenArray);
 
    long highIndex;
    SafeArrayGetUBound(psa, 1, &highIndex); // Get index number of highest array element
 
    ASSERT ( count == ( highIndex + 1) );
 
    LPCOMPONENT2 m_childComponent = NULL;
    for( int i = 0; i < count; i++)
    {
        componentChildrenArray[i]->QueryInterface ( __uuidof(IComponent2), (void**)&m_childComponent );
 
        if( m_childComponent != NULL)
        {
            componentChildrenArray[i]->AddRef();
            for ( int i = 0; i < level; i++)
                fprintf ( m_DebugFile, "\t" );
 
        fprintf ( m_DebugFile, "%d. ", level );
 
        m_childComponent->get_Name2 ( &name );
        m_childComponent->get_ReferencedConfiguration ( &cfg );
        fwprintf (m_DebugFile, L" %s < %s >\n", name, cfg );
        TraverseComponents( m_childComponent, level+1);
 
        }
   
        m_childComponent = NULL;
    }
   
    hres = SafeArrayUnaccessData(psa); // Unaccess the SafeArray
    hres = SafeArrayDestroy(psa); // Destroy the SafeArray
}

Brendan L

unread,
May 14, 2008, 10:37:38 AM5/14/08
to SolidWorks-API
Andrey,

Thank you so much! That worked Beautifully!

Brendan

Brendan L

unread,
May 15, 2008, 2:55:54 PM5/15/08
to SolidWorks-API
As a sort of addendum question, you stated that getChildren worked
better than IGetChildren in my specific case. Do you know of any other
functions that have this issue... more specifically, do you know if
IRayIntersections and IRayIntersectionPoints have this issue? I seem
to have a discontinuity in the returns from those functions depending
on whether I call it from inside SolidWorks and when i call it from
MATLAB.

Best,
Brendan

Andrey Dankevich

unread,
May 16, 2008, 3:06:01 AM5/16/08
to SolidWorks-API, ble...@aerotonomy.com
Hi Brendan,
I think such functions are any which return "Pointer to an array", and in COM applications they must be replaced by the corresponding fuctions which return "VARIANT of type SafeArray".
 
Regards
Andrey
Reply all
Reply to author
Forward
0 new messages