Win32プログラミング講座 〜 Step28. メモリ監視ツールを作るA 〜




前回に引き続き、メモリ監視ツールに、オプション項目を付け足してみます。

今回作成するプログラムのサンプルファイルを置いておきますので、参考にしたい方はどうぞ☆
SystemWatcher2.zip(プロジェクトに必要なファイルがすべて入っています)

オプション項目って何をするの?

・更新間隔の設定
・最前面表示のオン/オフ

今回は、上記の2点と、それら設定項目のレジストリへの保存を試みます。


レジストリ操作

@ RegOpenKeyEx関数でレジストリキーをオープン
A RegQueryValueEx関数で値を読み込む / RegSetValueEx関数で値をセットする
B RegCloseKey関数でレジストリキーを閉じる

各関数のパラメータの詳細は、ヘルプファイルでご確認下さい。



作り方☆

前回のステップ27で作成したプロジェクトに手を加えていきます。
まず、MainWndのRAD画面を開き、下記のように、チェックボタン1つ、通常ボタン1つを挿入します。

次に、OptionButtonが押された時に表示するオプションダイアログを作ります。ProjectViewのMaterialタブ内のWindowフォルダを右クリックし、ウィンドウを挿入します。

OptionDlgにコントロールを挿入し、下の図のような構成に仕上げます。

MainWndのイベントコーディング

※太字は、前回からの変更点を表します。

' ----------------------------------------------------------------------------
'  イベント プロシージャ
' ----------------------------------------------------------------------------
' このファイルには、ウィンドウ [MainWnd] に関するイベントをコーディングします。
' ウィンドウ ハンドル: hMainWnd

' メモ - 以下の領域を、変数、構造体、定数、関数を宣言するための、
'        グローバル領域として利用することができます。
' ----------------------------------ここから----------------------------------

Dim RenewalTiming As Long    '更新間隔

' ----------------------------------ここまで----------------------------------

↑MainWnd.sbpの先頭部分には変更点はありません。RenewalTiming=500という行はあってもなくても構いません。


Sub MainWnd_Destroy()

    'タイマーを終了する
    KillTimer(hMainWnd,0)

    '------------------------------
    ' レジストリに設定値を書き込む
    '------------------------------

    Dim hKey As HKEY
    Dim IsTopMost As Long

    '「常に手前に表示する」ボタンにチェックが入っているかどうかを調べる
    If SendMessage(GetDlgItem(hMainWnd,Check_TopMost),BM_GETCHECK,0,0) Then
        IsTopMost=1
    Else
        IsTopMost=0
    End If

    'レジストリをオープン(サブキーが存在しなときは作成する)
    RegCreateKeyEx(HKEY_CURRENT_USER,"Software\SystemWatcher",0,NULL, _
                         REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,ByVal 0,hKey,0)

    '値 "IsTopMost" に変数 IsTopMost の内容をセットする
    RegSetValueEx(hKey,"IsTopMost",0,REG_DWORD,VarPtr(IsTopMost),Len(IsTopMost))

    '値 "RenewalTiming" に変数 RenewalTiming の内容をセットする
    RegSetValueEx(hKey,"RenewalTiming",0,REG_DWORD,VarPtr(RenewalTiming),Len(RenewalTiming))

    'レジストリ ハンドルを閉じる
    RegCloseKey(hKey)


    SystemWatcher_DestroyObjects()
    PostQuitMessage(0)
End Sub

↑Destroyイベントでは、設定内容のレジストリへの書き込みを行います。


Sub MainWnd_Create(ByRef CreateStruct As CREATESTRUCT)
    Dim buf As String
    Dim BufSize As Long
    Dim hProgBar As Long


    '--------------------------------
    ' レジストリから設定値を読み取る
    '--------------------------------

    Dim hKey As HKEY
    Dim IsTopMost As Long

    'レジストリをオープン
    If RegOpenKeyEx(HKEY_CURRENT_USER,"Software\SystemWatcher",
           0,KEY_ALL_ACCESS,hKey)=ERROR_SUCCESS Then

        '値 "IsTopMost" の内容を変数 IsTopMost にコピーする
        '※読み込みが失敗したときは自動的にIsTopMostの内容は0になる
        BufSize=Len(IsTopMost)
        RegQueryValueEx(hKey,"IsTopMost",0,0,VarPtr(IsTopMost),VarPtr(BufSize))

        '値 "RenewalTiming" の内容を変数 RenewalTiming にコピーする
        BufSize=Len(RenewalTiming)
        If RegQueryValueEx(hKey,"RenewalTiming",0,0,
                VarPtr(RenewalTiming),VarPtr(BufSize))<>ERROR_SUCCESS Then
            '読み込みが失敗したときは、デフォルト値の500にセットする
            RenewalTiming=500
        End If

        'レジストリを閉じる
        RegCloseKey(hKey)
    Else
        'レジストリキーが存在しないときはデフォルト値をセットする
        IsTopMost=0
        RenewalTiming=500
    End If

    If IsTopMost Then
        'IsTopMostの内容が0以外のときは、最前面ウィンドウにする
        SendDlgItemMessage(hMainWnd,Check_TopMost,BM_SETCHECK,BST_CHECKED,0)
        SetWindowPos(hMainWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE Or SWP_NOSIZE)
    End If


    '--------------------------
    ' OSのバージョン情報を取得
    '--------------------------
    Dim OsVerInfo As OSVERSIONINFO
    Dim BuildNum As Long
    OsVerInfo.dwOSVersionInfoSize=Len(OsVerInfo)
    GetVersionEx(OsVerInfo)

    If OsVerInfo.dwPlatformId=VER_PLATFORM_WIN32_WINDOWS Then
        'Windows 9x系OS(メジャーバージョンは常に4)
        Select Case OsVerInfo.dwMinorVersion
            Case 0
                buf="Windows 95"
            Case 10
                buf="Windows 98"
            Case 90
                buf="Windows Me"
        End Select
        BuildNum=LOWORD(OsVerInfo.dwBuildNumber)
    ElseIf OsVerInfo.dwPlatformId=VER_PLATFORM_WIN32_NT Then
        'Windows NT系OS
        If OsVerInfo.dwMajorVersion=4 Then
            buf="Windows NT"
        ElseIf OsVerInfo.dwMajorVersion=5 Then
            If OsVerInfo.dwMinorVersion=0 Then
                buf="Windows 2000"
            ElseIf OsVerInfo.dwMinorVersion=1 Then
                buf="Windows XP"
            End If
        End If
        BuildNum=OsVerInfo.dwBuildNumber
    End If

    'OS情報をウィンドウに表示する
    SetWindowText(GetDlgItem(hMainWnd,Static_OSName),buf)
    SetWindowText(GetDlgItem(hMainWnd,Static_OSBuildNum),Str$(BuildNum))
    SetWindowText(GetDlgItem(hMainWnd,Static_OSNote),OsVerInfo.szCSDVersion)


    '------------------
    ' メモリ情報を取得
    '------------------
    Dim MemStatus As MEMORYSTATUS
	Dim rate_Physical As Long, rate_Virtual As Long
    MemStatus.dwLength=Len(MemStatus)
    GlobalMemoryStatus(MemStatus)

    '物理メモリに関する情報を表示する
    rate_Physical=MemStatus.dwMemoryLoad
    SetWindowText(GetDlgItem(hMainWnd,Static_RatePhysical),Str$(rate_Physical)+"%")
    SetWindowText(GetDlgItem(hMainWnd,Static_TotalPhysical),Str$(Int(MemStatus.dwTotalPhys/1024))+"KB")
    SetWindowText(GetDlgItem(hMainWnd,Static_UsedPhysical),_
                         Str$(Int((MemStatus.dwTotalPhys-MemStatus.dwAvailPhys)/1024))+"KB")

    '仮想メモリに関する情報を表示する
    rate_Virtual= _
Int(CDbl(MemStatus.dwTotalPageFile-MemStatus.dwAvailPageFile)/CDbl(MemStatus.dwTotalPageFile)*100)
    SetWindowText(GetDlgItem(hMainWnd,Static_RateVirtual),Str$(rate_Virtual)+"%")
    SetWindowText(GetDlgItem(hMainWnd,Static_TotalVirtual),Str$(Int(MemStatus.dwTotalPageFile/1024))+"KB")
    SetWindowText(GetDlgItem(hMainWnd,Static_UsedVirtual),_
                         Str$(Int((MemStatus.dwTotalPageFile-MemStatus.dwAvailPageFile)/1024))+"KB")

    '物理メモリ使用率のプログレスバーの初期設定
    SendMessage(GetDlgItem(hMainWnd,ProgressBar_Physical),PBM_SETRANGE,0,MAKELONG(0,100))
    SendMessage(GetDlgItem(hMainWnd,ProgressBar_Physical),PBM_SETPOS,rate_Physical,0)

    '仮想メモリ使用率のプログレスバーの初期設定
    SendMessage(GetDlgItem(hMainWnd,ProgressBar_Virtual),PBM_SETRANGE,0,MAKELONG(0,100))
    SendMessage(GetDlgItem(hMainWnd,ProgressBar_Virtual),PBM_SETPOS,rate_Virtual,0)


    'メモリ使用率のタイマーを設定(RenewalTiming秒間隔)
    SetTimer(hMainWnd,0,RenewalTiming,0)
End Sub

↑Createイベントでは、レジストリの読み込みを行います。


Sub MainWnd_Timer(ByVal TimerID As Long)
    Dim MemStatus As MEMORYSTATUS
    Dim rate_Physical As Long, rate_Virtual As Long


    '------------------
    ' メモリ情報を取得
    '------------------

    MemStatus.dwLength=Len(MemStatus)
    GlobalMemoryStatus(MemStatus)

    '物理メモリに関する情報を更新する
    rate_Physical=MemStatus.dwMemoryLoad
    SetWindowText(GetDlgItem(hMainWnd,Static_RatePhysical),Str$(rate_Physical)+"%")
    SetWindowText(GetDlgItem(hMainWnd,Static_UsedPhysical),_
                         Str$(Int((MemStatus.dwTotalPhys-MemStatus.dwAvailPhys)/1024))+"KB")

    '仮想メモリに関する情報を更新する
    rate_Virtual= _
Int(CDbl(MemStatus.dwTotalPageFile-MemStatus.dwAvailPageFile)/CDbl(MemStatus.dwTotalPageFile)*100)
    SetWindowText(GetDlgItem(hMainWnd,Static_RateVirtual),Str$(rate_Virtual)+"%")
    SetWindowText(GetDlgItem(hMainWnd,Static_UsedVirtual),_
                         Str$(Int((MemStatus.dwTotalPageFile-MemStatus.dwAvailPageFile)/1024))+"KB")

    'プログレスバーの位置を設定
    SendMessage(GetDlgItem(hMainWnd,ProgressBar_Physical),PBM_SETPOS,rate_Physical,0)
    SendMessage(GetDlgItem(hMainWnd,ProgressBar_Virtual),PBM_SETPOS,rate_Virtual,0)
End Sub

↑Timerイベントに変更点はありません。


Sub MainWnd_Check_TopMost_Click()
    If SendMessage(GetDlgItem(hMainWnd,Check_TopMost),BM_GETCHECK,0,0) Then
        '最前面ウィンドウに設定する
        SetWindowPos(hMainWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE Or SWP_NOSIZE)
    Else
        '最前面ウィンドウを解除する
        SetWindowPos(hMainWnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE Or SWP_NOSIZE)
    End If
End Sub

↑「常に手前に表示する」ボタンがクリックされたときのイベントです。SetWindowPos関数を使って、最前面ウィンドウのオン/オフを行っています。


Sub MainWnd_OptionButton_Click()
    Dim ret As Long

    'オプション ダイアログ ボックスを表示する
    ret=DialogBox(hMainWnd,"OptionDlg")

    'キャンセルボタンが押された時は抜け出す
    If ret=-1 Then Exit Sub

    '更新タイミングを変更
    RenewalTiming=ret

    'タイマーを再始動させる
    KillTimer(hMainWnd,0)
    SetTimer(hMainWnd,0,RenewalTiming,0)
End Sub

↑「オプション」ボタンがクリックされたときのイベントです。DialogBox関数でOptionDlgを表示し、更新間隔の取得、設定を行います。


ここから下はOptionDlg.sbp内のコーディングになります。OptionDlgに関するイベントコーディングを行っていきます。

' ----------------------------------------------------------------------------
'  イベント プロシージャ
' ----------------------------------------------------------------------------
' このファイルには、ウィンドウ [OptionDlg] に関するイベントをコーディングします。
' ウィンドウ ハンドル: hOptionDlg

' メモ - 以下の領域を、変数、構造体、定数、関数を宣言するための、
'        グローバル領域として利用することができます。
' ----------------------------------ここから----------------------------------

Sub SetDlgCenter(ByVal hOwner As Long, ByVal hDlg As Long)
    Dim OwnerRect As RECT, DlgRect As RECT
    Dim x As Long, y As Long

    GetWindowRect(hOwner,OwnerRect)    'メイン ウィンドウの座標を取得
    GetWindowRect(hDlg,DlgRect)    'ダイアログボックスの座標を取得

    '新しい座標を計算
    x=((OwnerRect.right-OwnerRect.left)-(DlgRect.right-DlgRect.left))/2 + OwnerRect.left
    y=((OwnerRect.bottom-OwnerRect.top)-(DlgRect.bottom-DlgRect.top))/2 + OwnerRect.top

    '位置を変更
    SetWindowPos(hDlg,NULL,x,y,0,0,SWP_NOSIZE)
End Sub

' ----------------------------------ここまで----------------------------------

↑OptionDlg.sbpの先頭部分のコーディングです。SetDlgCenter関数には、指定したウィンドウを中央に配置する機能を持たせます。


Sub OptionDlg_Create(ByRef CreateStruct As CREATESTRUCT)

    'ダイアログボックスを中央に表示する
    SetDlgCenter(hMainWnd,hOptionDlg)

    'ラジオボタンの初期選択
    Select Case RenewalTiming
        Case 100
            SendMessage(GetDlgItem(hOptionDlg,RadioButton1),BM_SETCHECK,BST_CHECKED,0)
        Case 500
            SendMessage(GetDlgItem(hOptionDlg,RadioButton2),BM_SETCHECK,BST_CHECKED,0)
        Case Else
            SendMessage(GetDlgItem(hOptionDlg,RadioButton3),BM_SETCHECK,BST_CHECKED,0)
    End Select
End Sub

↑OptionDlgのCreateイベントです。RenewalTiming変数の内容を元に、ラジオボタンの初期化を行います。


Sub OptionDlg_OkButton_Click()
    Dim ret As Long

    '選択されているラジオボタンを調べる
    If SendMessage(GetDlgItem(hOptionDlg,RadioButton1),BM_GETCHECK,0,0) Then
        ret=100
    ElseIf SendMessage(GetDlgItem(hOptionDlg,RadioButton2),BM_GETCHECK,0,0) Then
        ret=500
    Else
        ret=1000
    End If

    '戻り値に変数retの内容をセットする
    EndDialog(hOptionDlg,ret)
End Sub

↑OptionDlgのOKボタンがクリックされたときのイベントです。選択されているラジオボタンを調べ、DialogBox関数の戻り値を設定します。この戻り値が、後に更新間隔を示すことになります。


Sub OptionDlg_CancelButton_Click()
    'キャンセルが押された時は、戻り値に-1をセットする
    EndDialog(hOptionDlg,-1)
End Sub

↑OptionDlgのキャンセルボタンがクリックされたときのイベントです。


これで作業は完了です。更新間隔の設定が正常に行われているかどうか、レジストリへの書き込み、読み込みが正常かどうかをチェックしてみましょう。

前へ戻る - 次へ進む
トップへ戻る


©2005 Discoversoft