0

Just as the question says. I would like to be able to make an array of strings in some VBA code, in this code I would like to make them a certain length. Then how would I pass them into a C++ DLL, in the DLL I would like to store a string in each element and make these elements accessible from the VBA afterwords. I have already done this for a single string, and for a double array as follows.

Dim myStr As String * sizeConst

Dim dataArray() As Double
ReDim dataArray(0 To (arrayLength - 1)) As Double

Then passing them to a DLL from within the VBA.

Public Declare Function myFunc _
Lib "PathToDLL.dll" _
(myStr As String, ByVal sizeConst As Integer, dataArray As Double, ByVal arrayLength As Long) As Long

Then in the DLL I can step through each element in the double array. However I don't know how to do this for a string array. I am unsure about the actual memory size of the strings I would be passing in from the VBA would they be of size sizeConst + 1? I need to know this to know how much I should increment to get to the next string element. Can someone show me how to declare a string array in VBA with a constant length for each element. Then how to pass that array to the DLL and how to increment to the next element in the string array in the DLL.

5
  • Thank you for down-voting my answer. If the answer for the question: "how to create an array of string of fixed size" does not met your criteria, you have to be more specific and provide proper details about your issue. Commented Jun 20, 2017 at 6:36
  • @MaciejLos The important part is "Then how would I pass them into a C++ DLL". See stackoverflow.com/questions/44396538/… for more context. Commented Jun 20, 2017 at 7:02
  • @GSerg, This is the second part of question. I provided this information: Note that your dll expects as an input **myStr As String**, not an array of strings, because of function declaration. The trick is the skill to ask a question! Commented Jun 20, 2017 at 7:58
  • @MaciejLos It is a common practice in VBA to declare the API parameter as "byref something" and then pass arr(lbound(arr)). Then the called site will have access to the entire array. Commented Jun 20, 2017 at 8:02
  • Maciej Los If you are talking to me about down-voting your answer, It was not me, I do not even have enough reputation to do so as I am new to stackOverflow. Thank you once again GSerg, and thank you for trying to help Maciej Los it was appreciated. Commented Jun 20, 2017 at 23:31

1 Answer 1

2

When you declare arr() as string in a Declared function, VB will send out an LPSAFEARRAY* (a double pointer, SAFEARRAY**) consisting of BSTRs (FADF_BSTR | FADF_HAVEVARTYPE). That is, the conversion to LPSTR will not be performed.

On the C++ side you would declare the parameter as LPSAFEARRAY* and use the SafeArray* family of functions to manipulate the data.

Note that you are responsible for freeing BSTRs you are going to replace, if you are going to replace them.

You will get all the information about the array size and dimensions from the LPSAFEARRAY, and each BSTR stores its string length.


Same happens when you declare arr() as string * some_length, but this time the SAFEARRAY will be of FADF_HAVEVARTYPE only, and SafeArrayGetVartype will return VT_ERROR. Each element of the safe array will be a preallocated blob of some_length wide chars (some_length * 2 bytes), with no zero terminator or string length stored separately. Arguably it's even easier to work with, because it's preallocated, you can simply fill the existing memory of each element.


If you were to use mere strings, without fixed length, you could also pass them in the same way you are passing the pointer to double:

declare function myFunc ... (byval strings as longptr, byval count as long)
dim s() as string
redim s(1 to 5)

myFunc varptr(s(lbound(s))), ubound(s) - lbound(s) + 1

Then on the C++ side you would receive BSTR* of the first string, and to advance to the next string you would add 1 to it like you would normally do with pointer math. You need to pass number of elements as a separate parameter to know how many strings there are.

This will not work for fixed-length strings.

Sign up to request clarification or add additional context in comments.

10 Comments

Thanks GSerg. I think I will simply use the non-fixed length example. how come the type on the c++ side would be LPWSTR rather than a pointer to the first BSTR, wouldn't there be extra memory from the other BSTR elements (the memory that stores the size) that I would have to dodge?
I want to stress again, how thankful I am of the help you are providing me in my previous post and this one as well.
@AlexWardlow I'm used to calling it LPWSTR because that's what happens most of the time on the C++ side. Yes, the pointers will be BSTR* too. You won't need to dodge anything because this is how BSTR is designed and because the string data (as opposed to string pointers) is not stored in a continuous block of memory one after another.
If I do not have *# to define length how big will they be. Len(s) displays 0. Will I have to do some allocation on the DLL side? Currently it crashes. Same with original code with a single string without the *# to define length. So I assume it is a memory allocation issue right?
@AlexWardlow The usual scenario is that the DLL has access to the converted string buffer provided by the compiler, so it has to use whatever space the string already has. If you don't preallocate string on the VB side you will have no space. You can go with this approach and preallocate on VB side. If you like you also can allocate BSTRs on the DLL side, just be sure to do it properly (msdn.microsoft.com/en-us/library/windows/desktop/…, msdn.microsoft.com/en-us/library/windows/desktop/… etc).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.