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; }