Выполнение кода сразу после загрузки .NET-dll

Иногда бывает необходимо до вызова команд (а еще лучше - прямо после загрузки кода) выполнить некоторые действия: установить системные переменные, установить пути поддержки и т.п.). В лиспе это просто:

1
2
3
4
5
6
(defun test()
  (alert "test")
  )

;; А вот и выполнение
(test)

Это то, что в лиспе часто называют "самовызовом". Выполнение кода начинается сразу после загрузки соответствующего lsp-файла в память.

Механизм достаточно удобный, несмотря на некоторые трудности, описанные здесь и здесь.

С .NET ситуация немного иная.

Для решения этой задачи в .NET-приложении должен быть определен специальный класс. К этому классу предъявляется несколько требований:

  1. Класс такого вида может быть только один внутри всей dll (насколько я понял)
  2. Класс должен быть объявлен как IExtensionApplication
  3. В классе должны присутствовать функции с именами Initialize() и Terminate()/ Уже по именам функций понятно, что они должны делать и в какой момент времени вызываются
  4. Функции Initialize() и Terminate() не могут быть объявлены статическими

Приведу сразу код (один достаточно скользкий момент чуть позже):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Windows.Forms;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;

namespace InitializationTest
{
  public class InitTest : Autodesk.AutoCAD.Runtime.IExtensionApplication
  {
    public void Initialize()
    {
      MessageBox.Show("initialization test", "test", MessageBoxButtons.OK, MessageBoxIcon.Information);
      Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
      ed.WriteMessage("\ninitialization test start...");
    }

    public void Terminate()
    {
      Console.WriteLine("finish!");
    }
  }
}

В общем-то все достаточно просто. Но! Обратите внимание, в функции Terminate() не используется объект Editor.

Объект Editor отсутствует потому, что функция Terminate() вызывается в тот момент, когда AutoCAD уже закрыт (ну или по крайней мере закрывается ;)), и получить доступ к Editor по меньшей мере затруднительно. Скажу честно: я попробовал сразу после Console.WriteLine поставить

Но сообщение не выводилось (подозреваю, что это связано именно с закрытием приложения-владельца, но не уверен).

Зачем может понадобиться вызов Terminate()? Да все просто. Например, гарантированно закрыть все открытые файлы, коннекты к базам данных или Internet и т.д..

Кроме всего прочего, теоретически можно в этом же классе прописывать и пользовательские команды. Но лично у меня при работе в AutoCAD 2008 команды "не находились", несмотря на корректно установленные параметры acdbmdg.dll и acmgd.dll. И опять-таки: этот класс не может содержать статические члены, соответственно dll придется загружать в каждый файл. Не очень приятное (для меня) известие.

Добавлено:
И еще один момент. Пока один. Первая загрузка вызывает Initialize(), что в общем-то ожидаемо. Но вот повторная загрузка (лично у меня) код инициализации не вызвала. Как побороть - пока не знаю.

P.S. За основу взят пост с thought-the-interface

Размещено в .NET · Метки: , ,



Комментарии

Есть 10 коммент. к “Выполнение кода сразу после загрузки .NET-dll”
  1. Андрей пишет:

    >Но вот повторная загрузка (лично у меня) код инициализации не вызвала. Как побороть – пока не знаю.

    А повторная загрузка и не происходит (попытки игнорируются). Поэтому и нет повторного вызова Initialize(). В домен (AppDomain) можно одну и ту же сборку загрузить только один раз. Выгрузить сборку нельзя, вместо этого следует выгружать домен, которых можно создавать в .NET приложениях столько, сколько потребуется. Однако, поскольку в AutoCAD этот момент реализован через задницу, то там все плагины грузятся в один единый домен. Т.е. выгрузка .NET плагинов в AutoCAD невозможна.

  2. Кулик Алексей aka kpblc пишет:

    Это одна из причин, по которым я стараюсь загрузку выполнять через mnl / lsp - по крайней мере они грузятся в каждый dwg :)

  3. Андрей пишет:

    >Это одна из причин, по которым я стараюсь загрузку выполнять через mnl / lsp – по крайней мере они грузятся в каждый dwg :)

    В dwg ничего не грузится. В AutoCAD существует два контекста: контекст приложения и контекст документа. То, что ты назвал "загрузкой в dwg" - это контекст приложения. LISP плагины грузятся в контекст документа. Функции, загруженные в контекст документа, доступны только из этого документа. Код, загруженный в контекст приложения, доступны во всех документах (как уже открытых, так и тех, что будут открыты в данной сессии позднее).

    Плагины .NET грузятся в контекст приложения. Плагины ARX могут быть загружены как в контексте приложения, так и в контексте документа (на усмотрение программиста).

  4. Андрей пишет:

    >То, что ты назвал “загрузкой в dwg” – это контекст приложения.

    Очепятка, хотел написать "- это контекст документа".

  5. Андрей пишет:

    Т.о. нет смысла пытаться грузить .NET библиотеку повторно, даже если бы это и было возможно: код и так будет доступен во всех документах, доступных в рамках текущей сессии AutoCAD. Следовательно твои опасения напрасны. :)

  6. Кулик Алексей aka kpblc пишет:

    >То, что ты назвал “загрузкой в dwg” – это контекст приложения.

    Очепятка, хотел написать “- это контекст документа”.

    Ну да, контекст документа, если использовать терминологию .NET / ObjecARX программирования :)

  7. Кулик Алексей aka kpblc пишет:

    Добавлю: нередко приходится загружать arx-сборки. А это уже касается и контекста документа.

  8. Andrey пишет:

    >Добавлю: нередко приходится загружать arx-сборки. А это уже касается и контекста документа.

    Я же писал, что контекст зависит от программиста, написавшего код:
    >Плагины ARX могут быть загружены как в контексте приложения, так и в контексте документа (на усмотрение программиста).

  9. Кулик Алексей aka kpblc пишет:

    Согласен. Но предсказать такое, мне кажется, достаточно проблематично. Тот же самый dwgconvert от Александра Ривилиса грузится в контекст документа, мне кажется.

  10. Andrey пишет:

    >Но предсказать такое, мне кажется, достаточно проблематично.

    Ну да, это только путём проверки на практике. :) Однако это не означает, что в качестве перестраховки нужно все библиотеки подряд пытаться подгрузить в контекст каждого документа в рамках текущей сессии AutoCAD. Просто по хорошему, контекст загрузки должен быть указан программистом в текстовом описании (обычно это файл readme.txt), поставляемом совместно с библиотекой. В этом случае пользователь, или CAD администратор, сразу поймёт, "достаточно ли одной таблетки".

    Хотя, я не знаю, какое поведение реализовано в Startup Suite для зарегистрированных в нём ARX приложений: возможно он определяет контекст ARX модуля, и исходя из этого либо грузит библиотеку единожды, либо вообще не парится с этим вопросом и грузит в контекст каждого документа. Можно было бы заморочиться с проверкой этого вопроса но, честно говоря, мне это не шибко интересно :)

Поделитесь своим мнением


Я не робот.