problem dealing with unicode in mexFunction

I made a mexfunction to find the Hwnd of a window if its wiindow title matches a string. This was done by using a mexFunction "getWinHwnd.cc". E.g., After mex 'getWinHwnd', in matlab call getWinHwnd('untitled - notepad.exe') will get the hwnd number of a window: untitled - notepad.exe .
The problem is that if the window title has non-ascii unicode characters, the hwndNew = FindWindow(NULL,TEXT(windowNameBuf)) failed. I do not know where is the problem. Thanks in advance.
#include <windows.h>
#include "mex.h"
// The gateway routine
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
// Input argument is a buffer to hold the window name
mxArray *Reply = NULL;
char *windowNameBuf;
mwSize buflen1;
const mxArray *string_array_ptr1 = prhs[0];
buflen1 = mxGetNumberOfElements(string_array_ptr1) + 1;
windowNameBuf = (char *) mxCalloc(buflen1, sizeof(char));
mxGetString(string_array_ptr1, windowNameBuf, buflen1);
// Call the C subroutine.
HWND hwndNew = FindWindow(NULL,TEXT(windowNameBuf));
Reply = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);
*(uint64_T *) mxGetData(Reply) = (uint64_T) hwndNew;
plhs[0] = Reply;
}

 Accepted Answer

Solved. Using mxArrayToString.

10 Comments

FYI, the mxArrayToString result is not on the garbage collection list. You will need to manually mxFree it when you are done to prevent a memory leak.
Dear Tursa, I got the following info from mxFree, it says that mxArrayToString dose not need to mxFree:
By default, memory parcels created by mxCalloc, mxMalloc, mxRealloc, mxArrayToString, and mxArrayToUTF8String are nonpersistent. The memory management facility automatically frees all nonpersistent memory whenever a MEX file completes. Thus, even if you do not call mxFree, MATLAB takes care of freeing the memory for you. Nevertheless, it is good programming practice to deallocate memory when you are through using it. Doing so generally makes the entire system run more efficiently.
Dear Tursa, the mexFunction runs well, but if there are more than one windows with same title exist, only the last active window was returned. Is there a way to return all the windows handle numbers matching that title? Thanks.
"... mxArrayToString dose not need to mxFree ..."
I will have to look into that tomorrow morning. If true, then it is a fairly recent change to this API function (and would satisfy what I have asked TMW to do many, many years ago).
OK, I did some checking and yes the doc you mention is correct for current versions. The result from mxArrayToString (and presumably mxArrayToUTF8String) are nonpersistent and are on the garbage collection list. This is good news to me. The change apparently occurred with the R2017a release. E.g.,
Using this mex routine:
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
char *cp;
if( nrhs && mxIsChar(prhs[0]) ) {
cp = mxArrayToString(prhs[0]); /* allocate but don't free it */
}
}
R2016b: (massive increase in Memory used by MATLAB)
>> version
ans =
9.1.0.441655 (R2016b)
>> mex mxArrayToString.c
Building with 'Microsoft Visual C++ 2013 Professional (C)'.
MEX completed successfully.
>> c = repmat('a',1,100000000);
>> memory
Maximum possible array: 54637 MB (5.729e+10 bytes) *
Memory available for all arrays: 54637 MB (5.729e+10 bytes) *
Memory used by MATLAB: 1291 MB (1.354e+09 bytes)
Physical Memory (RAM): 32690 MB (3.428e+10 bytes)
* Limited by System Memory (physical + swap file) available.
>> for k=1:100; mxArrayToString(c); end
>> memory
Maximum possible array: 45713 MB (4.793e+10 bytes) *
Memory available for all arrays: 45713 MB (4.793e+10 bytes) *
Memory used by MATLAB: 10830 MB (1.136e+10 bytes)
Physical Memory (RAM): 32690 MB (3.428e+10 bytes)
* Limited by System Memory (physical + swap file) available.
R2017a: (no significant increase in Memory used by MATLAB)
>> version
ans =
'9.2.0.556344 (R2017a)'
>> mex mxArrayToString.c
Building with 'Microsoft Windows SDK 7.1 (C)'.
MEX completed successfully.
>> c = repmat('a',1,100000000);
>> memory
Maximum possible array: 54632 MB (5.729e+10 bytes) *
Memory available for all arrays: 54632 MB (5.729e+10 bytes) *
Memory used by MATLAB: 1366 MB (1.432e+09 bytes)
Physical Memory (RAM): 32690 MB (3.428e+10 bytes)
* Limited by System Memory (physical + swap file) available.
>> for k=1:100; mxArrayToString(c); end
>> memory
Maximum possible array: 54675 MB (5.733e+10 bytes) *
Memory available for all arrays: 54675 MB (5.733e+10 bytes) *
Memory used by MATLAB: 1375 MB (1.442e+09 bytes)
Physical Memory (RAM): 32690 MB (3.428e+10 bytes)
* Limited by System Memory (physical + swap file) available.
Thanks for pointing this out to me! I will need to update my MATLAB version notes.
I use Matlab 2016a, and the doc from 2016a already says no need meFree. I was wondering how the R2016b example looks as if it did not free memory itself since it comes later than R2016a.
Run the code I showed above on your machine to confirm if your version leaks memory or not. I suspect it does and your doc is wrong, but you can run the code yourself to confirm.
Here is the R2016a results:
>> version
ans =
9.0.0.370719 (R2016a)
>> mex mxArrayToString.c
Building with 'MinGW64 Compiler (C)'.
MEX completed successfully.
>> c = repmat('a',1,100000000);
>> memory
Maximum possible array: 54545 MB (5.719e+10 bytes) *
Memory available for all arrays: 54545 MB (5.719e+10 bytes) *
Memory used by MATLAB: 1212 MB (1.271e+09 bytes)
Physical Memory (RAM): 32690 MB (3.428e+10 bytes)
* Limited by System Memory (physical + swap file) available.
>> for k=1:100; mxArrayToString(c); end
>> memory
Maximum possible array: 45208 MB (4.740e+10 bytes) *
Memory available for all arrays: 45208 MB (4.740e+10 bytes) *
Memory used by MATLAB: 10755 MB (1.128e+10 bytes)
Physical Memory (RAM): 32690 MB (3.428e+10 bytes)
* Limited by System Memory (physical + swap file) available.
So, as I suspected, your doc is wrong. mxArrayToString and mxArrayToUTF8String memory allocations are persistent, they are not on the garbage collection list, and they will leak memory if you don't manually mxFree it. Regardless of what the doc says, I believe all MATLAB versions R2016b and earlier behave this way.
Yes,I tried and found you are right. The doc is different from what I have seen.
>> version
ans =
9.0.0.341360 (R2016a)
>> mex mxArrayToString.c
Building with 'Microsoft Visual C++ 2010 (C)'.
MEX completed successfully.
>> c = repmat('a',1,100000000);
>> memory
Maximum possible array: 7256 MB (7.609e+09 bytes) *
Memory available for all arrays: 7256 MB (7.609e+09 bytes) *
Memory used by MATLAB: 1795 MB (1.882e+09 bytes)
Physical Memory (RAM): 8097 MB (8.490e+09 bytes)
* Limited by System Memory (physical + swap file) available.
>> for k=1:10; mxArrayToString(c); end
>> memory
Maximum possible array: 6396 MB (6.706e+09 bytes) *
Memory available for all arrays: 6396 MB (6.706e+09 bytes) *
Memory used by MATLAB: 2748 MB (2.881e+09 bytes)
Physical Memory (RAM): 8097 MB (8.490e+09 bytes)
* Limited by System Memory (physical + swap file) available.
>> memory
Maximum possible array: 6400 MB (6.711e+09 bytes) *
Memory available for all arrays: 6400 MB (6.711e+09 bytes) *
Memory used by MATLAB: 2748 MB (2.881e+09 bytes)
Physical Memory (RAM): 8097 MB (8.490e+09 bytes)
* Limited by System Memory (physical + swap file) available.
Below is the c code I adapted from other source. As I have never right c code before, could you help me on how to mexFree the mxArrayToString(string_array_ptr1)? Is there a need to state a variable for it in the beginning? Since the string is unicode from matlab, so the size of buffer for that string does not match the real size of unicode string, I cannot found a way to state it. Also, since the string_array_ptr1 is only a small string of dozens of bytes and called only a few times, will that memory leak cause a big broblem to the matlab? Thanks.
#include <windows.h>
#include "mex.h"
#include "matrix.h" //?
// The gateway routine
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
// Input argument is a buffer to hold the window name
mxArray *Reply = NULL;
char *windowNameBuf;
mwSize buflen1;
const mxArray *string_array_ptr1 = prhs[0];
buflen1 = mxGetNumberOfElements(string_array_ptr1) + 1;
windowNameBuf = (char *) mxCalloc(buflen1, sizeof(char));
mxGetString(string_array_ptr1, windowNameBuf, buflen1); //?
// Call the C subroutine.
// mxGetString: only with characters represented in single-byte encoding schemes. For characters represented in multibyte encoding schemes, use the C function mxArrayToString.
// mxArrayToString is similar to mxGetString, except that:
// It does not require the length of the string as an input.
// It supports both multi-byte and single-byte encoded characters. On Windows&reg; and Linux&reg; platforms, the user locale setting specifies the default encoding.
// HWND hwndNew = FindWindow(NULL,TEXT(windowNameBuf));
HWND hwndNew = FindWindow(NULL,mxArrayToString(string_array_ptr1));
Reply = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);
*(uint64_T *) mxGetData(Reply) = (uint64_T) hwndNew;
plhs[0] = Reply;
I made it this way, and mex was no problem:
char *str;
str = mxArrayToString(string_array_ptr1);
HWND hwndNew = FindWindow(NULL,str);
mxFree(str);

Sign in to comment.

More Answers (0)

Categories

Asked:

on 14 Aug 2018

Commented:

on 18 Aug 2018

Community Treasure Hunt

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

Start Hunting!