Работаем в сети с помощью libcurl
В этой статье я бы хотел осветить вопросы взаимодействия с Web и Ftp серверами в C++ программе.
Никто не запрещает программировать сокеты и самостоятельно реализовывать протоколы. Но зачем изобретать велосипед, когда существует готовое, отлаженное и мощное решение, способное удовлетворить практически любые Ваши потребности? Речь идет о библиотеке libcurl. Это простая в использовании, кроссплатформенная (поддерживаются Linux, Windows, Solaris, Qnx, FreeBSD, OpenBsd, MacOS X и многие другие) клиентская библиотека, позволяющая работать с протоколами FTP, FTPS, HTTP, HTTPS, SCP, SFTP, TFTP, TELNET, DICT, LDAP, LDAPS and FILE. Поддерживаются SSL сертефикаты, HTTP POST, HTTP PUT, FTP закачка, HTTP закачка, прокси-сервера, куки, аутентификация, восстановление закачки файла, тунелирование http proxy и многое другое. Libcurl имеет завязки на множество языков программирования, среди которых: C, C++, Java, Lisp, PHP, Ruby, Perl, Pascal, Haskell.
И самое главное — библиотека полностью свободна, как для некоммерческого, так и для коммерческого применения.
Разумеется, перед тем, как начать использование библиотеку — ее нужно получить, установить и дать возможность, своему компилятору, использовать ее. Рассмотрим выполнение этих действий, как обычно на примере двух платформ: Linux и Windows.
В случае Linux — все довольно просто, Вам необходимо скачать http://curl.haxx.se/download/curl-7.16.2.zip
В этом архиве содержиться полный исходный код библиотеки, скрипты сборки, а так же полная документация API и примеры (поэтому пользователям Windows так же не помешает скачать себе этот архив)
После распаковки — необходимо выполнить стандартную процедуру компиляции и установки, с помощью configure и make && make install. Это все, можно пользоваться возможностями библиотеки.
Для компиляции программы, следуюет добавлять к опциям компилятора
pkg-config --libs libcurl
pkg-config --cflags libcurl
либо
curl-config --libs libcurl
curl-config --cflags libcurl
В случае Windows — немного сложнее.
Вам необходимо скачать http://my.guardpuppy.com/libcurl-7.1…zlib-1.2.3.zip
Распаковать следующие файлы в указанные места:
libcurl.dll — распаковать в %SystemDrive%\%SystemRoot%\System32
libeay32.dll — распаковать в %SystemDrive%\%SystemRoot%\System32
ssleay32.dll — распаковать в %SystemDrive%\%SystemRoot%\System32
zlib1.dll — распаковать в %SystemDrive%\%SystemRoot%\System32
Если Вы используете Visual Studio 98, то libcurl_imp.lib распаковать в %SystemDrive%\Program Files\Microsoft Visual Studio\VC98\Lib
Если Вы используете VisualStudio 2005 и новее, то libcurl_imp.lib распаковать в %SystemDrive%\Program Files\Microsoft Visual Studio 9.0\VC\lib
Распаковать содержимое каталога include полность:
Если Вы используете Visual Studio 98, то распаковать в %SystemDrive%\Program Files\Microsoft Visual Studio\VC98\Include
Если Вы используете VisualStudio 2005 и новее, то libcurl_imp.lib распаковать в %SystemDrive%\Program Files\Microsoft Visual Studio 9.0\VC\Include
Следует обратить внимание, что перед компиляцией проекта, во всех версиях Visual Studio, необходимо зайти в параметры проекта, перейти в раздел опций линковщика (linking), выбрать из выпадающего списка группу input и в появившийся список подключаемых, при компиляции, библиотек добавить, в самом конце, libcurl_imp.lib
Так же в архиве содержится консольная утилита curl.exe, позволяющая использовать все возможности библиотеки, в командном режиме.
Теперь все готово и можно приступать к рассмотрению библиотеки и написанию кода.
Libcurl имеет два режима работы: так называемый простой интерфейс (The Easy interface) и многопоточный интерфейс (The multi interface).
Для использования библиотеки необходимо подключить заголовочный файл curl.h
#include <curl/curl.h>
Доступ к функциям библиотеки осущствляеются после открытия новой easy сессии и получения управляющего интерфейса типа CURL. Без открытия сессии — вызывать какие либо фукнции запрещено. Для выполнения всех этих действий служит функция curl_easy_init(), она выполняет инициализацию библиотеки, открытие сессии и возвращает объект типа CURL или же NULL, в случае, когда что-то пошло не так.
CURL *curl; //объект типа CURL
curl = curl_easy_init(); //инициализация
if(curl) //обязательная проверка
{
//выполнение всех дальнейших действий с библиотекой
}
Далее необходимо задать опции сессии, такие как URL, с которым мы собираемся работать, прокси сервер (если он есть), функции обратного вызова (о них ниже) и т.п.
Задание опций осуществляется с помощью функции curl_easy_setopt.
Рассмотрим ее объявление и параметры:
CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);
CURL *handle — указатель на интерфейс, который мы получили выше.
CURLoption option — название опции, которую следует задать.
parameter — параметр, который связывается с опцией, это может быть число, указатель на функцию, строка. Функцию можно вызывать несколько раз подряд, задавая необходимые опции. Все опции, по умолчанию, выключены.
Рассмотрим наиболее интересные и используемые опции, а так же их параметры.
CURLOPT_HEADER — применяется при работе с HTTP, ненулевое значение параметра заставляет библиотеку отображать заголовок в теле запрошенной страницы.
CURLOPT_WRITEFUNCTION — данная опция позволяет задавать, в качестве параметра, указатель на функцию обратного вызова. Эта функция вызывается библиотекой, каждый раз, когда принимаются какие либо данные, требующие дальнейшего использования или сохранения. Описание функции будеит преведено ниже.
CURLOPT_WRITEDATA — эта опция определяет параметр, как объект, в который производится запись принимаемых данных.
CURLOPT_READFUNCTION — опция полностью аналогичная CURLOPT_WRITEFUNCTION, но используетс для передачи данных удаленному узлу.
CURLOPT_READDATA — аналогично CURLOPT_WRITEDATA, но так же для передачи.
CURLOPT_ERRORBUFFER — опция определяет строковый параметр, в который будут записываться сообщения об ошибках в читабельном, для людей, виде.
CURLOPT_URL — очень важная опция, в параметре указывается строка — URL, с которым собираемся взаимодействовать. В строке параметра можно указать небходимый протокол, в виде стандартного префикса «http://» или «ftp://».
CURLOPT_PROXY — опция, определяет строковый параметр — адрес и порт прокси-сервера. Параметр имеет стандартный вид: айпи-адрес (или имя, если есть возможность это имя разрешить) сервера и через двоеточние порт. Например: «proxy:8080»
CURLOPT_PROXYTYPE — параметр этой опции задает тип прокси. Возможные значения параметра: CURLPROXY_HTTP, CURLPROXY_SOCKS4, CURLPROXY_SOCKS5
CURLOPT_HTTPPROXYTUNNEL — ненулевое значение параметра этой опции включает туннелирование вышеуказанного прокси.
CURLOPT_INTERFACE — строковый параметр этой опции задает внешний интерфейс, это может быть как айпи-адрес, так и имя. Разумеется, если сетевой интерфейс — единственный, эту опцию
CURLOPT_PORT — эта опция позволяет задать номер порта удаленного узла. Если эта опция не задается, для соеинения используется порт по умолчанию, для протокола (http — 80, ftp — 21 и т.д.).
CURLOPT_PROXYUSERPWD — эта опция используется для аутентификации на прокси-сервере. Параметр передается в виде строки «логин:пароль».
CURLOPT_USERPWD — опция используется для HTTP аутентификации. Параметр аналогичен предидущему.
CURLOPT_HTTPAUTH — параметр этой опции определяет тип HTTP аутентификации, возможные значения:
CURLAUTH_BASIC — базовый вид аутентификации, используемый, как правило, по умолчанию. Имя пользователя и пароль передаются открытым текстом.
CURLAUTH_DIGEST — является более безопасной версией предидущей.
CURLAUTH_GSSNEGOTIATE — метод аутентификации Microsoft, используемый на серверах этой компании. Поддерживает аутнетификацию Kerberos5. Для использования этого вида аутентификации необходима библиотека GSS.
CURLAUTH_NTLM — метод, так же разработанный и используемый Microsoft, для защиты использует хеширование. Требует наличия OpenSSL.
CURLAUTH_ANY — этот параметр заставляет libcurl выбрать все типы аутентификации, срабатывает метод наиболее подходящий к данному случаю.
CURLAUTH_ANYSAFE — то же самое, только не выбирается CURLAUTH_BASIC аутентификация.
Я показал лишь наиболее общие опции, их список, на самом деле, очень велик, подробнее с ними можно ознакомится в HTML документации к библиотеке.
Перед рассмотрением нашего первого примера стоит упомянуть еще две библиотечные функции, а так же функции обратного вызова, о которых я говорил выше.
void curl_easy_reset(CURL *handle) — выполняет повторную инициализацию библиотеки с установкой всеъ опций в значения по умолчанию.
void curl_easy_cleanup(CURL * handle) — Это функция должна вызываться самой последней и вызываться должна обязательно. Она выполняет завершение текущей сессии.
size_t function( void *ptr, size_t size, size_t nmemb, void *stream) — объявление функции, параметра опции CURLOPT_WRITEFUNCTION. Её аргументы:
ptr — указатель на принимаемые данные.
size — размер принимамого блока данных
nmemb — общее количество блоков данных, объем принимаемой информации определяется как size * nmemb
stream — это параметр опции CURLOPT_WRITEDATA, в который производится запись.
Возвращать функция должна общий размер принятой информации.
size_t function( void *ptr, size_t size, size_t nmemb, void *stream) — объявление функции, параметра опции CURLOPT_READFUNCTION. Назначение всех аргументов аналогичное, только здесь выполняется чтение данных из исходного stream и передача libcurl через ptr.
Возвращать функция должна общий размер переданной информации.
Теперь рассмотрим небольшой пример, показывающий инициализацию библиотеки, задание некоторых опций, а так же, знакомящий нас с еще одной важной функцией.
//подключение необходимых заголовочных файлов
#include <stdio.h>
#include <curl/curl.h>
//главная функция
int main(void)
{
//уже знакомый объект CURL
CURL *curl;
//объект - результат вызова функции curl_easy_perform
CURLcode res;
//выполняем инициализацю
curl = curl_easy_init();
if(curl) { //проверяем
//задаем опцию - получить страницу по адресу http://google.com
curl_easy_setopt(curl, CURLOPT_URL, "google.com");
//указываем прокси сервер
curl_easy_setopt(curl, CURLOPT_PROXY, "proxy:8080");
//задаем опцию отображение заголовка страницы
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
//вызываем функцию, выполняющюю все операции, заданные в опциях (получение страницы, передача данных и т.д.), результат - объект типа CURLcode
res = curl_easy_perform(curl);
//выполняем обязательное завершение сессии
curl_easy_cleanup(curl);
}
return 0;
}
Пример крайне прост и понятен, комментарии излишни. Отмечу, что перед выполнением дальнейших действий с данным — необходимо проверить значение res, если резултат — 0, значит все прошло успешно, иначе — ошибка. Её описание можно получить, задав вышеописанный CURLOPT_ERRORBUFFER.
Теперь рассмотрим более серьезный пример, получающий и отображающий на стандартном выводе HTML страницу (разумеется в виде самого исходного языка разметки, без рендеринга). Будем использовать все необходимые проверки и функцию обратного вызова.
//подключаем необходимые заголовочные файлы
#include <string>
#include <iostream>
#include "curl/curl.h"
//подключаем стандартное пространство имен
using namespace std;
//объявляем буфер, для хранения возможной ошибки, размер определяется в самой библиотеке
static char errorBuffer[CURL_ERROR_SIZE];
//объялвяем буфер принимаемых данных
static string buffer;
//функция обратного вызова
static int writer(char *data, size_t size, size_t nmemb, string *buffer)
{
//переменная - результат, по умолчанию нулевая
int result = 0;
//проверяем буфер
if (buffer != NULL)
{
//добавляем к буферу строки из data, в количестве nmemb
buffer->append(data, size * nmemb);
//вычисляем объем принятых данных
result = size * nmemb;
}
//вовзращаем результат
return result;
}
//главная функция
int main(void)
{
//необходимые CURL объекты
CURL *curl;
CURLcode result;
//инициализируем curl
curl = curl_easy_init();
//проверяем результат инициализации
if (curl)
{
//задаем все необходимые опции
//определяем, куда выводить ошибки
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
//задаем опцию - получить страницу по адресу http://google.com
curl_easy_setopt(curl, CURLOPT_URL, "google.com");
//указываем прокси сервер
curl_easy_setopt(curl, CURLOPT_PROXY, "proxy:8080");
//задаем опцию отображение заголовка страницы
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
//указываем функцию обратного вызова для записи получаемых данных
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
//указываем куда записывать принимаемые данные
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
//запускаем выполнение задачи
result = curl_easy_perform(curl);
//проверяем успешность выполнения операции
if (result == CURLE_OK)
//выводим полученные данные на стандартный вывод (консоль)
cout << buffer << "\n";
else
//выводим сообщение об ошибке
cout << "Ошибка! " << errorBuffer << endl;
}
//завершаем сессию
curl_easy_cleanup(curl);
return 0;
}
Добавлю к коду небольшие пояснения. Рассмотрим writer — функцию обратного вызова. Ее объявление нам уже знакомо. Функция должна возвращать общее количество принятых данных, иначе ошибка. Наша функция, в случае невыполнения действия записи в буфер будет возвращать значение result по умолчанию — 0. Собственно выполнение записи выполняется только в том случае, если буфер не является NULL. Т.к. мы работаем со строковыми данными — запись в буфер осуществляется вызовом метода append, класса string. Возвращаемое значение — произведение аргументов size и nmemb.
Задание опций дополнительных комментариев, думаю, не требует. После вызова curl_easy_perform происходит проверка возвращенного значения, если оно равно CURLE_OK (этот код определен в curl/curl.h) — происходит вывод содержимого буфера на экран (вывод можно организовать так же в файл или же передать другому приложению/участку, например html рендер-движку), иначе — выводится содержимое errorBuffer, содержащего текст ошибки. В самом конце происходит обязательное закрытие сесии. Этот же пример можно использовать для закачки файлов по фтп, заменив http на ftp, указав полный путь к файлу на сервере, а так же написав в функции writer код, пишуший получаемые байты в файл на диске. Разумеется, в таком случае, необходимо будет убрать вывод на экран.
Я постарался донести общие принципы использования этой библиотеки, больше примеров Вы можете найти в вышеописанном архиве, а так же на сайте разработчика: http://curl.haxx.se/libcurl/c/
Там же доступна обширная и полная документация.
Хм, вполне толково разъяснено, хотя остались пару неточностей, может не так понял, но, все равно, спасибо!
Позновательно спастбо. 😉
Хм, интересная реализация на данных программных средствах!
Столкнулся с такой проблемой, закачиваю файл на сервер следующим образом:
CURL *curl;
CURLcode res;
struct curl_httppost *formpost=NULL;
struct curl_httppost *lastptr=NULL;
struct curl_slist *headerlist=NULL;
static const char buf[] = «Expect:»;
curl_global_init(CURL_GLOBAL_ALL);
/* Fill in the file upload field */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, «characterprofiler»,
CURLFORM_FILE, profile,
CURLFORM_END);
/* Fill in the filename field */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, «password»,
CURLFORM_COPYCONTENTS, «123456»,
CURLFORM_END);
/* Fill in the submit field too, even if this is rarely needed */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, «process»,
CURLFORM_COPYCONTENTS, «process»,
CURLFORM_END);
curl = curl_easy_init();
/* initalize custom header list (stating that Expect: 100-continue is not
wanted */
headerlist = curl_slist_append(headerlist, buf);
if(curl) {
/* what URL that receives this POST */
curl_easy_setopt(curl, CURLOPT_URL, roster);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
/* then cleanup the formpost chain */
curl_formfree(formpost);
/* free slist */
curl_slist_free_all (headerlist);
};
т.е. указывая путь и имя файла в profile… А хотелось бы передавать файл непосредственно из памяти, предварительно сжав его (серверная сторона имеет возможность принимать файл в сжатом виде). Можно конечно создать временный файл со сжатым содержимым и передавать его, но мне такой вариант не нравится, облазил весь гугл, но по libcurl информаци очень мало и все как-то разрознено и очень кратко, может подскажете как реализовать передачу файла из памяти?
большое спасибо за очень полезную статью
Здравствуйте. Скажите пожалуйста почему у меня не распознаются функции: curl = curl_easy_init();
if(curl) { //проверяем
//задаем опцию — получить страницу по адресу http://google.com
curl_easy_setopt(curl, CURLOPT_URL, «google.com»);
//указываем прокси сервер
curl_easy_setopt(curl, CURLOPT_PROXY, «proxy:8080»);
//задаем опцию отображение заголовка страницы
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
//вызываем функцию, выполняющюю все операции, заданные в опциях (получение страницы, передача данных и т.д.), результат — объект типа CURLcode
res = curl_easy_perform(curl);
//выполняем обязательное завершение сессии
curl_easy_cleanup(curl);
причем на саму библиотеку компилятор не ругается, похоже интеграция в висуал студио 2008 прошла успешно…
после компиляции первого примера в этой статье, вылазиют такие ошибки:
1>3.obj : error LNK2019: unresolved external symbol __imp__curl_easy_cleanup referenced in function _main
1>3.obj : error LNK2019: unresolved external symbol __imp__curl_easy_perform referenced in function _main
1>3.obj : error LNK2019: unresolved external symbol __imp__curl_easy_setopt referenced in function _main
1>3.obj : error LNK2019: unresolved external symbol __imp__curl_easy_init referenced in function _main
1>C:\Documents and Settings\Admin\Мои документы\Visual Studio 2008\Projects\3\Debug\3.exe : fatal error LNK1120: 4 unresolved externals
1>Build log was saved at «file://c:\Documents and Settings\Admin\Мои документы\Visual Studio 2008\Projects\3\3\Debug\BuildLog.htm»
1>3 — 5 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
добавь в опции студии линковку библиотеки curl (как ОНО там у вас в винде зовется?)
Спасибо помргло.
Здравствуйте.
Столкнулся с такой проблемой при работе с библиотекой на убунту 10.04…
При добавлении в линкер вышесказанных опций при компиляции получаю от gcc ошибку
g++: curl-config: Нет такого файла или каталога
Компилил библиотеку из под рута. IDE — Code::Block. В чем может быть проблема подскажите пожалуйста.
Здравствуйте.
Столкнулся с такой проблемой при работе с библиотекой на убунту 10.04…
При добавлении в линкер вышесказанных опций при компиляции получаю от gcc ошибку
g++: curl-config: Нет такого файла или каталога
Компилил библиотеку из под рута. IDE – Code::Block. В чем может быть проблема подскажите пожалуйста.
Добрый вечер. В данном случае Ваша IDE просто не выполняет шелл-команду curl-config и скармливает эту строчку линкеру. Вы можете просто указать все опции компилятора и линкера вручуную, что бы узнать какие — просто введит в консоли curl-config —libs, должно вывести такое: -lcurl
Собственно это и есть опция линкера, одна единственная, добавляйте ее в опции среды и пробуйте собраться.
Недавно Станислав Подгорный(технический директор), в сотрудничестве с Александром Вербовским(PHP разработчик) разработали уникальное приложение под названием “My Market Value” , позволяющее проследить за процессами на рынке труда и соизмерить свои силы с ожиданиями по зароботной плате.
Даное приложение являеться новинкой в мире IT и не имеет аналогов в Украине и за рубежом. Благодаря уникальной разработке двух ярких индивидуальностей и истинных профессионалов своего дела, разработчики нашей страны получили возможность реально оценивать свои силы в сфере IT.
Оцените свои возможности, проследите за стремительно изменяющимися технологиями, освойте новые направления и творчески подходите к своим возможностям.
Теперь, оценить свои знания и навыки легко – несколько кликов – и вы в мире IT, в мире несоизмеримых возможностей и перспектив.
http://apps.facebook.com/mymarketvalue
Сделайте шаг навстречу своей мечте, получите работу, на которую вы заслуживаете и оцените свои таланты по достоинству!
http://apps.facebook.com/mymarketvalue
Недавно Станислав Подгорный(технический директор), в сотрудничестве с Александром Вербовским(PHP разработчик) разработали уникальное приложение под названием “My Market Value” , позволяющее проследить за процессами на рынке труда и соизмерить свои силы с ожиданиями по зароботной плате.
Даное приложение являеться новинкой в мире IT и не имеет аналогов в Украине и за рубежом. Благодаря уникальной разработке двух ярких индивидуальностей и истинных профессионалов своего дела, разработчики нашей страны получили возможность реально оценивать свои силы в сфере IT.
Оцените свои возможности, проследите за стремительно изменяющимися технологиями, освойте новые направления и творчески подходите к своим возможностям.
Теперь, оценить свои знания и навыки легко – несколько кликов – и вы в мире IT, в мире несоизмеримых возможностей и перспектив.
Сделайте шаг навстречу своей мечте, получите работу, на которую вы заслуживаете и оцените свои таланты по достоинству!
Здравствуйте!
Большое спасибо за столь интересный материал.
Но есть одна проблема, при запуске приложения на другом компьютере, выскакивает ошибка, что curllib.dll отсутствует на данном компьютере, подскажите как программно исправить положение? что бы не закидывать файлы в ручную в системные папки винды.
Спасибо.
2Dark:
curllib.dll в любом случае должна быть установлена на другой машине, если вы используете динамическую линковку. Из вашей ситуации два выхода:
1. использовать статическую линковку, раздуется исполняемый файл, но никаких библиотек не понадобится.
2. написать небольшой инсталлятор (хотя бы в виде скрипта), который будет устанавливать вашу программу и библитеку.
2Oleg Kutkov
Проблему решил тем, что залил все файлы с библиотеками, которые просила моя программа на другом компьютере, в папку с самой программой. Протестировал у всех знакомых на 9 компьютерах. Все работает.
Еще раз, спасибо за инфо.
А можете написать инструкцию, как сбилдить libcurl с поддержкой ssl? Я использую minGW, делаю по инструкции с сайта cURL, но постоянно получаю ошибки 🙁 Скачал OpenSSl и zlib с http://curl.haxx.se/download.html Прописал во всех makefile32.m32 пути к ним, компилю командой
mingw32-make mingw32-ssl-zlib
но все время получаю ошибку urldata.h:74:25: fatal error: openssl/rsa.h: No such file or directory
compilation terminated.
2Алек:
Он же явно пишет, что не может найти openssl/rsa.h. Это относится к заголовочным файлам openssl. Как правило, в юникс системах, заголовочные файлы располагаются в /usr/include, соответственно файлы будут искаться по такому пути. но gcc можно задать и дополнительный путь поиска, с помощью аргрумента -I т.е. вот так, например: -I/home/user/my_include и поиск заголовочных файлов будет выполнятся и в каталоге /home/user/my_include. Как правило, для получения заголовочных файлов, нужно установить соответствующий dev пакет, например вида openssl-dev (название будет может отличаться). Вообщем нужно найти местоположение заголовочных файлов ssl и указать компилятору или же установить соответствующий пакет.
У меня сейчас другая проблема. Я скачал последнюю версию скомпиленного в либ OpenSSL — http://www.gknw.net/mirror/curl/win32/curl-7.21.7-devel-mingw32.zip , скомпилил cUrl вместе с OpenSSL, положил cUrl и OpenSSL файлы библиотек в папку либов моего проекта, прописал к ним путь, сказал использовать библиотеки curl, eay32, ssl32, потом нашел на форуме, что надо еще и wsock32 and wldap32 libs. Добавил в лирективы компилятора -DCURL_STATICLIB, -DUSE_SSLEAY и -DUSE_OPENSSL. Проект скомпилировался, но не запускается — терминейтится без каких-либо сообщений об ошибке.
http://stackoverflow.com/questions/7013708/weird-things-with-libcurl-and-openssl я тут более детально описал. Ума не приложу, почему оно хочет эти длл! Очень нужна помощь!
sdfgsdfg
Выложите кто-нибудь библиотеку под Windows, в теме ссылка битая 😥