Funciones personalizadas > Escritura de programas C para funciones personalizadas
Escritura de programas C para funciones personalizadas
Para comenzar a escribir funciones personalizadas para Engineering Notebook, 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 Engineering Notebook. 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 Engineering Notebook.
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 Engineering Notebook. Este fichero contiene las estructuras de datos que permiten realizar las siguientes acciones:
Defina funciones que Engineering Notebook pueda leer.
Asigne y libere escalares y arrays de manera compatible con Engineering Notebook.
Cree mensajes de error que puedan devolverse a Engineering Notebook 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 Engineering Notebook. 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"
};
Engineering Notebook detecta las siguientes excepciones de coma flotante: sobrecarga, división por cero y operación no válida. En el caso de estas excepciones, Engineering Notebook muestra un mensaje de error de coma flotante debajo de la función. Asimismo, Engineering Notebook 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 Engineering Notebook.
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 Engineering Notebook.
// 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 Engineering Notebook
Rellene una estructura FUNCTIONINFO con la información necesaria para registrar la función en Engineering Notebook. Esta estructura define el nombre de la función en Engineering Notebook 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, Engineering Notebook, 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. Engineering Notebook 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 Engineering Notebook 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 Engineering Notebook (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.
Fue esto útil?