PDA

View Full Version : Moving memory location into QString



ebelcher
8th November 2016, 04:58
In my QT project, I'm accessing a DLL which acts as a bridge between my application and another platform. I note first of all that currently all is working very well!

I have one piece of code that requires me to include some of the standard Windows dlls in my build, and I'd like to get rid of them by using native QT code. The code is below.


QString GlobalSettings::mql4_ansi2unicode(quintptr _ptrStringMemory)
{
int szString=0;
uchar *ucValue=NULL;

if (_ptrStringMemory == 0)
{
return ("");
}
else
{
szString = lstrlenA((LPCSTR)_ptrStringMemory);

ucValue = new uchar[szString+1];
for (int i=0; i< szString+1; i++) // Allow for Null
ucValue[i]=0;

RtlMoveMemory((void *)ucValue, (void *)_ptrStringMemory, szString + 1);
QString strptr((const char *)ucValue);
delete [] ucValue;
LocalFree((HLOCAL)_ptrStringMemory);
return (strptr);
}
}


An example of how this code is used is as follows.


QString Bridge::Test()
{
quintptr Testptr=0;

typedef int (__stdcall *MyPrototype)();
MyPrototype myFunction =
(MyPrototype) QLibrary::resolve("NFX.Trading.Panel.Bridge.dll", "Test");
if (myFunction)
Testptr = myFunction();
return(globalclass.mql4_ansi2unicode(Testptr));
}


The function in the DLL returns a string. I need to check the string to see if I'm communicating with the bridge DLL okay.
While I understand in general what the mql4_ansi2unicode function is doing, I don't know how to do the same thing in QT.

Can anyone help?
Thanks

d_stranz
9th November 2016, 01:24
Isn't this exactly the same question you asked 3 months ago here (http://www.qtcentre.org/archive/index.php/t-66494.html)? Or are you now asking how to get rid of the call to mql4_ansi2unicode() by replacing it with something purely Qt?

This code implies that _ptrStringMemory points to a NULL-terminated C-string (because it is cast to a LPCSTR), but yet the code allocates an unsigned character array, wastes time filling it with zeros, and then replaces those zeros by copying the string into it using RtlMoveMemory. This new unsigned character array is then used to construct a QString but lies to the QString constructor by telling it the unsigned character array argument is really a signed char * pointer argument.

If _ptrStringMemory is really just a char * pointer (LPCSTR), then just create a QString using the pointer as the constructor argument and return that. No need for all the allocating and copying.

However, it still looks like _ptrStringMemory is allocated before it is passed to your function, so you will still need to call LocalFree() to avoid a memory leak. Perhaps you could replace this with a call to free() but who knows if Windows and C# will like that.

ebelcher
9th November 2016, 02:23
Thanks for the reply,

It is a similar question that I asked a while back yes, but that issue was solved. I'm now trying to get rid of mql4_ansi2unicode() entirely. The QT application is calling a function in a C# dll that has all it's exports exported as CallingConvention.StdCall.


[DllExport("Test", CallingConvention = CallingConvention.StdCall)]
public static string Test()
{
string sMessage = "The quick brown fox jumps over the lazy dog.";

return (sMessage);
}


In my calling code the function is typedef'd as

typedef int (__stdcall *MyPrototype)();


So, the dll function assigns a block of memory and passes the address back (in the form of an int) which I then need to read and then free. Sounds simple enough, and if I was working in C, I could see how to do it. However, doing as you suggest ' just create a QString using the pointer as the constructor argument and return that' hasn't worked until now. I just realised in my first atempt some time back, I wasn't casting the pointer properly.

One last thing. The function mql4_ansi2unicode is used in the other end of the application chain (non QT, but C++) for the following reason.

//| Lovely function that helps us to get ANSI strings from DLLs to our UNICODE format
//| http://forum.mql4.com/60708

As the DLL is written using MC C# and uses type 'string' which is now Unicode and QString is also Unicode by default, I'm assuming that I don't actually need to worry about what this function was originally trying to achieve?

Thanks for your help. I'll see if I have success eliminating mql4_ansi2unicode entriely.
Much appreciated.

d_stranz
9th November 2016, 16:53
Yes, QString is unicode by default, so you should be able to just assign the string.

Why do you declare your function prototype as returning "int"? Why not declare it as char * (or more likely wchar_t *) since that's what is really being returned?

Finally, the string is -not- being allocated in the DLL, so there should be no need to free it on your side. If anything is being allocated on the DLL side, it should be cleaned up by C# during its normal garbage collection. If you do try to free it, it will probably cause stack corruption if not an immediate crash.