第226章 FTPの設定をレジストリに保存する


今回は、FTPの基本的設定(ユーザーID、FTPアドレスなど)を ディレクトリに保存して、起動するたびにいちいち入力しなくても よいようにします。また、終了時のウィンドウの位置大きさも記憶して 次回起動時に再現するようにします。さらに、ファイルサイズで ソートしたとき辞書式にソートするのではなく、数字として並び替えを するように改善します。



「サイズ」でソートしてもきちんとソートできるようになりました。 FTPのリストビューも同様です。また「サイズ」列は右揃えに変更しました。



レジストリに書き込み、読み込みをするプログラムはすでに 第129章で解説してあります。 このとき登場しなかった関数にRegOpenKeyEx関数があります。 これは、キーをオープンします。

LONG RegOpenKeyEx( HKEY hKey, LPCTSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult );

RegCreateKeyEx 関数と違い指定されたキーが存在しないときは これを作成しません。

hKeyには、オープンしているキーハンドルまたは、HKEY_CLASS_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERを指定します。

lpSubKeyには、オープンするサブキーを指定します。

ulOptionsは予約済みです。(0を指定)

samDesiredには、セキュリティマスクを指定します。

phkResultには、キーハンドルを受け取る変数のポインタを指定します。

では、プログラムを見てみましょう。

リソース・スクリプトに変更はありません。

myftp.hに構造体のtypedefの追加とレジストリに書き込み、読み出しを する関数のプロトタイプ宣言が追加になっています。

// myftp.h ...省略 typedef struct _tagWINPOS { int x; int y; int wx; int wy; } WINPOS; ...省略 void MyGetInitialData(ACCOUNT *, FTPADDRESS *, WINPOS *); void MySetInitialData(ACCOUNT *, FTPADDRESS *, WINPOS *);

ウィンドウの位置大きさを格納する構造体をtypedefしてみました。 最後の2つの関数は名前のとおりです。

// myftp10.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <wininet.h> #include <windowsx.h> #include <commctrl.h> #include "resource.h" #include "myftp.h" const char szWindowTitle[] = "猫でもわかるFTP"; char szClassName[] = "myftp10"; //ウィンドウクラス BOOL bConnect = FALSE;//インターネットに接続しているかどうか

ウィンドウクラスの名前が変更になった程度です。

WinMain, InitApp, InitInstanceの各関数に変更はありません。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { ...省略 WINPOS winpos = {20, 20, 600, 450};//親ウィンドウの位置、大きさ switch (msg) { case WM_CREATE: MyGetInitialData(&myaccount, &myftpaddress, &winpos); MoveWindow(hWnd, winpos.x, winpos.y, winpos.wx, winpos.wy, TRUE); ...省略 case WM_CLOSE: if (bConnect) { MessageBox(hWnd, "インターネットの接続を切ってから終了してください", "注意", MB_OK); break; } id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { GetWindowRect(hWnd, &rc); winpos.x = rc.left; winpos.y = rc.top; winpos.wx = rc.right - rc.left; winpos.wy = rc.bottom -rc.top; MySetInitialData(&myaccount, &myftpaddress, &winpos); ...省略 } break; ...省略

まったく初回に起動するときのために winpos = {20, 20, 600, 450};と デフォルトの位置、大きさを指定しておきます。

WM_CREATEメッセージがきたらMyGetInitialDataでレジストから読み出して MoveWindowで位置、大きさを指定します。

終了時に、GetWindowRectでウィンドウの位置、大きさを取得して MySetInitialData関数でレジストリに書き込んでいます。

次に変更のあった関数はInsertMyColumnです。

void InsertMyColumn(HWND hList) { LVCOLUMN lc; lc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lc.fmt = LVCFMT_LEFT; lc.cx = 100; lc.pszText = "ファイル名"; lc.iSubItem = 0; ListView_InsertColumn(hList, 0, &lc); lc.fmt = LVCFMT_RIGHT; lc.cx = 75; lc.pszText = "サイズ"; lc.iSubItem = 1; ListView_InsertColumn(hList, 1, &lc); lc.fmt = LVCFMT_LEFT; lc.cx = 110; lc.pszText = "更新日時"; lc.iSubItem = 2; ListView_InsertColumn(hList, 2, &lc); return; }

iSubItemが1のとき(「サイズ」の時)fmtをLVCFMT_RIGHTに設定しています。

次に変更があったのはMyCompProc関数です。

int CALLBACK MyCompProc(LPARAM lp1, LPARAM lp2, LPARAM lp3) { static LVFINDINFO lvf; static int nItem1, nItem2; static char buf1[MAX_PATH], buf2[MAX_PATH]; SORTDATA *lpsd; lpsd = (SORTDATA *)lp3; lvf.flags = LVFI_PARAM; lvf.lParam = lp1; nItem1 = ListView_FindItem(lpsd->hwndList, -1, &lvf); lvf.lParam = lp2; nItem2 = ListView_FindItem(lpsd->hwndList, -1, &lvf); ListView_GetItemText(lpsd->hwndList, nItem1, lpsd->isortSubItem, buf1, sizeof(buf1)); ListView_GetItemText(lpsd->hwndList, nItem2, lpsd->isortSubItem, buf2, sizeof(buf2)); if (lpsd->isortSubItem != 1) { if (lpsd->iUPDOWN == UP) { return(stricmp(buf1, buf2)); } else { return(stricmp(buf1, buf2) * -1); } } else { if (lpsd->iUPDOWN == UP) { if (atoi(buf1) > atoi(buf2)) return 1; else if (atoi(buf1) == atoi(buf2)) return 0; else return -1; } else { if (atoi(buf1) > atoi(buf2)) return -1; else if (atoi(buf1) == atoi(buf2)) return 0; else return 1; } } }

ソートするのが「サイズ」以外(isortSubItemが1以外)の時は 今までと同じです。「サイズ」の時はbuf1,buf2を数値に戻して 比較を行っています。ただこれだけの違いです。

今回新たに作った関数は次の二つです。

void MyGetInitialData(ACCOUNT *lpac, FTPADDRESS *lpftpad, WINPOS *lpwinpos) { LONG lResult; DWORD dwDisposition; HKEY hKeyResult; DWORD dwData; DWORD dwType = REG_SZ, dwType2 = REG_DWORD; lResult = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\kumei\\myftp\\account", NULL, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyResult,&dwDisposition); if (lResult == ERROR_SUCCESS) { if (dwDisposition == REG_CREATED_NEW_KEY) { MessageBox(NULL, "キーが存在しないので新たに作成しました", "OK", MB_OK); } dwData = sizeof(lpac->szUserName); RegQueryValueEx(hKeyResult, "UserID", NULL, &dwType, (LPBYTE)(lpac->szUserName), &dwData); dwData = sizeof(lpac->szPassWord); RegQueryValueEx(hKeyResult, "PassWord", NULL, &dwType, (LPBYTE)(lpac->szPassWord), &dwData); dwData = sizeof(lpftpad->szHost); RegQueryValueEx(hKeyResult, "HostAddress", NULL, &dwType, (LPBYTE)(lpftpad->szHost), &dwData); dwData = sizeof(lpftpad->szBaseDir); RegQueryValueEx(hKeyResult, "BaseDir", NULL, &dwType, (LPBYTE)(lpftpad->szBaseDir), &dwData); } RegCloseKey(hKeyResult); lResult = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\kumei\\myftp\\windowpos", NULL, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyResult,&dwDisposition); if (lResult == ERROR_SUCCESS) { if (dwDisposition == REG_CREATED_NEW_KEY) { MessageBox(NULL, "キーを新規に作りました", "OK", MB_OK); return; } dwData = sizeof(lpwinpos->x); RegQueryValueEx(hKeyResult, "pos_x", NULL, &dwType2, (LPBYTE)&(lpwinpos->x), &dwData); dwData = sizeof(lpwinpos->y); RegQueryValueEx(hKeyResult, "pos_y", NULL, &dwType2, (LPBYTE)&(lpwinpos->y), &dwData); dwData = sizeof(lpwinpos->wx); RegQueryValueEx(hKeyResult, "size_wx", NULL, &dwType2, (LPBYTE)&(lpwinpos->wx), &dwData); dwData = sizeof(lpwinpos->wx); RegQueryValueEx(hKeyResult, "size_wy", NULL, &dwType2, (LPBYTE)&(lpwinpos->wy), &dwData); } RegCloseKey(hKeyResult); return; }

キーが存在しないときは、そのキーを作成して構造体には何も 書き込まずにreturnします。これで、WndProcで定義したデフォルトの 位置、大きさが使われます。

指定のキーが存在するときは値を読み出して、それぞれの構造体に 書き込みます。

ここでうっかり間違えやすいのが、dwDataを読み出すたびに設定するのを 忘れてしまうことです。たとえばユーザーIDやらパスワードやら、 FTPアドレスを格納するメンバ変数は64バイトに定義してあるので (myftp.h参照)つい

DWORD dwData = 64; ... lResult = RegCreateKeyEx(); RegQueryValueEx(hKeyResult, "UserID"...&dwData); RegQueryValueEx(hKeyResult, "PassWord"...&dwData); RegQueryValueEx(hKeyResult, "HostAddress"...&dwData); RegQueryValueEx(hKeyResult, "BaseDir"...&dwData); RegCloseKey();

としてしまうと、なかなかわかりにくいバグとなります。 RegQueryValueEx関数が戻ってくると実際にバッファにコピーされた バイト数がdwDataに格納されます。したがって次のRegQueryValueEx 関数が実行されるときはdwDataの値は64ではありません。次の取得する データが前回より小さいときは正しく実行されますが、そうでないときは 失敗します。そうすると正しく読み込めるものとそうでないものが出てきて かなりわかりにくいバグとなります。 第129章のGetIniDataString関数のようなものを作って 読み出す値を1つ1つこの関数で取得すると、このような間違いは起こりません。

void MySetInitialData(ACCOUNT *lpac, FTPADDRESS *lpftpad, WINPOS *lpwinpos) { HKEY hKey; RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\kumei\\myftp\\account", 0, KEY_ALL_ACCESS, &hKey); RegSetValueEx(hKey, "UserID", 0, REG_SZ, (LPBYTE)(lpac->szUserName), lstrlen(lpac->szUserName) + 1); RegSetValueEx(hKey, "PassWord", 0, REG_SZ, (LPBYTE)(lpac->szPassWord), lstrlen(lpac->szPassWord) + 1); RegSetValueEx(hKey, "HostAddress", 0, REG_SZ, (LPBYTE)(lpftpad->szHost), lstrlen(lpftpad->szHost) + 1); RegSetValueEx(hKey, "BaseDir", 0, REG_SZ, (LPBYTE)(lpftpad->szBaseDir), lstrlen(lpftpad->szBaseDir) + 1); RegCloseKey(hKey); RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\kumei\\myftp\\windowpos", 0, KEY_ALL_ACCESS, &hKey); RegSetValueEx(hKey, "pos_x", 0, REG_DWORD, (LPBYTE)&(lpwinpos->x), sizeof(lpwinpos->x)); RegSetValueEx(hKey, "pos_y", 0, REG_DWORD, (LPBYTE)&(lpwinpos->y), sizeof(lpwinpos->y)); RegSetValueEx(hKey, "size_wx", 0, REG_DWORD, (LPBYTE)&(lpwinpos->wx), sizeof(lpwinpos->wx)); RegSetValueEx(hKey, "size_wy", 0, REG_DWORD, (LPBYTE)&(lpwinpos->wy), sizeof(lpwinpos->wy)); RegCloseKey(hKey); return; }

レジストリに値を書き込む関数です。この関数が呼ばれるときは 必要なキーは存在しているはずなので、RegOpenKeyEx関数で オープンします。

今回はFTPとは直接関係のない部分の手直しでした。


[SDK第3部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 07/Sep/1999 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。