2016-07-01 26 views
0

クロスプラットフォームwxWidgetsでWin64とLinuxの両方に展開するVisual Studio 2013 CommunityでWin64で開発する。私はlibcurlのを使用して、C++で次curl.exeコマンドラインをエミュレートしようとしています:libcurlをC++でポストすると、コールバックパラメータが不要になる

curl.exe -X POST -g "single-url-string" 

これは、エンドユーザーが自分のデバイスを制御するために、単一のURL文字列を提供するアプリ、ののIoT機能のためであります。このロジックが外部プロセスとしてcurl.exeを実行するだけではない理由は、このロジックが独自のスレッドで実行され、wxWidgetsがメインスレッド外で外部実行ファイルを起動することをサポートしていないためです。

通常、curl.exeでPOSTを実行すると、投稿データがオプションとして提供されます。これはcurl.exeに、指定されたURLへのPOST操作であることを伝えます。ここにはそのPOSTのデータがあります。ご覧のとおり、私がしようとしているのはGETスタイルのURL(URLに埋め込まれたパラメータを使用)ですが、操作をPOSTに変更することです。これは、エンドユーザーに2つの別々のURLとデータ文字列を提供するように求めるだけでは複雑すぎるという調査結果が示されているため、このように行われています。だから、私たちはこの簡単なシングルストリングを思いつきました。エンドユーザは、通常、ストリングを解釈することなくデバイスマニュアルからストリングをコピーするだけで、別々の意味のあるストリングに分割することはほとんどありません。

私は単純なC++のlibcurl POSTルーチンを2つのバージョンで用意していますが、どちらのバージョンでも、書き込みコールバックで受け取ったパラメータが悪いです。 2つのバージョンは、1つのURL文字列を持つPOSTと、POST文字列の別のオプションとして提供されたPOSTデータです。

問題は、1)シングルストリングバージョンを使用してPOSTを実行せず、書き込みコールバックパラメータが不良です。 2)2つの文字列バージョンを使用するとPOSTが実行されますが、書き込みコールバックパラメータは異なる方法で悪いです。

両方のバージョンで書き込みコールバックのデータポインタパラメータがメモリアドレス1を指している場合、sizeパラメータは両方のバージョンで良好に表示されますが、nmembパラメータは巨大なランダム値(単一文字列バージョン)またはゼロPOSTバージョン)。

私のコードはありますが、私はcurl_global_init()をapp startで呼び出します。

size_t CX_IOT_THREAD::curl_write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) 
{ 
    // storage for transferred data: 
    const int dataStoreSize = CURL_MAX_WRITE_SIZE + 1; 
    char dataStore[dataStoreSize]; 
    memset(dataStore, 0, dataStoreSize); // zeroed out 

    size_t dataSize = size * nmemb; // bytes sent 

    if (dataSize) 
    { 
    memcpy(dataStore, ptr, dataSize); // copy into buffer sized so we'll have a terminating NULL char 

    wxString msg = wxString::Format(wxT("%s"), dataStore); // send as event, eventually to the log 
    mp_queue->Report(CX_IOTTHR_CMD_ACCESS_JOB, msg); 

    // must return byte count processed for libcurl to be happy: 
    return dataSize; /**/ 
    } 

return size; // should be dataSize, but because nmemb is bad, I’m using size; it works. 
} 

cx_int CX_IOT_THREAD::Post(std::string& url) 
{ 
    if (url.length() == 0) 
    return -1; 

    char errBuf[CURL_ERROR_SIZE]; 
    errBuf[0] = '\0'; 
    static const char *postthis = "name=Bloke&age=67"; 

    CURLcode ret; 
    CURL *hnd = curl_easy_init(); 
    curl_easy_setopt(hnd, CURLOPT_URL, url.c_str()); 
    curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, postthis); 
    curl_easy_setopt(hnd, CURLOPT_POSTFIELDSIZE, (long)strlen(postthis)); 
    curl_easy_setopt(hnd, CURLOPT_ERRORBUFFER, errBuf); 
    curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, &CX_IOT_THREAD::curl_write_callback); 
    curl_easy_setopt(hnd, CURLOPT_WRITEDATA, NULL); 
    curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L); 
    curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.49.1"); 
    curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); 
// curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST"); 
    ret = curl_easy_perform(hnd); 
    curl_easy_cleanup(hnd); 

    if (ret != CURLE_OK) 
    { 
     wxString msg = wxString::Format(wxT("Attempted POST failed, libcurl return code '%d'."), (cx_int)ret); 
     mp_queue->Report(CX_IOTTHR_CMD_ACCESS_JOB, msg, (cx_int)ret); 

     cx_int len = strlen(errBuf); 
     if (len > 0) 
     msg = wxString::Format("%s%s", errBuf, ((errBuf[len - 1] != '\n') ? "\n" : "")); 
     else msg = wxString::Format("%s\n", curl_easy_strerror(ret)); 
     mp_queue->Report(CX_IOTTHR_CMD_ACCESS_JOB, msg, (cx_int)ret); 
    } 
    return (cx_int)ret; 
} 

書き込みコールバックパラメータが悪い理由は何ですか?なぜ単一の文字列のバージョンは投稿をしないか? (1つの文字列のバージョンは上記の2つのPOSTFIELDSオプションがコメントアウトされ、CUSTOMREQUESTが有効になっています)。

+1

'curl_write_callback'は、万が一非静的メンバー関数ですか?それは飛ばないだろう。それは、静的メンバーまたは自由な関数である必要があります。あなたが見ているのは、すべてのパラメータが1つ上にシフトされていることです(あなたの関数が 'this'を期待し、カールがそれを渡さないので):1は' size'に入り、 'size'にある良い値は' nmemb' 。 –

+0

@IgorTandetnikそれはそれでした!あなたは今日私の神です。ありがとうございました! –

答えて

0

Igor Tandetnik氏に指摘するように、コールバックは静的でなければなりません。

+0

or ... [コールバックにC++非静的関数を使用する](https://curl.haxx.se/docs/faq.html#Using_C_non_static_functions_f) –

関連する問題