cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - New to the community? Learn how to post a question and get help from PTC and industry experts! X

C++ custom function

DM_10631844
6-Contributor

C++ custom function

 

11223344

 

 

1 ACCEPTED SOLUTION

Accepted Solutions

Hi,

Function to create a vector of given length made up of square of the number in DLL file "fc.dll".   DLL file is in the zip file enclosed. Put the DLL file in CustomFunctions folder of Prime installation directory.  Changing "fc.c" to create a square matrix with values on the diagonal is trivial so not done.

 

Capture.JPG

 

 

// fc.c : Defines the entry point for the DLL application.


#include "MCADINCL.H"
#include <math.h>

#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"
};


// this code executes the multiplication
// see the information of MathcadUserFunction
// to find out more
LRESULT  ExpandRealScalar(COMPLEXARRAY* const Product,
    LPCCOMPLEXSCALAR Scalar)
{
    unsigned int row, col;

    // check that the scalar argument is real
    if ((Scalar->imag != 0.0) || (Scalar->real < 1.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


    // allocate memory for the product
    if (!MathcadArrayAllocate(Product, floor(Scalar->real), 1,
        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 * Scalar->real;
    }
        // normal return
        return 0;
   }

    // fill out a FUNCTIONINFO structure with
    // the information needed for registering the
    // function with Mathcad
    FUNCTIONINFO fc =
    {
        // Name by which mathcad will recognize the function
        "fc",

        // description of "multiply" parameters to be used
        // by the Insert Function dialog box
        "a",

        // description of the function for the Insert Function dialog box       
        "returns the expansion of real scalar a",

        // pointer to the executible code
        // i.e. code that should be executed
        // when a user types in "fc(a)="
        (LPCFUNCTION)ExpandRealScalar,

        // multiply(a,M) returns a complex array
        COMPLEX_ARRAY,

        //fc(a) takes on one arguments
        1,

        // the first is a complex scalar
        { COMPLEX_SCALAR}
    };



    BOOL APIENTRY DllMain(HMODULE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
    )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
            //
                   // DLL is attaching to the address space of 
                   // the current process.
                   //

            // register the error message table
            // Note, that if your function never returns
            // an error -- you do not need to 
            // register an error message table
            if (CreateUserErrorMessageTable(
                hModule, NUMBER_OF_ERRORS, myErrorMessageTable))
                // and if the errors register OK
                // go ahead and
                // register user function
                CreateUserFunction(hModule, &fc);
            break;



        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }

#undef INTERRUPTED    
#undef INSUFFICIENT_MEMORY
#undef MUST_BE_REAL   
#undef NUMBER_OF_ERRORS

 

Cheers

Terry 

View solution in original post

7 REPLIES 7

Hi,

Function to create a vector of given length made up of square of the number in DLL file "fc.dll".   DLL file is in the zip file enclosed. Put the DLL file in CustomFunctions folder of Prime installation directory.  Changing "fc.c" to create a square matrix with values on the diagonal is trivial so not done.

 

Capture.JPG

 

 

// fc.c : Defines the entry point for the DLL application.


#include "MCADINCL.H"
#include <math.h>

#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"
};


// this code executes the multiplication
// see the information of MathcadUserFunction
// to find out more
LRESULT  ExpandRealScalar(COMPLEXARRAY* const Product,
    LPCCOMPLEXSCALAR Scalar)
{
    unsigned int row, col;

    // check that the scalar argument is real
    if ((Scalar->imag != 0.0) || (Scalar->real < 1.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


    // allocate memory for the product
    if (!MathcadArrayAllocate(Product, floor(Scalar->real), 1,
        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 * Scalar->real;
    }
        // normal return
        return 0;
   }

    // fill out a FUNCTIONINFO structure with
    // the information needed for registering the
    // function with Mathcad
    FUNCTIONINFO fc =
    {
        // Name by which mathcad will recognize the function
        "fc",

        // description of "multiply" parameters to be used
        // by the Insert Function dialog box
        "a",

        // description of the function for the Insert Function dialog box       
        "returns the expansion of real scalar a",

        // pointer to the executible code
        // i.e. code that should be executed
        // when a user types in "fc(a)="
        (LPCFUNCTION)ExpandRealScalar,

        // multiply(a,M) returns a complex array
        COMPLEX_ARRAY,

        //fc(a) takes on one arguments
        1,

        // the first is a complex scalar
        { COMPLEX_SCALAR}
    };



    BOOL APIENTRY DllMain(HMODULE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
    )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
            //
                   // DLL is attaching to the address space of 
                   // the current process.
                   //

            // register the error message table
            // Note, that if your function never returns
            // an error -- you do not need to 
            // register an error message table
            if (CreateUserErrorMessageTable(
                hModule, NUMBER_OF_ERRORS, myErrorMessageTable))
                // and if the errors register OK
                // go ahead and
                // register user function
                CreateUserFunction(hModule, &fc);
            break;



        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }

#undef INTERRUPTED    
#undef INSUFFICIENT_MEMORY
#undef MUST_BE_REAL   
#undef NUMBER_OF_ERRORS

 

Cheers

Terry 

Hello @DM_10631844,

 

It looks like you have a response from a community member. If it helped you solve your question please mark the reply as the Accepted Solution. 

Of course, if you have more to share on your issue, please let the Community know so other community members can continue to help you.

Thanks,
Vivek N.
Community Moderation Team.

Perfect thank you I have a question @terryhendicott you did it by command promp or by the visual studio program, I comment that I still do not understand how it would be to try to compile it by the visual studio program, by command it works well but I think that by program I do not add well the references etc if or I start from 0 can you indicate how it would be without the command promp thank you greetings

I compile by Borland C++ Builder 12 - paid for or Visual Studio Community 2022 - free.  Both use an IDE to make compilation easier.  I have used these so much have forgotten how to use the command line.  Using  a "*c" file forces c compilation not c++.

 

Four things to set are:

1)    Directory for include of  C:\Program Files\PTC\Mathcad Prime 10.0.0.0\Custom Functions

2)    #include "MCADINCL.H" in the source file *.c for the dll

3)    Directory for library C:\Program Files\PTC\Mathcad Prime 10.0.0.0\Custom Functions

4)    Inclusiion of the library mcaduser.lib

5)    I turn off wide character strings (optional)

 

1,3,4,5 are set by options in Project Properties in the IDE (Integrated Development Environment)

2 is in the source file.

 

Cheers

Terry

 

 

This is a project that I have but I would like to compile it in visual studio because with commands if I understand there are some of the steps you mention that have not worked for me
@terryhendicott

DM_10631844_0-1721703819495.pngDM_10631844_1-1721703827454.png

 

Hi,

Prime is a 64 bit program so needs 64 bit DLL's

Capture.JPG

Need to compile as c code so highlight file in solution explorer and right click and select rename file option

Capture4.jpg

 

Get rid of precompiled headers

Capture3.JPG

 

You need to explicitly call up the library to use it

Capture2.JPG

I also set the include and library directories to the original location of the header and library files.  It is the same directory.  I see you copied them into the solution directory. so no real need to set the directories

 

Cheers

Terry

Hi,

You change the properties like precompiled headers from the properties dialog launched like this:

Capture5.JPG

Top Tags