Shoutbox

DLL return value - Printable Version

-Shoutbox (https://shoutbox.menthix.net)
+-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58)
+--- Forum: Messenger Plus! for Live Messenger (/forumdisplay.php?fid=4)
+---- Forum: Scripting (/forumdisplay.php?fid=39)
+----- Thread: DLL return value (/showthread.php?tid=70004)

DLL return value by deAd on 12-28-2006 at 07:54 PM

I have a C++ DLL and I'd like to return an array of data. It is stored in a vector inside the DLL, but I don't know how to return it so it can be used in JScript.

Also, how do I make the function exports undecorated so I can just put the undecorated name of the function in the Function parameter of Interop.Call() ?
Solved, thanks J-Thread!


RE: Calling a DLL (two questions) by J-Thread on 12-28-2006 at 08:59 PM

I am not sure about the first one, but for the second one you should create a .def file containing something like:

code:
LIBRARY    YourModuleName

EXPORTS
                Function1
                Function2

RE: Calling a DLL (two questions) by deAd on 12-28-2006 at 09:02 PM

Should I remove the "__declspec(dllexport)" definitions?
EDIT: It seems they don't make a difference with the exports.def file. Thanks!!

I still can't return an array of values *-)...


RE: DLL return value by CookieRevised on 12-29-2006 at 09:57 AM

Like you use Interop.Call with Windows API's, you need to allocate some memory space in your script first (Interop.Allocate).

Then, in the script, you call the function in the DLL and you provide the pointer to that allocated space as a parameter. In your DLL you write whatever stuff you want to that pointer.

And make sure you don't exceed the available space! This can be done by providing a size parameter in the script when you call the function. Or write the size in the first x bytes (as much as you need, eg: 4 bytes, thus as a DWORD) of the allocated space. Both methods also used in many Windows APIs.

The data you write to that pointer can be whatever you want. It is how you handle and interpret that data in the script what makes sense of it.


RE: DLL return value by deAd on 12-29-2006 at 04:28 PM

What if you don't know how much space you need? I could create another function that returns a DWORD telling how much space you'd need but it's possible that this value could change between calls (not likely though, as there wouldn't be much of a time gap :P)...


RE: DLL return value by CookieRevised on 12-29-2006 at 05:12 PM

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()