Mathcad EFI плагин

Mathcad EFI плагин - уни - Сообщения

#1 Опубликовано: 19.11.2010 13:50:59
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Назначение: Подключение старого (неуправляемого) рабочего численного кода (C, C++, Pascal, Fortran 95/2003) к SMath Studio через интерфейс Mathcad User 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.
Россия навсегда! Вячеслав Мезенцев
2 пользователям понравился этот пост
densy 25.07.2020 17:33:00, Serg 25.01.2014 13:15:00
#2 Опубликовано: 19.11.2010 15:05:33
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Пока вставил относительный путь. Залил шаблон проекта в svn. Кто что-нить понимает в этом тёмном деле может глянуть в репозиторий и предложить идеи.

Там одно Решение с двумя проектами. Следующий вопрос, который у меня появился: Как одновременно отлаживать управляемый и неуправляемый код? Это вообще возможно?

Там я выложил рабочий проект для тестирования. Как им пользоваться:
1. Скачиваем, компилируем.
2. Создаём папку UserEFI в plugins\ и кидаем туда mcaduser.dll.
3. В plugins\ кидаем mcadefi.dll
4. Запускаем всё это дело под отладчиком и аттачимся к SMath.
5. В плагине есть одна тестовая функция test(), ставим на неё точку останова и вызываем из программы функцию с один параметром.

Вот тут я и встрял. Как при отладке перейти в неуправляемый код? Раньше такими нехорошими манипуляциями не занимался...
Россия навсегда! Вячеслав Мезенцев
#3 Опубликовано: 19.11.2010 15:37:16
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Ответ на последний мой вопрос:
Цитата

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++? Которая брала бы данные в «родном» для С# виде и преобразовывала бы в требуемый для C++ библиотеки.

Думаю, что так и надо делать. Только вот будут ли "видеть" такую managed C++ mcaduser.dll пользовательские библиотеки Mathcad?
Россия навсегда! Вячеслав Мезенцев
#4 Опубликовано: 20.11.2010 04:40:09
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Изменил тестовый проект. Теперь библиотека посредник (mcaduser.dll) пишется на managed C++. Одновременно она экспортирует native С функции для пользовательских библиотек маткада, которые являются обёртками для статических методов класса посредника (управляемого и доступного из плагина mcadefi.dll).

Теперь mcaduser.dll нужно помещать рядом с mcadefi.dll. Придётся путь к нему прописывать, чтобы библиотеки из папки UserEFI могли увидеть библиотеку.

Этот вариант в сто раз проще будет предыдущего. Не надо никакого маршаллинга. Осталось только всё это написать.
Россия навсегда! Вячеслав Мезенцев
#5 Опубликовано: 20.11.2010 10:37:19
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

И так, мои познания истощаются. Добавил тестовую маткадовскую библиотеку в проект. Теперь у нас в проекте одновременно три библиотеки:
1. Плагин для SMath
2. EFI менеджер
3. Плагин для Mathcad

Сейчас можно одновременно отлаживать все три библиотеки разом. В плагине SMath есть тестовая функция test(), которая выполняет загрузку всех плагинов, которые находятся в папке plugins\userefi (маленькими буквами). На неё нужно ставить точку останова. Далее тестовый маткадовский плагин при загрузке вызывает функцию CreateFunction(). Связка работает, т.е. трио фурычит.

Следующая проблема: как создать динамический массив внутри класса CEFIManger() (mcaduser.dll) из структур TermInfo? Мне уже передаются описания функций из маткадовских библиотек, а вот куда это складывать и в каком формате не понятно. Тут раздел уже managed и unmanaged кода.
Россия навсегда! Вячеслав Мезенцев
#6 Опубликовано: 20.11.2010 16:04:46
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Сделал 4-ю часть работы. Вот пример кидания в папку plugins\userefi\ файла wspmcad.dll (170 Кб) - это набор из более чем 100 функций пакета WaterSteamPro 6.5.0.58 (05 апреля 2010):

Загрузились все функции Всё очень просто. Осталось немного... заставить их работать.
Россия навсегда! Вячеслав Мезенцев
1 пользователям понравился этот пост
densy 25.07.2020 17:34:00
#7 Опубликовано: 20.11.2010 17:59:56
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Ревизия 38. Поддерживается загрузка имён функций из Mathcad-библиотек.
Все функции "заглушены". При вызове любой из подключённых функций результатом будет её номер во внутреннем массиве всех подключенных маткадовских функций.

Осталось:
- формирование массива параметров для передачи в функцию с переменным количеством параметров. Сложность в том, что параметры определены в управляемом коде, а функция с переменным количеством параметров в неуправляемом.
- поддержка работы с памятью;
- поддержка регистрации сообщений об ошибках.
Россия навсегда! Вячеслав Мезенцев
#8 Опубликовано: 21.11.2010 03:22:40
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Вопрос для спецов по приплюснутому си: как автоматически передать параметры в функцию с переменным количеством параметров, если количество параметров известно только в runtime?
typedef LRESULT (* LPCFUNCTION ) ( void * const, const void * const, ... );
Это маткадовская плагинная функция. Вот её нужно вызвать, но количество параметров известно только в runtime.
Россия навсегда! Вячеслав Мезенцев
#9 Опубликовано: 21.11.2010 15:03:36
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Ну что? Есть желающие потестить, а
Пока реализовал только работу с числовыми параметрами.

И так, поясняю ЧТО это означает для SMath Studio.

Плагин mcadefi.dll + mcaduser.dll (оба должны находится в папке plugins) реализуют возможность подключения маткадовских пользовательских библиотек.
По-другому это можно сказать так: SMath Studio поддерживает работу с плагинами второго уровня, согласно интерфейса UserEFI программы Mathcad.

Правила работы: Тоже самое как с маткадом. Создаём папку userefi (маленькими буквами) в папке plugins и копируем туда маткадовские пользовательские библиотеки. Всё, дальше используем.

Релиз более менее нормальный сделаю позже для простых смертных, а пока предлагаю потестировать тем, кто может собрать бинарики из исходников. Там, кстати, есть и тестовая библиотека.

Как тестировать: Пишем простую dll с несколькими функциями и проверяем её работу в Mathcad, дальше делаем тоже самое с SMath Studio. Вот и всё.

Последние обновления см. в репозитории.


П.С. Да, забыл сказать. Не знаю как сейчас там с .Net'овским паскалем, но потом покажу как на обычном Win32API паскале написать плагин второго уровня для SMath Studio. Чисто для прикола. Дельфисты тоже люди
Россия навсегда! Вячеслав Мезенцев
2 пользователям понравился этот пост
Mikka 22.11.2010 04:53:00, Andrey Ivashov 22.11.2010 21:17:00
#10 Опубликовано: 22.11.2010 09:18:27
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Андрей, такой вопрос. А можно в численном плагине как-то добраться до параметра-строки?
Мне показалось что 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".
Россия навсегда! Вячеслав Мезенцев
#11 Опубликовано: 22.11.2010 15:36:13
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Ревизия 41. Добавил поддержку матриц. Это уже практически полноценная работа с маткадовскими пользовательскими библиотеками. Ещё есть несколько важных моментов: регистрация сообщений об ошибках и работа со строками.
Вложенные массивы я реализовывать не буду, т.к. они не документированы в маткаде и я не знаю, кроме себя, людей, кто этим пользовался.
Россия навсегда! Вячеслав Мезенцев
#12 Опубликовано: 22.11.2010 16:58:10
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Ещё пример. С маткадом стандартно идут две пользовательские библиотеки с исходниками. Это два файла: KRONECKR.DLL и DIGAMMA.DLL.
При копировании этих файлов в папку: plugins\userefi\ мы получаем следующую картинку их работы:

К сожалению, динамическое подключение файла mcaduser.dll, которое применяется в некоторых "продвинутых" пользовательских библиотеках, у меня пока не поддерживается. Я не знаю пока почему.
Россия навсегда! Вячеслав Мезенцев
#13 Опубликовано: 22.11.2010 18:02:13
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Можете потестировать: mcadefi.7z
Россия навсегда! Вячеслав Мезенцев
4 пользователям понравился этот пост
densy 25.07.2020 17:38:00, Mikka 23.11.2010 02:43:00, build_your_web 22.11.2010 18:13:00, Andrey Ivashov 22.11.2010 21:17:00
#14 Опубликовано: 22.11.2010 18:12:49
build_your_web

build_your_web

4 сообщений из 127 понравились пользователям.

Группа: User

Паскаля в .Net, на сколько я знаю, не существует.
#15 Опубликовано: 22.11.2010 21:16:00
Andrey Ivashov

Andrey Ivashov

2269 сообщений из 3734 понравились пользователям.

Группа: Super Administrator

Ничего себе! Вот это работа! Здорово и спасибо!

Wrote

Андрей, такой вопрос. А можно в численном плагине как-то добраться до параметра-строки?


Если c1 - TNumber, то нужно проверить if (c1.obj is TDouble), затем приводить (TDouble)c1.obj, ну а у самого экземпляра TDouble имеются свойства isText и Text.

С уважением, Андрей Ивашов.

P.S.: Извиняюсь, что не участвую. Сейчас совершенно нет времени на разработку - взял небольшой перерыв.
#16 Опубликовано: 23.11.2010 03:59:30
Samar

Samar

2 сообщений из 107 понравились пользователям.

Группа: User

Wrote

Паскаля в .Net, на сколько я знаю, не существует.



pascalabc

Если не ошибаюсь, то у Embacadore есть свои наработки по .NET
www.math.by
1 пользователям понравился этот пост
уни 23.11.2010 08:04:00
#17 Опубликовано: 23.11.2010 08:05:33
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Обалдеть, наши уже сами среды пишут и компиляторы. Может быть даже можно попробовать плагинчик написать в этой среде. Вдруг получится.

ЧТо-то на параллельном форуме не могут плагин запустить. Файл mcaduser.dll у них не грузится... странно. В mcadefi он указан в References, может быть что-то с путями.

П.С. И ещё такой вопрос. Если имена функций совпадают, то как такая ситуация разруливается? Может каждой регистрирующейся функции присваивать отдельный идентификатор, чтобы коллизий не было?
Россия навсегда! Вячеслав Мезенцев
#18 Опубликовано: 23.11.2010 09:08:02
Andrey Ivashov

Andrey Ivashov

2269 сообщений из 3734 понравились пользователям.

Группа: Super Administrator

Я вчера пытался запустить на MS Vista - тоже не подгрузился плагин (программа ругалась на оба файла, положенных в корень папки plugins). Я подумал, что проблема наверное в том, что система 64-битная. Сегодня попробовал на обычной WinXP SP2 - тоже самое.

Если имена функций из нескольких плагинов совпадают, то выигрывает тот, который встретится первым в массиве ссылок на дополнения Думаю стоит добавить в менеджере дополнений возможность менять порядок загруженных библиотек вручную.
#19 Опубликовано: 23.11.2010 09:40:59
zhuk

zhuk

13 сообщений из 120 понравились пользователям.

Группа: User

под виндой (winxp sp3 x86) плагин запустился с полпинка. под моно же ничего работать не хочет
неофициальный справочник https://sites.google.com/site/mikkhalichlab/home jabber конференция smath@conference.jabber.ru
#20 Опубликовано: 23.11.2010 10:28:42
уни

уни

156 сообщений из 355 понравились пользователям.

Группа: User

Причину искать долго придётся, т.к. скорее всего это что-то связанное с настройками проекта. Код там сам по себе очень простой и с чем связаны эти ошибки трудно сказать.
Я тут вспомнил, что и у меня появлялась ошибка, когда я клал mcaduser.dll в папку plugins, но потом пропала. Но это было, когда я не поменял ключ компилятора на /clr при сборке проекта.

Между прочим, mcaduser.dll можно расположить и выше папки plugins, т.е. в корне программы. У меня так тоже работает.
Россия навсегда! Вячеслав Мезенцев
  • Новые сообщения Новые сообщения
  • Нет новых сообщений Нет новых сообщений