quote:
Originally posted by deAd
What if you don't know how much space you need?
As I explained in the MSN chat, by creating the data in the first function and storing it until the second function has been called. Or by creating the data with the first call and with a specific set of parameters (eg: everything 0, except the buffersize) and storing it until a second call is done with a valid buffer as one of the parameters.
Look at the Windows APIs which can return variable sized data...
They either consist of actually two APIs, where you first need to call the first API to get the size of the returned data, and then call the second API to get the actual data.
Or it is 1 function which you need to call twice. The first time with all the parameters being null, except the buffersize parameter. And the second time with a pointer to the actual buffer.
Many times, in the second call they return the length of the written data too. So you, as a caller, can check if how much has been written to the buffer (the returned datalength is non zero).
See the registry APIs for example: RegQueryValue which works in exact the same way.
Another example, and a slightly different method, but with the same principles (a large enough buffersize must be given, or yuo need to call the function twice to recieve the appropiate buffersize) is done by RegQueryMultipleValues. This API works with an array btw.
Also, in your DLL, make sure you first check the size of the actual allocated memory space by the caller. In this check, the given buffersize is of no matter, you need to check the allocated memory size against the size it would require to write all your data to the memory. This is very mandatory so that you don't write beyond the memory space available to your function.
^^ and if you do this properly, you can even make it that the caller must only call your function once, on the condition that the buffer is large enough so the function can directly write all the data to the buffer. If the buffer is not large enough, still write data to the buffer (until the end) and set the return value of your function to ERROR_MORE_DATA or something.
thus, for example the user can do:
// This will allocate the exact amount of needed memory
var BufferSize = 0
var ReturnValue = Interop.Call("your.dll", yourfunc, 0, BufferSize)
var Buffer = Interop.Allocate(BufferSize)
var ReturnValue = Interop.Call("your.dll", yourfunc, Buffer.DataPtr, BufferSize)
ReturnValue is 0
Buffer is filled with
BufferSize bytes of data
BufferSize is the amount of data bytes in the buffer
or
// This will allocate more memory than needed
var BufferSize = 4096
var Buffer = Interop.Allocate(BufferSize)
var ReturnValue = Interop.Call("your.dll", yourfunc, Buffer.DataPtr, BufferSize)
ReturnValue is 0
Buffer is filled with x bytes of data
BufferSize is the amount of data bytes in the buffer (thus x)
or
// This will allocate too little memory
var BufferSize = 10
var Buffer = Interop.Allocate(BufferSize)
var ReturnValue = Interop.Call("your.dll", yourfunc, Buffer.DataPtr, BufferSize)
ReturnValue is ERROR_MORE_DATA
Buffer is filled with 10 bytes of data
BufferSize contains the actual needed bytes
PS: as a sidenote, many people use those registry APIs (or any other API which requires a big enough buffer by the user) in the wrong way. Many calll such APIs with a fixed buffersize and do not first retrieve the appropiate buffersize. And they even less check if the returned buffer and returned size is non zero to see if the buffer wasn't too small...
------------------------------------------------------------------------------------------
A total other approach you can take, and much easier for you to program (I think) is to use a
VBArray aka
SafeArray as return value of your function. Provided C++ knows this kind of data type of course, dunno (but it should though).
var vbArray = new VBArray(Interop.Call("your.dll", yourfunc))
var jsArray = vbArray.toArray()