Cast between COM types in C++

By Adam Nagy

Sometimes you may need to cast an object to a different type. E.g. when trying to get to the Parameters property of a ComponentDefinition got from a ComponentOccurrence. ComponentDefinition does not have a Parameters property, but PartComponentDefinition and AssemblyComponentDefinition do.
You have two ways to solve this problem:
1) Either use early binding and cast ComponentDefinition to PartComponentDefinition or AssemblyComponentDefinition using CComQIPtr (QI = Query Interface)
2) Use late binding to access the Parameters property through the ComponentDefinition object

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
  int nRetCode = 0;
 
  HRESULT Result = NOERROR;
 
  ::CoInitialize(NULL);
 
  // Access Inventor
  {
    CLSID InvAppClsid;
    Result = CLSIDFromProgID (_T("Inventor.Application"), &InvAppClsid);
    if (FAILED(Result)) return Result;
 
    CComPtr pInvAppUnk;
    Result = ::GetActiveObject (InvAppClsid, NULL, &pInvAppUnk);
    if (FAILED (Result))
      _tprintf_s(_T("Could not get the active Inventor instancen"));
    if (FAILED(Result)) return Result;
 
    CComPtr pInvApp;
    Result = pInvAppUnk->QueryInterface(
      __uuidof(Application), (void **) &pInvApp);
    if (FAILED(Result)) return Result;
 
    CComPtr pAddIn = 
      pInvApp->ApplicationAddIns->ItemById[
        _T("{3BDD8D79-2179-4B11-8A5A-257B1C0263AC}")];
 
    // Get Parameters 
    {
      // First the occurrence needs to be selected
      // in the user interface
      CComQIPtr oOcc = 
        pInvApp->ActiveDocument->SelectSet->Item[1];
 
      // 1) Use early binding and CComQIPtr
 
      CComPtr pParams;
      CComQIPtr pPartCompDef =         oOcc->Definition;
      if (pPartCompDef)
      {
        // It is a part component definition, so we can get the 
        // parameters of the part definition
        pParams = pPartCompDef->Parameters;
      }
 
      CComQIPtr pAsmCompDef =         oOcc->Definition;
      if (pAsmCompDef)
      {
        // It is an assembly component definition, so we         // can get the parameters of the assembly definition
        pParams = pAsmCompDef->Parameters;
      }
 
      MessageBox(NULL, pParams->Item[1]->Name, 
        _T("Name of first parameter (early binding)"), MB_OK);
 
      // 2) Use late binding
      // This requires the AutoWrap function from article
      // http://adndevblog.typepad.com/manufacturing/2013/09/run-ilogic-rule-from-external-application.html
 
      // Since both PartComponentDefinition and 
      // AssemblyComponentDefinition have a Parameters property
      // we could get it like this too
      VARIANT res;
      AutoWrap(
        DISPATCH_PROPERTYGET, &res, oOcc->Definition,         _T("Parameters"), 0);
      CComQIPtr pParamsLate = res.pdispVal;  
 
      MessageBox(NULL, pParamsLate->Item[1]->Name, 
        _T("Name of first parameter (late binding)"), MB_OK);
    }  }  ::CoUninitialize();
return nRetCode;}

Comments

Leave a Reply

Discover more from Autodesk Developer Blog

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

Continue reading