MFC や .NET に頼らないで、なるべく一般的な API は... と探したら、Windows のソケット API に近い WinInet と呼ばれる一連の API があるようです。HINTERNET 構造体を識別子として、http や ftp の通信ができます。文字列はマルチバイト (CString系) ではなく、Unicode 文字セット (wstring 系) を使用しています。
[wget.cpp]
#include "stdafx.h"
#pragma comment(lib, "Wininet.lib")
const DWORD BUF_SIZE = 128 * 1024;
static bool wget(std::string &url, std::string &dest_fn){
HINTERNET hInet = InternetOpen(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if(hInet == NULL){
std::cerr << "Failed to open, lastErr = " << GetLastError() << std::endl;
return false;
}
wchar_t *wcs = new wchar_t[url.length() * 2 + 1];
mbstowcs(wcs, url.c_str(), url.length() + 1);
HINTERNET hFile = InternetOpenUrl(hInet, wcs, NULL, 0, 0, 0);
delete [] wcs;
std::ofstream ofs(dest_fn);
char buf[BUF_SIZE];
for(;;){
DWORD tmpSize;
InternetReadFile(hFile, buf, BUF_SIZE, &tmpSize);
if(tmpSize <= 0){
break;
}
buf[tmpSize] = '\0';
ofs << buf;
}
ofs.close();
InternetCloseHandle(hInet);
return true;
}
int main(int argc, char* argv[]){
std::string url = "http://funini.com/kei/";
std::string dest_fn = "hoge.txt";
wget(url, dest_fn);
return 0;
}
[stdafx.h]
#pragma once
#include "targetver.h"
#include <string>
#include <iostream>
#include <fstream>
#include <windows.h>
#include <Wininet.h>
実行すると、http://funini.com/kei/ が hoge.txt として保存されます。
http サーバ上のファイルをダウンロードする Windows プログラム(Win32)を書きたかったので調べてみたら、
MFCを使うのが簡単そうだから、そうしてみました。
動作としては、Windows版のWgetみたいな動作をするアプリを書いてみました。
/**
* 指定されたURLのファイルを、指定されたファイル名で
* ダウンロードする関数 @@ Kei Takahashi
*
* 返り値: ダウンロード成功(True)/失敗(False)
* 使用例:
* bool ret = download("funini.png","http://funini.com/imgs/funini.png");
*
*
* - MFCプロジェクト上で使用して下さい
* - stdafx.hで以下のようにヘッダファイルをincludeして下さい。
* #include <afxinet.h>
*
*/
bool download(CString fn, CString url) {
const int BUF_LEN=1024;
BYTE lpBuff[BUF_LEN];
// 接続を張って、リモートのファイルにアクセスできるようにする
CInternetSession cSec(NULL, 1, INTERNET_OPEN_TYPE_PRECONFIG, NULL,NULL,0 );// # Use IE Settings
CStdioFile* remoteFile = cSec.OpenURL(url, 1, INTERNET_FLAG_TRANSFER_BINARY|INTERNET_FLAG_RELOAD, NULL, 0);
if(remoteFile == NULL) return false;
// ローカルファイルを開いて、ダウンロード開始
CStdioFile localFile;
localFile.Open(fn, CFile::modeCreate | CFile::modeWrite | CFile::shareDenyNone | CFile::typeBinary);
for(;;){
int n = remoteFile->Read(lpBuff, BUF_LEN);
localFile.Write(lpBuff,n);
if(n > BUF_LEN) break;
}
localFile.Close();
// 後処理
delete remoteFile;
return true;
}