How do I get a C++ structure 'behind' a libpointer?

14 vues (au cours des 30 derniers jours)
Lasse B.
Lasse B. le 19 Déc 2011
Hi there
I'm using an old 7.5.0/R2007b version of Matlab, and I'm experiencing a problem when reading structures created by an external C++ function.
I'm calling the function
struct_new* GetStruct_new(uint16 const val);
via loadlibrary and calllib. I'm also using a prototype file to circumvent a packing problem I had some months ago.
The structure is declared as follows in C++ code:
typedef struct
{
float32 u16_Upper;
float32 u16_Lower;
float32* pf32_Parameters;
}
match_s;
typedef struct
{
uint16 u16_Start;
uint16 u16_End;
match_s* ps_1st_Match;
match_s* ps_2nd_Match;
}
results_s;
typedef struct
{
uint16 u16_Depth;
uint16 u16_Width;
uint16 u16_Height;
uint16* pu16_InData;
uint16* pu16_OutData;
results_s s_Results[256];
uint8 bla[256];
uint8* blubb[256];
}
struct_new;
...and in the prototype file:
structs.match_s.packing=4;
structs.match_s.members=struct('u16_ED_Upper', 'single', 'u16_ED_Lower', 'single', 'pf32_ED_Parameters', 'singlePtr');
structs.results_s.packing=4;
structs.results_s.members=struct('u16_Start', 'uint16', 'u16_End', 'uint16', 'ps_1st_Match', 'match_sPtr', 'ps_2nd_Match', 'match_sPtr');
structs.struct_new.packing=4;
structs.struct_new.members=struct('u16_Depth', 'uint16', 'u16_Width', 'uint16', 'u16_Height', 'uint16', 'pu16_InData', 'uint16Ptr', 'pu16_OutData', 'uint16Ptr', 's_Results', 'results_s#256', 'bla', 'uint8#256', 'blubb', 'uint8Ptr#256');
In Matlab I do the following:
>> addpath ('\\projects\Binford\KX-2500\')
>> loadlibrary ('KX_drives.dll', @KX-2500, 'alias', 'KX');
>> params = calllib('KX', 'GetStruct_new', 11);
>> par = get(params, 'Value');
>> par.s_Results
ans =
libpointer
This libpointer is my problem, as I have no clue how to resolve it into an array of s_Result structures and read/write them. I've searched the documentation, but I wasn't able to find something that could help me on this one; most exapmles were about creating pointers, not the opposite way.
Thanks in advance!

Réponse acceptée

Philip Borghesani
Philip Borghesani le 13 Mar 2012
Given:
structs.struct_new.members=struct('u16_Depth', 'uint16', 'u16_Width', 'uint16', 'u16_Height', 'uint16', 'pu16_InData', 'uint16Ptr', 'pu16_OutData', 'uint16Ptr', 's_Results', 'results_s#256', 'bla', 'uint8#256', 'blubb', 'uint8Ptr#256');
I expect you are getting some warnings when you call loadlibrary. Loadlibrary cannot properly process 'results_s#256' or 'uint8Ptr#256 your options are to redeclare these fields as a vector of a basic data type or change your structure.
For structures this complex you may be better off with a mex file or writing a helper dll that can access the structure and return its members or pointers to the desired members.
  1 commentaire
Lasse B.
Lasse B. le 19 Mar 2012
I didn't get a warning (or maybe it was suppressed).
Anyway, I decided to go the way you proposed and wrote a helper/wrapper dll. Seems to work now.
Thanks for your help (all three of you).

Connectez-vous pour commenter.

Plus de réponses (3)

Ampere Kui
Ampere Kui le 19 Fév 2012
You will need to cast the data into something that Matlab can understand.
addpath ('\\projects\Binford\KX-2500\')
loadlibrary ('KX_drives.dll', @KX-2500, 'alias', 'KX');
params = calllib('KX', 'GetStruct_new', 11);
par = get(params, 'Value');
tmp = par.s_Results;
% Assuming setdatatype works on variable tmp.
setdatatype(tmp, 'uint8Ptr');
% The struct s_Results has the following data structure:
% 2 bytes
% 2 bytes
% 4 bytes memory address (8 bytes if you are on 64-bit system)
% 4 bytes memory address (8 bytes if you are on 64-bit system)
m = getfield(libstruct('results_s'), structsize);
bytes = numel(tmp.value);
n = bytes /m;
% Resize the output so that each column corresponds to one structure.
v = reshape(tmp.value, m, n);
% Obtain all the u16_Start and u16_End variables. Note that you won't be able to get libpointer to ps_1st_Match and ps_wnd_Match this way.
toVector = @(x) x(:);
u16_Start = typecast(toVector(v(1:2,:)), 'uint16');
u16_End = typecast(toVector(v(3:4,:)), 'uint16');
Alternately, you can copy each column into a libstruct of type results_s to obtain the entire structure. If you have a function foo() that returns a pointer to one results_s structure, then you can try this:
% Copy one column of data from v to the libpointer from foo().
s = calllib('KX', 'foo');
setdatatype(s, 'uint8Ptr');
s.value = v(:,1);
setdatatype(s, 'results_sPtr');
% The structure in the first cell of the array:
disp(s.value);

Kaustubha Govind
Kaustubha Govind le 19 Déc 2011
Do you get anything useful by trying:
par.s_Results.Value;

Lasse B.
Lasse B. le 13 Mar 2012
Hi again,
sorry for the delay.
Kaustubha Govind wrote
> Do you get anything useful by trying:
> par.s_Results.Value;
Unfortunately, no. All I get is an error message:
??? The datatype and size of the value must be defined before the value can be retrieved.
Ampere Kui wrote
You will need to cast the data into something that Matlab can understand.
I tried your example, but it didn't work either. The line
bytes = numel(tmp.value);
produced the same error message as above. Since the datatype is set to 'uint8Ptr' (I checked this) the size is the likely problem source.
Still, since I theoretically know the dimensions of my structure, I tried to go on with
v = reshape(tmp.value, 12, 256);
which yielded the same error message once more.
Any more ideas?

Catégories

En savoir plus sur Call C from MATLAB dans Help Center et File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by