Interfacing with matlab dlls from Delphi

I am trying to use functions written in Matlab from Delphi. The test function is very simple, it just adds one to an input variable as follows:

function [Output] = AddOne(Input)
Output=Input+1;

I've managed to compile it ok and access the dll from delphi, but I get an access violation at the line where I try to use the function.

l define the function in Delphi as follows:

In the interface:

function MatlabFunc(NRetValues: Integer;var Output: Variant;var Input: Variant): Variant; cdecl;

In the implementation:

function MatlabFunc(NRetValues: Integer;var Output: Variant;var Input: Variant): Variant; cdecl; external 'AddOne.dll' name '_mlxAddOne';

Then call it:
Input:=1;
MatlabFunc(1,Output,Input);

I've installed all the relevant matlab runtime libraries and everything seems to work ok, I think it's just a matter of figuring out the correct calling convention. Or do I have to use mclInitializeApplication or something? It does appear from web searches that people have had similar problems and that some people have managed to solve it, but no-one explains quite how.
PaulC76Asked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
epasquierConnect With a Mentor Commented:
Ok, I'm about sure that those Delphi declarations are good, compared to the C headers. So, since it returns False, and don't raise exceptions of any kind, we have to suppose that the call is working, but for a reason it cannot initialize MathLab... Maybe some wrong parameter in you MathLab environment
0
 
epasquierCommented:
the calling convention is most probably stdcall;

for the parameters types translation, it would be useful to have C headers (.H files), probably generated when you compile your function.
I doubt very much that those parameters are Variant.

I think also that you have to call the initialize function for the lib, and call the Terminate when done.

something like
function MatlabFunc(NRetValues: Integer;var Output: Variant;var Input: Variant): Variant; stdcall; external 'AddOne.dll' name '_mlxAddOne';

procedure AddOneInitialize; stdcall; external 'AddOne.dll'  name '_MatlabFuncInitialize';

procedure AddOneTerminate; stdcall; external 'AddOne.dll'  name '_MatlabFuncInitialize';

Open in new window

0
 
developmentguruPresidentCommented:
The MatLab compiler generates both the dll and a header filer.  Can you post the header file?  Many experts are good at translating a C / C++ header into the correct Delphi calling conventions.  From what I have been able to tell MatLab generates CDecl calling conventions.
0
What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

 
PaulC76Author Commented:
I have since tried calling the mclInitializeApplication first and then using a function which has no parameters and still get the same error. In the interface I now have:
function InitialiseMatlab(): Boolean; cdecl;
function NoParam(): Boolean; cdecl;

Open in new window

and in the implementation:

  function InitialiseMatlab(Options: Variant; Count: Word): Boolean; cdecl; external 'NoParam.dll' name '_NoParamInitialize';
function NoParam(): Boolean; cdecl; external 'NoParam.dll' name '_mlfNoParam';

Open in new window


The function in matlab is as follows:

function NoParam
x=2;
x=x+1;

Open in new window


The InitialiseMatlab function executes ok, but returns false. An access violation then occurs when NoParam tries to execute. Matlab generates a header file and c code, which are attached.

 NoParam.h NoParam.c

The header file has the relevant interfaces to the function:

extern LIB_NoParam_C_API 
bool MW_CALL_CONV NoParamInitializeWithHandlers(mclOutputHandlerFcn error_handler,
                                                mclOutputHandlerFcn print_handler);

extern LIB_NoParam_C_API 
bool MW_CALL_CONV NoParamInitialize(void);

extern LIB_NoParam_C_API 
void MW_CALL_CONV NoParamTerminate(void);

extern LIB_NoParam_C_API 
bool MW_CALL_CONV mlxNoParam(int nlhs, mxArray *plhs[],
                             int nrhs, mxArray *prhs[]);

extern LIB_NoParam_C_API bool MW_CALL_CONV mlfNoParam();

Open in new window


Any parameters if needed are mxArray types, which is partially defined in the header file Matrix.h as follows:

#if defined(ARRAY_ACCESS_INLINING) && !defined(MATLAB_COMPILER_GENERATED_CODE)
/*
 * This modified version of the mxArray structure is needed to support
 * the ARRAY_ACCESS_INLINING macros.  NOTE: The elements in this structure
 * should not be accessed directly.  Inlined MEX-files are NOT guaranteed
 * to be portable from one release of MATLAB to another.
 */

struct mxArray_tag {
    void    *reserved;
    int      reserved1[2];
    void    *reserved2;
    int      number_of_dims;
    unsigned int reserved3;
    struct {
        unsigned int    scalar_flag : 1;
	unsigned int	flag1 : 1; 
        unsigned int    flag2 : 1;
        unsigned int    flag3 : 1;
        unsigned int    flag4 : 1;
        unsigned int    flag5 : 1;
        unsigned int    flag6 : 1;
        unsigned int    flag7 : 1;
        unsigned int    private_data_flag : 1;
        unsigned int    flag8 : 1;
        unsigned int    flag9 : 1;
        unsigned int    flag10 : 1;
        unsigned int    flag11 : 4;
        unsigned int    flag12 : 8;
        unsigned int    flag13 : 8;
    }   flags;
    unsigned int reserved4[2];
    union {
        struct {
            void  *pdata;
            void  *pimag_data;
            void  *reserved5;
            int    reserved6[3];
        }   number_array;
    }   data;
};
#endif /* ARRAY_ACCESS_INLINING */

Open in new window


Converting that to Delphi is the point where I give up I think, I've spent more time than I have for this already.
0
 
PaulC76Author Commented:
My previous comment was a bit confusing. In the example I posted I didn't use the global mclInitializeApplication, but the local initialisation function NoParamInitialize. I have since tried with mclInitializeApplication as follows:

Interface:
TCharPointer = ^Char;
TCharPointerPointer =^TCharPointer;
function InitialiseMatlab(const Options:  TCharPointerPointer; Count: Word): Boolean; cdecl; 

Open in new window

Implementation:
function InitialiseMatlab(const Options:  TCharPointerPointer; Count: Word): Boolean; cdecl; external 'mclmcrrt76.dll' name 'mclInitializeApplication';

Open in new window

The C header as given in the Matlab help is:
bool mclInitializeApplication(const char **options, int count);

Open in new window

In the example in the Matlab help "mclInitializeApplication(NULL,0);" is given as an example of usage, I've tried "InitialiseMatlab(nil,0);" and passing pointers to pointers to #0, but always get a return value of False.
0
 
epasquierCommented:
why do you have thie ?
function InitialiseMatlab(Options: Variant; Count: Word): Boolean; cdecl; external 'NoParam.dll' name '_NoParamInitialize';

shouldn't you call this :

function InitialiseMatlab: Boolean; cdecl; external 'NoParam.dll' name '_NoParamInitialize';

if InitialiseMatlab Then ShowMessage('Good') Else Raise Exception.Create('Could not initialize MathLab Dll');

Open in new window


then : TCharPointer = ^Char;
that type already exists, that's PChar. But I recommend using PAnsiChar, because if you have Delphi >=2009 then Char = WideChar (unicode), so for C dll you have to use ANSIChar explicitly. And Count is not Word (2 bytes) but Integer (or Cardinal)

function InitialiseMatlabOptions(const Options:  ^PANSIChar; Count: Integer ): Boolean; cdecl; external 'NoParam.dll' name 'mclInitializeApplication';

Open in new window

0
 
PaulC76Author Commented:
Very sorry, the function was InitialiseMatlab was defined as you have it in your first code segment, it was copied from code I was in the middle of changing to use the mclInitialize function instead of NoParamInitialize. I also had originally defined Count as an Integer, but changed it to Word as part of my desperate and lazy trial and error approach. Also Delphi doesn't allow you to define pointers as function parameters in the function prototype (e.g.^PANSIChar), you have to define them as types first.

Anyway, I've since done as you kindly suggested and it still returns false. Thanks very much for your help with this, but please don't waste any more time on it, as I'm not able to spend too long on it myself now and I don't want to trouble anyone else with it too much.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.