函式定义 DLL内的函式名 摘要说明
void DllName01(void) @DllName01$qv 因为是CPP程式码
void _stdcall DllName02(void) @DllName02$qqsv 所以函式名都被修
void _cdecl DllName03(void) @DllName03$qv 饰过。
void _pascal DllName04(void) @DLLNAME04$QV
void _fastcall DllName05(void) @DllName05$qqrv
- 以上结果是否令你丈二金钢、摸不着头绪。这是因为我们的程式名称若以CPP为延伸名,C++Builder会以C++ 特有的命名方式来为函式命名,这种命名方式会在函式名称後加上其使用参数的性质,如参数类别等。这在C++ 中有一个特别的名称,叫做mangled name,这是一种为了要实作出多载函式所发出的命名规则。(注:在C++ 中Add(int) 和Add(double) 可以同时存在,因此必须在object code区分之)。同时这种命名方式由於各个编译器厂商使用的方式各不相同,因此在撰写DLL时要避免使用之。为了要避开以上问题,我们改以下列的宣告方式:
#define _DLLNAME01_H_
#ifndef DLLNAME
#define EXTERN __declspec(dllimport)
#else
#define EXTERN __declspec(dllexport)
#endif
extern "C" {
EXTERN void DllName011(void);
EXTERN void _stdcall DllName022(void);
EXTERN void _cdecl DllName033(void);
EXTERN void _pascal DllName044(void);
EXTERN void _fastcall DllName055(void);
};
#endif
其中extern "C" {琕琕.}; 是用来告诉编译器使用C的命名方式,不要使用C++ 的mangled name。若是其中只有一个函式时,你可以直接以下列方式宣告之:
extern "C" void __stdcall ShowImage();
现在我们可以检视除去mangled name後的函式名称:
函式定义 DLL内的函式名 摘要说明
void DllName01(void) _DllName01 名称加底线
void _stdcall DllName02(void) DllName02 名称未变
void _cdecl DllName03(void) _DllName03 名称加底线
void _pascal DllName04(void) DLLNAME04 名称大写
void _fastcall DllName05(void) @DllName05 名称加@
以上我们可得知,在未加修饰字时和使用_cdecl修饰字时的名称是一样的。而 _pascal修饰字所产生的函式名则和16位元的标准DLL 函式名相同(这在VC++ 是不被接受的),__fastcall的函式名称则加上 @。
其中在WIN32中使用最多的是 _stdcall修饰字,这也是你要撰写一个可以和其他语言共同使用时所使用的修饰字,其次则为 __cdecl修饰字,这是用来传送不定参数型别的函式如printf、sprintf等使用的。其馀两者几乎在DLL没有机会使用。
结论:
由上可知,在C++Builder中撰写DLL时必须注意以下事项:
使用 __declspec(dllimport)及 __declspec(dllexport)的标准型式。
1. 注意C++ 的函式名称编码(mangled name)。
2. 注意修饰字的使用。除非使用不定参数的函式,否则必使用 __stdcall修饰字。
(4) 不要把 __declspec的使用和 __stdcall混淆了。此二者并没有绝对的相关性。即使是程式老手都可能栽在此处,切记,切记!
怎麽样,在看完了以上的介绍後,是否有晃然大悟的感觉。在了解以上的规则後,今後不论在撰写或是使用DLL时遭遇连结的问题时,应该难不倒你吧!
最後,我们将标准的DLL宣告方式列於後,以加深你的印象:
#ifndef _SHOWIMG_H_
#define _SHOWIMG_H_
#ifndef IMGDLL
#define EXTERN __declspec(dllimport)
#else
#define EXTERN __declspec(dllexport)
#endif
extern "C" EXTERN void __stdcall ShowImage(void);
#endif
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
语言双雄' C++Builder 和Visual C++ 连结
前面我们已经把关於C++Builder撰写DLL所应注意到的事项介绍完了,现在我们来谈另一个重点 - C++Builder和Visual C++ 的连结。若是你没有使用过Visual C++ 的话,可以将此部份略去。若是你在程式设计时必须使用到Visual C++ 的DLL或是必须提供DLL给VC++ 或是VB使用时,也许会带给你意想不到的收获。
VC++ 使用C++Builder的DLL函式
在Visual C++ 中使用C++Builder的DLL的函式方法和在C++Builder中使用大同小异,唯有几件事情必须要注意。
(一)Visual C++ 的LIB档格式和C++Builder的LIB格式不同,因此你必须重新产生一个 LIB。不过,可惜的是VC++ 在32位元的版本中并未提供IMPLIB.EXE函式(这点一直令许多人百思不解),因此你无法很方便地产生LIB档。解决方法有二:其一是在VC++ 内撰写一个同名称的空的DLL函式,令其产生LIB档,其二则是使用 LoadLibrary、GetProcAddress式的明确呼叫方式。
(二)使用前面提到的标准写法。
C++Builder中使用VC++ 的DLL函式
在C++Builder中使用VC++ 的DLL函式时要注意的是Microsoft在Visual C++ 中使用的特殊命名规则。在VC++ 中命名规则除了前面谈到的几项之外,它还使用了一个特殊的参数命名法,简言之,就是在函数名称後面加上参数的大小,这种命名方法会造成C++Builder,VB,Delphi使用的上的困扰。举例来说
extern "C" _declspec(dllexport) void __stdcall ShowImage(void);
在VC++ 中产生的函式名称为ShowImage@0(其中0表示参数大小),而不是如在C++Builder中产生的ShowImage,这是VC++ 已知的问题,这个问题也造成了很多使用non-VC++ 的使用者的问题,解决之道是在该DLL的DEF档中加上以下的叙述
EXPORTS
ShowImage=ShowImage@0
如此便可以产生正确的函式名了,若是你不想修改DEF档,你也可以在程式中加入以下的连结指引
#pragma comment(linker,"/exports:ShowImage=ShowImage@0")
假设你不确定其正确的名称,可以利用DumpBin或是TDump观察之。
以上是针对VC++ 的程式设计的所作的额外说明。最後我们以一个VC++ 程式呼叫本单元的About Dialog DLL做为结束。
此程式的关键程式码如下:
void CVcusedllApp::OnAppAbout()
{
void (*ShowImage)(void);
HINSTANCE hInst;
hInst = LoadLibrary("DLLSAMP2.DLL");
(FARPROC &)ShowImage=GetProcAddress(hInst,"ShowImage");
ShowImage();
FreeLibrary(hInst);
}
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
Export C Functions for Use in C or C++ Language Executables
Home | Overview | How Do I | FAQ | Details | Sample
If you have functions in a DLL written in C that you want to access from a C-language or C++-language module, you should use the __cplusplus preprocessor macro to determine which language is being compiled, and then declare these functions with C linkage if being used from a C++-language module. If you use this technique and provide header files for your DLL, these functions can be used by C and C++ users with no change.
The following code shows a header file which can be used by C and C++ client applications:
// MyCFuncs.h
#ifdef __cplusplus
extern "C" { // only need to export C interface if
// used by C++ source code
#endif
__declspec( dllimport ) void MyCFunc();
__declspec( dllimport ) void AnotherCFunc();
#ifdef __cplusplus
}
#endif
If you need to link C functions to your C++ executable and the function declaration header files have not used the above technique, in the C++ source file, do the following to prevent the compiler from decorating the C function names:
extern "C" {
#include "MyCHeader.h"
}
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
How do I share data in my DLL with an application or with other DLLs?
Home | Overview | How Do I | FAQ | Details | Sample
Win32 DLLs are mapped into the address space of the calling process. By default, each process using a DLL has its own instance of the DLL global and static variables. If your DLL needs to share data with other Win32 DLLs loaded by a different application or with different mappings of the same DLL, then you can use either of the following approaches:
· Create named data sections using the #pragma statement.
· Use memory-mapped files.
To set up a new named section, use the #pragma data_seg directive. You then must specify the correct sharing attributes for this new named data section in your .DEF file. For more information about creating named data sections, see the following Knowledge Base articles:
· "How to Share Data Between Different Mappings of a DLL" (Q125677).
· "Specifying Shared and Nonshared Data in a DLL" (Q100634).
· "How to Specify Shared and Nonshared Data in a DLL" (Q89817).
· "Sharing All Data in a DLL" (Q109619).
However, if you need to share a C++ class instance, you should use a memory-mapped file, because each time a process attaches to the DLL, the constructor for the object is called. For example:
#pragma data_seg(".myseg")
_declspec(dllexport) CTest Counter1(0);
_declspec(dllexport) short Counter2 = 0;
#pragma data_seg()
Assume that the variables Counter1 and Counter2 are incremented in a function in the DLL. The value of Counter2 increases as expected, but on each process attach, the constructor for Counter1 is called reinitializing it to zero. In order to share Counter1, you must use a memory-mapped file. For more information about memory-mapped files, see File Mapping in the Win32 SDK documentation
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
Using __declspec(dllimport) and __declspec(dllexport)
Home | Overview | How Do I | FAQ | Details | Sample
The 32-bit edition of Visual C++ uses __declspec(dllimport) and __declspec(dllexport) to replace the __export keyword previously used in 16-bit versions of Visual C++.
You do not need to use __declspec(dllimport) for your code to compile correctly, but doing so allows the compiler to generate better code. The compiler is able to generate better code because it knows for sure whether a function exists in a DLL or not, so the compiler can produce code that skips a level of indirection that would normally be present in a function call that crossed a DLL boundary. However, you must use __declspec(dllimport) in order to import variables used in a DLL.
With the proper .DEF file EXPORTS section, __declspec(dllexport) is not required. __declspec(dllexport) was added to provide an easy way to export functions from an .EXE or .DLL without using a .DEF file.
The Win32 Portable Executable format is designed to minimize the number of pages that must be touched to fix imports. To do this, it places all the import addresses for any program in one place called the Import Address Table. This allows the loader to modify only one or two pages when accessing these imports.
Using _declspec(dllimport) for Function Calls
In the following code example, assume func1
is a function that resides in a DLL separate from the .EXE file that contains the main function.
Without __declspec(dllimport), given this code:
void main(void)
{
func1();
}
the compiler generates code that looks like this:
call func1
and the linker translates the call into something like this:
call 0x4000000 ; The address of 'func1'.
If func1
exists in another DLL, the linker can't resolve this directly because it has no way of knowing what the address of func1
is. In 16-bit environments, the linker adds this code address to a list in the .EXE that the loader would patch at run time with the correct address. In 32-bit environments, the linker generates a thunk of which it does know the address. The thunk looks like:
0x40000000: jmp DWORD PTR __imp_func1
Here __imp_func1
is the address for func1
's slot in the import address table of the .EXE file. All the addresses are thus known to the linker. The loader only has to update the .EXE file's import address table at load time for everything to work correctly.
Therefore, using __declspec(dllimport) is better because if the linker does not generate a thunk if it is not required. Thunks make the code larger (on RISC systems, it can be several instructions) and can degrade your cache performance. If you tell the compiler the function is in a DLL, it can generate an indirect call for you.
So now this code:
__declspec(dllimport) void func1(void);
void main(void)
{
func1();
}
generates this instruction:
call DWORD PTR __imp_func1
There is no thunk and no jmp
instruction, so the code is smaller and faster.
On the other hand, for function calls inside a DLL, you don't want to have to use an indirect call. You already know a function's address. Time and space is required to load and store the address of the function before an indirect call, so a direct call is always faster and smaller. You only want to use __declspec(dllimport) when calling DLL functions from the outside the DLL itself. Don't use __declspec(dllimport) on functions inside a DLL when building that DLL.
Using _declspec(dllexport)
Microsoft introduced __export in the 16-bit compiler version of Visual C++ to allow the compiler to generate the export names automatically and place them in a .LIB file. This .LIB file could then be used just like a static .LIB to link with a DLL.
Microsoft added __declspec(dllexport) to continue this convenience. Its purpose is to add the export directive to the object file so you don't need a .DEF file.
This convenience is most apparent when trying to export decorated C++ function names. There is no standard specification for name decoration, so the name of an exported function may change between compiler versions. If you use __declspec(dllexport), recompiling the DLL and dependent .EXE files is necessary only to account for any naming convention changes.
Many export directives, such as ordinals, NONAME, and PRIVATE, can be made only in a .DEF file, and there is no way to specify these attributes without a .DEF file. However, using __declspec(dllexport) in addition to using a .DEF file does not cause build errors.
As a reference, search through the Win32 WINBASE.H header file. It contains examples of __declspec(dllimport) usage.
Using __declspec(dllexport) and __declspec(dllimport) on Data
In the case of data, using __declspec(dllimport) is a convenience item that removes a layer of indirection. When you import data from a DLL, you still have to go through the import address table. In the Win32 days before __declspec(dllimport), this meant you had to remember to do an extra level of indirection when accessing data exported from the DLL:
// project.h
#ifdef _DLL // If accessing the data from inside //the DLL
ULONG ulDataInDll;
#else // If accessing the data from //outside the DLL
ULONG *ulDataInDll;
#endif
You would then export the data in your .DEF file:
// project.def
LIBRARY project
EXPORTS
ulDataInDll CONSTANT
and access it outside the DLL:
if (*ulDataInDll == 0L)
{
// Do stuff here
}
When you mark the data as __declspec(dllimport), the compiler automatically generates the indirection code for you. You no longer have to worry about the steps above. As stated previously, do not use __declspec(dllimport) declaration on the data when building the DLL. Functions within the DLL will not use the import address table to access the data object; therefore, you will not have the extra level of indirection present.
To export the data automatically from the DLL, use this declaration:
__declspec(dllexport) ULONG ulDataInDLL;
Using a .DEF File
If you choose to use __declspec(dllimport) along with a .DEF file, you should change the .DEF file to use DATA in place of CONSTANT to reduce the likelihood that incorrect coding will cause a problem:
// project.def
LIBRARY project
EXPORTS
ulDataInDll DATA
The following table shows why:
Keyword | Emits in the import library | Exports |
|
|
|
|
|
|
Using __declspec(dllimport) and CONSTANT lists both the __imp_
version and the undecorated name in the .LIB DLL import library that is created to allow explicit linking. Using __declspec(dllimport) and DATA lists just the __imp_
version of the name.
If you use CONSTANT, either of the following code constructs could be used to access the ulDataInDll
:
__declspec(dllimport) ULONG ulDataInDll; /*prototype*/
if (ulDataInDll == 0L) /*sample code fragment*/
-or-
ULONG *ulDataInDll; /*prototype*/
if (*ulDataInDll == 0L) /*sample code fragment*/
However, if you use DATA in your .DEF file, only code compiled with the following definition can access the variable ulDataInDll
:
__declspec(dllimport) ULONG ulDataInDll;
if (ulDataInDll == 0L) /*sample code fragment*/
Using CONSTANT is more risky because if you forget to use the extra level of indirection, you could potentially access the import address table's pointer to the variable — not the variable itself. This type of problem can often manifest as an access violation because the import address table is currently made read-only by the Microsoft compiler and linkers.
The Current Visual C++ linker issues a warning if it sees CONSTANT in the .DEF file to account for this case. The only real reason to use CONSTANT is if you can't recompile some object file where the header file didn't list __declspec(dllimport) on the prototype.
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
你所遇到的这几个宏是为了进行条件编译。一般情况下,源程序中所有的行都参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”。有时,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。
条件编译命令最常见的形式为:
#ifdef 标识符
程序段1
#else
程序段2
#endif
它的作用是:当标识符已经被定义过(一般是用#define命令定义),则对程序段1进行编译,否则编译程序段2。
其中#else部分也可以没有,即:
#ifdef
程序段1
#denif
这里的“程序段”可以是语句组,也可以是命令行。这种条件编译可以提高C源程序的通用性。如果一个C源程序在不同计算机系统上系统上运行,而不同的计算机又有一定的差异。例如,我们有一个数据类型,在Windows平台中,应该使用long类型表示,而在其他平台应该使用float表示,这样往往需要对源程序作必要的修改,这就降低了程序的通用性。可以用以下的条件编译:
#ifdef WINDOWS
#define MYTYPE long
#else
#define MYTYPE float
#endif
如果在Windows上编译程序,则可以在程序的开始加上
#define WINDOWS
这样则编译下面的命令行:
#define MYTYPE long
如果在这组条件编译命令之前曾出现以下命令行:
#define WINDOWS 0
则预编译后程序中的MYTYPE都用float代替。这样,源程序可以不必作任何修改就可以用于不同类型的计算机系统。当然以上介绍的只是一种简单的情况,可以根据此思路设计出其它的条件编译。
例如,在调试程序时,常常希望输出一些所需的信息,而在调试完成后不再输出这些信息。可以在源程序中插入以下的条件编译段:
#ifdef DEBUG
print ("device_open(%p)/n", file);
#endif
如果在它的前面有以下命令行:
#define DEBUG
则在程序运行时输出file指针的值,以便调试分析。调试完成后只需将这个define命令行删除即可。有人可能觉得不用条件编译也可达此目的,即在调试时加一批printf语句,调试后一一将printf语句删除去。的确,这是可以的。但是,当调试时加的printf语句比较多时,修改的工作量是很大的。用条件编译,则不必一一删改printf语句,只需删除前面的一条“#define DEBUG”命令即可,这时所有的用DEBUG作标识符的条件编译段都使其中的printf语句不起作用,即起统一控制的作用,如同一个“开关”一样。
有时也采用下面的形式:
#ifndef 标识符
程序段1
#else
程序段2
#endif
只是第一行与第一种形式不同:将“ifdef”改为“ifndef”。它的作用是:若标识符未被定义则编译程序段1,否则编译程序段2。这种形式与第一种形式的作用相反。
以上两种形式用法差不多,根据需要任选一种,视方便而定。
还有一种形式,就是#if后面的是一个表达式,而不是一个简单的标识符:
#if 表达式
程序段1
#else
程序段2
#endif
它的作用是:当指定的表达式值为真(非零)时就编译程序段1,否则编译程序段2。可以事先给定一定条件,使程序在不同的条件下执行不同的功能。
例如:输入一行字母字符,根据需要设置条件编译,使之能将字母全改为大写输出,或全改为小写字母输出。
#define LETTER 1
main()
{
char str[20]="C Language",c;
int i=0;
while((c=str[i])!='/0'){
i++;
#if LETTER
if(c>='a'&&c<='z') c=c-32;
#else
if(c>='A'&&c<='Z') c=c+32;
#endif
printf("%c",c);
}
}
运行结果为:C LANGUAGE
现在先定义LETTER为1,这样在预处理条件编译命令时,由于LETTER为真(非零),则对第一个if语句进行编译,运行时使小写字母变大写。如果将程序第一行改为:
#define LETTER 0
则在预处理时,对第二个if语句进行编译处理,使大写字母变成小写字母(大写字母与相应的小写字母的ASCII代码差32)。此时运行情况为:
c language
有人会问:不用条件编译命令而直接用if语句也能达到要求,用条件编译命令有什么好处呢?的确,此问题完全可以不用条件编译处理,但那样做目标程序长(因为所有语句都编译),而采用条件编译,可以减少被编译的语句,从而减少目标的长度。当条件编译段比较多时,目标程序长度可以大大减少。
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
下面我们看一下常见的预处理指令:
#define 宏定义
#undef 未定义宏
#include 文本包含
#ifdef 如果宏被定义就进行编译
#ifndef 如果宏未被定义就进行编译
#endif 结束编译块的控制
#if 表达式非零就对代码进行编译
#else 作为其他预处理的剩余选项进行编译
#elif 这是一种#else和#if的组合选项
#line 改变当前的行数和文件名称
#error 输出一个错误信息
#pragma 为编译程序提供非常规的控制流信息
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
Subject: Re: How to pass parameters to a DLL generated from MAtlab???
Author: LePhan <LePhan@LePhanPublishing.com>
Date: Thu, 4 Mar 2004 23:52:27 -0500
Hi,
Suppose you have a function in M-file, mySquare.m. After you
generated mySquarelib.dll, you can call your function as follows:
double CalculateMySquare(double x) {
mxArray *x_ptr;
mxArray *y_ptr;
double *pVal ;
/* Create a mxArray to input into mlfMySquare(..) function */
x_ptr = mlfScalar(x);
/* call the initial function */
mySquarelibInitialize() ;
/* call the implementation function */
y_ptr = mlfMySquare(x_ptr);
/* call the termination function */
mySquarelibTerminate() ;
/* return value from mlfMySquare(..) is a mxArray, so we
will translate to C++ type */
pVal = mxGetPr(y_ptr);
double y = *pVal ;
return y ;
}
More of details are in our book, MATLAB C/C++, in
www.LePhanPublishing.com
Hope it helps.
LePhan,
Tunayu wrote:
>>
> Hello !,
> I have made a Dll file from matlab ,so as to I can call it in a
> VC++ enviroment,however ,I don't know the detail data strcture of
> the
> so-called "mArray-tab",so I failed to pass parametere to the dll
> .Is
> there someone here can help me? URGENT!!!!!!
> Following is my m-function:
> function f=dd(x)
> f=x.^2;
> How can I call a dll file made from thid m-function???????
> can you give me any help ??????
> Thanks a lot!!!!!!!!!
> Yours
> Tunayu
>
>
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
Introduction
Some times it is required that we build a shared library (DLL) from an m-file. M-files are functions that are written in Matlab editor and can be used from Matlab command prompt. In m-files, we employ Matlab built-in functions or toolbox functions to compute something. In my past articles, I showed you some ways to use Matlab engine (vis. API, C++ class or Matlab engine API) for employing Matlab built-in functions, but what about functions that we develop? How can we use them in VC? Is there any interface? This article shows you an idea to employ your own Matlab functions.
Shared Libraries
Shared libraries or DLLs are files that export some functions. We can use exported functions in any language. Here is a brief instruction to build shared libraries from Matlab m-files:
1. Compile your m-file into a DLL (from Matlab command prompt):
mcc -t -L C -W lib:mylib -T link:lib -h <M-file> libmmfile.mlib
The -t option tells the Matlab compiler to translate the m-file to the target language. The -L option specifies the target language, which is chosen to be C. The -W option tells the Matlab compiler to build a wrapper for the library with the name specified by "lib:". The -T option tells the compiler what stage should be reached and for what intentions. Here we link our application together to build a shared library (DLL). Specifying libmmfile.mlib tells Matlab compiler to link against Matlab m-file math routine.
This step will produce mylib.dll, mylib.lib and mylib.h. For debugging purposes, you can add the -g switch to produce a DLL suitable for debugging in MSVC.
For example, I wrote my own mean function and saved it as MeanFunction.m:
function y=MeanFunction(x)
[m,n]=size(x);
k=0;
for i=1:n
k=k+x(i);
end
y=k/n;
and compiled it with mcc:
mcc -t -L C -W lib:MeanFunctionLib -T link:lib MeanFunction.m libmmfile.mlib
2. Create your project in VC. In your main CPP file, include your function header file and add the related library. Here I create a simple console application. Make sure to call initialization and termination routines from your code before and after of calling the m-file function.
3. #include "stdafx.h"
4. #include "matlab.h"
5. #include "MeanFunctionLib.h"
6.
7. #pragma comment(lib, "libmx.lib")
8. #pragma comment(lib, "libmatlb.lib")
9. #pragma comment(lib, "libmat.lib")
10. #pragma comment(lib, "libmmfile.lib")
11. #pragma comment(lib, "MeanFunctionLib.lib")
12.
13. int main(int argc, char* argv[])
14. {
15. mxArray* result;
16. mxArray* x;
17. double myArray[5]={10.2, 3, 6.3, 5.4, 5.9};
18.
19. x=mxCreateDoubleMatrix(1, 5, mxREAL);
20. memcpy(mxGetPr(x), myArray, 5 * sizeof(double));
21.
22. MeanFunctionLibInitialize();
23.
24. result=mlfMeanfunction(x);
25.
26. MeanFunctionLibTerminate();
27.
28. mlfPrintMatrix(result);
29.
30. mxDestroyArray(x);
31. mxDestroyArray(result);
32.
33. return 0;
}
34. Build your project.
Notice that you must use Matlab C API or Matlab C++ class library to use mxArray
or mwArray
. For more information, refer to my articles:
- Solving Engineering Problems Using MATLAB C API
- Solving Engineering Problems Using MATLAB C++ Math Library
Enjoy!
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
Loading and Unloading the Library
To give MATLAB access to external functions in a shared library, you must first load the library into memory. Once loaded, you can request information about any of the functions in the library and call them directly from MATLAB. When the library is no longer needed, you will need to unload it from memory to conserve memory usage.
To load a shared library into MATLAB, use the loadlibrary
function. The syntax for loadlibrary
is
· loadlibrary('shrlib', 'hfile')
where shrlib
is the filename for the .dll
shared library file, and hfile
is the filename for the header file that contains the function prototypes. See the reference page for loadlibrary
for variations in the syntax that you can use.
Note The header file provides signatures for the functions in the library and is a required argument for |
As an example, you can use loadlibrary
to load the libmx
library that defines the MATLAB mx
routines. The first statement below forms the directory specification for the matrix.h
header file for the mx
routines. The second loads the library from libmx.dll
, also specifying the header file:
· hfile = [matlabroot '/extern/include/matrix.h'];
· loadlibrary('libmx', hfile)
There are also several optional arguments that you can use with loadlibrary
. See the loadlibrary
reference page for more information.
To unload the library and free up the memory that it occupied, use the unloadlibrary
function. For example,
· unloadlibrary libmx
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
Introduction
As all of you know, MATLAB is a powerful engineering language. Because of some limitation, some tasks take very long time to proceed. Also MATLAB is an interpreter not a compiler. For this reason, executing a MATLAB program (m file) is time consuming. For solving this problem, Mathworks provides us C Math Library or in common language, MATLAB API. A developer can employ these APIs to solve engineering problems very fast and easy. This article is about how can use these APIs.
MATrix LABoratory
MATLAB is abbreviation of Matrix Laboratory. This means every computation was performed in matrix form. In other hand every data type wrapped in matrix form and every functions take these matrix as input argument.
For example you want to multiply to polynomial as follow:
A = (3x2 + 5x + 7) (4x5 + 3x3 - x2 + 1)
You can use two matrices for coefficients of any polynomials:
[3 5 7] for (3x2 + 5x + 7) and [4 0 3 -1 0 1] for (4x5 + 3x3 - x2 + 1), using conv function, we can obtain coefficients of result: conv([3 5 7], [4 0 3 -1 0 1]):
A = [12 20 37 12 16 -4 5 7]
means: A= 12x7 + 20x6 + 37x5 + 12x4 + 16x3 - 4x2 + 5x + 7
C Math Library
The functions fall into two groups: the mathematical functions and the utility functions. We use mathematical functions for computing and utility functions for constructing an array or matrix or printing content of a matrix. Every matrices represented by mxArray
a data type introduced by MATLAB for constructing a matrix. As I said before, every data must be wrapped in a matrix form in other hand: mxArray
One C prototype supports all the possible ways to call a particular MATLAB C Math Library function. You can reconstruct the C prototype by examining the MATLAB syntax for a function. In the following procedure, the MATLAB function svd() and the corresponding library function mlfSvd() are used to illustrate the process.
MATLAB Syntax
s = svd (X)
[U, S, V] = svd (X)
[U, S, V] = svd (X, 0)
The C prototype for mlfSvd() is constructed step-by-step. Until the last step, the prototype is incomplete.
Adding the Output Arguments
1- Find the statement that includes the largest number of output arguments.
Choose:
[U, S, V] = svd (X, 0)
2- Subtract out the first output argument, U, to be the return value from the function. The data type for the return value is mxArray*.
mxArray* mlfSvd(
3- Add the remaining number of MATLAB output arguments, S and V, as the first, second, etc., arguments to the C function. The data type for a C output argument is mxArray**.
mxArray* mlfSvd(mxArray **S, mxArray **V
Adding the Input Arguments
1- Find the syntax that includes the largest number of input arguments.
Choose:
[U, S, V] = svd (X, 0)
2- Add that number of input arguments, X and Zero, to the prototype, one after another following the output arguments. The data type for an input argument is mxArray*.
mxArray* mlfSvd (mxArray** S, mxArray** V, mxArray* X, mxArray* Zero);
The prototype is complete.
How to Translate a MATLAB Call into a C Call
This procedure demonstrates how to translate the MATLAB svd() calls into MATLAB C Math Library calls to mlfSvd(). The procedure applies to library functions in general.
Note that within a call to a MATLAB C Math Library function, an output argument is preceded by &, an input argument is not.
MATLAB Syntax:
s = svd (X)
[U, S, V] = svd (X)
[U, S, V] = svd (X, 0)
The MATLAB arguments to svd() fall into these categories:
U (or s) is a required output argument.
S and V are optional output arguments.
X is a required input argument.
Zero is an optional input argument.
1- Declare input, output, and return variables as mxArray* variables, and assign values to the input variables.
2- Make the first output argument the return value from the function.
s =
U =
U =
3- Pass any additional required or optional output arguments as the first arguments to the function. Pass a NULL argument wherever an optional output argument does not apply to the particular call.
s = mlfSvd (NULL, NULL,
U = mlfSvd(&S, &V,
U = mlfSvd(&S, &V,
4- Pass any required or optional input arguments that apply to the C function, following the output arguments. Pass a NULL argument wherever an optional input argument does not apply to the particular call.
s = mlfSvd (NULL, NULL, X, NULL);
U = mlfSvd (&S, &V, X, NULL);
U = mlfSvd (&S, &V, X, Zero);
Mathematical Functions
Every mathematical functions are begin with mlf prefix. mlf is an abbreviation for MATLAB Function. Below is a list of useful mathematical functions:
mlfPlus, mlfMinus | mlfMtimes, mlfMpower | mlfAcos, mlfAsin | mlfConv |
mlfConj | mlfDec2bin, mlfDec2hex | mlfDisp | mlfFft, mlfFft2 |
mlfLinspace | mlfMax, mlfMin | mlfRoots | mlfRot90 |
For example, Conv statement in MATLAB will become mlfConv in C.
Utility Functions
We use utility functions for some tasks like printing content of a matrix or saving/loading data to/from a file. Every utility functions are begin with mx prefix. Below is a list of some utility functions:
mxCalloc, mxFree | mxCreateDoubleMatrix | mxCreateNumericArray | mxCreateString |
mxGetPi, mxGetPr | mxMalloc, mxRealloc | mxGetData, mxSetData | mxDestroyArray |
Using C Math Library
To add support of MATLAB C Math Library follow these instructions:
1- Add following line at the end of stdafx.h
#include <matlab.h>
matlab.h is interface of MATLAB APIs. Add directory of MATLAB interface files (*.h) to Visual Studio (Tools -> Options -> Directories). For example: x:/matlab/extern/include where x is drive letter of matlab path.
2- Add desired libraries to your project (In this example, libmat.lib, libmx.lib, libmatlbmx.lib and libmatlb.lib)
3- Compile your project!
Sample Program
#include "stdafx.h"
int main(int argc, char* argv[])
{
double dblArray[]={1, 2, 3, 4, 5, 6, 7, 8, 9}; mxArray *A, *B;
A=mxCreateDoubleMatrix(3, 3, mxREAL);
//copy array to matrix A
memcpy(mxGetPr(A), dblArray, 9 * sizeof(double));
A=mlfMTimes(A, A); //A=A.^2;
mlfPrintMatrix(A);
//Creating Magic Matrix
B=mlfMagic(mlfScalar(3)); //Magic matrix of order 3 mlfPrintMatrix(B); mxDestroyArray(A); mxDestroyArray(B);
return 0;
}
Requirements
1- MATLAB v5.0 or higher
2- MATLAB C Math Library Toolbox
3- Knowledge of MATLAB programming!
References
1- MATLAB C Math Library (Mathworks)
2- C Math Library Reference (Mathworks)
Enjoy!