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
|