Mathcad EFI плагин - уни - Сообщения
Характеристики интерфейса:
1. Поддерживаемые типы:
- комплексное число (double);
- комплексная матрица (double);
- строка (ASCIIZ);
2. Поддержка исключений (HRESULT) при помощи таблицы сообщений об ошибках.
3. Одна выходная переменная и от 1 до 10 входных переменных.
Особенности:
1. Это дополнение работает только в 32-разрядных Windows (*)! Это связано с тем, что нельзя просто так вызвать 32-разрядный код из 64-разрядной системы.
2. Создаваемая пользовательская библиотека является вещью в себе, т.е. функциям не доступны средства математической системы (SMath Studio, Mathcad). Другими словами, дополнение не предоставляет пользовательской библиотеке доступ к средствам (функциям) математической программы.
3. Код в неуправляемом пространстве Windows работает в разы быстрее, чем его аналог в DotNet.
4. Среда Microsoft Visual Studio поддерживает отладку кода одновременно в управляемом и неуправляемом пространстве, поэтому нет каких-либо ограничений на создание такого рода библиотек (под Windows).
5. Вложенные массивы не поддерживаются (т.к. недокументированы и работают только в Mathcad 11.x).
(*) - для 64-разрядной версии Windows нужно использовать 32-разрядную версию запускаемого файла программы, который можно найти тут.
Примеры пользовательских библиотек, использующих EFI:
1. На C (С++): test
2. На OPascal (Delphi7): NumericalRecipesPascal
3. На ассемблере (RadAsm): test2 (не завершён)
4. На фортране (IVFC XE 12): TestFortran, тема: Плагин на фортране
Примечание: Новый код нужно писать уже в управляемой среде .Net (C#, C++/CLI, VB.Net).
Доброго, уважаемые форумчане.
Начал тут писать плагин для подключения маткадовских библиотек. Писать одновременно на двух языках трудновато.
Давно на С++ не программил, так что ждите плагин не скоро... забыл даже как классы описываются. Короче, отстал от жизни как всегда.
Технология пока видится очень простой. Я создал сборку из двух проектов. Один из них - это mcaduser.dll (C++, Win32API), а второй - непостредственно сам плагин - efi.dll (C#, .Net). В папке дополнений SMath Studio создаётся папка UserEFI и в неё кидаются все маткадовские пользовательские библиотеки, а также сам mcaduser.dll.
В mcaduser.dll я напишу специальный менеджер, который будет работать на две стороны: подключать библиотеки и выдавать информацию о них наверх в SMath. Тут дело тёмное, маршаллинг этот... и ещё говорят стало проще программировать.
Вопрос у меня такой. Может кто в курсе как в C# осуществляется динамический вызов функции из неуправляемой dll? Т.е. без DllImport.
Там одно Решение с двумя проектами. Следующий вопрос, который у меня появился: Как одновременно отлаживать управляемый и неуправляемый код? Это вообще возможно?
Там я выложил рабочий проект для тестирования. Как им пользоваться:
1. Скачиваем, компилируем.
2. Создаём папку UserEFI в plugins\ и кидаем туда mcaduser.dll.
3. В plugins\ кидаем mcadefi.dll
4. Запускаем всё это дело под отладчиком и аттачимся к SMath.
5. В плагине есть одна тестовая функция test(), ставим на неё точку останова и вызываем из программы функцию с один параметром.
Вот тут я и встрял. Как при отладке перейти в неуправляемый код? Раньше такими нехорошими манипуляциями не занимался...
Всё, теперь можно уже приступать к экспериментам.ЦитатаUnder Tools.Options dialog, select the Debugging category, and make sure the "Enable Just My Code" setting is unchecked.
From the Project properties, select the Debug tab, and then ensure that "Enable unmanaged code debugging" is checked.
Once you've got these squared away, you should get the mixed mode debugging support working.
Also, if you use "Debug.Attach To Process" , be sure to hit the "Select..." button in the "Attach To Process" dialog, and select both Managed and Native debugging support.
Ссылки:
1. http://olegtarasov.me/2010/10/smeshivaem-managed-i-native-kod/
2. http://habrahabr.ru/blogs/net/105232/
3. http://habrahabr.ru/blogs/programming/47732/
qehgt, писал 30 сентября 2010, 22:19:
Думаю, что так и надо делать. Только вот будут ли "видеть" такую managed C++ mcaduser.dll пользовательские библиотеки Mathcad?ЦитатаА почему бы не использовать промежуточную библиотеку на Managed C++? Которая брала бы данные в «родном» для С# виде и преобразовывала бы в требуемый для C++ библиотеки.
Теперь mcaduser.dll нужно помещать рядом с mcadefi.dll. Придётся путь к нему прописывать, чтобы библиотеки из папки UserEFI могли увидеть библиотеку.
Этот вариант в сто раз проще будет предыдущего. Не надо никакого маршаллинга. Осталось только всё это написать.
1. Плагин для SMath
2. EFI менеджер
3. Плагин для Mathcad
Сейчас можно одновременно отлаживать все три библиотеки разом. В плагине SMath есть тестовая функция test(), которая выполняет загрузку всех плагинов, которые находятся в папке plugins\userefi (маленькими буквами). На неё нужно ставить точку останова. Далее тестовый маткадовский плагин при загрузке вызывает функцию CreateFunction(). Связка работает, т.е. трио фурычит.
Следующая проблема: как создать динамический массив внутри класса CEFIManger() (mcaduser.dll) из структур TermInfo? Мне уже передаются описания функций из маткадовских библиотек, а вот куда это складывать и в каком формате не понятно. Тут раздел уже managed и unmanaged кода.
Загрузились все функции

Все функции "заглушены". При вызове любой из подключённых функций результатом будет её номер во внутреннем массиве всех подключенных маткадовских функций.
Осталось:
- формирование массива параметров для передачи в функцию с переменным количеством параметров. Сложность в том, что параметры определены в управляемом коде, а функция с переменным количеством параметров в неуправляемом.
- поддержка работы с памятью;
- поддержка регистрации сообщений об ошибках.
typedef LRESULT (* LPCFUNCTION ) ( void * const, const void * const, ... );

Пока реализовал только работу с числовыми параметрами.
И так, поясняю ЧТО это означает для SMath Studio.
Плагин mcadefi.dll + mcaduser.dll (оба должны находится в папке plugins) реализуют возможность подключения маткадовских пользовательских библиотек.
По-другому это можно сказать так: SMath Studio поддерживает работу с плагинами второго уровня, согласно интерфейса UserEFI программы Mathcad.
Правила работы: Тоже самое как с маткадом. Создаём папку userefi (маленькими буквами) в папке plugins и копируем туда маткадовские пользовательские библиотеки. Всё, дальше используем.
Релиз более менее нормальный сделаю позже для простых смертных, а пока предлагаю потестировать тем, кто может собрать бинарики из исходников. Там, кстати, есть и тестовая библиотека.
Как тестировать: Пишем простую dll с несколькими функциями и проверяем её работу в Mathcad, дальше делаем тоже самое с SMath Studio. Вот и всё.
Последние обновления см. в репозитории.
П.С. Да, забыл сказать. Не знаю как сейчас там с .Net'овским паскалем, но потом покажу как на обычном Win32API паскале написать плагин второго уровня для SMath Studio. Чисто для прикола. Дельфисты тоже люди

Мне показалось что TDouble содержит поля для доступа к строке, но вот привести TNumber к TDouble не могу.
Пишу вот так (С++/CLI):
case STRING: {
if ( ( ( TDouble^ ) args[ii] )->isText == false ) throw gcnew Exception( "var[" + ( ii - 1 ) + "] is not a string." );
LPMCSTRING pmcString = ( LPMCSTRING ) ::malloc( sizeof( MCSTRING ) / sizeof( char ) );
pmcString->str = ( char * ) ::Marshal::StringToHGlobalAnsi( ( ( TDouble^ ) args[ii] )->Text ).ToPointer();
buf[ ii + 1 ] = pmcString;
break;
}
Но так ( ( TDouble^ ) args[ii] )->isText делать нельзя. Компилируется, но не приводится по факту. Программа пишет ошибку, что такое сделать не может: "Не могу привести TNumber к TDouble".
Вложенные массивы я реализовывать не буду, т.к. они не документированы в маткаде и я не знаю, кроме себя, людей, кто этим пользовался.
При копировании этих файлов в папку: plugins\userefi\ мы получаем следующую картинку их работы:
К сожалению, динамическое подключение файла mcaduser.dll, которое применяется в некоторых "продвинутых" пользовательских библиотеках, у меня пока не поддерживается. Я не знаю пока почему.
WroteАндрей, такой вопрос. А можно в численном плагине как-то добраться до параметра-строки?
Если c1 - TNumber, то нужно проверить if (c1.obj is TDouble), затем приводить (TDouble)c1.obj, ну а у самого экземпляра TDouble имеются свойства isText и Text.
С уважением, Андрей Ивашов.
P.S.: Извиняюсь, что не участвую. Сейчас совершенно нет времени на разработку - взял небольшой перерыв.
WroteПаскаля в .Net, на сколько я знаю, не существует.
pascalabc
Если не ошибаюсь, то у Embacadore есть свои наработки по .NET
ЧТо-то на параллельном форуме не могут плагин запустить. Файл mcaduser.dll у них не грузится... странно. В mcadefi он указан в References, может быть что-то с путями.
П.С. И ещё такой вопрос. Если имена функций совпадают, то как такая ситуация разруливается? Может каждой регистрирующейся функции присваивать отдельный идентификатор, чтобы коллизий не было?
Если имена функций из нескольких плагинов совпадают, то выигрывает тот, который встретится первым в массиве ссылок на дополнения

Я тут вспомнил, что и у меня появлялась ошибка, когда я клал mcaduser.dll в папку plugins, но потом пропала. Но это было, когда я не поменял ключ компилятора на /clr при сборке проекта.
Между прочим, mcaduser.dll можно расположить и выше папки plugins, т.е. в корне программы. У меня так тоже работает.
-
Новые сообщения
-
Нет новых сообщений