MATLAB Answers

0

How to pass a string (LPSTR) command to my C++ function?

Peter Foerster さんによって質問されました 2018 年 11 月 13 日
最新アクティビティ Guillaume
さんによって 編集されました 2018 年 11 月 14 日
Hello all,
I have a C++-dll, which I have loaded with loadlibrary. I can also list the functions in the dll, which tells me that the call is
[int16, int8Ptr] = wsaSetSCPI(int64 (handle), int8Ptr (command))
command is basically a SCPI command string that I need to pass in and never see again. My call looks like this
command = 'INPUT:MODE SH';
[error, command] = calllib('wsaInterface', 'wsaSetSCPI', hndl, command)
It returns:
Error using calllib
Array must be numeric or logical or a pointer to one
‘ or “ does not make a difference here. I also tried converting it around a bit, but didn’t find the right way to pass it. I believe that when using the ‘ ‘ notation, it is passed as a char array, so essentially a int8 array. In the C++ dll the command parameter is defined as LPSTR.
What surprises me, is that MATLAB does not seem to mind the LPSTR, because in another function call I can pass an empty, preallocated char array by reference and get back reasonable responses written into it. If anything, I would expect problems with that.
Can you please point me in the right direction on how to pass the command on to my function?

  1 件のコメント

An addendum:
I have now gotten rid of the error message, but the function call still does not execute smoothly. Apparently I have to typecast from char to Int8:
[length, getSCPIresponse] = calllib('wsaInterface', 'wsaGetSCPI_s', hndl, uint8('*IDN?'), getSCPIresponse)
However, the command still does not seem to be passed correctly, as I don't get the right response. I know this command works, because I can test it in other applications.

サインイン to comment.

製品


リリース

R2018b

2 件の回答

回答者: Philip Borghesani 2018 年 11 月 14 日
編集済み: Philip Borghesani 2018 年 11 月 14 日
 採用された回答

There are two ways to work around this and you almost got it.
Option 1: When casting from a char to a uint8 type in matlab to pass as a string you must manualy add the NULL :
[uint8('*IDN?') 0] %concatinate a null on onto end of string
Option two: Fix the function decleration so that MATLAB will accept a character array as input. There are two ways to do this: You can create a modified header file using char * or other type that matlab will translate to a cstring or you can create a loader file with the mfilename option to loadlibrary and manualy modify that as needed.
For a quick fix I recommend option 1. If you want to simplify the process and make other fixes I suggest a custom loader file.

  3 件のコメント

Peter Foerster 2018 年 11 月 14 日
This is it, thank you so much!
The sad part about this is that it was one of the first things I thought about when I ran into the problem. I tried using the char representation and asigning it to a variable with an added 0, e.g.:
cmd = [42 73 68 78 63 0]
For some reason that did not work, so I thought that can't be it.
Option 1 it is for now.
Philip Borghesani 2018 年 11 月 14 日
The cause of confusion here is that c (prior to c99) only has char and unsigned char types that are used for both bytes and strings so loadlibrary has to guess based on wether the value is const, and other typedefs name clues, if the value is intended to be a string or array of bytes. It sometimes gets this wrong.
Guillaume
2018 年 11 月 14 日
Option 1 it is for now.
To me it looks like all your problem stem from the fact that the function signature is badly defined at the C++, as I've written in my latest comment to my answer.
If matlab interprets |LPSTR | as int8Ptr that's because it is typedef'd as such in your header. LPSTR should be typedef'd to char*.
And since your pointer are to non-const, matlab also has to create extra return values because your function says: I can modify the pointee. So really, your LPSTR should be LPCSTR typedef'd as const char*.
Note that in C++, char and int8_t are two different types in C++. In particular, while int8_t is signed, there's no guarantee that char is (it's implementation defined).
So option 2 might be to just fix your function declarations at the C++ level.

サインイン to comment.


Guillaume
Answer by Guillaume
on 13 Nov 2018

I think you need to go back through the documentation of the function that you're using. I would never expect to have to pass a string to a function that ask for a int8Ptr, particularly since it's implementation-defined in C++ whether plain char is signed or unsigned (whereas int8 is signed) so a cast from char to int8 may not even be valid. int8Ptr and LPSTR are really not the same types.
It seems to me your function expects an array of signed bytes which you can get in matlab using the function int8 (not uint8) but I expect matlab to do the cast itself when you pass a numerical array to the function.

  4 件のコメント

Guillaume
2018 年 11 月 14 日
I'm very confused. In your question you talk about wsaSetSCPI with signature
[int16, int8Ptr] = wsaSetSCPI(int64 (handle), int8Ptr (command))
But now you talk about wsaGetSCPI_s. They're not the same functions and don't have the same signature at all.
Which of the two functions is causing problem?
You should pass a char vector (1xn) (or a scalar string since R2016b) to a function that expects LPSTR pointers. You should pass a numerical array (possibly as int8 if matlab doesn't autoconvert it) to a function that expects a int8Ptr, .
edit: Also, I just realised that none of your functions are expecting pointers to const. Do the functions actually modify the pointed to values? Is the dll actually written in C++ or in C?
Thanks for your answer and sorry for the confusion! I made a mistake in copying the lines. This happened because, I have 3 similar functions with similar problems:
[int16, int8Ptr] = wsaSetSCPI(int64 (handle), int8Ptr (command))
[lib.pointer, int8Ptr] = wsaGetSCPI(int64 (handle), int8Ptr (command))
[int16, int8Ptr, int8Ptr] = wsaGetSCPI_s(int64 (handle), int8Ptr (command), int8Ptr (response))
wsaGetSCPI_s was created, because we had some trouble with the LPStr return type in wsaGetSCPI. All of these functions are causing problems, but I assume that they have the same solution.
When calling wsaSetSCPI with a command, I know has to work, I get an error that it couldn't set the property. At least it's an error number from the dll.
When calling wsaGetSCPI, I get back a libpointer and the string I put in, but when I try to get(libpointer) I get an error:
Error using lib.pointer/get
The datatype and size of the value must be defined before the value can be retrieved.
When calling wsaGetSCPI_s, I get back an error from the dll, telling me that the query returns no response. The response array contains the command string(converted to int8) I put in.
When calling it with the *IDN? command, get back the correct length of the response, but the response itself contains *IDN?
The dll is written in C++ and even though the command strings are not defined as const, the commands do not have to be modified. Do you think it is worth defining a function that accepts const *char for the command?
As I said above, I have an ErrorMessage function, that can accept an array argument and write the error string into it as an LPStr just fine.
Guillaume
2018 年 11 月 14 日
I would think that the lib.pointer issue is different from your dll errors issue.
What is the actual C++ signature of the 3 functions? And what are you giving to loadlibrary for matlab to find the signature? The C++ header file? A proto file? It's very puzzling that matlab translate LPSTR into Int8Ptr but that would be all down to what you're telling loadlibrary.
If your functions do not modify the inputs, then really they should be defined as pointers to const. On the C++ side, it will enable some compiler optimisations. For matlab it will make a major difference in the function signature. The reason you've got all these int8Ptr as outputs of your functions is because the pointers are non-const. For matlab, a pointer to const is the same as passing by value, so it's very straight-forward. A pointer to non-const is pass-by-reference so matlab needs to put extra machinery in place to translate that to pass-by-value of the matlab world.
Since you're the author of the dll, can't you attach a debugger to matlab to see what actual value the dll receives?

サインイン to comment.



Translated by