I'm having trouble learning how to use MEX files, and all of the documentation (even this one: https://www.mathworks.com/help/matlab/matlab_external/standalone-example.html#zmw57dd0e18781, which seemed simple at first but completely lost me after a couple paragraphs) is going WAY over my head.
Right now, I'm trying to use code from a .dll and I don't have the original source code, but I do have a header file with function prototypes of all of the functions that I need, all within extern "C".
So instead of changing these functions or really doing anything all that complicated, I'm just trying to use the .dll functions in my MATLAB code. Here's an example of one of my functions (I have twenty):
#include "mex.h"
#include "AllFunctions.h"
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[]){
if(nrhs != 0) {
mexErrMsgIdAndTxt("Error: myfun.c",
"Cannot have any inputs.");
}
if(nlhs != 1) {
mexErrMsgIdAndTxt("Error: myfun.c",
"One output required.");
}
double *output; //output
/* create the output matrix */
plhs[0] = mxCreateDoubleMatrix(1,1,mxREAL);
/* get a pointer to the real data in the output matrix */
output = mxGetPr(plhs[0]);
/* call the computational routine */
myfun;
}
It has no inputs and one output. Most of my functions have a few simple inputs and one output, and a few functions pass pointers. Loadlibrary completely fails for me, and the solutions given on multiple threads do not pertain to me, so I'm trying to use MEX's instead.
I'd like to know if this is the proper approach and maybe what I should include to make this actually work before I make twenty functions that don't work. They all work in tandem with each other, so it is very difficult to test one function and then move on from there. Thanks for helping me out.
PS: Please don't tell me I need to go study MEXs more, as I am doing so as you type up your response. If there is another thing I should be looking at, I'll be very grateful. Any help is appreciated, but please don't tell me to spend my time researching (unless its something specific) before I ask beginner questions because I did a lot of research before posting this question, and I am continuing to do so afterwards.

5 Kommentare

Steven Lord
Steven Lord am 21 Jun. 2017
"Right now, I'm trying to use code from a .dll and I don't have the original source code, but I do have a header file with function prototypes of all of the functions that I need, all within extern "C"."
Based on that, my first thought would be to try using loadlibrary. Since you say "Loadlibrary completely fails for me", perhaps if you show how you're calling loadlibrary and give the full error message we can help you get that approach working.
James Tursa
James Tursa am 21 Jun. 2017
Bearbeitet: James Tursa am 21 Jun. 2017
Are you somehow expecting that myfun call in your mex routine to call a function by that name in your dll just because you included the header file? (It won't). When you are compiling your mex routine, are you trying to link in that dll?
"show how you're calling loadlibrary and give the full error message" - Steven Lord
There are far more errors than I can show, but to sum it all up in a few snippets, I'm getting this:
and this:
and this:
from this:
loadlibrary('AllFunctions.dll','AllFunctions.h');
and this:
loadlibrary('AllFunctions');
There are some functions within the dll that have pointers as inputs (which, from certain articles seems like a bad idea). Is that what this is about?
Also, I realize now that a left-hand argument (plhs[0]) needs to capture the output of myfun, so I'll do just that.
Thanks!
Mandeguz
Mandeguz am 22 Jun. 2017
"Are you somehow expecting that myfun call in your mex routine to call a function by that name in your dll just because you included the header file? (It won't)." - James Tursa
How do you call a specific function in the dll then, if not my name? Doesn't it work that way in C?
"When you are compiling your mex routine, are you trying to link in that dll?"
Not sure what you mean. How do you link a dll to your mex routine? Do you have to include it like the header file?
Hopefully, this will clarify things. Thanks!
Alright, after checking in on some of the responses and researching the material as well as I could, I'm left with the following error:
Error using mex
C:\Users\guzmanjj\AppData\Local\Temp\mex_510323448540256_3152\myfun.obj:myfun.cpp:(.text+0xf2):
undefined reference to `__imp_myfun'
collect2.exe: error: ld returned 1 exit status
whenever I run this command:
mex -setup C++;
mex myfun.cpp
I have the correct C/C++ compiler and permissions to use it. The correct path is set to grab this function. I thought my code was written well based off of MATLAB's own examples. Here is my C++ file:
#include "mex.h"
#include "myheader.h"
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[]){
/* check for proper number of arguments */
if(nrhs != 2)
mexErrMsgIdAndTxt("Error: myfun.cpp","Two inputs required.");
if(nlhs != 1)
mexErrMsgIdAndTxt("Error: myfun.cpp","One output required.");
/* variables */
double in_one; //input 1
double in_two; //input 2
double out; //output
/* make sure that both input arguments are type double */
if( !mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) || mxGetNumberOfElements(prhs[0])!=1 )
mexErrMsgIdAndTxt("Error: myfun.cpp","Input 1 must be type double.");
if( !mxIsDouble(prhs[1]) || mxIsComplex(prhs[1]) || mxGetNumberOfElements(prhs[1])!=1 )
mexErrMsgIdAndTxt("Error: myfun.cpp","Input 2 must be type double.");
/* get the values of the scalar inputs */
in_one = mxGetScalar(prhs[0]);
in_two = mxGetScalar(prhs[1]);
/* create the output scalar */
out = mxGetScalar(plhs[0]);
/* call the computational routine */
out = myfun(in_one,in_two);
}
And here's my header file:
#pragma once
#include <windows.h>
#include "WinDef.h" //include BOOL definition
#ifdef MYFUNPACKAGE_EXPORTS
#define MYFUN_PACKAGE_API __declspec(dllexport)
#else
#define MYFUN_PACKAGE_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern MY_DLL_API BOOL myfun(unsigned int in_one, unsigned int in_two);
#ifdef __cplusplus
}
#endif
My dll file cannot be read. I cannot get the source code unless I decompile the dll, which I would like help with if that is absoluetly necessary; I'd rather avoid that if I could.
I believe the problem is that I do not know how to directly connect my dll to my cpp/mex file. I'm looking more into loadlibrary currently, but I still have not had any success. If anyone could clear up this mex problem, that would be very helpful. Thanks

Melden Sie sich an, um zu kommentieren.

 Akzeptierte Antwort

James Tursa
James Tursa am 5 Jul. 2017
Bearbeitet: James Tursa am 5 Jul. 2017

1 Stimme

For the mex routine approach, assuming you can link with the library properly per Philip's comments, I have the following comments:
if(nlhs != 1)
mexErrMsgIdAndTxt("Error: myfun.cpp","One output required.");
The above line requires the user to specify an output variable when calling your code. This is usually too strict a requirement to place on a user. A more friendly approach is to require "at most 1" output" so that the result can simply go into ans. Note that even if nlhs==0, MATLAB always has room for at least one output in the plhs array. So this is advised:
if(nlhs > 1)
mexErrMsgIdAndTxt("Error: myfun.cpp","At most one output required.");
Then there are these lines:
/* create the output scalar */
out = mxGetScalar(plhs[0]);
/* call the computational routine */
out = myfun(in_one,in_two);
The above lines will crash MATLAB. The plhs[0] variable does not exist when you enter the mex routine ... that is something that you, the programmer, must create before you can use it. Thus the mxGetScalar(plhs[0]) call accesses invalid memory and crashes MATLAB. And even if you had created plhs[0] previously, the above lines of code would not get the next out result from myfun into plhs[0]. So these lines should be coded this way instead:
/* call the computational routine */
out = myfun(in_one,in_two);
/* create the output scalar */
plhs[0] = mxCreateDoubleScalar(out);

8 Kommentare

Mandeguz
Mandeguz am 5 Jul. 2017
Thanks for the tips. Clear, understandable, I'll implement immediately.
Mandeguz
Mandeguz am 5 Jul. 2017
Bearbeitet: Mandeguz am 5 Jul. 2017
Would it work like this then, defining plhs[0] and then placing the scalar value into it?
/* call the computational routine */
out = myfun(in_one,in_two);
/* create the output scalar */
plhs[0] = mxCreateDoubleMatrix(1,1,mxREAL);
plhs[0] = mxCreateDoubleScalar(out);
James Tursa
James Tursa am 5 Jul. 2017
Bearbeitet: James Tursa am 5 Jul. 2017
What you have posted leaks memory (at least temporarily). Here's why:
plhs[0] = mxCreateDoubleMatrix(1,1,mxREAL);
The above line creates an mxArray and places a pointer to it into the plhs[0] spot. All fine and good. Currently it contains a value of 0.0 in the data area.
plhs[0] = mxCreateDoubleScalar(out);
The above line creates a brand new mxArray variable and places a pointer to it into the plhs[0] spot, overwriting the current pointer that was there from your mxCreateDoubleMatrix call. You have now lost your only pointer to the first dynamically allocated plhs[0] mxArray variable and are leaking all of the memory associated with it. As it turns out, MATLAB will be nice to you and garbage collect this memory when the mex routine returns control to the caller, but it is still not the correct way to code this.
You can either do it exactly as I have posted earlier, or you could have done this if you want to create plhs[0] first:
/* create the output scalar */
plhs[0] = mxCreateDoubleMatrix(1,1,mxREAL);
/* call the computational routine */
out = myfun(in_one,in_two);
/* copy the output to plhs[0] */
*(mxGetPr(plhs[0])) = out;
James Tursa
James Tursa am 5 Jul. 2017
No. You can create the data anytime you want. You don't have to create output mxArray variables before you do any calculations to create the output data. Often it is convenient to do so because of programming considerations, but it is not at all a requirement.
What I meant was that you have to create plhs[0] before using it as an argument to any function like mxGetScalar(plhs[0]) or mxGetPr(plhs[0]) etc. These functions assume the pointer that gets passed to them points to a valid mxArray, so they dereference the pointer and start accessing the associated memory. If you haven't created plhs[0] before you call these functions, you are essentially passing in a garbage pointer.
Thank you so much, everything has been helpful so far. Another question, if you have multiple outputs (say myfun makes a reference to in_two, thus changing its value), would the output code look something like this?
/* create the output scalar */
plhs[0] = mxCreateDoubleMatrix(1,2,mxREAL);
/* call the computational routine */
out = myfun(in_one,in_two);
/* copy the output to plhs[0] */
*(mxGetPr(plhs[0])) = out;
*(mxGetPr(plhs[0])++) = in_two;
Or maybe you have to reference it like this?
/* create the output scalar */
plhs[0] = mxCreateDoubleMatrix(1,2,mxREAL);
/* create a reference to the output scalar */
int (&z)[2] = plhs[0];
/* call the computational routine */
out = myfun(in_one,in_two);
/* copy the output to z array */
*(mxGetPr(z[0])) = out;
*(mxGetPr(z[1])) = in_two;
To clarify, I want the output of my mex function to be a 1-by-2 matrix with the first cell being out and the second cell being in_two, so that I can run the following code:
mex -setup C++;
mex myfun.cpp;
% in_one, in_two, and out
% are a, b, and c in my
% MATLAB code
myout = myfun(a,b); %mex routine
a; %in_one remains unchanged
b = myout(2); %in_two changes by reference
c = myout(1); %out is created via return value
James Tursa
James Tursa am 6 Jul. 2017
Bearbeitet: James Tursa am 6 Jul. 2017
Here is how I would do it:
double *pr;
:
/* create the output scalar */
plhs[0] = mxCreateDoubleMatrix(1,2,mxREAL);
/* call the computational routine */
out = myfun(in_one,in_two);
/* copy the output to plhs[0] */
pr = mxGetPr(plhs[0]);
pr[0] = out;
pr[1] = in_two;
Although I am confused by your comment "in_two changes by reference". There is nothing shown in your code that changes the in_two value. It will come back as exactly the same value that was passed into the mex routine (unless perhaps it is being passed by reference into myfun and modified there?).
I forgot something in the header file, it really looks like this:
#pragma once
#include <windows.h>
#include "WinDef.h" //include BOOL definition
#ifdef MYFUNPACKAGE_EXPORTS
#define MYFUN_PACKAGE_API __declspec(dllexport)
#else
#define MYFUN_PACKAGE_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern MY_DLL_API BOOL myfun(unsigned int in_one, unsigned int & in_two);
#ifdef __cplusplus
}
#endif
I believe that's a C++ reference (not a pointer but similar to it) but if I'm wrong, then I need to figure out why that's there and what to do about it in the mex (I did not write this header file, I only added the #ifdef __cplusplus lines).
James Tursa
James Tursa am 7 Jul. 2017
The prototype for the in_two argument using & means that yes the argument is being passed by reference, and any changes made to in_two inside of myfun will be made to the original variable.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (1)

Philip Borghesani
Philip Borghesani am 5 Jul. 2017
Bearbeitet: Philip Borghesani am 5 Jul. 2017

1 Stimme

I suggest a two pronged approach.
  1. Get Loadlibrary working if at all possible. There is only one real error in your loadlibrary output (the last line) the rest are warnings caused by parsing windows.h and can safely be ignored. The error is the last line and is due to a missing #ifdef __cplusplus I think you fixed it in the header you are using for myfun for mex. Using loadlibrary will save you from writing a large number of simple mex files or a large mex file with a gateway.
  2. You may find that some functions are better called from a mex file. As alluded to by James Tursa, to call a dll from a mex file you must link with its corresponding library. The mex command gives information on how to link with an extra lib file. On Linux this is the same shared library that loadlibrary would use but on Windows this must be a .lib file. If you have mex configured for mingGW you may need to generate a lib file for that compiler. You were probably supplied with a lib file for Microsoft compilers.
I suggest new questions that are specific to current problems you are having with loadlibrary or mex. Solving multiple problems in a single answer causes confusion... Learning how a function is called from mex (or c) helps quite a bit in how to structure code that calls that function with loadlibrary

Kategorien

Mehr zu Write C Functions Callable from MATLAB (MEX Files) finden Sie in Hilfe-Center und File Exchange

Tags

Gefragt:

am 21 Jun. 2017

Kommentiert:

am 10 Jul. 2017

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by