Пользовательские функции > Написание C-программ для пользовательских функций
  
Написание C-программ для пользовательских функций
Чтобы помочь вам приступить к написанию пользовательских функций для PTC Mathcad, имеется ряд примеров кода. См. файл MULTIPLY.C, который находится в подпапке Custom Functions\multiply папки установки PTC Mathcad. MULTIPLY.C содержит функцию с двумя аргументами, которая умножает скаляр на массив. Когда вы скомпилируете и правильно скомпонуете ее, новая функция multiply(a, M) станет доступной после перезапуска PTC Mathcad.
Подробное описание кода в MULTIPLY.C следует далее. Чтобы увидеть код полностью, откройте файл в Visual Studio или любом текстовом редакторе.
Заголовки
#include "mcadincl.h"
Ваша программа C должна включать файл заголовков mcadincl.h, находящийся в подпапке Custom Functions папки установки PTC Mathcad. Этот файл содержит структуры данных, которые позволяют выполнять следующие действия.
Определять функции, которые может читать PTC Mathcad.
Выделять и освобождать скаляры и массивы совместимым с PTC Mathcad способом.
Создавать сообщения об ошибках, которые могут быть возвращены в PTC Mathcad с помощью графического пользовательского интерфейса.
Сообщения об ошибках
Как правило, следующая часть программы определяет коды ошибок для типов ошибок, возникновения которых можно ожидать. Обеспечьте перехват ошибок для несоответствующих типов данных, поскольку это один из наиболее часто встречающихся случаев неправильного применения функций PTC Mathcad. Они определяются совместно, поэтому легко подсчитать общее количество ошибок. Общая сумма требуется функцией CreateUserErrorMessageTable.
#define INTERRUPTED 1
#define INSUFFICIENT_MEMORY 2
#define MUST_BE_REAL 3
#define NUMBER_OF_ERRORS 3
// table of error messages
// if your function never returns an error -- you do not need to create this table
char * myErrorMessageTable[NUMBER_OF_ERRORS] =
{
"interrupted",.
"insufficient memory",
"must be real"
};
PTC Mathcad перехватывает следующие исключения в операциях с плавающей запятой: переполнение, деление на нуль и недопустимая операция. В случае этих исключений PTC Mathcad отображает сообщение об ошибке операции с плавающей запятой под функцией. Когда возникает одна из таких ошибок, PTC Mathcad также освобождает всю выделенную память.
Алгоритм
Далее следует код, который выполняет ваш алгоритм. Если вы преобразуете код из существующей библиотеки, необходимо привести его к типам COMPLEXARRAY, COMPLEXSCALAR и MCSTRING, передаваемым и ожидаемым PTC Mathcad.
Первый аргумент в алгоритме является указателем на возвращаемое значение, в данном случае Product. Остальные аргументы являются указателями на входные значения, поступающие из PTC Mathcad.
// this code executes the multiplication
LRESULT MultiplyRealArrayByRealScalar( COMPLEXARRAY * const Product,
LPCCOMPLEXSCALAR Scalar, LPCCOMPLEXARRAY Array )
{
unsigned int row, col;
// check that the scalar argument is real
if ( Scalar->imag != 0.0)
// if it is not, display "must be real" error message
// under the scalar argument ( the 1st argument )
return MAKELRESULT( MUST_BE_REAL, 1)

// check that the array argument is real
if ( Array->hImag != NULL )
// if it is not, display "must be real" error message
// under the array argument ( the 2nd argument )
return MAKELRESULT( MUST_BE_REAL, 2);
// allocate memory for the product
if( !MathcadArrayAllocate( Product, Array-rows,Array-cols,
TRUE, // allocate memory for the real part
FALSE )) // do not allocate memory for the imaginary part

// if allocation is not successful, return with the appropriate error code
return INSUFFICIENT_MEMORY;
// if all is well so far -- go ahead and perform the multiplication
for ( col = 0; col < Product-> cols; col++ )
{
// check that a user has not tried to interrupt the calculation
if (isUserInterrupted())
{
// if user has interrupted -- free the allocated memory
MathcadArrayFree( Product );
// and return with an appropriate error code
return INTERRUPTED;
}
for ( row = 0; row < Product-> rows; row++ )
Product->hReal[col][row] =
Scalar-> real*Array-> hReal[col][row];
}

// normal return
return 0;
}
Регистрация функции в PTC Mathcad
Заполните структуру FUNCTIONINFO информацией, необходимой для регистрации функции в PTC Mathcad. Эта структура определяет имя функции в PTC Mathcad, а не имя алгоритма MultiplyRealArrayByRealScalar. Кроме того, она определяет параметры и описание, а также указатель на используемый алгоритм.
FUNCTIONINFO multiply =
{
// name by which Mathcad will recognize the function
"multiply",

// description of "multiply" parameters to be used
"a,M",

// description of the function
"returns the product of real scalar a and real array M",

// pointer to the executable code
// i.e. code that should be executed when a user types "multiply(a,M)="
(LPCFUNCTION)MultiplyRealArrayByRealScalar;

// multiply(a, M) returns a complex array
COMPLEX_ARRAY,
// multiply takes on two arguments
2,
// the first is a complex scalar, the second a complex array
{ COMPLEX_SCALAR, COMPLEX_ARRAY}
};
Выполните динамическую компоновку библиотеки
DLL обозначает библиотеку динамической компоновки. Следующий код делает эту библиотеку доступной для других функций Windows, в частности PTC Mathcad, через DLL-интерфейс Windows. Необходимо также указать ссылку на точку входа через программную среду. Когда DLL загружается, точка входа DLL вызывается операционной системой. PTC Mathcad требует, чтобы вы регистрировали свои пользовательские функции и свою таблицу сообщений об ошибках во время загрузки DLL.
// DLL entry point code
// the _CRT_INIT function is needed if you are using Microsoft's 32-bit compiler

BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved);
BOOL WINAPI DllEntryPoint (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{    
case DLL_PROCESS_ATTACH:
// DLL is attaching to the address space of the current process
if (!_CRT_INIT(hDLL, dwReason, lpReserved))
return FALSE;
Регистрация таблицы сообщений об ошибках и функции
Если ваша функция никогда не возвращает ошибку, таблица сообщений об ошибках не требуется. Можно зарегистрировать только одну таблицу сообщений об ошибках на DLL, но можно зарегистрировать несколько функций на DLL. Необходимо также очистить любые остающиеся процессы или определения.
if ( CreateUserErrorMessageTable( hDLL, NUMBER_OF_ERRORS, myErrorMessageTable ) )
// and if the errors register properly, register the user function
CreateUserFunction( hDLL, &multiply );
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
if (!_CRT_INIT(hDLL, dwReason, lpReserved))
return FALSE;
break;
}
return TRUE;
}
#undef INTERRUPTED
#undef INSUFFICIENT_MEMORY
#undef MUST_BE_REAL
#undef NUMBER_OF_ERRORS
Дополнительная информация
Все значения, передаваемые в и из PTC Mathcad, являются комплексными, имеющими и действительную, и мнимую части в своей структуре (см. mcadincl.h). Необходимо разделить действительную и мнимую части, если вы намереваетесь обрабатывать их независимо.
Массивы индексируются сначала по столбцу, а затем по строке в отличие от порядка индексов в PTC Mathcad (сначала по строке, затем по столбцу).
Все массивы предполагаются двумерными. Если нужно сослаться на вектор, задайте для первого индекса массива (столбец) значение 0.