A while back I started working on a wrapper for the
libcurl easy interface. (libcurl is the DLL version of
cURL.) I got it pretty much done, except there is an error while doing a form POST that I couldn't nail down. I'm posting it here because it still has a lot of uses even without the ability to POST, and because someone taking a fresh look at it might be able to spot my mistake.
I based it upon olfen's libcurl example.
Here is the libcurl documentation: http://curl.haxx.se/libcurl/c/
Downloads:
libcurl.ahk - The wrapper include file.
libcurl.dll - Win32 libcurl 7.18.1 without SSL. (latest version on 5/20/2008)
libcurl.dll - Win32 libcurl 7.18.1 with SSL. Requires
SSL libraries.
libcurl_test.ahk - olfen's test script running through the wrapper.
libcurl_imageshacktest.ahk - A modified test script that posts to imageshack. (erroneous)
The test scripts require
FileHelper.ahk.
Functions:
The functions use the global variables CurlDllName and hCurlModule. Be sure not to overwrite them.
CurlGlobalInit( Location = "", flags = 3 )
You must call this first. It loads the DLL and returns
curl_global_init( flags ) or -1 if the DLL failed to load. (0 = Success) Location is the path to libcurl and the file name minus ".dll". If Location is omitted, it defaults to "libcurl". It stores the name in a global variable so the other functions will know it.
Code:
;Flags:
;CURL_GLOBAL_SSL = 1
;CURL_GLOBAL_WIN32 = 2
;CURL_GLOBAL_ALL = 3
;CURL_GLOBAL_NOTHING = 0
;CURL_GLOBAL_DEFAULT = 3
CurlGlobalInit( "Common\libcurl" )
CurlGlobalInit( "", 2 ) ; CURL_GLOBAL_WIN32
CurlGlobalInit( "libcurl-4", 0 )
CurlFreeLibrary()This frees the libcurl DLL. All handles and pointers created by libcurl will be invalidated and libcurl will become unusable until CurlGlobalInit() is called again.
CurlEasyInit()Returns
curl_easy_init().
CurlEasyReset( EasyHandle )Calls
curl_easy_reset( EasyHandle ).
CurlEasyCleanup( EasyHandle )Calls
curl_easy_cleanup( EasyHandle ).
CurlShowErrors( Yes = true )If set to true, causes some of the wrapper functions to display libcurl string errors in message boxes.
CurlEasySetOption( EasyHandle, Option, Parameter )If Parameter is an integer it returns
curl_easy_setopt( EasyHandle, Option, Parameter ). Otherwise, it returns
curl_easy_setopt( EasyHandle, Option, &Parameter ).
You can use CurlEasyDefineOptions() to define the CURLOPT options as variables for easier use of this function.
CurlSlistAppend( ByRef pSlist, String )Calls
curl_slist_append( pSlist, String ) and sets pSlist to the returned value.
CurlSlistFreeAll( ByRef pSlist )Calls
curl_slist_free_all( pSlist ) and sets pSlist to 0.
CurlFormAdd( ByRef pFirstItem, ByRef pLastItem, Option1, Value1, Option2 = 0, Value2 = 0, ........, Option8 = 0, Value8 = 0 )Returns
curl_formadd( &pFirstItem, &pLastItem, Option1, Value1, Option2, Value2, ........, Option8, Value8 ). Non-numeric strings are automatically handled correctly. Numeric strings or user-inputted strings should be passed as an address (& operator). If this is the first call and is supposed to initialize the form, you should set pFirstItem and pLastItem to 0 prior to calling this function.
You can use CurlEasyDefineOptions() to define the CURLFORM options as variables for easier use of this function.
Note: curl_formadd() is not limited to 8 options. Writing more options into this function and increasing the string conversion loop will allow more.CurlFormFree( pFirstItem )Calls
curl_formfree( pFirstItem ).
CurlEasyPerform( EasyHandle )Returns
curl_easy_perform( EasyHandle ).
CurlEasyGetinfo( EasyHandle, Information )Returns the output of
curl_easy_getinfo( EasyHandle, Information, Ouput ). The function automatically manages the interpretation of the output.
CurlEasyStrError( ErrorCode )Returns
curl_easy_strerror( ErrorCode ).
CurlEasyEscape( EasyHandle, URL )Returns
curl_easy_escape( EasyHandle, URL ) through CurlFreeGet().
CurlEasyUnescape( EasyHandle, URL )Returns
curl_easy_unescape( EasyHandle, URL ) through CurlFreeGet().
CurlVersion()Returns
curl_version().
CurlFreeGet( pString )Some libcurl functions that return a string say that you should use curl_free() to delete it when you're done with it. This function copies the string at the address specified in pString, calls
curl_free( pString ), and returns the copy. It is used internally by other wrapper functions.
MergeDouble( l, h )Merges the low and high parts of a "Double" together and returns it. Useful for CURLOPT_PROGRESSFUNCTION.
CurlGetInfoType( Information )Returns the data type of a CURLINFO option. It is used internally by other wrapper functions.
CurlGetInfoDefine( All = true )Defines variables to match the CURLINFO C constants. If All is false, it will only define the data types.
CurlEasyGetOptionType( Option )Returns the CURLOPTTYPE of a CURLOPT option.
CurlEasyDefineOptions( All = true )Defines variables to match the CURLOPTTYPE C constants and CURL_ERROR_SIZE. If All is true, it will also define the CURLFORM and CURLOPT constants.
Error Details:libcurl gives error #27 "Out of memory" with the message "failed creating formpost data." With some debugging, I was able to trace the failure point in the libcurl code.
In
libcurl_imageshacktest.ahk libcurl fails in the internal function Curl_getFormData when it hits this:
Code:
result = AddFormDataf(&form, &size, "\"");
if (result)
break;
(Near line 1150 in formdata.c)
It seems to be passing in a huge value for size, which causes the memory allocation error inside of it. I also recall seeing a string filled with binary.
This apparently indicates that there's a bad pointer somewhere, but I wasn't able to find anything in my code.
Converting from cURL to libcurl
cURL provides the option "
--libcurl" which will write out the equivalent libcurl C code.
Quote:
--libcurl <file>
Append this option to any ordinary curl command line, and you will get a libcurl-using source code written to the file that does the equivalent operation of what your command line operation does!
NOTE: this does not properly support -F and the sending of multipart formposts, so in those cases the output program will be missing necessary calls to curl_formadd(3), and possibly more.
If this option is used several times, the last given file name will be used. (Added in 7.16.1)
You can either use the resulting code as a reference for using the AHK wrapper or convert the code and use the program as-is.