Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Passing C++ strings by reference
#1
Hi,

Please, I don't know how to pass a string variable from C++ to QM. Any help?

Regards
#2
When QM macro calls dll function?
#3
Yes, when QM calls a dll function. I've tried char* and char*& with no results.

With other type of data, no problem.
#4
What strings the dll uses - ANSI or Unicode? If char*, it is ANSI. It's better to use Unicode strings, because ANSI string encoding does not match QM string encoding in Unicode mode (UTF-8), and then dll should know QM encoding and give correct string.
#5
Oh thanks!.

Do you mind to post a little example of how to pass a variable string from a dll function?

Thanks in advance.
#6
Can do like most Windows API functions, eg GetWindowText.
If using Unicode strings, easier is to allocate and return BSTR, eg with SysAllocString.
With ANSI strings not so easy.
#7
i'll take a look at it later. Thanks.
#8
Code:
Copy      Help
#include <oleauto.h>
extern "C" __declspec(dllexport)
BSTR ReturnBSTR()
{
return SysAllocString(L"string");
}

Macro Macro1993
Code:
Copy      Help
dll "mydll" BSTR'ReturnBSTR

str s
s=ReturnBSTR
out s
#9
It worked very well. Thanks for your reply.

Is it possible to pass arrays of strings and arrays of int/double data?
#10
How the array is initially stored in the C++ function?
#11
Something like this:

Macro Macro205
Code:
Copy      Help
ARRAY(double) arr.create(10)

arr[0]=2.00154
...

dll "$desktop$\myDLL.dll" double'myfunc

out myfunc(&arr)

Safe arrays of n elements, 1 or 2 dimensions...
#12
Done for int/double:

Macro Macro205
Code:
Copy      Help
dll "myDLL" double'myfunc

ARRAY(double) arr.create(5)

arr[0]=1.0001
;...

double result=myfunc(&arr[0], arr.len)

out result


C++
Code:
Copy      Help
extern "C" __declspec(dllexport) double myfunc(double *pointerElement0, int arrlen);

double myfunc(double *pointerElement0, int arrlen)
{
,double result=0;
,
,for (int i = 0; i < arrlen; i++)
,{
,,result+=pointerElement0[i]; // ;; example
,}

return result;
}

Any ideas on how to receive an array of int or str?
#13
Macro Macro2009
Code:
Copy      Help
dll "..." !myfunc ARRAY(BSTR)a

ARRAY(BSTR) b.create(5)
out myfunc(b)
ARRAY(str) a.create(b.len); for(_i 0 a.len) a[_i]=b[_i] ;;tip: create function for this
out a

extern "C" __declspec(dllexport)
bool myfunc(SAFEARRAY* a) //ARRAY(BSTR)
{
if(!a || !(a->fFeatures&FADF_BSTR) || a->cDims!=1 || a->rgsabound[0].lLbound || a->cLocks) return 0;
BSTR* p=(BSTR*)a->pvData, *pe=p+a->rgsabound[0].cElements;
for(; p<pe; p++) *p=SysAllocString(L"test");
return true;
}

It is possible to make calling the function simpler. For example, set a callback function that allocates array and converts BSTR to str. Then caller will not have to do it.
#14
Hi again.

Thanks for your help on this topic. I love QM for fast development and I use some dll in C in the main QM program when performance is crucial.
If you don't mind, I would need some further help in this area. I know that is out of the scope of this forum but maybe it will also useful for some QM fellows.

My question is for resizing the safearray after populated. I have checked the MS docs about safearray resize, but there are no examples and with so many pointers I am a little lost.

I have used tricks like tokens and checked in QM, but it is not very elegant. In QM we use 'redim' but how to resize the safearray from C++ before to return to QM? Any examples, please?

Thanks in advance for your help.
#15
C++
Code:
Copy      Help
#include <oleauto.h>
typedef SAFEARRAY* ARRAY; //QM ARRAY in C++ is SAFEARRAY*

//Creates or resizes 1-dim ARRAY.
//vt - array type VT_ constant. VT_I4 for int, VT_BSTR for BSTR, etc. Used only when creating.
//Sets added elements to 0/empty. Frees removed elements if need (BSTR, VARIANT etc).
extern "C" __declspec(dllexport)
HRESULT ResizeSafeArray(ARRAY& a, int n, int vt)
{
,HRESULT hr;
,SAFEARRAYBOUND b={n};
,//int nOld=0;
,if(a) //resize
,{
,,//nOld=a->rgsabound[0].cElements;
,,if(hr=SafeArrayRedim(a, &b)) return hr;
,}
,else //create
,{
,,a=SafeArrayCreate(vt, 1, &b);
,,if(!a) return E_OUTOFMEMORY;
,}

,return 0;
}

QM
Macro Macro2114
Code:
Copy      Help
dll "test.dll" #ResizeSafeArray ARRAY*a n vt

ARRAY(int) a
if(ResizeSafeArray(&a 3 VT_INT)) end "error"
for(_i 0 a.len) a[_i]=_i
if(ResizeSafeArray(&a 4 VT_INT)) end "error"
for(_i 0 a.len) out a[_i]

ARRAY(BSTR) b
if(ResizeSafeArray(&b 3 VT_BSTR)) end "error"
for(_i 0 b.len) b[_i]=F"string {_i}"
if(ResizeSafeArray(&b 4 VT_BSTR)) end "error"
for(_i 0 b.len) out b[_i]
#16
Thank you! I spent hours trying to deal with this!
This piece of code is really useful and expands the QM capabilities to new frontiers.

Thanks again and have a nice day!
#17
Good morning!

Any help on how to use SAFEARRAY with 2 dimensions in C++, please?

Thanks

Gintaras Wrote:Macro Macro2009
Code:
Copy      Help
dll "..." !myfunc ARRAY(BSTR)a

ARRAY(BSTR) b.create(5)
out myfunc(b)
ARRAY(str) a.create(b.len); for(_i 0 a.len) a[_i]=b[_i] ;;tip: create function for this
out a

extern "C" __declspec(dllexport)
bool myfunc(SAFEARRAY* a) //ARRAY(BSTR)
{
if(!a || !(a->fFeatures&FADF_BSTR) || a->cDims!=1 || a->rgsabound[0].lLbound || a->cLocks) return 0;
BSTR* p=(BSTR*)a->pvData, *pe=p+a->rgsabound[0].cElements;
for(; p<pe; p++) *p=SysAllocString(L"test");
return true;
}

It is possible to make calling the function simpler. For example, set a callback function that allocates array and converts BSTR to str. Then caller will not have to do it.
#18
a->cDims will be 2.
And there will be a->rgsabound[0] and a->rgsabound[1]. They define each dimension. Maybe swapped, ie 0 is the second dimension, 1 is the first, don't remember.
Then pe=p+a->rgsabound[0].cElements*rgsabound[1].cElements.
All elements are in the single memory block p that is only logically divided into dimensions.
#19
Wow! Confusedhock:

It works fine! Thanks for your help.
Best regards.


Forum Jump:


Users browsing this thread: 1 Guest(s)