top / index / prev / next / target / source

2002-11-26 diary: HTTP経由ファイル取得ツール(Visual C++版)

いがぴょんの日記 日記形式でつづる いがぴょんコラム ウェブページです。

old-v2

HTTP経由ファイル取得ツール(Visual C++版)

WinInetを使ったプログラム開発に携わることに

WinInetを使ったプログラム開発に携わることに

WinInet APIを使ったプログラム開発に携わることになりました。Visual C++.NETベースで開発する模様です。さて WinInet APIの使い方は 何を見れば良いのでしょう (笑)、、、そういえば Visual C++を使った仕事って 久しぶりです。たまには C++も使わないと忘れてしまいますからね。

HTTP経由ファイル取得

ごく簡単な HTTP経由ファイル取得ツール (Visual C++版)読者の方へ、、、バグっていたらツッコミ下さい。(バグっていると ちとマズいのであった…) HttpGet.cpp

/**
* シンプルHTTP GETクライアント
* 2002.11.26 t.iga
*/

#include <afx.h>
#include <afxwin.h>
#include <afxinet.h>

CWinApp theApp;

/**
 * 転送時のバッファサイズ
 */
const int BUF_SIZE = 2048;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {

    // MFC を初期化して、エラーの場合は結果を印刷します。
    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) {
        _tprintf(_T("MFCの初期化に失敗しました.\n"));
        return 1;
    }

    if (argc <= 1) {
        printf("Usage: HttpGet.exe http://www.google.co.jp/\n");
        return -1;
    }

    try {
        char* uri = argv[1];

        DWORD protocol = 0;
        CString serverName;
        CString fileName;
        INTERNET_PORT port;

        if (AfxParseURL(uri, protocol, serverName, fileName, port) == false) {
            printf("URLの分解に失敗しました。");
            return -1;
        }

        printf("プロトコル[%ld] ポート[%ld] サーバ[%s] ファイル名[%s]\n",
               protocol, port, (LPCSTR)serverName, (LPCSTR)fileName);

        CInternetSession session("HttpGet - simple http client");
        CHttpConnection* conn = session.GetHttpConnection(
                                    serverName,
                                    CHttpConnection::HTTP_VERB_GET,
                                    port, NULL, NULL);
        CHttpFile* file = conn->OpenRequest(
                              CHttpConnection::HTTP_VERB_GET, fileName,
                              NULL, 1, NULL, NULL,
                              INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE);

        file->AddRequestHeaders("Accept: text/*\r\nUser-Agent: HttpGet\r\n");
        file->SendRequest();

        DWORD statusCode;
        file->QueryInfoStatusCode(statusCode);
        if (statusCode >= 300) {
            printf("何かしらエラー:%ld\n", statusCode);
            return -1;
        }

        TCHAR buf[BUF_SIZE + 1];
        for (;;) {
            int result = file->Read(buf, BUF_SIZE);
            if (result <= 0) {
                break;
            }
            buf[result] = 0x00;
            printf(buf);
        }

        file->Close();
        delete file;
        conn->Close();
        delete conn;
        session.Close();
    } catch (CInternetException* ex) {
        TCHAR szMsg[1024];
        ex->GetErrorMessage(szMsg, 1024);
        printf("Error occur: %s", szMsg);
        ex->Delete();
    }
    return 0;
}

WinInetはCOMベースであるような記述があり、とりあえずMFCラッパー側で実装してみました。でもそれとは別に Win32 Platform SDK に wininet.hというヘッダーファイルがありこっちは生でAPIが呼べるようにも思います。さてはて。(気分的には 生でAPIを呼びたいのですけれどもね)

で、もう少しつっこんで調べてみたら、HINTERNET InternetOpen()というWin32 APIがあるのがわかりました。こっちは 生APIで C++ではなくってC風に記述できます。さあて Cで行くべきかC++で行くべきか…。ちなみに C言語で生APIの方法は 下記ページに詳細が載っていました。

良くできたウェブページでした。

2002.12.10 追記

Cでアクセスするために別のサンプルを探したりしてみました。(MFCのAPIが どうも怪しいので…)下記のページを参考にしました。

できあがった C言語API側のWinInetを呼び出すバージョンです。

C版を作って強く認識しました。私 まだC++の方は覚えていました。C言語について、すっきり忘れていました

(笑) HttpGet.c (C言語バージョン)

/**
* シンプルHTTP GETクライアント
* wininet.libをリンクに追加することが必要です。
* 2002.12.10 t.iga
*/
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#include <stdlib.h> 

#define BUFSIZE         (1024)

int main(int argc, char* argv[])
{
    HINTERNET hsession = 0;
    HINTERNET hconnect = 0;
    HINTERNET hrequest = 0;
    char szBuf[1025];
    DWORD dwSize = 0;

    hsession = InternetOpen("HttpGet - simple http client",
                            INTERNET_OPEN_TYPE_PRECONFIG,
                            NULL, NULL, 0);
    if (hsession == NULL)
    {
        printf("hsession==NULL");
        return -1;
    }

    hconnect = InternetConnect(
                   hsession,
                   "www.tcct.zaq.ne.jp",
                   80,
                   "iga",
                   "password",
                   INTERNET_SERVICE_HTTP,
                   0,
                   10000);
    if (hconnect == NULL)
    {
        printf("hconnect==NULL");
        return -1;
    }

    hrequest = HttpOpenRequest(
                   hconnect,
                   "GET",
                   "/iga/tosiki/igapyon/diary/2002/ig021126.html",
                   NULL,
                   NULL,
                   NULL,
                   INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE,
                   NULL);
    if (hrequest == NULL)
    {
        printf("hrequest==NULL");
        return -1;
    }

    if (HttpSendRequest(
                hrequest,
                NULL,
                0,
                NULL,
                0) == FALSE)
    {
        printf("HttpSendRequest() が失敗しました\n");
        return -1;
    }

    szBuf[0] = 0;

    {
        dwSize = BUFSIZE;
        if (HttpQueryInfo(
                    hrequest,
                    HTTP_QUERY_CONTENT_LENGTH,

                    szBuf, &dwSize, 0))
        {
            szBuf[dwSize] = 0;
            printf("長さ[%s]\n", szBuf);
        }

        dwSize = BUFSIZE;
        if (HttpQueryInfo(
                    hrequest,
                    HTTP_QUERY_STATUS_CODE,
                    szBuf, &dwSize, 0))
        {
            szBuf[dwSize] = 0;
            printf("ステータス[%s]\n", szBuf);
        }

        dwSize = BUFSIZE;
        if (HttpQueryInfo(
                    hrequest,
                    HTTP_QUERY_STATUS_TEXT,
                    szBuf, &dwSize, 0))
        {
            szBuf[dwSize] = 0;
            printf("ステータス文字列[%s]\n", szBuf);
        }
    }


    for (;;)
    {
        dwSize = BUFSIZE;
        if (InternetReadFile(
                    hrequest,
                    szBuf,
                    dwSize,
                    &dwSize) == FALSE)
        {
            break;
        }

        if (dwSize <= 0)
        {
            break;
        }

        szBuf[dwSize] = 0;
        printf("%s\n", szBuf);
    }

    InternetCloseHandle(hrequest);
    InternetCloseHandle(hconnect);
    InternetCloseHandle(hsession);

    return 0;
}

やっぱりMFCを使わない方が 私には似合っています。

関連する日記

昨日はがんばりました

ごごごってJavaのプログラミングをしました。とっても効率よくコーディングしたのですが、500行くらいしか書くことが出来ませんでした。というか効率良く書いた場合には 私は 500行/1日程度なのでしょうかね(笑)

世間のニュースから () 2002


この日記について