Passing pointer argument in MATLAB to a C-DLL function foo(char**)

情到浓时终转凉″ 提交于 2019-11-28 11:29:22
Amro

The answer is to build a pointer to a c-string using the LIBPOINTER function as @JonasHeidelberg suggested. Let me expand his solution with a working example..

First lets build a simple DLL:

version.h

#ifndef VERSION_H
#define VERSION_H

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
#   ifdef BUILDING_DLL
#       define DLL_IMPORT_EXPORT __declspec(dllexport)
#   else
#       define DLL_IMPORT_EXPORT __declspec(dllimport)
#   endif
#else
#   define DLL_IMPORT_EXPORT
#endif

DLL_IMPORT_EXPORT void myGetVersion(char**str);

#ifdef __cplusplus
}
#endif

#endif

version.c

#include "version.h"
#include <string.h>

DLL_IMPORT_EXPORT void myGetVersion(char **str)
{
    *str = strdup("1.0.0");
}

You can use your preferred compiler to build the DLL library (Visual Studio, MinGW GCC, ..). I am using MinGW to compile the above, here is the makefile I am using:

Makefile

CC = gcc

all: main

libversion.dll: version.c
    $(CC) -DBUILDING_DLL version.c -I. -shared -o libversion.dll

main: libversion.dll main.c
    $(CC) main.c -o main -L. -lversion

clean:
    rm -rf *.o *.dll *.exe

Before we move to MATLAB, lets test the library with a C program:

main.c

#include <stdio.h>
#include <stdlib.h>
#include "version.h"

int main()
{
    char *str = NULL;
    myGetVersion(&str);
    printf("%s\n", str);
    free(str);

    return 0;
}

Now that all is working, here is how to use this library from MATLAB:

testDLL.m

%# load DLL and check exported functions
loadlibrary libversion.dll version.h
assert( libisloaded('libversion') )
libfunctions libversion -full

%# pass c-string by reference
pstr = libpointer('stringPtrPtr',{''}); %# we use a cellarray of strings
get(pstr)
calllib('libversion','myGetVersion',pstr)
dllVersion = pstr.Value{1}

%# unload DLL
unloadlibrary libversion

The output with the string returned:

Functions in library libversion:
stringPtrPtr myGetVersion(stringPtrPtr)

       Value: {''}
    DataType: 'stringPtrPtr'

dllVersion =
1.0.0

Looking at Working with pointers, section Passing an Array of Strings in the MATLAB documentation (linked from the help page you linked in your question), it seems you need to construct a libpointer object in MATLAB, something like

version = libpointer('stringPtrPtr',{''}); %# corrected according to Amro's comment
calllib('yourCdll', 'myGetVersion', version)

(I don't have a DLL to test this with right now, and I'm not very firm on C pointers, so no guarantee... hope this is a step in the right direction)

I could not get @Amro's solution to work (old version of MATLAB?). So, I had to do something a little more creative:

pstr = libpointer('voidPtr');
ret = calllib('libversion', 'myGetVersion', pstr);
% establish the length
n = 0;
while n==0 || pstr.Value(n) ~= 0
    n=n+1;
    pstr.setdatatype('uint8Ptr', 1, n);
end
% truncate to exclude the NULL character
pstr.setdatatype('uint8Ptr', 1, n-1);
% convert to string
display(char(pstr.Value))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!