MFC
INI ファイルによる情報の保存(マルチユーザー対応)


HomeProgramming TipsMFC Tips[MFC-008]

ヘビーユーザーの希望はあくまでも ini ファイルでの環境保存です。
私もここは一つ、ini ファイルでの環境保存を行いたいと思います。

■ 保存場所

ini ファイルを使う場合、全体共通設定は自分(exeファイル)の場所に保存します。
…でした。現在は、All Users\Application data に保存するのが良いとされています。
ユーザー別情報は [user profile]\Application data がベストです。

これらのフォルダは SHGetFolderPath() により場所を取得してから使います。


    // ユーザー毎の情報保存先
    TCHAR szAppUserData[MAX_PATH];
    ::SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, szAppUserData);

    // 全ユーザー共通の情報保存先
    TCHAR szAppAllData[MAX_PATH];
    ::SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szAppAllData);



■ 準備

まず、コンパイル条件を変更します。
MFC であれば、stdafx.h の定義を書き換えます。


#ifndef _WIN32_IE
#define _WIN32_IE 0x0500
#endif


とりあえず、一般的な約束事に習い、会社名/アプリ名とします。
SetRegistryKey(); は削除してください。これがあるとレジストリに書き込みにいきます。

フォルダが存在しない場合は、自分で作らなければいけません。
複数のフォルダを一気に掘るには MakeSureDirectoryPathExists() がお勧めです。
これを使うにはヘッダとライブラリを指定します。


#include "Imagehlp.h"
#pragma comment(lib, "Imagehlp.lib")



例えば、私 VALGUS が、MixerStrapper の情報を ini ファイルとして書き込むのであれば、


    TCHAR szAppUser[MAX_PATH];
    if FAILED(::SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, szAppUser))
        return FALSE;
    CString strAppUser = szAppUser;
    strAppUser += _T("\\VALGUS\\");
    ::MakeSureDirectoryPathExists(strAppUser);
    strAppUser += _T("MixerStrapper.ini");


と、なります。

MFC の ini ファイルアクセスはデフォルトで Windows フォルダとなっています。
そのため、Application data にアクセス先を変更します。
メンバ変数 m_pszProfileName を任意の場所に変更すれば良いです。
場所は InitInstance のなるべく後方です。


    if (m_pszProfileName) free((void*)m_pszProfileName);
    m_pszProfileName = _tcsdup(strAppUser);


勝手に new しましたので、作った本人が責任持って開放しなければいけません。
※2005/07/16追記
まず、m_pszProfileName は、new ではなく _tcsdup() で確保されていますので、delete ではなく free で削除するのが正しいです。
次に m_pszProfileName は値が入っていることが前提ですので、自分で削除してはいけません。
以上、お詫びして訂正いたします。ご指摘ご指導くださったヴォーガ氏に感謝します。


■ アクセス(保存)

データを保存するには WriteProfileInt(数値情報の保存)、WriteProfileString(文字情報の保存)を使います。
準備で用意したアクセス先は CMyApp メンバですので、そこから情報を取り出します。


    CWinApp* pApp = AfxGetApp();
    pApp->WriteProfileInt(_T("セクション名"), _T("エントリ名"), 書き込む値);
    pApp->WriteProfileString(_T("セクション名"), _T("エントリ名"), 書き込む文字列);


例えば、


    pApp->WriteProfileInt(_T("Default"), _T("VolumeValue"), 50);
    pApp->WriteProfileString(_T("Default"), _T("VolumeName"), _T("音量"));



このプログラムを実行すると VALGUS\MixerStrapper.ini ファイルに


[Default]
VolumeValue=50
VolumeName=音量


と書き込まれます。
値が正しく書き込まれたかどうかは戻り値が TRUE(成功)か否かで判断します。


    CWinApp* pApp = AfxGetApp();
    if (!pApp->WriteProfileInt(_T("Default"), _T("VolumeValue"), 50)){
        // 書き込み失敗
    }



■ アクセス(読込)

データを読み込むには GetProfileInt(数値情報の読込)、GetProfileString(文字情報の読込)を使います。



    CWinApp* pApp = AfxGetApp();
    UINT uValue = pApp->GetProfileInt(_T("セクション名"), _T("エントリ名"), 規定値);
    CString str = pApp->GetProfileString(_T("セクション名"), _T("エントリ名"));


例えば、


    CString strName = pApp->GetProfileString(_T("Default"), _T("VolumeName"));
    int nVol = pApp->GetProfileInt(_T("Default"), _T("VolumeValue"), -1);
    ASSERT(!strName.IsEmpty());
    ASSERT(nVol != -1);


まずまず簡単ですね。



 Copyright 2005 VALGUS. All Rights Reserved.