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

19/01/2019

Как из arx-приложения получить все загруженные в AutoCAD .NET-сборки

Как из arx-приложения получить все загруженные в AutoCAD .NET-сборки

Arx-приложение может быть native и mixed. В любом случае, чтобы получить все .NET-сборки нужно воспользоваться методом AppDomain:: GetAssemblies. Для mixed-кода это совсем просто:

Код - C++: [Выделить]
  1. //-----------------------------------------------------------------------------
  2. //----- acrxEntryPoint.cpp
  3. //-----------------------------------------------------------------------------
  4. #include "StdAfx.h"
  5. #include "resource.h"
  6. #include "Psapi.h"
  7.  
  8. using namespace System;
  9. using namespace System::Reflection;
  10. using namespace Autodesk::AutoCAD::ApplicationServices;
  11. using namespace Autodesk::AutoCAD::DatabaseServices;
  12. using namespace Autodesk::AutoCAD::EditorInput;
  13.  
  14. //-----------------------------------------------------------------------------
  15. //----- ObjectARX EntryPoint
  16. class CGetLoadedApp : public AcRxArxApp {
  17.  
  18. public:
  19.   CGetLoadedApp() : AcRxArxApp() {}
  20.  
  21.   virtual AcRx::AppRetCode On_kInitAppMsg(void *pkt) {
  22.     AcRx::AppRetCode retCode = AcRxArxApp::On_kInitAppMsg(pkt);
  23.     return (retCode);
  24.   }
  25.  
  26.   virtual AcRx::AppRetCode On_kUnloadAppMsg(void *pkt) {
  27.     AcRx::AppRetCode retCode = AcRxArxApp::On_kUnloadAppMsg(pkt);
  28.     return (retCode);
  29.   }
  30.  
  31.   virtual void RegisterServerComponents() {  }
  32.  
  33.   static void RivilisGetLoadedMGD() {
  34.     Document^ doc = Application::DocumentManager->MdiActiveDocument;
  35.  
  36.     if (doc == nullptr) return;
  37.     Editor^ ed = doc->Editor;
  38.     for each (Assembly^ ass in AppDomain::CurrentDomain->GetAssemblies())
  39.     {
  40.       ed->WriteMessage("\nName = {0}", ass->GetName(false)->Name);
  41.       ed->WriteMessage("\n\tFull Name = {0}", ass->FullName);
  42.       try  {
  43.         ed->WriteMessage("\n\tLocation = {0}", ass->Location);
  44.       }
  45.       catch (...) {
  46.         ed->WriteMessage("\n\tNo Location. Possible dynamic assembly");
  47.       };
  48.     }
  49.   }
  50. };
  51.  
  52. //-----------------------------------------------------------------------------
  53. IMPLEMENT_ARX_ENTRYPOINT(CGetLoadedApp)
  54.  
  55. ACED_ARXCOMMAND_ENTRY_AUTO(CGetLoadedApp, Rivilis, GetLoadedMGD, GetLoadedMGD, ACRX_CMD_MODAL, NULL)

Из native-приложения это сделать несколько сложнее, но тоже возможно. За основу берётся вот этот алгоритм: https://blogs.msdn.microsoft.com/calvin_hsia/2013/12/05/use-reflection-from-native-c-code-to-run-managed-code/

В результате получаем такой код:

Код - C++: [Выделить]
  1. //-----------------------------------------------------------------------------
  2. //----- acrxEntryPoint.cpp
  3. //-----------------------------------------------------------------------------
  4. #include "StdAfx.h"
  5. #include "resource.h"
  6.  
  7. #include <atlsafe.h>
  8. #import <mscorlib.tlb> rename("ReportEvent","ReportEventManaged")
  9. #include <metahost.h>
  10. #pragma comment(lib,"mscoree.lib")
  11. #include <mscoree.h>
  12. #include <comdef.h>
  13.  
  14. using namespace mscorlib;
  15.  
  16. //-----------------------------------------------------------------------------
  17. //----- ObjectARX EntryPoint
  18. class CGetMgdFromNativeApp : public AcRxArxApp {
  19.  
  20. public:
  21.   CGetMgdFromNativeApp() : AcRxArxApp() {}
  22.  
  23.   virtual AcRx::AppRetCode On_kInitAppMsg(void *pkt) {
  24.     AcRx::AppRetCode retCode = AcRxArxApp::On_kInitAppMsg(pkt);
  25.     return (retCode);
  26.   }
  27.  
  28.   virtual AcRx::AppRetCode On_kUnloadAppMsg(void *pkt) {
  29.     AcRx::AppRetCode retCode = AcRxArxApp::On_kUnloadAppMsg(pkt);
  30.     return (retCode);
  31.   }
  32.  
  33.   virtual void RegisterServerComponents() {
  34.     //----- Self-register COM server upon loading.
  35.     if (FAILED(::DllRegisterServer()))
  36.       acutPrintf(_RXST("Failed to register COM server.\n"));
  37.   }
  38.  
  39.   static void RivilisGetManagedDlls() {
  40.     CComPtr<ICLRMetaHost> spClrMetaHost;
  41.     // Получаем MetaHost
  42.     HRESULT hr = CLRCreateInstance(
  43.       CLSID_CLRMetaHost,
  44.       IID_PPV_ARGS(&spClrMetaHost)
  45.     );
  46.     _ASSERT(hr == S_OK);
  47.  
  48.     // Получаем runtime-версию (соответствует .NET 4)
  49.     CComPtr<ICLRRuntimeInfo> spCLRRuntimeInfo;
  50.     hr = spClrMetaHost->GetRuntime(L"v4.0.30319",
  51.       IID_PPV_ARGS(&spCLRRuntimeInfo)
  52.     );
  53.     _ASSERT(hr == S_OK);
  54.  
  55.     // Получаем CorRuntimeHost
  56.     CComPtr<ICorRuntimeHost> spCorRuntimeHost;
  57.     hr = spCLRRuntimeInfo->GetInterface(
  58.       CLSID_CorRuntimeHost,
  59.       IID_PPV_ARGS(&spCorRuntimeHost)
  60.     );
  61.     _ASSERT(hr == S_OK);
  62.  
  63.     // Стартуем CLR
  64.     hr = spCorRuntimeHost->Start();
  65.     _ASSERT(hr == S_OK);
  66.  
  67.     // Получаем домен приложения по-умолчанию
  68.     CComPtr<IUnknown> spAppDomainThunk;
  69.     hr = spCorRuntimeHost->GetDefaultDomain(&spAppDomainThunk);
  70.     _ASSERT(hr == S_OK);
  71.  
  72.     // Конвертируем AppDomain IUnknown в _AppDomain
  73.     CComPtr<_AppDomain> spAppDomain;
  74.     hr = spAppDomainThunk->QueryInterface(IID_PPV_ARGS(&spAppDomain));
  75.     _ASSERT(hr == S_OK);
  76.     // Получаем массив сборок домена
  77.     SAFEARRAY *pAssemblyArray = spAppDomain->GetAssemblies();
  78.  
  79.     CComSafeArray<IUnknown*> csaAssemblies;
  80.     csaAssemblies.Attach(pAssemblyArray);
  81.     long cAssemblies = csaAssemblies.GetCount();
  82.     for (long i = 0; i < cAssemblies; i++)
  83.     {
  84.       CComPtr<_Assembly> spAssembly;
  85.       spAssembly = csaAssemblies[i];
  86.       if (spAssembly == NULL)
  87.         continue;
  88.       CComBSTR asmFullName;
  89.       hr = spAssembly->get_FullName(&asmFullName);
  90.       if (FAILED(hr))
  91.         continue;
  92.       AcString asmName = asmFullName;
  93.       int iComma = asmName.find(L',');
  94.       if (iComma > 0) asmName = asmName.left(iComma);
  95.       acutPrintf(L"\n\nName:%s", asmName.constPtr());
  96.       acutPrintf(L"\n\tFull Name:%s", asmFullName);
  97.       CComBSTR asmLocatation;
  98.       hr = spAssembly->get_Location(&asmLocatation);
  99.       if (!FAILED(hr))
  100.         acutPrintf(L"\n\tLocation: %s", asmLocatation);
  101.       else
  102.         acutPrintf(L"\n\tLocation not found");
  103.     }
  104.     // Останавливаем CLR
  105.     hr = spCorRuntimeHost->Stop();
  106.     _ASSERT(hr == S_OK);
  107.  
  108.   }
  109.  
  110. };
  111.  
  112. //-----------------------------------------------------------------------------
  113. IMPLEMENT_ARX_ENTRYPOINT(CGetMgdFromNativeApp)
  114.  
  115. ACED_ARXCOMMAND_ENTRY_AUTO(CGetMgdFromNativeApp, Rivilis, GetManagedDlls, GetManagedDlls, ACRX_CMD_MODAL, NULL)

Результат работы команды GetManagedDlls:

 

Автор: Александр Ривилис

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

Опубликовано 19.01.2019
Отредактировано 19.01.2019 в 17:30:31