ADN Open CIS
Сообщество программистов Autodesk в СНГ

27/09/2013

Запуск правил iLogic из внешнего приложения

При работе с объектами iLogic из Inventor AddIn доступ к ним можно реализовать в режиме раннего связывания.  Если же требуется получить к ним доступ из внешнего приложения, приходится пользоваться поздним связыванием.  Причина кроется в том, что объекты iLogic не являются истинными  COM объектами, они в действительности представляют собой обертки для .NET объектов.

В случае VB .NET всегда легко было работать с поздним связыванием, для этого достаточно было декларировать переменные как тип Object вместо использования конкретного типа.  В четвертой версии C# для той же цели можно воспользоваться ключевым словом dynamic

Ниже приведен фрагмент кода внешнего приложения, эквивалентного in-process приложению из поста http://adndevblog.typepad.com/manufacturing/2013/04/call-ilogic-from-net.html.

Код - C#: [Выделить]
  1. static void test_iLogic()
  2. {
  3.   Inventor.Application oApp =
  4.     System.Runtime.InteropServices.Marshal.
  5.     GetActiveObject("Inventor.Application") as Inventor.Application;
  6.   //iLogic is also an addin which has its guid
  7.   string iLogicAddinGuid = "{3BDD8D79-2179-4B11-8A5A-257B1C0263AC}";
  8.  
  9.   Inventor.ApplicationAddIn addin = null;
  10.   try
  11.   {
  12.     // try to get iLogic addin
  13.     addin = oApp.ApplicationAddIns.get_ItemById(iLogicAddinGuid);
  14.   }
  15.   catch
  16.   {
  17.     // any error...
  18.   }
  19.  
  20.   if (addin != null)
  21.   {
  22.     // activate the addin
  23.     if (!addin.Activated)
  24.       addin.Activate();
  25.  
  26.     // entrance of iLogic
  27.     dynamic _iLogicAutomation = addin.Automation;
  28.  
  29.     Document oCurrentDoc = oApp.ActiveDocument;
  30.  
  31.     dynamic myRule = null;
  32.     //dump all rules
  33.     foreach (dynamic eachRule in _iLogicAutomation.Rules(oCurrentDoc))
  34.     {
  35.       if (eachRule.Name == "MyRule")
  36.       {
  37.         myRule = eachRule;
  38.         //list the code of rule to the list box
  39.         MessageBox.Show(myRule.Text);
  40.         break;
  41.       }
  42.     }
  43.     if (myRule != null)
  44.       _iLogicAutomation.RunRule(oCurrentDoc, "MyRule");
  45.   }
  46. }

В случае C++ дело обстоит несколько сложнее.  В MSDN по этой теме есть хорошая обзорная статься «How To Use Visual C++ to Access DocumentProperties with Automation» http://support.microsoft.com/kb/238393.

Код - C++: [Выделить]
  1. // http://support.microsoft.com/kb/238393
  2. //
  3. // AutoWrap() - Automation helper function...
  4. //
  5. HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp,
  6.       LPOLESTR ptName, int cArgs...)
  7. {
  8.   // Begin variable-argument list...
  9.   va_list marker;
  10.   va_start(marker, cArgs);
  11.  
  12.   if(!pDisp) {
  13.     MessageBox(NULL, _T("NULL IDispatch passed to AutoWrap()"),
  14.       _T("Error"), 0x10010);
  15.     _exit(0);
  16.   }
  17.  
  18.   // Variables used...
  19.   DISPPARAMS dp = { NULL, NULL, 0, 0 };
  20.   DISPID dispidNamed = DISPID_PROPERTYPUT;
  21.   DISPID dispID;
  22.   HRESULT hr;
  23.   TCHAR buf[200];
  24.  
  25.   // Get DISPID for name passed...
  26.   hr = pDisp->GetIDsOfNames(
  27.     IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);
  28.  
  29.   if(FAILED(hr)) {
  30.     _stprintf(buf,
  31.       _T("IDispatch::GetIDsOfNames(\"%s\") failed w/err0x%08lx"),
  32.       ptName, hr);
  33.     MessageBox(NULL, buf, _T("AutoWrap()"), 0x10010);
  34.     _exit(0);
  35.     return hr;
  36.   }
  37.  
  38.   // Allocate memory for arguments...
  39.   VARIANT *pArgs = new VARIANT[cArgs+1];
  40.  
  41.   // Extract arguments...
  42.   for(int i=0; i<cArgs; i++) {
  43.     pArgs[i] = va_arg(marker, VARIANT);
  44.   }
  45.  
  46.   // Build DISPPARAMS
  47.   dp.cArgs = cArgs;
  48.   dp.rgvarg = pArgs;
  49.  
  50.   // Handle special-case for property-puts!
  51.   if(autoType & DISPATCH_PROPERTYPUT) {
  52.     dp.cNamedArgs = 1;
  53.     dp.rgdispidNamedArgs = &dispidNamed;
  54.   }
  55.  
  56.   // Make the call!
  57.   hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
  58.     autoType, &dp, pvResult, NULL, NULL);
  59.  
  60.   if(FAILED(hr)) {
  61.     _stprintf(buf,
  62.       _T("IDispatch::Invoke(\"%s\"=%08lx) failed w/err 0x%08lx"),
  63.       ptName, dispID, hr);
  64.     MessageBox(NULL, buf, _T("AutoWrap()"), 0x10010);
  65.     _exit(0);
  66.     return hr;
  67.   }
  68.  
  69.   // End variable-argument section...
  70.   va_end(marker);
  71.  
  72.   delete [] pArgs;
  73.  
  74.   return hr;
  75. }
  76.  
  77. int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
  78. {
  79.   int nRetCode = 0;
  80.  
  81.   HRESULT Result = NOERROR;
  82.  
  83.   ::CoInitialize(NULL);
  84.  
  85.   // Access Inventor
  86.   {
  87.     CLSID InvAppClsid;
  88.     Result = CLSIDFromProgID (
  89.       _T("Inventor.Application"), &InvAppClsid);
  90.     if (FAILED(Result)) return Result;
  91.  
  92.     CComPtr<IUnknown> pInvAppUnk;
  93.     Result = ::GetActiveObject (InvAppClsid, NULL, &pInvAppUnk);
  94.     if (FAILED (Result))
  95.       _tprintf_s(_T("Could not get the active Inventor instance\n"));
  96.     if (FAILED(Result)) return Result;
  97.  
  98.     CComPtr<Application> pInvApp;
  99.     Result = pInvAppUnk->QueryInterface(
  100.       __uuidof(Application), (void **) &pInvApp);
  101.     if (FAILED(Result)) return Result;
  102.  
  103.     CComPtr<ApplicationAddIn> pAddIn =
  104.       pInvApp->ApplicationAddIns->ItemById[
  105.         _T("{3BDD8D79-2179-4B11-8A5A-257B1C0263AC}")];
  106.  
  107.     // Calling iLogic functions
  108.     {
  109.       CComPtr<IDispatch> pAuto = pAddIn->Automation;
  110.  
  111.       CComPtr<Document> pDoc = pInvApp->ActiveDocument;
  112.  
  113.       VARIANT ret;
  114.       VARIANT param1;
  115.  
  116.       param1.vt = VT_DISPATCH;
  117.       param1.pdispVal = pDoc;
  118.       Result = AutoWrap(
  119.         DISPATCH_PROPERTYGET, &ret, pAuto, _T("Rules"), 1, param1);
  120.  
  121.       // Rules() returns an IEnumarator - it will be wrapped as
  122.       // IEnumVARIANT returned by GetEnumerator()
  123.       // http://stackoverflow.com/questions/7399447/com-use-ienumerable-in-atl-c-project
  124.       CComPtr<IDispatch> pRules = ret.pdispVal;
  125.       Result = AutoWrap(
  126.         DISPATCH_METHOD, &ret, pRules, _T("GetEnumerator"), 0);
  127.  
  128.       CComQIPtr<IEnumVARIANT> pRulesEnum = ret.punkVal;
  129.  
  130.       VARIANT rule;
  131.       ULONG celt = 1, celtFetched;
  132.       while (pRulesEnum->Next(celt, &rule, &celtFetched) == S_OK)
  133.       {
  134.         CComPtr<IDispatch> pRule = rule.pdispVal;
  135.         Result = AutoWrap(
  136.           DISPATCH_PROPERTYGET, &ret, pRule, _T("Name"), 0);
  137.         BSTR name = ret.bstrVal;
  138.  
  139.         if (_tcscmp(name, _T("MyRule")) == 0)
  140.         {
  141.           Result = AutoWrap(
  142.             DISPATCH_PROPERTYGET, &ret, pRule, _T("Text"), 0);
  143.           BSTR text = ret.bstrVal;
  144.           MessageBox(NULL, text, _T("Rule Text"), MB_OK);
  145.  
  146.           VARIANT param2;
  147.           param2.vt = VT_BSTR;
  148.           param2.bstrVal = name;
  149.           // Parameters need to be added in reverse order.
  150.           // In the C# code you'd call it like
  151.           // _iLogicAutomation.RunRule(oCurrentDoc, "MyRule");
  152.           Result = AutoWrap(
  153.             DISPATCH_METHOD, &ret, pAuto, _T("RunRule"),
  154.             2, param2, param1);
  155.         }
  156.       }
  157.     }
  158.   }
  159.    ::CoUninitialize();
  160.    return nRetCode;
  161. }

 

Оригинал: http://adndevblog.typepad.com/manufacturing/2013/09/run-ilogic-rule-from-external-application.html

Обсуждение: http://adn-cis.org/forum/index.php?topic=233

Опубликовано 27.09.2013
Отредактировано 05.11.2013 в 14:53:15