Escritura de programas C para funciones personalizadas
Para comenzar a escribir funciones personalizadas para PTC Mathcad, se incluyen varias muestras de código. Consulte el fichero MULTIPLY.C que se encuentra en el subdirectorio Custom Functions\multiply del directorio de instalación de PTC Mathcad. MULTIPLY.C contiene una función de dos argumentos que multiplica un escalar por un array. Si se compila y enlazar correctamente, la nueva función multiply(a, M) estará disponible al reiniciar PTC Mathcad.
A continuación, se ofrece una descripción detallada del código de MULTIPLY.C. Para ver el código en su totalidad, abra el fichero en Visual Studio o en cualquier editor de texto.
Encabezados
#include "mcadincl.h"
El programa C debe incluir el fichero de encabezado mcadincl.h, que se encuentra en el subdirectorio Custom Functions del directorio de instalación de PTC Mathcad. Este fichero contiene las estructuras de datos que permiten realizar las siguientes acciones:
• Defina funciones que PTC Mathcad pueda leer.
• Asigne y libere escalares y arrays de manera compatible con PTC Mathcad.
• Cree mensajes de error que puedan devolverse a PTC Mathcad mediante una interfaz gráfica de usuario.
Mensajes de error
Por lo general, la siguiente parte del programa define códigos de error para los tipos de errores que el usuario puede experimentar. Asegúrese de detectar los errores de tipos de datos inadecuados, ya que estos se encuentran entre los usos indebidos más comunes de las funciones de PTC Mathcad. Estos se definen en conjunto, por lo que resulta sencillo contar el número total de errores. Este total es necesario para la función 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 detecta las siguientes excepciones de coma flotante: sobrecarga, división por cero y operación no válida. En el caso de estas excepciones, PTC Mathcad muestra un mensaje de error de coma flotante debajo de la función. Asimismo, PTC Mathcad libera toda la memoria asignada cuando se produce uno de estos errores.
Algoritmo
A continuación, se incluye el código que ejecuta el algoritmo. Si se está convirtiendo código de una biblioteca existente, debe reformularse con los tipos COMPLEXARRAY, COMPLEXSCALAR y MCSTRING transferidos y previstos por PTC Mathcad.
El primer argumento para el algoritmo es un puntero al valor de retorno, en este caso, Product. Los argumentos restantes son punteros a los valores de entrada procedentes de 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; }
Registre la función en PTC Mathcad
Rellene una estructura FUNCTIONINFO con la información necesaria para registrar la función en PTC Mathcad. Esta estructura define el nombre de la función en PTC Mathcad y no el nombre el algoritmo MultiplyRealArrayByRealScalar. También define los parámetros y proporciona una descripción, además de un puntero al algoritmo utilizado.
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} };
Enlace dinámico de la biblioteca
DLL son las siglas en inglés de "biblioteca de vínculos dinámicos". El código siguiente permite que la biblioteca esté disponible para otras funciones de Windows, en especial, PTC Mathcad, a través de la interfaz DLL de Windows. También se debe especificar una referencia al punto de entrada a través del entorno de programación. El sistema operativo llama al punto de entrada de DLL cuando se carga la DLL. PTC Mathcad requiere que se registren las funciones personalizadas y la tabla de mensajes de error durante la carga de la 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;
Registro de la tabla de mensajes de error y la función
Si la función nunca devuelve un error, no se requiere ninguna tabla de mensajes de error. Solo se puede registrar una sola tabla de mensajes de error por DLL, pero se puede registrar más de una función por DLL. Los procesos o definiciones restantes deben repararse.
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
Información adicional
• Todos los valores transferidos a y de PTC Mathcad son complejos, e incluyen una parte real y otra imaginaria en su estructura (véase mcadincl.h). Es necesario dividir las partes real e imaginaria si se prevé manipularlas de manera independiente.
• Los arrays se indexan por columna y, a continuación, por fila, en lugar de seguir el orden de los índices de PTC Mathcad (por fila y, a continuación, por columna).
• Se supone que todos los arrays tienen dos dimensiones. Si desea hacer referencia a un vector, defina índice de la primera matriz (columna) en 0.