Просто я тоже думал для одной программы плагин на .NET сделать. Правда ещё не начинал, так что про корректность идеи ничего сказать не могу, но саму идею всё же расскажу.
- Пишем одну dll, в ней делаем экспортируемые функции так, как того ожидает вызывающая программа.
- Объявляем где-то (думаю про эту же библиотеку, но если это вызывает проблемы, то можно положить отдельно) .NET'овский интерфейс плагина.
- Плагины сами по себе делаются в отдельных dll, причём имеют ссылку на библиотеку с интерфейсом. Они предоставляют публичный класс, реализующий данный интерфейс. Пусть файл одного из таких плагинов называется SomePlugin.dll.
- Для вызывающей программы кладём понятный для неё файл оболочки с именем SomePlugin.wrapper.dll. Он будет выполнять роль переходника между программой и .net-плагином в файле SomePlugin.dll.
При этом сама оболочка выполняет следующие действия:
- При инициализации узнаёт своё имя файла SomePlugin.wrapper.dll.
- При помощи рефлексии подгружает соседний файл SomePlugin.dll (для получения его имени выкидывается лишний кусок собственного).
- При помощи рефлексии создаёт инстанс класса плагина и приводит его к интерфейсу.
- Вызовы экспортируемых функций прокидываются классу через соответствующие методы интерфейса. Аналогично в обратную сторону прокидываются возвращаемые значения.
- По необходимости можно реализовать вызовы методов программы аналогичным способом. Например, передать некий объект в конструктор плагина.
При таком подходе должен получиться один переходник, который не нужно перекомпилировать - нужно просто переименовывать его в соответствии с именем плагина и класть рядом. Хотя есть небольшой минус в том, что будет лежать охапка одинаковых файлов под разными именами и в случае изменения переходника это всё придётся апдейтить. С другой стороны, тут несколько иная цель - минимизировать затраты на разработку и изменение плагина, а не переходника (потому что ручная декомпиляция, изменение и повторная компиляция - это не то, что бы хотелось делать много раз, особенно во время разработки плагина, когда он перекомпилируется чуть ли не каждые 5 минут. Ну и из плюсов - можно создать дополнительную версию переходника с логированием отладочной информации (а может даже с выводом на форму, чтобы в реалтайме видеть, как идёт взаимодействие программы с плагином).
Да, интерфейс нужен чтобы по минимуму использовать рефлексию - она всё-таки достаточно затратна и не хотелось бы просто так уменьшать производительность. Изначальная мысль, что интерфейс находится в библиотеке обёртки, на которую ссылается плагин (как на бинарный файл, имя сразу в соответствии с именем плагина), но есть сомнения в отсутствии принципиальных косяков при таком подходе. Вполне возможно, что понадобится третий файл, содержащий интерфейс, на который будут ссылаться и вреппер, и плагин. В таком случае, этот файл окажется общим для всех плагинов (иначе придётся перекомпилировать вреппер под плагин, чего хочется избежать).
Класс для вызова методов приложения (если он существует) кладётся туда же, куда интерфейс плагина.
PS: Очень хотелось бы услышать комментарии по поводу этой идеи, а то она существует уже давно, но только на уровне идеи - никак не доберусь до её реализации... Вдруг есть какие-то принципиальные моменты, оставшиеся незамеченными.