int Web_Downloader(char *Server_Host_Address, char *FileLocation, char *Referer , char *SaveDirectory , char *SaveName )
{
//返り値一覧
//
//-106:ERR_INTERNET_DISCONNECTED インターネットに接続されていない。
//-403:"403 Forbidden" サーバーにリクエストが拒否された。
//-404:"404 Not Found" 指定したURLにドキュメントが存在しない。
//-1 その他のエラー
HINTERNET hInternet;
HINTERNET hHttpSession;
HINTERNET hHttpRequest;
// WININET初期化
hInternet = InternetOpen(
"Web_Downloader",
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
0);
// サーバへ接続
hHttpSession = InternetConnect(
hInternet,
Server_Host_Address,
INTERNET_DEFAULT_HTTP_PORT,//HTTP_PORT
NULL,
NULL,
INTERNET_SERVICE_HTTP,//SERVICE_HTTP
0,
0);
// HTTP要求の作成
hHttpRequest = HttpOpenRequest(
hHttpSession,
"GET",
FileLocation,
NULL,
Referer,
NULL,
0,
0);
// 作成したHTTP要求の発行
BOOL bHttpSendRequest = HttpSendRequest(
hHttpRequest,
NULL,
0,
NULL,
0);
if( bHttpSendRequest == 0 ){//bHttpSendRequestが0の場合はインターネットに接続されいないので、エラーを返す。
return -106;//106:ERR_INTERNET_DISCONNECTED
}
//404や403エラーが発生していないか、を確認する。
//char BufSizeText[1000];
//DWORD BufSizeTextSize = 1000;
DWORD StatusCode , StatusCode_Size = sizeof(DWORD);
BOOL bHttpQueryInfo_STATUS = HttpQueryInfo( //エラーコードを数値として返してくれる。
hHttpRequest,
HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER , //「HTTP_QUERY_FLAG_NUMBER」を指定しなかった場合、文字列として返されるので、char型の配列をバッファに用意すればいい。
&StatusCode, //BufSizeText //「HTTP_QUERY_FLAG_NUMBER」を指定しない場合(&の有無に注意)
&StatusCode_Size, //&BufSizeTextSize //「HTTP_QUERY_FLAG_NUMBER」を指定しない場合
NULL);
if( StatusCode != HTTP_STATUS_OK ){
//エラー処理
//リソースの解放
InternetCloseHandle(hHttpRequest);//「HttpQueryInfo()」および「InternetReadFile()」は「InternetCloseHandle()」の必要は無い。
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hInternet);
//一回試しただけだが、106エラーは検出できなかった。
//(おそらくサーバーから応答の無いエラーは検出できないと考えられる。)
//(WinInet.hを見れば分かるが、106エラーは定義すらされていない。検出できる訳が無かった。)
if(StatusCode==403){
return -403; //404エラー
}else if(StatusCode==404){
return -404; //403エラー
}else{
return -1; //その他のエラーについては、今回扱わないので全て-1とする。「return StatusCode;」あるいは「「return (-1*StatusCode);」」としてもよかったのだが、今回は他の関数との都合でこのようにした。
}
}else{
//ダウンロード処理。
//ファイルのダウンロードに必要とされるバッファのサイズを確認する。
DWORD RequiredBufSize , RequiredBufSize_Size = sizeof(DWORD);
BOOL bHttpQueryInfo_ContentLength = HttpQueryInfo( //エラーコードを数値として返してくれる。
hHttpRequest,
HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER ,
&RequiredBufSize,
&RequiredBufSize_Size,
NULL);
//必要なサイズだけメモリを確保する。
char *Buf_main = (char *)malloc(RequiredBufSize*sizeof(char));
char Buf_SaveName[200];
sprintf_s( Buf_SaveName , sizeof(Buf_SaveName) , "%s\\%s" , SaveDirectory , SaveName );//保存するファイル名の生成
FILE *file;
fopen_s(&file, Buf_SaveName ,"wb");
DWORD ReadSize; //一回の操作で読みだされたサイズ
DWORD ReadSize_sum=0; //読み出しサイズの合計
// コンテンツの内容を取得
do{
BOOL bInternetReadFile = InternetReadFile(
hHttpRequest,
Buf_main,
RequiredBufSize,// BufSize,
&ReadSize);
//ブレークポイント掛けて、物理的にネットケーブルを抜き差しして、HttpSendRequestはエラー無しで通し、InternetReadFileでエラーを出そうとしたけど、出ないから、
//こっちのエラー処理は不要。(HttpSendRequestだけでokと言う事)
//実際にファイルの保存までやってみたけど、mp3が正しく保存されている。
//恐らくだが、HttpSendRequestが成功した時点でダウンロードは全て完了している。
//ただし、
//バッファ一回のループでダウンロードできなかったり、サーバー側が分割してファイルを送信してくる場合には、どうなるか分からないので、一応確認だけしておく。
if( bInternetReadFile == 0 ){//bInternetReadFileが0の場合はインターネットに接続されいないので、エラーを返す。
free(Buf_main);
return -106;//106:ERR_INTERNET_DISCONNECTED
}
ReadSize_sum += ReadSize;
//ファイルへの書き出し。
fwrite(Buf_main,ReadSize,1,file);//fwrite(&Buf_main,ReadSize,1,file);としても誤って動いてしまうし、普通に再生もできるが、Chromeでダウンロードしたファイルとバイナリエディタで比較すると、ファイルの先頭と末尾の辺りにゴミが混じるので注意。
}while(ReadSize!=0);//一回で読みだせるとは限らないので、ループを回す。
fclose(file);
free(Buf_main);
if(ReadSize_sum != RequiredBufSize){
//「HttpQueryInfo()」で取得したファイルサイズと、実際に読みだしたファイルサイズが違う場合はエラーを返す。
//もし、サーバーからの応答が遅い???などの理由で上手く行かない場合は、上記の「do{}while();」文に、
//(必要であれば「Sleep();」を挟みながら、)サイズが一致するまでループを回すのもありだと思う。
//(当然だが、試行回数に制限を入れておかないと、無限ループに陥る可能性があるので注意。)
//ただ、自分の環境では、そのような事例はまだ無いので、実装はしない。
return -1;
}
}
InternetCloseHandle(hHttpRequest);//「HttpQueryInfo()」および「InternetReadFile()」については「InternetCloseHandle()」する必要は無い。
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hInternet);
return 0;
}