ご存知のようにレジストリが壊れると悲惨なことになりますので 念には念をいれて、バックアップをとってから始めてください。
さて、前回までのプログラムで保存する情報は、「表示する文字列」
と「スピード」でした。実際にこの情報を格納したレジストリを次に示します。
HKEY_CURRENT_USERキーの下にSoftwareというサブキーがあります。
この下に通常は「会社名」「アプリケーション名」「いろいろな設定」
というような感じでサブキーを作ってデータを保存します。
左の例ではSoftwareの下に「Kumei」というサブキー(会社名または個人名)があり その下にソフトの名前を示す「saver03」というサブキーがあります。 右のウィンドウを見ると「SPEED」と「TEXT」という「名前」があり その横に「300」とか「"粂井康孝 制作"」というデータが保存されているのが わかります。 なお、このような構成をHKEY_CURRENT_USERに作ると 「HKEY_USERS」「.Default」「Software」の下にも全く同じものが 自動的に作られます。
これで、新しいサブキーを作ったりオープンしたりします。LONG RegCreateKeyEx( HKEY hKey, // 親のキー LPCTSTR lpSubKey, // サブキーの名前 DWORD Reserved, // 予約済み(0にする) LPTSTR lpClass, // キーのクラス名 DWORD dwOptions, // キーの記憶オプション REGSAM samDesired, // キーアクセスのオプション LPSECURITY_ATTRIBUTES lpSecurityAttributes, //セキュリティ属性(NULLの時デフォルト) PHKEY phkResult, // 新しいサブキーを受け取るバッファのポインタ LPDWORD lpdwDisposition // 処理後の結果 );
今回はHKEY_CURRENT_USERの下のサブキーを作るのでこれがhKeyとなります。
また、サブキーの名前は"Software\\Kumei\\saver03"というように ディレクトリを指定するのと同じ方法です。(「\」記号は2つずつ つけます。そうしないと\saver03があると「\s」というエスケープシーケンスと 区別が付かなくなるからです。この手の話はC言語の参考書の最初の方に出ています)
Reservedは0にしておきます。
lpClassはキーのクラス名を指定します。(""を指定)
dwOptionsには、REG_OPTION_NON_VOLATILE かREG_OPTION_VOLATILE を 指定します。前者はデータをディスクに書き込みます。後者は書き込みません。
samDesiredには、キーアクセスオプションです。通常はKEY_ALL_ACCESSです。 詳細はヘルプを見てください。
lpSecurityAttributesにはセキュリティ属性を指定します。特別なことをしないときは NULLです。
phkResultは新しいサブキーを受け取るバッファを指定します。
lpdwDispositionには処理後の結果が入ります。サブキーが作成されたときは REG_CREATED_NEW_KEYが入ります。既存のキーがオープンされたときは REG_OPEND_EXISTING_KEYとなります。
戻り値は成功するとERROR_SUCCESSが返されます。失敗したときはエラーコードが 返されます。
hKeyにはRegCreateKeyExで取得したキーを指定します。LONG RegSetValueEx( HKEY hKey, // キーのハンドル LPCTSTR lpValueName, // 設定する値の名前 DWORD Reserved, // 予約済み(0にしておく) DWORD dwType, // データのタイプ CONST BYTE *lpData, // 値に保存するデータへのポインタ DWORD cbData // データの大きさ );
lpValueNameには設定する値の名前です。
dwTypeにはデータタイプを指定します。 REG_DWORDは32ビット値、REG_SZは文字列などを指定します。
lpDataは値に保存するデータへのポインタです。CONST BYTE *なので 実際に使うときは型キャストなどに注意してください。
cbDataにはデータの大きさを指定します。
これで、新しいサブキーを作って値を保存できるようになりました。 使い終わったらキーをクローズします。
これでキーをクローズします。成功したらERROR_SUCCESSが 返されます。失敗したときはエラーコードが返されます。LONG RegCloseKey( HKEY hKey // handle of key to close );
これで値を読み出します。LONG RegQueryValueEx( HKEY hKey, // キーのハンドル LPTSTR lpValueName, // 呼び出す値の名前 LPDWORD lpReserved, // 予約済み(NULLを指定) LPDWORD lpType, // 値のタイプへのポインタ LPBYTE lpData, // データバッファへのポインタ LPDWORD lpcbData // データバッファの大きさへのポインタ );
hKeyはオープンしたキーのハンドルを指定します。
lpValueNameには、呼び出す値の名前を指定します。
lpReservedは常にNULLです。
lpTypeとか、lpcbDataはわかりにくいのですが
というようにしておいて、これらのポインタを指定します。DWORD dwType = REG_SZ; DWORD dwByte = 32;
lpDataには値を受け取るバッファへのポインタを指定します。 データ型に注意してください。
では、プログラムを見てみましょう。
自前のヘッダーファイルです。// saver03.h #define IDC_STATIC -1 #define IDC_EDIT1 2001 #define IDC_EDIT2 2003 #define ID_TIMER 32767
今回はストリングテープルを使いません。 後は、前回にほぼ同じです。// saver03.rc #include <windows.h> #include <scrnsave.h> #include "saver03.h" ///////////////////////////////////////////////////////////////////////////// // // Bitmap // MYBMP1 BITMAP DISCARDABLE "cat1.bmp" MYBMP2 BITMAP DISCARDABLE "cat2.bmp" ///////////////////////////////////////////////////////////////////////////// // // Dialog // DLG_SCRNSAVECONFIGURE DIALOG DISCARDABLE 0, 0, 187, 93 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "設定" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,130,7,50,14 PUSHBUTTON "キャンセル",IDCANCEL,130,24,50,14 EDITTEXT IDC_EDIT1,5,19,82,18,ES_AUTOHSCROLL LTEXT "表示する文字列",IDC_STATIC,6,7,48,8 LTEXT "スピード(1-5000)",IDC_STATIC,7,47,50,8 EDITTEXT IDC_EDIT2,5,59,82,18,ES_AUTOHSCROLL END
プログラムを簡略化するため、HKEY_CURRENT_USERやサブキーの位置を defineしておきました。また、レジストリに値を書いたり読み出したりする 関数も作ることにしました。自作関数のSetIniDataDWORDの第2引数は ポインタではなくDWORD型であることに注意してください。 (あとで関数の中身を見ればわかります)// saver03.cpp #define hParentKey HKEY_CURRENT_USER //親キー #define lpszSubKey "Software\\Kumei\\saver03" //今回作るサブキー #include <windows.h> #include <scrnsave.h> #include "saver03.h" char szText[40]; //スクリーンセーバーに表示する文字列 int nSpeed; //SetTimerにセットする値 //レジストリに読み書きする自作関数 void GetIniDataString(char *, char *); void GetIniDataDWORD(char *, DWORD *); void SetIniDataString(char *, char *); void SetIniDataDWORD(char *, DWORD);
WM_CREATEのところで早速自作関数のGetIniDataStringやGetIniDataDWORD を呼び出して「表示する文字列」とか「スピード」のデータを 読み出しています。他は、前回と同じです。LRESULT WINAPI ScreenSaverProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { RECT rc; HDC hdc, hdc_mem; static int wx, wy; int x1, x2, y1, y2, r, g, b, bmp_w, bmp_h; HBRUSH hBrush, hOldBrush; HBITMAP hBitmap; BITMAP bmp_info; switch(msg) { case WM_CREATE: GetIniDataString("TEXT", szText); GetIniDataDWORD("SPEED", (DWORD *)&nSpeed); GetClientRect(hWnd, &rc); wx = rc.right - rc.left; wy = rc.bottom - rc.top; SetTimer(hWnd, ID_TIMER, nSpeed, NULL); break; case WM_TIMER: r = rand() % 256; g = rand() % 256; b = rand() % 256; hdc = GetDC(hMainWindow); x1 = rand() % wx; y1 = rand() % wy; TextOut(hdc, x1, y1, szText, strlen(szText)); hBrush = CreateSolidBrush(RGB(r, g, b)); hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); x1 = rand() % wx; y1 = rand() % wy; x2 = rand() % wx; y2 = rand() % wy; Rectangle(hdc, x1, y1, x2, y2); if (r % 2 == 0) hBitmap = LoadBitmap(hMainInstance, "MYBMP1"); else hBitmap = LoadBitmap(hMainInstance, "MYBMP2"); GetObject(hBitmap, sizeof(BITMAP), &bmp_info); bmp_w = bmp_info.bmWidth; bmp_h = bmp_info.bmHeight; hdc_mem = CreateCompatibleDC(hdc); SelectObject(hdc_mem, hBitmap); x1 = rand() % wx; y1 = rand() % wy; x2 = rand() % wx; y2 = rand() % wy; BitBlt(hdc, x1, y1, bmp_w, bmp_h, hdc_mem, 0, 0, SRCCOPY); DeleteDC(hdc_mem); DeleteObject(hBitmap); SelectObject(hdc, hOldBrush); DeleteObject(hBrush); ReleaseDC(hMainWindow, hdc); break; case WM_DESTROY: KillTimer(hWnd, ID_TIMER); PostQuitMessage(0); return 0; default: break; } return DefScreenSaverProc(hWnd, msg, wParam, lParam); }
設定ダイアログボックスのプロシージャです。 WM_INITDIALOGのところでレジストリから文字列やらスピードの値を 読み出しています。 GetPrivateProfileStringやGetPrivateProfileInt関数の 場合はデフォルトの値を指定できますが、今回の自作関数では デフォルトの値まで面倒をみていないので自分で設定します。 つまり、レジストリにまだ値が設定されていない場合は nSpeedやszTextに0, ""が設定されてしまいます。 そのような場合は300, "粂井康孝 制作"を設定するようにプログラムして おきました。BOOL WINAPI ScreenSaverConfigureDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { char szTemp[32]; switch (msg) { case WM_INITDIALOG: GetIniDataString("TEXT", szText); if(strcmp(szText, "") == 0) strcpy(szText, "粂井康孝 制作"); SetDlgItemText(hDlg, IDC_EDIT1, szText); GetIniDataDWORD("SPEED", (LPDWORD)&nSpeed); if (nSpeed == 0) nSpeed = 300; wsprintf(szTemp, "%d", nSpeed); SetDlgItemText(hDlg, IDC_EDIT2, szTemp); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: GetDlgItemText(hDlg, IDC_EDIT1, szText, sizeof(szText)); SetIniDataString("TEXT", szText); nSpeed = GetDlgItemInt(hDlg, IDC_EDIT2, NULL, FALSE); SetIniDataDWORD("SPEED", nSpeed); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } return FALSE; }
OKボタンが押されたらエジットボックスから新しい値を読み出して レジストリに書き込みます。
前回同様何もせずにTRUEを返します。BOOL WINAPI RegisterDialogClasses(HANDLE hInst) { return TRUE; }
自作関数の中身です。保存する値の名前と、値(文字列)を指定すると lpszKeyの位置にその値の名前と値が保存されます。void SetIniDataString(char *szName, char *szData) { HKEY hKey; DWORD dwPosition; LONG lResult; RegCreateKeyEx(hParentKey, lpszSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwPosition); lResult = RegSetValueEx(hKey, szName, 0, REG_SZ, (CONST BYTE *)szData, lstrlen(szData)); RegCloseKey(hKey); return; }
RegCreateKeyEx関数の第1引数(hParentKey)は最初にdefineした HKEY_CURRENT_USERです。同じくlpszSubKeyは"Software\\Kumei\\saver03" です。hKeyにキーハンドルが保存されます。dwPositionを調べるとキーの 新規作成か既存キーのオープンかがわかります。(ここでは調べていません)
RegSetValueExでは先ほど取得したhKeyを使ってデータを保存します。 char *型でもらってきたデータをCONST BYTE *型にキャストして 保存している点に注意してください。
残り3つの自作関数を一度に表示しました。1つずつ見ていけば 別に難しくありません。 セットしたり読み出したりするデータが数値か文字列によって 関数を別々に作りましたが、1つにまとめてみてください。 その方がすっきりします。void SetIniDataDWORD(char *szName, DWORD dwData) { HKEY hKey; DWORD dwPosition; RegCreateKeyEx(hParentKey, lpszSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwPosition); RegSetValueEx(hKey, szName, 0, REG_DWORD, (CONST BYTE *)&dwData, sizeof(DWORD)); RegCloseKey(hKey); return; } void GetIniDataString(char *szName, char *szValue) { HKEY hKey; DWORD dwPosition; DWORD dwType = REG_SZ; DWORD dwByte = 32; RegCreateKeyEx(hParentKey, lpszSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwPosition); RegQueryValueEx(hKey, szName, NULL, &dwType, (BYTE *)szValue, &dwByte); RegCloseKey(hKey); return; } void GetIniDataDWORD(char *szName, DWORD *dwValue) { HKEY hKey; DWORD dwPosition; DWORD dwType = REG_DWORD; DWORD dwByte = 32; RegCreateKeyEx(hParentKey, lpszSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwPosition); RegQueryValueEx(hKey, szName, NULL, &dwType, (BYTE *)dwValue, &dwByte); RegCloseKey(hKey); return; }
Update 12/Jun/1998 By Y.Kumei