WinAPI FTPダウンロードの完了検知

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,458

fearz

score 5

C++のWINAPIアプリケーションです。
非同期(WININET_API_FLAG_ASYNC)で接続したFTPセッションで、
FtpFileGet()でファイルをダウンロードしようとしています。
そこで、ダウンロード終了の検知ができずに困っております

InternetSetStatusCallback()で指定するコールバック関数で、

1 : INTERNET_STATUS_HANDLE_CREATED
2 : INTERNET_STATUS_RESPONSE_RECEIVEDでプログレス
3 : INTERNET_STATUS_REQUEST_COMPLETE

の順番かと予想していましたが、実際は1.で止まっています。
ファイルはダウンロードされて中身も正しいようです。
CREATEDを以て完了と判断してよいものか、
名前からするとそうではない気もするため悩んでいます。

本来はどの順番で来るものか、
ドキュメントも調べてみたのですが見つけることができませんでした。

セオリーとしてダウンロード完了をどのように判断すればよいか、
ご存じの方がいらっしゃいましたらご教授頂けないでしょうか

現状の、接続からコールバックまわりのコードをシンプルにしたものです。
実際にはダウンロード前に一覧取得していますのでファイルを次々とダウンロードする処理となります。

HINTERNET hnet = NULL;
HINTERNET hftp = NULL;
u32 dlsize = 100;
u32 dlsize_cur = 0;

void CALLBACK ftp_callback
(
    HINTERNET hnet,
    DWORD dw_context,
    DWORD dw_status,
    LPVOID status_info,
    DWORD status_info_len
){
    switch( dw_status )
    {
        case INTERNET_STATUS_HANDLE_CREATED:
        {
            if( app_status == 接続中 )
            {
                LPINTERNET_ASYNC_RESULT result = (LPINTERNET_ASYNC_RESULT) status_info;
                hftp = (HINTERNET) result->dwResult;
            }
            break;
        }
        case INTERNET_STATUS_REQUEST_COMPLETE:
        {
            if( app_status == 接続中 )
            {
                //    ※ここには来る
                download_core();
            }
            break;
        }
        case INTERNET_STATUS_RESPONSE_RECEIVED:
        {
            //    ※ここに来ない
            if( app_status == ダウンロード中 )
            {
                LPDWORD bytes = (LPDWORD)status_info;
                if( dlsize < *bytes ) dlsize = *bytes;

                if( dlsize >= dlsize_cur )
                {
                    //    ファイルのサイズ分ダウンロードされたので、
                    //    ダウンロード完了とする。
                    //    ...次のファイルダウンロード処理へ...
                }
            }
            break;
        }
    }
}

//    ダウンロード指示
void download()
{
    hnet = InternetOpen(
        "ftp_client",
        INTERNET_OPEN_TYPE_DIRECT,
        NULL,
        NULL,
        WININET_API_FLAG_ASYNC
    );
    if( hnet==NULL ) return エラー;

    //    コールバック登録
    InternetSetStatusCallback(
        hnet,
        (INTERNET_STATUS_CALLBACK)&ftp_callback
    );

    hftp = InternetConnect
    (
        hnet,
        "xx.xx.xx.xx",
        INTERNET_DEFAULT_FTP_PORT,
        NULL,
        NULL,
        INTERNET_SERVICE_FTP,
        NULL,
        (DWORD)&context
    );
    if( hftp != NULL )
    {
        download_core();
    }
    else if( GetLastError()==ERROR_IO_PENDING ) app_status = 接続中
    else { return 接続エラー }
}

void download_core()
{
    if( ! hftp ) return;
    if( FtpGetFile(
        hftp,
        "filename.txt",
        "C:\\test\\test.txt",
        false,
        FILE_ATTRIBUTE_NORMAL,
        FTP_TRANSFER_TYPE_BINARY,
        NULL
    ) == FALSE ){
        エラー処理
    }
    app_status = ダウンロード中

    //    ※ここまでは来る
    //    上記メソッド実行時に、INTERNET_STATUS_HANDLE_CREATED
    //    を受け取り、ファイルも出来上がっているが、
    //    その他のイベントが来ない
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • KoichiSugiyama

    2016/07/09 16:44

    コールバック関数はどういうものを書かれたか、差し障りがなければコードを提示してもらった方がアドバイスしやすいです。

    キャンセル

回答 2

0

うろ覚えで申し訳ないですが、非同期通信の場合、INTERNET_STATUS_REQUEST_COMPLETEが来た段階で完了として良かったように記憶しています。なので、上記のコードではINTERNET_STATUS_HANDLE_CREATEDを受け取った段階でdownload_core()関数を実行できるのではないでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/07/11 11:17

    ご回答ありがとうございます。
    FtpGetFile()実行後は、INTERNET_STATUS_HANDLE_CREATEDしか受け取っておらず、
    INTERNET_STATUS_REQUEST_COMPLETEは来ませんでした。

    キャンセル

0

以下のページは参考になりませんか。

Missing INTERNET_STATUS_REQUEST_COMPLETE callback after calling Wininet’s FtpOpenFile() in asynchronous mode

INTERNET_FLAG_RELOADが必要なのかな?
ダメでしたらすみません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.21%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる