PCでの活動記録をスクリーンキャプチャで残す

これは以前書いた記事 http://d.hatena.ne.jp/itouhiro/20101216 の改訂版です。改善した点:

  • BATファイルを実行する代わりに、「タスクスケジューラ」を使うようにした。

[しゃべり担当] パソコンで作業してると、いつのまにかネットを見ていて時間をつぶしていたりする。で、あとから何してたんだっけ? 思い出せないぞ‥‥ということがある。


[合いの手担当] よくあるね。


[しゃべり担当] そこで、一定時間、私の場合は5分ごとにスクリーンキャプチャを撮影することにした。それを後で見れば何をしていたか思い出せる。


[合いの手担当] 思い出してどうするの?


[しゃべり担当] 毎日どう時間を使っていたか、記録しているんだ。表計算ソフト使って記録に残している。あとで眺めると日記にもなる。


[合いの手担当] ふーん。


[しゃべり担当] で、その「5分ごとにスクリーンキャプチャに残す方法」を説明する。
できれば軽くてメモリ食わないほうがいいし、Alt+TABキーで作業ウィンドウを選ぶときにでてきてほしくない。


動作環境
OS: Windows 7 / XP
ソフトウェア: MiniCap 1.21.01


スクリーンキャプチャするソフト

MiniCap を使う。このソフトは以下の利点がある。

  • 無料
  • Win7のAeroでもキャプチャ可能。
  • コマンドラインで画像形式やサイズを指定可能。
  • マルチディスプレイにも対応。
    こういう2つディスプレイがあるとき、以下のように記録される。

    記録される画像


[合いの手担当] 記録画像をもっと大きくできない?


[しゃべり担当] 設定は変更できるよ。あとで説明する。

http://www.donationcoder.com/Software/Mouser/MiniCap/
で、 MiniCapSetup.exe をダウンロードする。

ファイル名の拡張子を7zに変えて、たとえば MiniCapSetup.exe.7z にして解凍する。


今回は C:\home\bin\MiniCap に MiniCap.exeほかのファイルを配置する。


一定時間ごとに起動するには‥‥

Windows標準装備の「タスクスケジューラー」を使用する。
この設定によって、

  • 一度設定すると、Windows再起動後も自動的に実行される。
    • つまり、普段はまったく意識しなくても自動的に記録し続けてくれる。
  • 停止・再開も簡単。


登録方法は http://www.atmarkit.co.jp/fwin2k/win2ktips/1332reptsk/reptsk.html に書いてある。
すこし詳しく説明すると、


具体的には……

  • [コントロールパネル-タスク-追加](WindowsXP) [コントロールパネル-管理ツール-タスクスケジューラ-追加](Windows7) でC:\home\bin\MiniCap\MiniCap.exe 指定する。
  • [スケジュールtab-詳細設定]で「繰り返し実行」をチェック。[間隔5分、継続時間24時間] にする。これで5分毎にスクリーンキャプチャを撮影できる。
  • [タスクtab - ログオン時のみ実行]をチェック。
  • [タスクtab - 実行するファイル名]を C:\home\MiniCap\MiniCap.exe -customdate "$Y-$m-$d $H.$M" -save "r:\cap\$customdate$.jpg" -capturedesktop -exit -resizexp 50 -resizeyp 50 -compress 3 にする(WinXP)。Win7の場合はMiniCap.exeの次からは「引数の追加」に指定する。


停止したいときは、タスクスケジューラの [実行する](WinXP)、 [有効](Win7) チェックボックスを外せばいい。


ここではRドライブのcapフォルダに保存しているぞ。 -save "r:\cap\$customdate$.jpg"という箇所でそれを指定している。
Rドライブがあって、R:\capフォルダが存在しないときは、capフォルダは自動的に作成される。
しかしRドライブがないときはMiniCapのダイアログ(ウインドウ)がでてくる。どこに保存するか聞かれる。キャンセルすればよい。


Windows 7 の設定詳細


Windows7のコントロールパネルはどこに何があるかよくわからない‥‥。[小さいアイコン]にすればなんとかわかるぞ。[管理ツール→タスクスケジューラ]を選ぶ。



[基本タスクの作成]をクリックしてMiniCapという名前(別の名前でもいい)で登録する。最初の登録画面では1日1回実行までしか指定できないので、1日1回実行とする。



登録したMiniCapタスクを選択して [プロパティ] をクリック。[間隔5分、継続時間24時間] にする(画面では継続時間 無制限となっているがこれでもよい)。これで5分毎にスクリーンキャプチャを撮影できる。


Windows XP の設定詳細


[合いの手担当] 記録画像の大きさとかを設定変更する方法は?


[しゃべり担当] -resizexp 50 -resizeyp 50 というのが、縦横ともに 50% に縮小します、という設定なんだ。


書き換えて、 -resizexp 100 -resizeyp 100 とすれば縮小しないで実サイズで保存するし、数字を 25 にすれば、縦横4分の1で保存する。


JPGの圧縮率は -compress 10 なら最もキレイだけどファイル容量が大きい、 -compress 1 なら最も見た目はよくないけどファイルサイズが小さい。
JPGじゃなくてPNG保存するなら -save "...jpg" の jpg を png に変更する。


ほかにも細かな設定は http://www.donationcoder.com/Software/Mouser/MiniCap/ に書いてあるよ。


RAMドライブを使う

上の手順で動作はするのだが、私はさらに変更したい。というのも、このスクリーンキャプチャした画像はプライバシーばればれなので、他人に見られないようにしたい。その方法は2つある。

  1. 暗号化フォルダに保存。
    暗号化フォルダに保存は、TrueCrypt等使えば可能だが、やめておく。キャプチャ画像はそんな大きなファイルサイズでもないし(1時間で360KBくらい)、保存しておいて20年後に眺めるとかもできる。しかし個人的には記録したあとは忘れたいし、消してしまう。

  2. RAMドライブに保存。
    今回はRAMドライブを使う。RAMドライブに保存して、RAMドライブのファイルはPCの電源OFFで消える設定にしておけば、キャプチャ画像は、PCの電源OFFやOS再起動で自動的に削除されるし、HDDの削除ファイル復元でも復活しない(HDDに保存してないから)ので安全だ。


どちらにしても問題がある。暗号化ドライブやRAMドライブは、OS起動直後はマウントされてしなくて存在しない。RAMドライブ作成ソフトにRamPhantomを使ってるんだけど、OS起動後ログインして、デスクトップが表示されて、その40秒後くらいにやっとRドライブがマウントされて使用可能になる。


その40秒のあいだにMiniCapが動作すると、まだRドライブがないから保存先フォルダが作れないので、MiniCapは「フォルダがありませんよ」ダイアログを出してくる。キャンセルボタンを押せばいいんだけど、個人的にはそんなことしたくない。できるだけ裏方でいてほしいので。


そこで、もし保存先フォルダが存在せず、フォルダ作成もできない(Rドライブが存在しない)場合はMiniCapを起動しない、そんなソフトを作成した。
すごく簡単な C言語 + Win32API のプログラムだけど。Rドライブが存在するか確認(confirm)して、あれば実行(execute)するので confexec.exe というファイル名。GitHubに置いてみたいんだけどGitHubの使い方が不明だ‥‥。



追記: https://github.com/itouhiro/confexec でexeを取得できます。


設定方法
さきほどのタスクスケジューラの実行ファイル(と引数)を変える。

C:\home\bin\MiniCap\confexec.exe -w 61 -d "r:\cap" "MiniCap.exe -customdate \"$Y-$m-$d $H.$M\" -save \"r:\cap\$customdate$.jpg\" -capturedesktop -exit -resizexp 50 -resizeyp 50 -compress 3"

作業フォルダは以下になっているはずだが、なっていなければ、以下を指定する。
C:\home\bin\MiniCap

Windows 7 の設定詳細


この画像では -w 61 が抜けているけど、これを追加しておいたほうがよいみたいだ。ない場合Windows7をスリープから起こしたときに「MiniCap.ini プロセスはファイルにアクセスできません。別のプロセスが使用中です」というダイアログが出ることがあったから。
この -w 61 というのは 61秒待って、それからMiniCap実行するというオプションだ。開始時間を0:04にしておき、61秒後に実行すると指定すれば、ちょうど 13:00, 13:05, 13:10,.. のようにきっちり5の倍数分ごとにスクリーンキャプチャを撮れる。

Windows XP の設定詳細


confexecのソース

コンパイラは gnupack-devel http://sourceforge.jp/projects/gnupack/ を使った。devel版には Mingw32のgccが入っているので、Cygwinに依存しないWindowsプログラムを生成できる。


コンパイラオプションに -mwindows を指定すれば、コマンドラインアプリでもDOS窓コマンドプロンプト)出さずに済む。しかし外部exeファイルを実行するためsystem()関数使うとDOS窓が出てきた。system()の代わりにexternalProcess関数使えばDOS窓出さずにすんだ。余談だが、externalProcess関数の説明が2003年はmsdnにあった(digioTxtという当時作ったプログラムのソースに書いてあった)のだが、今見ると当時のURLでもGoogle検索でも見つからない。Win32APIは使われなくなってきたのか‥‥


[合いの手担当] て君も64bitOS使ってコンパイルしたじゃない? Win32APIって32bit向けAPIでしょ。今だとdotNET Framework使うのがラクなのかなあ


confexec.c

// -*- coding:utf-8 -*-
// Time-stamp: <2012-01-16 12:31 JST>
// confirm existance of the directory and execute

// this program will do
// - Wait seconds 指定秒のウェイト(-w 60)
// - Check existance of the directory ドライブ、フォルダの存在確認(-d "r:\cap")
// - execute 指定コマンド実行("C:\bin\foo.exe -a 1 -f \"r:\cap\aa.jpg\"")

// how to compile (with gnupack-devel 7.02):
//    gcc -O2 -mwindows -o confexec.exe confexec.c ; strip confexec.exe


// func prototype
//
static int externalProcess(char *app, char *param, int wait);

//#include <stdio.h> // printf()
#include <stdlib.h> // exit(), system()
#include <string.h> // memset(), strncpy()
#include "getopt.h" //getopt()
#include <Windows.h> // Sleep()
#include <dirent.h> // opendir()
#include <sys/stat.h> // mkdir()
enum {WAIT, NOWAIT};


int main(int argc, char **argv){
    // variables for getopt
    //
    int opt;
    extern char *optarg;
    extern int optind, opterr;

    // variables
    //
    int wait_sec = 0;
    char dirname[256];
    memset(dirname, 0x00, 256);

    // command line option
    //
    while((opt = getopt(argc, argv, "w:d:")) != -1){
        switch(opt){
        case 'w':
            //printf("wait = %d\n", atoi(optarg));
            wait_sec = atoi(optarg);
            break;
        case 'd':
            //printf("dir = %s\n", optarg);
            strncpy(dirname, optarg, 255);
            break;
        default:
            break;
        }
    }
    argc -= optind;
    argv += optind;

    // confirm existance of argv[0]
    //
    if(argc < 1) exit(EXIT_FAILURE);
    //printf("error arg (%d) = %s\n", argc, argv[0]); exit(-1);

    // wait
    //
    //printf("wait=%d dir=%s)\n", wait_sec, dirname);
    Sleep(wait_sec * 1000);

    // confirm existance of a directory
    //
    if (*dirname != '\0'){
        DIR *dr;
        dr = opendir(dirname);
        if(dr == NULL){
            if(mkdir(dirname)) exit(EXIT_FAILURE);
        }
        // printf("%s is not found\n", dirname);
    }

    // execute
    //
    externalProcess(NULL, argv[0], NOWAIT);
    //system(argv[0]);  // <- CommandPrompt(MS-DOS prompt) appeared

    exit(EXIT_SUCCESS);
}

static int externalProcess(char *app, char *param, int wait){
    STARTUPINFO stinfo;
    PROCESS_INFORMATION psinfo;

    ZeroMemory( &stinfo, sizeof(stinfo) );
    stinfo.cb = sizeof(stinfo);
    ZeroMemory( &psinfo, sizeof(psinfo) );
    CreateProcess(app, param, NULL, NULL, FALSE, 0, NULL, 
                  NULL,
                  &stinfo, &psinfo);
    // Wait until child process exits.
    if(wait == WAIT)
        WaitForSingleObject( psinfo.hProcess, INFINITE );

    // Close process and thread handles. 
    CloseHandle( psinfo.hProcess );
    CloseHandle( psinfo.hThread );

    return 0;
}


プログラミング .NET Framework  第3版 (マイクロソフト公式解説書)

プログラミング .NET Framework 第3版 (マイクロソフト公式解説書)