Sign in to follow this  
Followers 0
jonny1234

If DLL creates buffer, can AutoIt access it?

12 posts in this topic

Hi,

In a DLL (written in C), there is a simple function:

EXPORT int buffer_test(char **buffer, int *buffer_size)
{

    if (*buffer)
        free(*buffer);

    *buffer = malloc(6);
    strcpy(*buffer, "HELLO\0");
    *buffer_size = strlen(*buffer);

    return(0);
}

which I call from a program (also written in C), using:

char *buffer = NULL;
int buffer_size = 0;
buffer_test(&buffer, &buffer_size);
printf("buffer:%s\n", buffer);
printf("buffer_size:%d\n", buffer_size);
if (buffer)
    free(buffer);

which displays:

buffer:HELLO

buffer_size:5

as you would expect.

Please can you tell me how to use DllCall in AutoIt to call such a DLL function. I have tried various approaches with no success. I can get AutoIt to access the returned buffer size (by passing a pointer to a structure containing an int), but can't get AutoIt to access the buffer itself. I don't know how I should be passing the buffer parameter from AutoIt in order to match the "char **" in the DLL.

Any help or advice would be much appreciated.

Regards,

Jonny

Share this post


Link to post
Share on other sites



You might want to reconsider the DLL code. You're freeing memory inside and outside the DLL, which is generally not a good thing to do. Typically, it is the responsibility of the program calling the DLL to allocate and deallocate resources. As for how to call your Dll, it would have been nice to see the AutoIt code that you've tried, but I'll take a stab in the dark to try and help you out:

Func BufferTest()
  Local $rBuffer, $pBuffer
  Local $rSize, $pSize

  $rBuffer = DllStructCreate("char[4096]")
  $pBuffer = DllStructGetPtr($rBuffer)
  $rSize = DllStructCreate("int")
  $pSize = DllStructGetPtr($rSize)

  DllCall("your.dll", "int", "buffer_test", "ptr", $pBuffer, "ptr", $pSize)

  ConsoleWrite("Buffer: " & DllStructGetData($rBuffer, 1))
  ConsoleWrite("Buffer size: " & DllStructGetData($rSize, 1))
EndFunc

No warranty on syntax as I did this off the top of my head. If you want some working examples, I do this type of thing in almost all of the Auto3Lib modules. Take a look there for some ideas.


Auto3Lib: A library of over 1200 functions for AutoIt

Share this post


Link to post
Share on other sites

Thanks for the reply.

As for how to call your Dll, it would have been nice to see the AutoIt code that you've tried

Sorry, but it was in such a mess because of all the different approaches I'd tried.

The problem is that I don't know how much data the DLL will return. Your solution assumes a maximum of 4096 characters. The DLL may return several megabytes, or it may return only a few bytes, which is why the buffer is dynamically created by the DLL.

At the moment, I can get the DLL to return the buffer pointer to AutoIt, so I'll probably use the CopyMemory API call to copy the buffer contents to memory which has been allocated by AutoIt after the call to the DLL, when AutoIt will then know the size of the buffer.

Unless there is a better approach that anyone knows of.

Regards,

Jonny

Share this post


Link to post
Share on other sites

I'll probably use the CopyMemory API call to copy the buffer contents to memory which has been allocated by AutoIt after the call to the DLL, when AutoIt will then know the size of the buffer.

I forgot to say that I would call the CopyMemory API within a new DLL function, passing the pre-allocated buffer from AutoIt.

Regards,

Jonny

Share this post


Link to post
Share on other sites

Your solution assumes a maximum of 4096 characters.

It was only an example as you didn't give me much to work with. You can change the size to the max that AutoIt will allow. See the documentation for details.

I don't want to may you angry, but let me offer you some advice. I've done a lot of work with Dlls from document management to real time machine control. Almost all of them allow you to pass a null in the buffer pointer and/or buffer size and they will return the size of the buffer that you need. You're making this thing way too complicated and it'll come back to haunt you one day if you're not careful.

My 2 cents worth. :lmao:


Auto3Lib: A library of over 1200 functions for AutoIt

Share this post


Link to post
Share on other sites

I've done a lot of work with Dlls from document management to real time machine control. Almost all of them allow you to pass a null in the buffer pointer and/or buffer size and they will return the size of the buffer that you need.

I agree, and I have written some DLL's which take a null buffer pointer on the first call and they return the buffer size, so that on the second call you can pass the right size of buffer. In the case of the DLL I'm writing, it would effectively mean executing the whole DLL function twice, as there is no quick way to find the buffer size on the first call.

So that leaves me with the other option which is to set the buffer size to AutoIt's maximum of 2 billion characters (according to the help file), which seems inefficient.

Regards,

Jonny

Share this post


Link to post
Share on other sites

So calling a DLL function twice and wasting a few hundred microseconds is less efficient than passing a 2 gigabyte string? :lmao:


Auto3Lib: A library of over 1200 functions for AutoIt

Share this post


Link to post
Share on other sites

So calling a DLL function twice and wasting a few hundred microseconds is less efficient than passing a 2 gigabyte string?

How did you manage to time my DLL function?

Regards,

Jonny

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

How did you manage to time my DLL function?

Exactly how long does it take to return the length of a buffer?

Take a machine with 512 MB of memory and allocate a 2 GB memory buffer. Then pass that memory buffer to your two Dlls that act on the entire memory space. Then tell me which one was quicker.

Edited by PaulIA

Auto3Lib: A library of over 1200 functions for AutoIt

Share this post


Link to post
Share on other sites

I haven't given you enough information, which is why our communication is losing its effectiveness.

The DLL function makes a call to a device connected to a COM port. The device returns its result in a buffer, the size of which is unknown until the device has completed the command. You know the way in which you read a certain number of characters at a time from a COM port, building up a buffer, until there are no more characters to read except the string "OK" (which means the command was successful) or "ERROR" (meaning failure)? It is this buffer that I wish to return to AutoIt.

Regards,

Jonny

P.S. I can take a telling and have no difficulty in submitting to anyone's higher knowledge. I am constantly learning how to explain myself more clearly. Please be patient.

Share this post


Link to post
Share on other sites

Ah! Now we're getting somewhere! Hey, I'm not trying to troll you or anything, just trying to give you some advice. Sometimes, when I'm neck deep in a problem, I need somebody to give me a second opinion.

If you're working with a COM port, chances are that time is on your side (code wise). If I was going at this one, I'd skip the whole Dll issue and poll the COM port in a seperate thread. Typically, you'd have a head pointer, a tail pointer and a buffer count. One thread uses the head pointer to put data in and increments the buffer count. The main thread uses the tail pointer and decrements the buffer counter. (I'm assuming you know to use some type of lock mechanism when incrementing/decrementing the buffer counter). You can share memory between the threads about a hundred different ways.

I'm thinking that the Dll solution has a lot of potential pitfalls that you're going to have to address. Especially if you're going to allocate a hunk of memory and pass it around a lot. I can't imagine that it would be faster than the above, but that's just my opinion.

Anyway, hope some of this has been helpful.


Auto3Lib: A library of over 1200 functions for AutoIt

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

I'm thinking that the Dll solution has a lot of potential pitfalls that you're going to have to address. Especially if you're going to allocate a hunk of memory and pass it around a lot. I can't imagine that it would be faster than the above, but that's just my opinion.

Anyway, hope some of this has been helpful.

Yes, it has been helpful. Thanks. It has made me realise that there is no need to return the buffer to AutoIt; instead, the DLL can just analyze the buffer locally, and return an appropriate message to AutoIt based on the buffer contents. This should turn out to be adequate (and much simpler).

But I will keep your threading option in mind as I may need it in future.

Thanks for your time.

Regards,

Jonny

Edited by jonny1234

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0