WinINet(InternetReadFile)によるファイル(HTMLも含む)のダウンロード

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