George Kamel
2009-11-17 18:22:02 UTC
Hi,
I am having a problem in passing a SAFEARRAY of BSTRs from a C++ DLL to a VB
2008 application. I am able to pass an array of doubles without any issue.
However, coming to a SAFEARRAY, it does not seem to be passing anything back,
i.e. the array in VB remains empty after calling the C++ function.
This is the code of the DLL that I am using, which compiles okay and is
called without returning any errors:
extern "C" int __declspec(dllexport) __stdcall DLLTestFunction(SAFEARRAY*
Label, double* Value);
int __stdcall DLLTestFunction(SAFEARRAY* Label, double* Value)
{
USES_CONVERSION;
char buffer[20] = {""}; // used to store ANSI string
HRESULT hr = S_OK;
SAFEARRAYBOUND aDim[1];
aDim[0].lLbound = 0; // Visual Basic arrays start with index 0
aDim[0].cElements = 20; // Number of SAFEARRAY elements to create
Label = SafeArrayCreate(VT_VARIANT, 1, aDim); // Create SAFEARRAY
if (Label != NULL)
{
long aLong[1];
// iterate over array adding VARIANTs of type VT_BSTR
for (unsigned long i = aDim[0].lLbound ; i < (aDim[0].cElements +
aDim[0].lLbound) ; i++)
{
VARIANT vOut; // Create VARIANT and
VariantInit(&vOut); // initialise it and
vOut.vt = VT_BSTR; // set its type
strcpy_s(buffer, "SomeText"); // Load buffer with text to copy to
SAFEARRAY
vOut.bstrVal = ::SysAllocString(A2BSTR(buffer)); // system wide "new"
aLong[0] = i; // set index value
if (hr = SafeArrayPutElement(Label, aLong, &vOut)) // copy VARIANT to
SAFEARRAY
{
VariantClear(&vOut); // release BSTR from memory on error
SafeArrayDestroy(Label); // does a deep destroy on error
return 1; // return non-zero value
}
VariantClear(&vOut); // does a deep destroy of source VARIANT
Value[i] = i; // Set Value array to for loop index
} // end iteration
}
return 0;
}
I have tested the C++ code by itself within a main() function, initialising
the SAFEARRAY at the beginning:
SAFEARRAY *Label;
and by the end of the function, I am getting the SAFEARRAY filled as
expected. So the problem seems to be in passing the array back to VB.
The following is the code that I am using to call the code from within VB:
<DllImport("MyDLL.dll")> _
Public Function DLLTestFunction( _
<MarshalAs(UnmanagedType.SafeArray,
SafeArraySubType:=VarEnum.VT_BSTR)> _
ByRef Label() As String, _
ByRef Value As Double) As Integer
End Function
Dim Label(0 To 19) As String
Dim Value(0 To 19) As Double
Dim RetVal As Integer
RetVal = DLLTestFunction(Label, Value(0))
As the C++ code runs fine by itself, I think the problem must be in the way
I am calling the function in VB, or in the C++ DLL function header.
Any help to resolve this would be greatly appreciated.
George
I am having a problem in passing a SAFEARRAY of BSTRs from a C++ DLL to a VB
2008 application. I am able to pass an array of doubles without any issue.
However, coming to a SAFEARRAY, it does not seem to be passing anything back,
i.e. the array in VB remains empty after calling the C++ function.
This is the code of the DLL that I am using, which compiles okay and is
called without returning any errors:
extern "C" int __declspec(dllexport) __stdcall DLLTestFunction(SAFEARRAY*
Label, double* Value);
int __stdcall DLLTestFunction(SAFEARRAY* Label, double* Value)
{
USES_CONVERSION;
char buffer[20] = {""}; // used to store ANSI string
HRESULT hr = S_OK;
SAFEARRAYBOUND aDim[1];
aDim[0].lLbound = 0; // Visual Basic arrays start with index 0
aDim[0].cElements = 20; // Number of SAFEARRAY elements to create
Label = SafeArrayCreate(VT_VARIANT, 1, aDim); // Create SAFEARRAY
if (Label != NULL)
{
long aLong[1];
// iterate over array adding VARIANTs of type VT_BSTR
for (unsigned long i = aDim[0].lLbound ; i < (aDim[0].cElements +
aDim[0].lLbound) ; i++)
{
VARIANT vOut; // Create VARIANT and
VariantInit(&vOut); // initialise it and
vOut.vt = VT_BSTR; // set its type
strcpy_s(buffer, "SomeText"); // Load buffer with text to copy to
SAFEARRAY
vOut.bstrVal = ::SysAllocString(A2BSTR(buffer)); // system wide "new"
aLong[0] = i; // set index value
if (hr = SafeArrayPutElement(Label, aLong, &vOut)) // copy VARIANT to
SAFEARRAY
{
VariantClear(&vOut); // release BSTR from memory on error
SafeArrayDestroy(Label); // does a deep destroy on error
return 1; // return non-zero value
}
VariantClear(&vOut); // does a deep destroy of source VARIANT
Value[i] = i; // Set Value array to for loop index
} // end iteration
}
return 0;
}
I have tested the C++ code by itself within a main() function, initialising
the SAFEARRAY at the beginning:
SAFEARRAY *Label;
and by the end of the function, I am getting the SAFEARRAY filled as
expected. So the problem seems to be in passing the array back to VB.
The following is the code that I am using to call the code from within VB:
<DllImport("MyDLL.dll")> _
Public Function DLLTestFunction( _
<MarshalAs(UnmanagedType.SafeArray,
SafeArraySubType:=VarEnum.VT_BSTR)> _
ByRef Label() As String, _
ByRef Value As Double) As Integer
End Function
Dim Label(0 To 19) As String
Dim Value(0 To 19) As Double
Dim RetVal As Integer
RetVal = DLLTestFunction(Label, Value(0))
As the C++ code runs fine by itself, I think the problem must be in the way
I am calling the function in VB, or in the C++ DLL function header.
Any help to resolve this would be greatly appreciated.
George