为自定义函数编写 C 程序
要开始为 PTC Mathcad 写入自定义函数,已包含了若干个代码样本。请参阅位于 PTC Mathcad 安装目录的 Custom Functions/multiply 子目录下的文件 MULTIPLY.C。MULTIPLY.C 包含一个将标量乘以数组的双自变量函数。在编译并正确链接它时,重新启动 PTC Mathcad,新函数 multiply(a, M) 变得可用。
MULTIPLY.C 中代码的详细说明如下:要查看其全部代码,请在 Visual Studio 或任一文本编辑器中打开该文件。
头部
#include "mcadincl.h"
C 程序必须包含 mcadincl.h 头文件,其位于 PTC Mathcad 安装目录的 Custom Functions 子目录下。该文件中包含的数据结构允许您执行以下操作:
• 定义 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 也将释放分配的所有内存。
算法
下面是执行算法的代码。如果正在从现有库转换代码,则必须使用由 PTC Mathcad 传递并预期的 COMPLEXARRAY、COMPLEXSCALAR 和 MCSTRING 类型重写它。
算法的第一个自变量是指向返回值的指针,在这种情况下,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 DLL 界面使该库对其他 Windows 函数可用,尤其 PTC Mathcad。您还必须通过编程环境指定对入口点的引用。在加载 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。