[BlueLeaf1336]> PROGRAM>

IEのキャッシュファイルを列挙する

historyTOP

2006/09/21:作成

はじめにTOP

もう何度も書いているような気がしますが...すでに使い古されたサンプルで何をいまさら感漂うものになりました。特に、すでに様々なところで書きつくされていてどうしようもないぐらいそのままパクるしか手がないといえます。

しかしそれもインターネットにつながっていれば、の話です。つながっていない時に知りたい知りたい知りたいあー知りたいと思い立つと、リンク先なんて屁のツッパリにもなりません。といって、パクリを正当化しておきます。

参考にしたURLです。

ちなみに、今回のオリジナルは、サンプル: "IEのキャッシュファイルを列挙" です。コールバック関数を渡して使うなど、もう本当にそのままです。

ところで、このコードで実際にキャッシュファイルを列挙すると以上に使用メモリを食います。どこかで何かがもれているのかも。でも、何度も実行すると頭打ちになることも確か。

ソースコードTOP

type TEnumCacheFilesProc = function(const lpCacheEntry: PInternetCacheEntryInfo): Boolean of object;

//-----------------------------------------------------------------------------
//  IEのインターネットキャッシュファイルを列挙する
//-----------------------------------------------------------------------------
//  http://forum.nifty.com/fdelphi/samples/01398.html
//  サンプル: "IEのキャッシュファイルを列挙"
//  http://www.geocities.jp/wininet_dll_jp/cache1.html
//  http://www.runan.net/program/tips/API/wininet_FindFirstUrlCacheEntry.shtml
//  FindFirstUrlCacheEntry - WinInet -
//  http://support.microsoft.com/default.aspx?scid=kb%3Bja%3B894941
//  CE.NET 4.2: Wininet キャッシュの列挙について
//  http://www.mitene.or.jp/~sugisita/vb6_net.html
//  み〜くんパパの仕事部屋 - ネットワーク、インターネット

//  //-----------------------------------------------------------------------------
//  //  フォーム宣言
//  type
//    TForm1 = class(TForm)
//      procedure Button1Click(Sender: TObject);
//    private
//      FPrevFile: String;
//      function EnumCacheFile(const lpCacheEntry: PInternetCacheEntryInfo): Boolean;
//    public
//  
//    end;
//  
//  //-----------------------------------------------------------------------------
//  //  キャッシュ列挙用コールバック関数
//  function TForm1.EnumCacheFile(const lpCacheEntry: PInternetCacheEntryInfo): Boolean;
//  var
//      LPath: String;
//  begin
//      //  いったん文字列変数に収めないと化ける?
//      LPath := (lpCacheEntry^.lpszLocalFileName);
//      //  (念のため)存在確認
//      if (FileExists(LPath)) then
//      begin
//          //  なぜ? 同じファイルが2回列挙される?
//          if (FPrevFile <> LPath) then
//          begin
//              //  TODO
//          end;
//          FPrevFile := LPath;
//      end;
//      //  列挙続行
//      Result := True;
//  end;
//  //-----------------------------------------------------------------------------
//  //  列挙
//  procedure TForm1.Button1Click(Sender: TObject);
//  begin
//      EnumInternetCacheFiles(EnumCacheFile, LErr);
//  end;

function EnumInternetCacheFiles(Proc: TEnumCacheFilesProc; var AError: String): Boolean;
var
    dwEntrySize: DWORD;
    hCacheDir: THandle;
    lpCacheEntry: PInternetCacheEntryInfo;
    LError: Cardinal;
    LResult: Boolean;
begin
    Result := False;

    //  取得領域の初期サイズ(足りないかもしれないし充分かもしれない)
    dwEntrySize := MAX_CACHE_ENTRY_INFO_SIZE;
    //  取得領域を確保
    GetMem(lpCacheEntry, dwEntrySize);
    //  キャッシュハンドル初期化
    hCacheDir := 0;

    //  成功するか、致命的に失敗するまでやり直す
    while (True) do
    begin
        //  構造体にサイズを設定
        lpCacheEntry^.dwStructSize := dwEntrySize;
        //  キャッシュハンドル取得
        hCacheDir := FindFirstUrlCacheEntryEx(
                nil, 0, NORMAL_CACHE_ENTRY or STICKY_CACHE_ENTRY,
                0, lpCacheEntry, @dwEntrySize, nil, nil, nil);
        //  成功
        if (hCacheDir <> 0) then
        begin
            Break;
        end
        //  失敗
        else
        begin
            LError := GetLastError();
            //  キャッシュなし
            if (LError = ERROR_NO_MORE_ITEMS) then
            begin
                Result := True;
                //  メモリ解放
                FreeMem(lpCacheEntry);
                //  終了
                Exit;
            end
            //  バッファの容量不足(dwEntrySize に必要サイズあり)
            else if (LError = ERROR_INSUFFICIENT_BUFFER) then
            begin
                //  バッファ拡張
                ReallocMem(lpCacheEntry, dwEntrySize);
            end
            //  どうしようもなし
            else
            begin
                AError := SysErrorMessage(LError);
                //  メモリ解放
                FreeMem(lpCacheEntry);
                //  終了
                Exit;
            end;
        end;
    end;

    //  実際にキャッシュを列挙する(すでにひとつ目は取得済み)
    while (True) do
    begin
        //  コールバック
        LResult := Proc(lpCacheEntry);
        //  列挙中断?
        if (not LResult) then
        begin
            Result := True;
            //  ユーザーによるキャンセル
            AError := SysErrorMessage(1223);
            //  終了
            Break;
        end;

        //  構造体にサイズを設定
        lpCacheEntry^.dwStructSize := dwEntrySize;
        //  次のファイルを検索
        LResult := FindNextUrlCacheEntryEx(hCacheDir, lpCacheEntry, @dwEntrySize, nil, nil, nil);
        //  失敗
        if (not LResult) then
        begin
            LError := GetLastError();
            //  キャッシュなし
            if (LError = ERROR_NO_MORE_ITEMS) then
            begin
                Result := True;
                AError := SysErrorMessage(LError);
                //  終了
                Exit;
            end
            //  バッファの容量不足(dwEntrySize に必要サイズあり)
            else if (LError = ERROR_INSUFFICIENT_BUFFER) then
            begin
                //  バッファ拡張
                ReallocMem(lpCacheEntry, dwEntrySize);
            end
            //  どうしようもなし
            else
            begin
                AError := SysErrorMessage(LError);
                //  終了
                Break;
            end;
        end;
    end;

    //  メモリ解放
    FindCloseUrlCache(hCacheDir);
    FreeMem(lpCacheEntry);
end;

サンプルTOP

NetUtils20060921.zip(237,008bytes)※ソースコードと実行ファイルです。

テストに使ったプログラムです。どちらかというと、キャッシュファイルから特定の拡張子のファイルを楽に取り出せないのか? が出発地点なので少しは実用性を求めたんですが、多分使わないですね。もう少し何かが要りそうな。

「表示更新」で列挙を開始します。このとき指定した拡張子のファイルだけをリストビューに表示します。列挙したファイルにチェックを入れて「ファイル複製」をクリックすると、好きなフォルダにコピーできます。

サンプルでは動画関係の拡張子を指定しているので、コピーには結構時間がかかります。にもかかわらずカーソルがそのままなのでいつコピーが終わったのかわかりません。

リストビューの列をクリックすると並べ替えができます。新しいファイルからチェックを入れたい場合や、サイズの大きなファイルだけを上に持ってきたいときに便利です。

「Version」ボタンでこのプログラムのメモリ使用量を確認できます。起動直後と列挙後で使用量がえらく違うのにびっくりできます。

EOFTOP