-
cURL class
I'm building a worker class that should download stuff, via cURL.
however, cURL has some oddities in it (using my functions to buffer and send progress, etc) and i'm far from understanding classes and pointers right.
Basically, one of the options requires access to one of my functions (pointer), and it passes it what it downloaded. I'll have to do the rest, like writing it to a file, displaying or processing the data.
It works fine as a 'standard' program, but I have no idea how i should make cURL access a class function. I've tried a few workarounds, but my program crashed everytime.
Basically,
Code:
class pw
{
public:
int state;
string target;
string file;
string contents;
int progress;
pw();
private:
CURL *curl;
CURLcode result;
int gauge;
string buffer;
char errorBuffer[CURL_ERROR_SIZE];
//functions
int progressUpdater(int* gauge, double dltotal, double dlnow, double ultotal, double ulnow);
int writer(char *data, size_t size, size_t nmemb, std::string *buffer);
};
..and somewhere in the constructor:
Code:
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writer);
I need the last parameter to point individual instance function "writer".
I've tried:
&pw::writer
this->writer
&writer
this->writer
None works. How can I do it?
-
I was having similar problems before when I was pointing it to a member function. I'm not certain but now that I think about it if you make it static it might work. Alternatively just have the function outside the class like I did.
Also, I believe that the prototyle for writer has parameters: void*, size_t, size_t and void* ... it might have problems with explicitly pointing it to a char* and std::string. Not certain about that though. If it does you can just typecast and such, but
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, function_name ) should work ...
-
Hmm, that seems to work. However, now I can't get curl to execute. whenever i run curl_easy_perform, the program crashes.
And I can't declare the CURL object anything else but a pointer in the class :/ damn, this is weird and i stopped understanding why i'm doing any corrections.
Code:
int pw::exec()
{
// Set URL
curl_easy_setopt(pw::curl, CURLOPT_URL, &pw::target);
std::cout << "1\n"; //code crashes after this point
// Attempt to retrieve the remote page
CURLcode temp;
temp = curl_easy_perform(pw::curl); // i believe it crashes here. I can't seem to access the curl object anyhow.
std::cout << "2\n"; //code crashes before this point
// Always cleanup
curl_easy_cleanup(pw::curl);
std::cout << "3\n";
// Did we succeed?
if (pw::result == CURLE_OK)
{
std::cout << buffer;
}
else
{
std::cout << "Error: [" << result << "] - " << errorBuffer;
}
}
-
Right. Well take out all the pw::'s. They aren't necessary. You have CURLcode already. Just assign the of curl_easy_perform to result.
Code:
int pw::exec()
{
// Set URL
curl_easy_setopt(curl, CURLOPT_URL, &target);
std::cout << "1\n"; //code crashes after this point
// Attempt to retrieve the remote page
result = curl_easy_perform(curl); // i believe it crashes here. I can't seem to access the curl object anyhow.
std::cout << "2\n"; //code crashes before this point
// Did we succeed?
if (result == CURLE_OK)
{
std::cout << buffer;
}
else
{
std::cout << "Error: [" << result << "] - " << errorBuffer;
}
}
Also, you should cleanup in the destrutor.
-
Well you need to get a 'this' pointer from somewhere, since cURL knows nothing about C++.
Code:
#include <iostream>
#include <string>
class foo {
std::string me;
public:
foo ( std::string ident ) : me(ident) { }
static void wrapper ( void *thisptr ) { /* must be static, to stop implicit 'this' param */
foo *instance = static_cast<foo*>(thisptr);
instance->func();
}
void func ( void ) {
std::cout << "WooHoo " << me << std::endl;
}
};
static void *curlinst;
void curlSetInst ( void *p ) {
curlinst = p;
}
void curlcb ( void ) {
/* Invoke the static class member function */
/* Use the saved 'this' pointer as the parameter */
/* to allow the wrapper to invoke the actual member function */
/* with the correct this pointer. */
foo::wrapper( curlinst );
}
int main ( ) {
foo var("howdy");
curlSetInst( &var ); /* see CURLOPT_WRITEDATA */
curlcb();
return 0;
}
> int writer(char *data, size_t size, size_t nmemb, std::string *buffer);
Nope, the last param will be a void*, not a std::string.
Use the above to make data represent your 'this' function, from which you'll be able to get the rest of your class data.
-
is there an easier way to get around this? I've been experimenting with the above class for several hours and i haven't really understood anything. my c skills suck.
-
Well you're trying to mix C and C++, and calling C++ code from C takes some doing.
Post more of your latest code.
-
I haven't made any new code on my project, I've been trying to understand yours :) But it's too complex for me, i guess.
Is there an easy to use C++ curl wrapper? I've found curlpp, but it's too complex.
-
Generally, making object oriented interfaces for some complex functionality (curl isn't trivial, at least) makes for complex interface classes. It may be possible to hide a lot of the funcitonality behind the scenes if the functionality you need is restricted to a small subset of the library you are interfacing to, but you can't just hide all that functionality completely and still expect it to automatically know what you want to do and how.
The callback functionality you are after is a common scenario for Windows C++ programming (since the Windows API makes use of callbacks for plenty of things), and the solution is to make a static wrapper that gets the class pointer from a void pointer, like Salem shows.
If you want C to understand classes, you need C++, and libraries or APIs that aren't written in/for C++ won't do that...
--
Mats
-
There is the curlpp project ... http://curl.haxx.se/libcurl/cplusplus/ I've never used it now so I don't know how it works or if it's any good ... As far as I know it's just wrapping code but it should work ...