前回と同じ修正が必要。
またこのサンプルを実行するとレギストリに永遠に値が残るのでこれは重大な問題だと癒える。


前回に引き続き、メモリ監視ツールに、オプション項目を付け足してみます。
今回作成するプログラムのサンプルファイルを置いておきますので、参考にしたい方はどうぞ☆
SystemWatcher2.zip(プロジェクトに必要なファイルがすべて入っています)

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

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

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


レジストリ操作

① RegOpenKeyEx関数でレジストリキーをオープン
② RegQueryValueEx関数で値を読み込む / RegSetValueEx関数で値をセットする
③ 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のキャンセルボタンがクリックされたときのイベントです。


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