19/01/2019
Как из arx-приложения получить все загруженные в AutoCAD .NET-сборки
Как из arx-приложения получить все загруженные в AutoCAD .NET-сборки
Arx-приложение может быть native и mixed. В любом случае, чтобы получить все .NET-сборки нужно воспользоваться методом AppDomain:: GetAssemblies. Для mixed-кода это совсем просто:
Код - C++: [Выделить]
- //-----------------------------------------------------------------------------
- //----- acrxEntryPoint.cpp
- //-----------------------------------------------------------------------------
- #include "StdAfx.h"
- #include "resource.h"
- #include "Psapi.h"
- using namespace System;
- using namespace System::Reflection;
- using namespace Autodesk::AutoCAD::ApplicationServices;
- using namespace Autodesk::AutoCAD::DatabaseServices;
- using namespace Autodesk::AutoCAD::EditorInput;
- //-----------------------------------------------------------------------------
- //----- ObjectARX EntryPoint
- class CGetLoadedApp : public AcRxArxApp {
- public:
- CGetLoadedApp() : AcRxArxApp() {}
- virtual AcRx::AppRetCode On_kInitAppMsg(void *pkt) {
- AcRx::AppRetCode retCode = AcRxArxApp::On_kInitAppMsg(pkt);
- return (retCode);
- }
- virtual AcRx::AppRetCode On_kUnloadAppMsg(void *pkt) {
- AcRx::AppRetCode retCode = AcRxArxApp::On_kUnloadAppMsg(pkt);
- return (retCode);
- }
- virtual void RegisterServerComponents() { }
- static void RivilisGetLoadedMGD() {
- Document^ doc = Application::DocumentManager->MdiActiveDocument;
- if (doc == nullptr) return;
- Editor^ ed = doc->Editor;
- for each (Assembly^ ass in AppDomain::CurrentDomain->GetAssemblies())
- {
- ed->WriteMessage("\nName = {0}", ass->GetName(false)->Name);
- ed->WriteMessage("\n\tFull Name = {0}", ass->FullName);
- try {
- ed->WriteMessage("\n\tLocation = {0}", ass->Location);
- }
- catch (...) {
- ed->WriteMessage("\n\tNo Location. Possible dynamic assembly");
- };
- }
- }
- };
- //-----------------------------------------------------------------------------
- IMPLEMENT_ARX_ENTRYPOINT(CGetLoadedApp)
- 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++: [Выделить]
- //-----------------------------------------------------------------------------
- //----- acrxEntryPoint.cpp
- //-----------------------------------------------------------------------------
- #include "StdAfx.h"
- #include "resource.h"
- #include <atlsafe.h>
- #import <mscorlib.tlb> rename("ReportEvent","ReportEventManaged")
- #include <metahost.h>
- #pragma comment(lib,"mscoree.lib")
- #include <mscoree.h>
- #include <comdef.h>
- using namespace mscorlib;
- //-----------------------------------------------------------------------------
- //----- ObjectARX EntryPoint
- class CGetMgdFromNativeApp : public AcRxArxApp {
- public:
- CGetMgdFromNativeApp() : AcRxArxApp() {}
- virtual AcRx::AppRetCode On_kInitAppMsg(void *pkt) {
- AcRx::AppRetCode retCode = AcRxArxApp::On_kInitAppMsg(pkt);
- return (retCode);
- }
- virtual AcRx::AppRetCode On_kUnloadAppMsg(void *pkt) {
- AcRx::AppRetCode retCode = AcRxArxApp::On_kUnloadAppMsg(pkt);
- return (retCode);
- }
- virtual void RegisterServerComponents() {
- //----- Self-register COM server upon loading.
- if (FAILED(::DllRegisterServer()))
- acutPrintf(_RXST("Failed to register COM server.\n"));
- }
- static void RivilisGetManagedDlls() {
- CComPtr<ICLRMetaHost> spClrMetaHost;
- // Получаем MetaHost
- HRESULT hr = CLRCreateInstance(
- CLSID_CLRMetaHost,
- IID_PPV_ARGS(&spClrMetaHost)
- );
- _ASSERT(hr == S_OK);
- // Получаем runtime-версию (соответствует .NET 4)
- CComPtr<ICLRRuntimeInfo> spCLRRuntimeInfo;
- hr = spClrMetaHost->GetRuntime(L"v4.0.30319",
- IID_PPV_ARGS(&spCLRRuntimeInfo)
- );
- _ASSERT(hr == S_OK);
- // Получаем CorRuntimeHost
- CComPtr<ICorRuntimeHost> spCorRuntimeHost;
- hr = spCLRRuntimeInfo->GetInterface(
- CLSID_CorRuntimeHost,
- IID_PPV_ARGS(&spCorRuntimeHost)
- );
- _ASSERT(hr == S_OK);
- // Стартуем CLR
- hr = spCorRuntimeHost->Start();
- _ASSERT(hr == S_OK);
- // Получаем домен приложения по-умолчанию
- CComPtr<IUnknown> spAppDomainThunk;
- hr = spCorRuntimeHost->GetDefaultDomain(&spAppDomainThunk);
- _ASSERT(hr == S_OK);
- // Конвертируем AppDomain IUnknown в _AppDomain
- CComPtr<_AppDomain> spAppDomain;
- hr = spAppDomainThunk->QueryInterface(IID_PPV_ARGS(&spAppDomain));
- _ASSERT(hr == S_OK);
- // Получаем массив сборок домена
- SAFEARRAY *pAssemblyArray = spAppDomain->GetAssemblies();
- CComSafeArray<IUnknown*> csaAssemblies;
- csaAssemblies.Attach(pAssemblyArray);
- long cAssemblies = csaAssemblies.GetCount();
- for (long i = 0; i < cAssemblies; i++)
- {
- CComPtr<_Assembly> spAssembly;
- spAssembly = csaAssemblies[i];
- if (spAssembly == NULL)
- continue;
- CComBSTR asmFullName;
- hr = spAssembly->get_FullName(&asmFullName);
- if (FAILED(hr))
- continue;
- AcString asmName = asmFullName;
- int iComma = asmName.find(L',');
- if (iComma > 0) asmName = asmName.left(iComma);
- acutPrintf(L"\n\nName:%s", asmName.constPtr());
- acutPrintf(L"\n\tFull Name:%s", asmFullName);
- CComBSTR asmLocatation;
- hr = spAssembly->get_Location(&asmLocatation);
- if (!FAILED(hr))
- acutPrintf(L"\n\tLocation: %s", asmLocatation);
- else
- acutPrintf(L"\n\tLocation not found");
- }
- // Останавливаем CLR
- hr = spCorRuntimeHost->Stop();
- _ASSERT(hr == S_OK);
- }
- };
- //-----------------------------------------------------------------------------
- IMPLEMENT_ARX_ENTRYPOINT(CGetMgdFromNativeApp)
- ACED_ARXCOMMAND_ENTRY_AUTO(CGetMgdFromNativeApp, Rivilis, GetManagedDlls, GetManagedDlls, ACRX_CMD_MODAL, NULL)
Результат работы команды GetManagedDlls:
Автор: Александр Ривилис
Отредактировано 19.01.2019 в 17:30:31
Обсуждение: http://adn-cis.org/forum/index.php?topic=9036
Опубликовано 19.01.2019Отредактировано 19.01.2019 в 17:30:31