月刊ソフト作り!
Make The Software For VisualBasic


『スクリーンセーバーを作る(中級編)』
2002.Feb.04

 Presented by kouta_y
感想等は掲示板、苦情はメールへ。

会社
スクリーンセーバー中級編。
この辺りからAPI関数を使います。


前回の続き

さて、前回の初級編ではベース作りだけでした。
今回は、前回やらなかった、

・ 引数による条件分岐
・ 設定の保存
・ マウスを消す
・ ウィンドウを一番前へ

こんな感じです。
ちょっとレベルが上がるので、多少覚悟してください。(と言っても大した程ではない)


標準モジュールを追加する

さて、まずメインとなるモジュールを作ります。
今まではフォームモジュール内にコードを書いていましたが、標準モジュールを使い、グローバルな処理をさせます。
今回は前回サンプルとして作ったプロジェクトをそのまま使います。

前回のサンプル


プロジェクトの階層が表示されているツールボックス内で右クリックし、「追加(A)」→「標準モジュール(M)」を選択します。
んで、標準モジュールを開きます。

オブジェクト名は「mdl_main」と変えてください。


で、次に「Sub Main」というプロージャを作り、下のコードを打ち込んでください。

Sub Main()
'スタートアッププロージャ
Dim cmd As String


'コマンドライン引数を取得
cmd = Command()

Select Case UCase$(Left$(cmd, 2))
   Case "/A": 'パスワード
   Case "/C": '設定
   Case "/P": 'プレビュー
   Case "/S": '実行
   Case Else:
End Select

End Sub

以上が実行時に飛んでくる引数となります。
Commandというのは、実行時の引数を取得する関数です。
UCaseは、大文字に変換する関数です。
小文字の場合もある為こうしています。


グローバル変数を宣言します。
以下の変数をグローバル領域に宣言してください。

Private path  As String 'カレントパス
Public msg    As String '表示する文字
Public intval As Long   '表示間隔

いつもの「Dim」ではなく「Public」で宣言しています。
「Public(パブリック)」とは、外部参照が可能、つまりグローバルな変数という意味です。
「Private(プライベート)」とは、外部参照不可、つまりモジュール内(プライベート領域)でのみ使用可となります。


API関数を宣言する。

ちょっと単調な作業ですが、もうちょっと我慢してください。

・ 設定の保存/取得のAPI
・ マウス消去/表示のAPI
・ ウィンドウの位置設定のAPI

この3つはVBのみでは実現不可です。
「設定」に関しては、ファイルへの保存方法を自作するとか、レジストリなどを使用すれば出来ますが、今回は拡張子が.iniの設定ファイル(初期化ファイルとも言う)を使用するやり方です。

'設定の保存(文字列)
Private Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" ( _
   ByVal lpApplicationName As String, _
    ByVal
lpKeyName As Any, _
    ByVal
lpString As Any, _
    ByVal
lpFileName As String _
) As Long

'設定の取得(文字列)
Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" ( _
    ByVal lpApplicationName As String, _
    ByVal
lpKeyName As Any, _
    ByVal
lpDefault As String, _
    ByVal
lpReturnedString As String, _
    ByVal
nSize As Long, _
    ByVal
lpFileName As String _
) As Long

'設定の取得(数値)
Private Declare Function GetPrivateProfileInt Lib "kernel32" Alias "GetPrivateProfileIntA" ( _
    ByVal lpApplicationName As String, _
    ByVal
lpKeyName As String, _
    ByVal
nDefault As Long, _
    ByVal
lpFileName As String _
) As Long

'マウスの表示
Private Declare Function ShowCursor Lib "user32" ( _
    ByVal bShow As Long _
) As Long

'ウィンドウ位置
Private Declare Function SetWindowPos Lib "user32" ( _
    ByVal hwnd As Long, _
    ByVal
hWndInsertAfter As Long, _
    ByVal
x As Long, _
    ByVal
y As Long, _
    ByVal
cx As Long, _
    ByVal
cy As Long, _
    ByVal
wFlags As Long _
) As Long

なんかごちゃごちゃ書いてありますね。
筆者はこれを全て手打ちした訳ではありません。
VBを持っている人なら、付属に「APIビューワ」というソフトがついてきている筈です。
そこから関数名で検索をかけ「コピー」を押すと、クリップボードにコピーされますので、そのまま「貼り付け」でOKです。

改行しているのは、作者の趣味なので、特に「しないとダメ」という訳ではないです。


最後に上のAPIで使う定数を宣言します。
これもAPIビューアを使えばラクチンです。
「種類」を「定数」に変更して、検索をかけます。

Private Const SWP_NOSIZE      As Long = &H1    'サイズ変更なし
Private Const SWP_NOMOVE      As Long = &H2    '移動しない
Private Const SWP_SHOWWINDOW  As Long = &H40   'ウィンドウ表示
Private Const HWND_TOPMOST    As Long = -1     '一番前へ
Private Const HWND_NOTOPMOST  As Long = -2     '一番前解除

「SetWindowPos」で使う定数のみです。


自作関数の作成

さて、次に自作関数を作ります。
先ほど宣言したAPIは引数がいっぱいあって大変です。
それをいちいち打ち込むのも面倒なので、必要な引数のみ渡せる関数を作成します。


マウスの表示/非表示

Public Function MouseShow(ByVal i As Long)
'マウス表示
'i = 1: 表示
'i = 0: 非表示

Dim rec As Long
Do

    rec = ShowCursor(i)
   If i Then
        If
rec > 0 Then Exit Do
    Else
        If
rec < 0 Then Exit Do
    End If
Loop
End Function

ShowCursor関数の詳しい挙動はここをみてください。
この自作関数は、引数に0を渡せばマウス非表示、それ以外だと表示。と切り替えます。
使うタイミングは、スクリーンセーバーが起動したらマウスを消し、ウィンドウが閉じたら表示(元に戻す)させるようにします。


ウィンドウのZ順位変更

Public Function WinTop(ByVal hWnd As Long, ByVal Flag As Boolean)
'Z位置変更
'flag = True:  最前面
'flag = Flase: 解除

If Flag Then
    Call
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, _
                      SWP_SHOWWINDOW Or SWP_NOSIZE Or SWP_NOMOVE)
Else
    Call
SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, _
                      SWP_SHOWWINDOW Or SWP_NOSIZE Or SWP_NOMOVE)
End If
End Function

SetWindowPos関数は、Z順位だけでなく、位置やサイズを変更させる事も可能です。
今回は最前面か、普通か、を引数Flagで切り分けます。
使うタイミングはマウスと一緒で、起動時に最前面。終了時に元へ戻すとします。


設定保存

Public Function SetINI()
'設定の保存

Call WritePrivateProfileString("MyScr", "Message", msg, path & "\MyScr.ini")
Call WritePrivateProfileString("MyScr", "Interval", CStr(intval), path & "\MyScr.ini")

End Function

WritePrivateProfileString関数の引数の意味は

1: セクション名
2: キー名
3: 設定する文字列
4: ファイルのパス

です。
グローバル変数を保存しています。
使うタイミングは、「設定」されたら。です。
CStr()とは、「文字列型として渡す」という意味です。


設定取得

Public Function GetINI()
'設定の取得

msg = Space(250) '領域の確保 250byte(適当です)
Call GetPrivateProfileString("MyScr", "Message", "たろの部屋", msg, Len(msg), path & "\MyScr.ini")
intval = GetPrivateProfileInt("MyScr", "Interval", 500, path & "\MyScr.ini")

msg = Trim$(msg) 'スペース削除
End Function

引数の意味は、上とほとんど同じですが、3番目の引数は「デフォルト値」となります。
GetPrivatePrifileStringの方は、5番目の引数で、取得するサイズをバイト単位で指定します。
GetPrivateProfileIntの方は、戻り値が取得した値となります。
使うタイミングは、スタートアップルーチン内(Sub Main)です。



とりあえず、だらだらと綴りましたが、作る関数はこれで全部です。


設定ダイアログを作る

次に、スクリーンセーバーの設定をさせるダイアログを作ります。
単調な作業ですが、もうちょっと、もうちょっと我慢してください。


フォームモジュールを追加。

プロジェクトの階層が表示されているツールボックス内で右クリックし、「追加(A)」→「フォームモジュール(F)」を選択します。
んで、いろいろあるテンプレートから「フォームモジュール」を追加します。


これ



プロパティを変える。

以下のような感じでプロパティを変えてください。
特に遵守しなくてはいけないという程ではありません。

(オブジェクト名) Frm_Set
BorderStyle 3 - 固定ダイアログ
Caption MyScrの設定
StartUpPosition 1 - オーナーフォームの中央

コントロールを作る

ここではテキストボックス、ラベル、ボタンの3種類を2つずつ使います。

それぞれこんな感じです。

Label1
Caption 表示する文字列
Label2
Caption 表示間隔(ミリ秒)
Text1
(オブジェクト名) txt_msg
Text2
(オブジェクト名) txt_intval
Alignment 1 - 右揃え
IMEMode 3 - オフ固定
MaxLength 3
Command1
(オブジェクト名) cmd_ok
Caption OK
Default True
Command2
(オブジェクト名) cmd_cancel
Cancel True
Caption キャンセル

レイアウトはこんな感じ。




Labelのオブジェクト名を変更しないのは、実行時(プログラム上では)使用しない為です。(変更する意味がない)
Text2のIMEModeを「オフ固定」にしているのは、全角文字を入力させない為です。
ボタンの「Default」とか「Cancel」というのは、EnterキーもしくはEscキーを押した時のデフォルトボタンという意味です。


筆者は「レイアウトを決めてからコードを書く」という癖がある為とりあえず先にレイアウトを作りました。(その逆の方がやりやすいという人もいるでしょう)


設定ダイアログのコード


さて、「設定」の処理に入ります。
まずコードのエディタ画面を開いてください。


起動時の処理  -  Form_Load
これはテキストボックスへ現在の設定(グローバル変数の内容)を表示させます。

設定の処理  -  cmd_ok_Click
まず正しい情報が入力されたか判定してから、グローバル変数へ値を格納させます。
そして設定の保存をし、ダイアログを閉じます。

キャンセル時の処理  -  cmd_cancel_click
何もせずダイアログを閉じます。


大して難しい処理ではありませんので、ここはご自分でコードを打ってみてください。
数値の判定には、IsNumeric関数。
ダイアログを閉じるには、Unload Me。
設定の取得は、Sub Main内に記述しますので、ここでは省いて結構です。


メインフォームのコード修正

前回作ったサンプルではタイマーの間隔、表示文字は固定でしたが、今回はユーザーが任意で決める為、固定ではいけません。

まず「Private Const」宣言していたものを消し、値を設定しているコードをちょっと編集します。

'ラベルの内容をセット
Label.Caption = msg

'タイマーをセット
Timer.Interval = intval

なんのこっちゃありません。
こんだけです。


自作関数を呼び出す

さっき作った自作関数を起動時と終了時に呼び出します。

Form_LoadイベントプロージャとForm_Unloadイベントプロージャに「MouseShow」と「WinTop」関数を追加してください。
この辺もご自分で追加してみてください。


Sub Main編集

さて、スタートアッププロージャである「Sub Main」の編集をします。
最初に書いた「Select Case」で引数を判別しているので、それぞれの場所に、それぞれのフォームを表示させます。

以下がSub Mainの最終的なコード。

Sub Main()
'スタートアッププロージャ
Dim cmd As String


'コマンドライン引数を取得
cmd = Command()

'カレントパスを取得
path = CurDir$()

'設定取得
Call GetINI

Select Case UCase$(Left$(cmd, 2))
   Case "/A": 'パスワード(無視)
   Case "/C": '設定
        Frm_set.Show

   Case "/P": 'プレビュー(無視)
   Case "/S": '実行
        Frm_main.Show

   Case Else:
       Frm_set.Show

End Select

End Sub

実行

さて、ここまで出来たら1回試しに実行してみましょう。
「プロジェクト(P)」→「MyScrのプロパティ(E)」→「実行可能ファイルの作成」→「コマンドライン引数」でデバッグ時に渡す引数を設定できます。

それぞれの引数でちゃんと実行出来ました?

え?できない?
そんな筈はない。
筆者のはちゃ〜んと・・・、ちゃ〜んと・・・。

できねぇ!


はい。ごめんなさい。
1つ大事な事を忘れてました。
どういう引数を渡してもメインフォームが起動してしまう方は以下の設定を行ってください。

プロジェクトのプロパティから、「スタートアップの設定(S)」を「Frm_Main」から「Sub Main」に変更してください。
これで起動時に走るプロージャが、Frm_MainからSub Mainへ変更されます。

で、もう1回実行してみてください。


正しく動きました?
動かない人は、おそらくコードの打ち間違いです。
この辺でやったブレークポイントなどでデバッグしてください。(デバッグ → バグを除く)


えー、今回はAPI関数なども使ってますので、これが出来れば十分中級と言えるのではないでしょうか?

しかし今回作ったスクリーンセーバー。
これでもまだ必要最低限の機能を搭載したのみであって、完璧ではありません。

・ フォントとか、色の設定もさせたい
・ 表示のさせかたを、点滅だけでなくスクロールとかさせたい
・ あまり長い文字列だと両端が表示されなくなってしまう
・ プレビュー機能やパスワードは・・・?


たろが思いつくだけでこんだけあります。
プレビュー・パスワードについては、次回の「上級編」でやりたいと思います。
その他の機能拡張についてはご自分でやってみるのも良いかと思います。


さて、では今回やったサンプルを下からダウンロードできるようにしました。
「うーん自分で考えたけど、どーしてもわからん!」
という人は参考にしてください。

vb03.lzh(10.6KB)