スクリーンセーバーを作ろう!
(1)スクリーンセーバーとして機能させるための部分
スクリーンセーバーを作るポイント
(1)ライブラリ scrnsave.lib を使う。
(2)お約束の3つの関数を用意する。

ってところです。
ん?ライブラリって何?ってか?
ライブラリってくらいだから大英図書館の特殊工作員のザ・ペーパーか?なんのこっちゃ・・・(^^;;;
スクリーンセーバー作るため道具が入ってる道具箱みたいなもんです。
つまりこれを利用すれば、誰でも簡単にスクリーンセーバーが作れちゃうのね。d(^^;;;

(2)のお約束3つの関数ってのは
ScreenSaverProc()
ScreenSaverConfigureDialog()
RegisterDialogClasses()

です。
んじゃ、一つずつ見ていきましょう!

ScreenSaverProc()スクリーンセーバーメッセージ処理部です。
メッセージってなんだ?マッサージか?o(≧Д≦)o
まぁOSから送られているもんなんだけど
ウィンドウが作られたよぉ〜とか、表示されたよぉ〜とか閉じられたよぉ〜とか
そういうのが随時お知らせプログラムの方にくるんだけど、それがメッセージ
う〜む。いい加減な解説・・・m(_ _)m
で、まぁいろんなメッセージがくるんだけど
それに対応した処理させるのが ScreenSaverProc() ってことです。
LRESULT WINAPI ScreenSaverProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg) {
        case WM_CREATE:
            // 起動時やる処理はここに書く
            break;

        case WM_TIMER:
            // タイマーを使った時の処理はここ
            break;

        case WM_DESTROY:
            // 終了時の処理はここに書く
            PostQuitMessage(0);
            return 0;
        default:
            break;
    }
    return DefScreenSaverProc(hWnd, msg, wParam, lParam);
}
WM_CREATE WM_TIMER WM_DESTROY この3つ処理があれば大体大丈夫でしょう!
それぞれ、ウィンドウ生成時タイマー割り込み時ウィンドウ終了時です。
スクリーンセーバ起動時に初期化、タイマーをセットしたりして
終了時にはあと処理。タイマーの処理は画像を表示したりすればOKさっ!
ってことで、実際は↓こうなります。
mouget.cppの一部
LRESULT WINAPI ScreenSaverProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    RECT rc;
    static int wx, wy;
    int x1, y1 ;
    int    sts ;
    int i ;

    switch(msg) {
        // ↓起動時にくるメッセージ
        case WM_CREATE:
            // ↓ウィンドウのサイズを測る
            GetClientRect(hWnd, &rc);
            wx = rc.right - rc.left;
            wy = rc.bottom - rc.top;
            // ↓気にしないで・・・m(_ _)m
            if ( wx < 640 ) break ;

            // ↓領域の初期化
            for ( i = 0 ; i < 10 ; i++ ) {
                hGlobal[i] = NULL ;
            }
            // ↓乱数の初期化・・・っていうか・・・
            srand((unsigned)time(NULL));

            // ↓ini ファイルの読込み
            sprintf( szAppName, MOUAPP_NAME ) ;
            sprintf( szIniFile, MOUINI_NAME ) ;
            DWflag = GetPrivateProfileInt(szAppName, MOU_KEY_DOWNLOAD, 0, szIniFile);

            // ↓"常時接続"にチェックしてるかしてないかの判断
            if ( DWflag == 1 ) {
                // チェックしてある時の処理
                // ↓ダウンロードしているファイルの削除
                DeleteImg() ;
                // ↓ダウンロード実行!
                sts = GetImgList() ;
                if ( sts == 0 ) {
                    // ↓エラーダイアログ
                    MessageBox( hWnd, "ダウンロードに失敗しました。",
                                        MOU_DLG_TITLE, MB_OK | MB_ICONSTOP ) ;
                    break;
                }
                // ↓画像のダウンロード
                sts = GetImage() ;
                if ( sts == 0 ) {
                    // ↓エラーダイアログ
                    MessageBox( hWnd, "ダウンロードに失敗しました。",
                                        MOU_DLG_TITLE, MB_OK | MB_ICONSTOP ) ;
                    break;
                }
            }
            // ↓画像を読み込みメモリ上へ
            ImgCnt = GetPrivateProfileInt(szAppName, MOU_KEY_IMGCNT, 0, szIniFile);
            sts = ReadImg() ;
            if ( sts == 0 ) {
                // ↓エラーダイアログ
                MessageBox( hWnd, "画像をダウンロードしてください。",
                                    MOU_DLG_TITLE, MB_OK | MB_ICONSTOP ) ;
                break ;
            }

            Rflag = TRUE ;

            // ↓タイマーセット!
            SetTimer(hWnd, ID_TIMER, 1000, NULL);
            break;

        // ↓タイマーメッセージ処理
        case WM_TIMER:
            // ↓座標を乱数にて求める
            x1 = rand() % (wx - 400);
            y1 = rand() % (wy - 300);
            ImgNum ++ ;
            if ( ImgNum > (ImgCnt-1) ) ImgNum = 0 ;

            // ↓画像の表示
            ImagePut( hWnd, x1, y1 ) ; 

            break;

        // ↓ウィンドウ終了処理
        case WM_DESTROY:
            // ↓タイマーを切る
            KillTimer(hWnd, ID_TIMER);
            // ↓領域の開放
            for ( i = 0 ; i < 10 ; i++ ) {
                if ( hGlobal[i] != NULL ) {
                    iPicture[i]->Release() ;
                    GlobalFree( hGlobal ) ;
                }
            }
            PostQuitMessage(0);
            return 0;
        default:
            break;
    }
    return DefScreenSaverProc(hWnd, msg, wParam, lParam);
}
なんのこっちゃ・・・でもいつもよりコメントは多めに書いているんですが・・・
詳しくは他の項目の説明をした後でないとわかりにくいかもしれないので簡単に。
WM_CREATE の時には
いくつか初期化処理をしてますね。iniファイルから値を拾ったりもしています。
で「常時接続」ならダウンロードのロジックが走ります。
ダウンロード部分は次章で説明します。
画像を読み込んで、タイマーを1000ms つまり1秒毎ってことで
SetTimer(hWnd, ID_TIMER, 1000, NULL);
で張ってます。
WM_TIMER の時には、つまり1秒毎呼ばれるところです。
乱数で座標を求めて、画像を表示しておしまいです。
画像表示部も後々の章で説明します。
ところで乱数で座標を求めている。
x1 = rand() % (wx - 400);
y1 = rand() % (wy - 300);
って何???
wxとかwyってのはウィンドウの縦と横の長さね。WM_CREATEで求めてますね。
-400 とか -300 は?もうセンセの画像って大体400×300が多いので
画面からハミ出ない様にしてあります・・・(^^;;;



次に
ScreenSaverConfigureDialog()スクリーンセーバーの設定のダイアログ
のメッセージを処理するところね。
↓このダイアログの処理ね。

このダイアログデザイン↓リソースファイルに書かれてます。
まぁ普通はリソースエディタで簡単に書けるもんです。
mouget.rcの一部
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

DLG_SCRNSAVECONFIGURE DIALOG DISCARDABLE  0, 0, 158, 87
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "もうげっとスクリーンセーバーβ4"
FONT 9, "MS Pゴシック"
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,71,69,40,14
    CONTROL         "常時接続",IDC_ONLINE,"Button",BS_AUTOCHECKBOX | 
                    WS_TABSTOP,106,21,43,10
    PUSHBUTTON      "Download",IDC_DOWNLOAD,107,40,40,14
    PUSHBUTTON      "Cancel",IDCANCEL,115,69,40,14
    GROUPBOX        "設定",IDC_STATIC,100,6,54,55
    ICON            IDI_MOU,IDC_STATIC,2,3,20,21
    LTEXT           "もうげっと\nスクリーンセーバー",IDC_STATIC,30,5,67,21
    LTEXT           "Picture by もうの世界\nProgramed by\n       デジタルまるやま製作所",
                    IDC_STATIC,3,32,95,31
END
ダイアログのIDDLG_SCRNSAVECONFIGURE です。
これはお約束みたいですよ。
OKボタンIDOK
CancelボタンIDCANCEL
常時接続チェックボックスIDC_ONLINE
ダウンロードのボタンIDC_DOWNLOAD
とそれぞれボタンにIDが振られてます。
んじゃ、これを踏まえて ScreenSaverConfigureDialog() の方を見てみましょう!
mouget.cppの一部
BOOL WINAPI ScreenSaverConfigureDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    char szTemp[32];
    int    sts ;

    switch (msg) {
        // ↓ダイアログ表示時にくるメッセージ
        case WM_INITDIALOG:
            // ↓ini ファイルの読み込み
            sprintf( szAppName, MOUAPP_NAME ) ;
            sprintf( szIniFile, MOUINI_NAME ) ;
            DWflag = GetPrivateProfileInt(szAppName, MOU_KEY_DOWNLOAD, 0, szIniFile);
            // ↓ダイアログに反映!
            SendMessage(GetDlgItem(hDlg, IDC_ONLINE), BM_SETCHECK, DWflag, (LPARAM)0);
            return TRUE;

        // ↓ボタンとか押した時にくるメッセージ
        case WM_COMMAND:
            switch (LOWORD(wParam)) {
                // ↓OKボタンを押した時の処理
                case IDOK:
                    // ↓チェックボックス結果を ini ファイルに保存
                    DWflag = SendMessage(GetDlgItem(hDlg, IDC_ONLINE),
                                               BM_GETCHECK, (WPARAM) 0, (LPARAM)0);
                    wsprintf(szTemp, "%d", DWflag);
                    WritePrivateProfileString(szAppName, MOU_KEY_DOWNLOAD, szTemp, szIniFile);
                    EndDialog(hDlg, IDOK);
                    return TRUE;
                // ↓Cancelボタンを押した時の処理
                case IDCANCEL:
                    EndDialog(hDlg, IDCANCEL);
                    return TRUE;
                // ↓DOWNLOADボタンを押した時の処理
                case IDC_DOWNLOAD :
                    // ↓ダウンロードしているファイルの削除
                    DeleteImg() ;
                    // ↓ダウンロード実行!
                    sts = GetImgList() ;
                    if ( sts == 0 ) {
                        // ↓エラーダイアログ
                        MessageBox( hDlg, "ダウンロードに失敗しました。",
                                            MOU_DLG_TITLE, MB_OK | MB_ICONSTOP ) ;
                        break;
                    }
                    // ↓画像のダウンロード
                    sts = GetImage() ;
                    if ( sts == 0 ) {
                        // ↓エラーダイアログ
                        MessageBox( hDlg, "ダウンロードに失敗しました。",
                                            MOU_DLG_TITLE, MB_OK | MB_ICONSTOP ) ;
                        break;
                    }
                    // ↓ダウンロード終了通知ダイアログ
                    MessageBox( hDlg, "ダウンロード完了しました。",
                                        MOU_DLG_TITLE, MB_OK | MB_ICONINFORMATION ) ;
                    return TRUE;
            }
            return FALSE;
    }
    return FALSE;
}
WM_COMMAND のところでダイアログのボタン押された時処理が行われてますね。
まぁポイントってところは特にないですね。



最後にはRegisterDialogClasses()は・・・知らない・・・(^^;;;
なんかウィンドウクラスが云々の関数らしいがわかんないので TRUE を返しておしまい。
mouget.cpp の一部
BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
{
    return TRUE;
}

って感じで、スクリーンセーバー外枠できました
ん?WinMain()いらないのかって???
なんかねぇ〜 scrnsave.libやってくれてるらしいっす。

←前へ →次へ