2011年5月3日火曜日

firefoxの起動を確かめるソフトをwin32sdkで作成

今使っているPC、買ってから8年くらい経つんですよね。 最近特に重く感じます。 少し前に投稿したように、そろそろ買いかえ時でしょうか?

PCの重さが一番気になるのは起動直後です。 セキュリティソフトやその他の常駐ソフトがガリガリ動いていて、さらに最初にブラウザを立ち上げることが多いので重さ感倍増です。 ブラウザがfirefoxだからヒトシオ。

その、起動直後にブラウザを立ち上げようとしたとき、ツールバーに登録したショートカットアイコンをクリックしても重さのドサクサにまぎれて受け付けられないことがあり、困ってしまいます。 ハードディスクのガリガリが収まって、「そろそろブラウザが表示されるかな?」というときに、実はクリックが無視されていて立ち上がってこないことがあるのです。 ほんのちょっと時間を損した気分になります。 このマシンをいつまで使うかはわからないけど、とりあえずの一時しのぎでもクリックが受け付けられたか確認する方法を探さないと...

そこでまず思いついたのがスプラッシュ画面です。 アプリケーション起動前にロゴとかバージョンとかを表示する小さなウィンドウのことです。 普通のソフトなら邪魔なスプラッシュ画面ですが、「ちゃんと起動したか確認したい」ってときには使えなくもないですね。 firefoxで見たことはないですけど、設定を変えたら出てこないかな?

と思って検索したけどありませんでしたね。 その代わり「Splash!」というアドオンを発見しました。 でも、アドオンじゃダメなんです。 なぜなら、アドオンを入れるとfirefoxの起動が遅くなってしまうから。

「より重くしてどうする!」ってことでこれは却下。

次に考えたのは、batファイルでスプラッシュ画面っぽい何かを出すということ。 batファイルに関して検索してみたら、こんな情報がありました。

絵はIrfanViewで簡単に出せるようですね。 今回探した中に音を軽く簡単に出す方法はありませんでした。 上のリンクにある方法だと、ieとかメディアプレイヤーとかが出てきてしまいます。 それじゃあなぁ...

絵だけでいいなら、batファイルでIrfanView → firefoxの順に起動させればOKです。 しかし、調べているうちに絵と音両方を出さないと気がすまなくなってしまいました。 そういうわけで、自分でコーディングすることに。

使う言語は軽くないと意味がありません。 ってことで、お手軽なjavaとC#とjavascript(Rhino)は却下。 久しぶりにwin32apiとC++でやるか?

あれ? Visual C++が無い?

Visual C# 2005 Express Editionしか無いですね。 PCに入っているC++は...っと、Borland C++ Compiler 5.5 だけでした。 今回はbccで作りましょう。

コードは「猫でも分かる」とかその他tipsサイトとかを回ってこんな感じに。 WM_CREATEでfirefoxを立ち上げて、bmpファイルを読み込み、音を鳴らします。 WM_PAINTで読み込んだ画像の表示。 500ミリ秒ごとに発行されるWM_TIMERでfirefoxが表示されたか確認し、表示されていたら終了します。 左クリックされても終了。

// RunFirefox.cpp
#include <windows.h>
#include <tchar.h>

#define WINDOW_WIDTH   (640)
#define WINDOW_HEIGHT  (480)
#define ID_TIMER       (32767)
#define TIMER_INTERVAL (500)
#define WAV_FILE_NAME      (_T("run.wav"))
#define BMP_FILE_NAME      (_T("run.bmp"))
#define EXE_FILE_NAME      (_T("firefox.exe"))
#define APP_CLASS_NAME     (_T("RunFirefox"))
#define FIREFOX_CLASS_NAME (_T("MozillaWindowClass"))

BOOL    RegisterAppClass(HINSTANCE hInst);
BOOL    CreateAppWindow(HINSTANCE hInst, int nCmdShow);
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow)
{
    HWND hWnd;
    MSG msg;

    if(!RegisterAppClass(hInst) )
        return FALSE;
    if(!CreateAppWindow(hInst, nCmdShow) )
        return FALSE;

    while(GetMessage(&msg, NULL, 0, 0) )
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return FALSE;
}

BOOL RegisterAppClass(HINSTANCE hInst)
{
    WNDCLASS wc;
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInst;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = APP_CLASS_NAME;
    
    return RegisterClass(&wc);
}

BOOL CreateAppWindow(HINSTANCE hInst, int nCmdShow)
{
    HWND hWnd;
    
    hWnd = CreateWindow(
        APP_CLASS_NAME,
        APP_CLASS_NAME,
        WS_POPUP,
        (GetSystemMetrics(SM_CXSCREEN) - WINDOW_WIDTH ) / 2,
        (GetSystemMetrics(SM_CYSCREEN) - WINDOW_HEIGHT) / 2,
        WINDOW_WIDTH,
        WINDOW_HEIGHT,
        NULL,
        NULL,
        hInst,
        NULL);
    
    if(!hWnd)
        return FALSE;
    
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    static HBITMAP hBitmap    = NULL;
    static HDC     hBitmapDC  = NULL;
    HWND hFirefoxWnd = NULL;
    HDC  hDC = NULL;
    PAINTSTRUCT ps;
    
    switch( msg )
    {
    case WM_CREATE:
        ShellExecute(NULL, _T("open"), EXE_FILE_NAME, NULL, NULL, SW_SHOW);
        hBitmap = (HBITMAP)LoadImage(NULL, BMP_FILE_NAME, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
        hBitmapDC = CreateCompatibleDC(NULL);
        SelectObject(hBitmapDC, hBitmap);
        PlaySound(WAV_FILE_NAME, NULL, SND_ASYNC | SND_FILENAME);
        SetTimer(hWnd, ID_TIMER, TIMER_INTERVAL, NULL);
        break;
    case WM_TIMER:
        hFirefoxWnd = FindWindow(FIREFOX_CLASS_NAME, NULL);
        if(hFirefoxWnd && IsWindowVisible(hFirefoxWnd) )
        {
            KillTimer(hWnd, ID_TIMER);
            DestroyWindow(hWnd);
        }
        break;
    case WM_PAINT:
        hDC = BeginPaint(hWnd, &ps);
        BitBlt(hDC, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, hBitmapDC, 0, 0, SRCCOPY);
        EndPaint(hWnd, &ps);
        break;
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_DESTROY:
        DeleteObject(hBitmap);
        DeleteDC(hBitmapDC);
        KillTimer(hWnd, ID_TIMER);
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hWnd, msg, wp, lp);
}

win32apiのtipsサイトめぐり、懐かしすぎです。 そして、懐かしすぎてコンパイルの方法が分からない。 ナンテコッタ。

googleで「bcc32 設定」を検索してコンパイルのやり方を確認。 bcc32.cfgとかilink32.cfgとかは書いてあるはずなので、こんなcc.batでいいかな?

SET PATH=D:\tool\bcc\Bin
D:\tool\bcc\Bin\bcc32 -W RunFirefox.cpp

makeとかantじゃなくてcc.batですよ!? これって自分が小学生のときに読んだC言語の入門書にあった知識です。 いくら懐かしいからって記憶をたどりすぎになってます。 しかし、120行程度のコードをコンパイルするためだけに、一生懸命makefileの書き方を思い出すのは面倒です。 makeはカンベンってことでひとつ。

コンパイルで警告がいくつか出たけど、

D:\~\RunFirefox>D:\tool\bcc\Bin\bcc32 -W RunFirefox.cpp
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
RunFirefox.cpp:
警告 W8057 RunFirefox.cpp 35: パラメータ 'hPrevInst' は一度も使用されない(関数 __stdcall WinMain(HINSTANCE__ *,HINSTANCE__ *,char *,int) )
警告 W8057 RunFirefox.cpp 35: パラメータ 'lpsCmdLine' は一度も使用されない(関数 __stdcall WinMain(HINSTANCE__ *,HINSTANCE__ *,char *,int) )
警告 W8004 RunFirefox.cpp 84: 'hDC' に代入した値は使われていない(関数 __stdcall WndProc(HWND__ *,unsigned int,unsigned int,long) )
警告 W8004 RunFirefox.cpp 83: 'hFirefoxWnd' に代入した値は使われていない(関数 __stdcall WndProc(HWND__ *,unsigned int,unsigned int,long) )
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

D:\~\RunFirefox>

使っていない変数とか初期値の警告だけだったので気にしない。 ってことで完成です。 あとは適当にbmpファイルを描いて、フリー素材で音を探してきて、firefoxのフォルダにRunFirefox.exeと絵と音を放り込めば終了。 手抜きコードなのに、それなりに時間がかかってしまった。

ん? run.bmpのファイルサイズ901KB!? でかっ。

でも、他の画像形式を読めるようにコードを改良するのも面倒だし、画像サイズを小さくして16色ビットマップにして済ませるか...