Windowsレジストリ データの値をプログラムのリソースから取得する方法

提供:yonewiki

各種レジストリ設定・技術に戻る。

概要

 プログラムファイル(*.exe)の中にあるリソース文字列から文字列型のデータを取得することができます。リソースはプログラムファイル内で国際化した状態で格納されていることがあるので、同じリソースIDを指定するにしても、OS側の言語・地域の設定によって表示させる文字を切り替えることができると言えるでしょう。


 あーそうそう。その前にプログラムのリソースに文字列を保有させる方法が必要だよね。国際化ね。i18nだっけ。そうそう。それ。Internationalization=i18nね。数略語だよ。ヌメロニムね。Wikipediaの記事を読んできてみ。あ、知らなかった人だけね。


 開発プロジェクトの設定で、日本語版、英語版を選んで個別の言語ごとのプログラムファイルを作る場合と、起動した人が好きな言語を選択できるようにする2つの手法があると思う。言語ごとに、ユーザインターフェイスの大きさを調整しないといけなかったりするケースもあるし、どっちも大変だよね。でも、ここでは国際化できるのは別の話で、プログラムファイルの中のリソースIDから、文字列を引っ張り出す仕組みと、レジストリのデータとしての記述方法について説明します。


リソースを保有するアプリケーションを作ろう

 どちらかというと開発系のお話なので、開発系の記事の方に同じような内容を記事にしないといけないなぁと思います。この項目の内容は別記事化する予定(しました。)です。


 レジストリから文字列を取得できるというテストをやるために、リソースを保有するアプリケーションを作ってみよう。この記事をみてる人で、ここではじめてレジストリのDATA値にアプリケーションのリソース文字列を取得できることを知った人のなかで、実際にやる気のある人いるといいな。結構、地味に面倒な記事だよね。誰かに刺さるといいな。


 まずコンソールアプリケーションを作ってみよう。特に何もしないアプリケーションでいいよね。さみしいからリソースから設定した文字列を読み込むプログラムにしてみましょう。コンソールアプリケーションを作る基礎の基礎は説明済みなのです。こちらあたりを読むといいでしょう。


 という、わけで先にmain関数まわりに打ち込むべきプログラムを示します。

#include <Windows.h>
#include <iostream>
#include "resource.h"

#include <locale.h>
#include <io.h>
#include <fcntl.h>
int main(){
    HINSTANCE hInstance = GetModuleHandle(NULL);
    wchar_t buffer[256];
    int originalMode = _setmode(_fileno(stdout), _O_TEXT);

    if (LoadString(hInstance, IDS_STRING104, buffer, sizeof(buffer) / sizeof(buffer[0])) > 0) {

        // UTF-8 にコンソールを設定
        _setmode(_fileno(stdout), _O_U8TEXT);

        // Unicode 日本語文字列を表示, bufferも表示できる。
        wprintf(L"こんにちは、世界!\n");
        std::wcout << buffer << std::endl;

        // 元のモードに戻す。元のモードだとsjisに変換しないと駄目になる。
        _setmode(_fileno(stdout), originalMode);

        // SJISに変換
        int requiredSize = WideCharToMultiByte(CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL);
        if (requiredSize > 0) {
            char* sjisBuffer = new char[requiredSize];
            WideCharToMultiByte(CP_ACP, 0, buffer, -1, sjisBuffer, requiredSize, NULL, NULL);

            // 読み込んだ文字列をSJISとして表示
            std::cout << sjisBuffer << std::endl;

            delete[] sjisBuffer;
        }
        else {
            std::cerr << "Failed to convert to SJIS." << std::endl;
        }
    }
    else {
        std::cerr << "Failed to load string resource." << std::endl;
    }
    return 0;
}


 で、このプログラムを入力した上で、リソースを作る必要がありますので、ソリューションエクスプローラから[リソースファイル]フィルタの上で右クリックして表示されるメニュー[追加]-[リソース]を選択します。UIから追加するリソースはプロジェクト名と同じもの一つだけです。複数のリソースファイルを設定することもできます。vcxprojファイルに直接テキスト編集する方法については別の記事で言及したいと思います。


 そして、文字列リソースを追加するため、ソリューションエクスプローラからプロジェクト名.rcを右クリックして、メニュー[追加]-[リソース]を選択します。すると今度はリソース選択ダイアログが表示されるので、項目から[String Table]を選択します。


 すると文字列編集エディタが立ち上がるので、ID・値・キャプションの3つのセットで一つの文字列リソースとなります。IDはIDS_STRING102、値は102から始まり、キャプション欄は空白になっていますので、ダブルクリックして日本語やら英語で適当に文字を打ち込んでもいいです。ここでは、自分は以下のように入力しました。


ID             値    キャプション
IDS_STRING102  9000  接続したときの音
IDS_STRING103  9001  エラーの時の音
IDS_STRING104  9002  転送したときの音


このようにして保存すると、ヘッダファイルresource.hも自動で生成されて、以下のようになります。


//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ で生成されたインクルード ファイル。
// ConsoleResource.rc で使用
//
#define IDS_STRING102                   9000
#define IDS_STRING103                   9001
#define IDS_STRING104                   9002

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        101
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           9003
#endif
#endif


 下の方の_APSなんちゃらは自動発番を管理するためのモノなので、つじつまが合う程度にいじると良いでしょう。「IDS_STRING102 9000」でresource.hが設定され、「IDS_STRING102 9000 接続したときの音」というリソースの設定がされているので、


IDS_STRING102,9000, "接続したときの音" というのが重要な組み合わせになります。コンソールアプリケーションでもリソースにアイコンも追加できるので、これも追加して生成したアプリケーション.exeのアイコンが変化するのを確かめるのも勉強になるでしょう。実行したときのアイコンは変えられませんけどね。


 これでビルド(メニュー[ビルド]-[ソリューションのビルド])すると、リソースを保有したアプリケーションが生成できます。お試しなのでDebug版だけでもビルドできれば十分でしょう。実行ファイルは「ソリューションのパス\x64\Debug」の中に生成されるので、このパスを覚えておきましょう。ここでは、このパスがC:\Users\User_ID\ssource\repos\ConsoleApp\x64\Debug\ConsoleResource.exeであったことにして話を進めましょう。

 

レジストリ設定を変更しよう。

 Windowsのサウンドの設定で確かめてみましょう。


 レジストリエディタでHKEY_CURRENT_USER\AppEvents\EventLabels\MySound_Connectedというキーを作成し(HKEY_CURRENT_USER\AppEvents\EventLabelsまでは既に存在しています。)、そのキーの中のレジストリデータを2つ設定します。


  • 名前(規定)でデータに"Connect"
  • 名前"DispFileName"でデータに"@C:\Users\User_ID\source\repos\ConsoleResource\x64\Debug\ConsoleResource.exe,-9000"


レジストリエディタ画面MySound_Connectedというキー


 とします。更にキー、HKEY_CURRENT_USER\AppEvents\Schemes\Apps\MySoundを作成します。HKEY_CURRENT_USER\AppEvents\Schemes\Appsまでは既に存在しています。


 MySoundのキーのレジストリデータとして、


  • 名前(規定)でデータに"MY SOUND"


レジストリエディタ画面MySoundのキー


 を作成します。更にHKEY_CURRENT_USER\AppEvents\Schemes\Apps\MySound\MySound_Connected\.current


レジストリエディタ画面MySound_Connected\.currentというキー


 というキーを作成します。MySoundConnecteというキーと更にその下に.currentというキーを作ることになります。


 これでコントロールパネルのサウンドのサウンドタブを開くと、プログラムイベントのWindowsのカテゴリのようなものに似た感じで、今作った、MY SOUNDというカテゴリのサウンド設定ができるようになっています。ここに「MY SOUND」-「接続したときの音」というものが出来上がっています。

結論

 このようにレジストリに設定した@C:\Users\User_ID\ssource\repos\ConsoleApp\x64\Debug\ConsoleResource.exe,-9000という設定によってリソース文字列ID 9000 に対応する文字が設定できます。負の数値にするというのは決まりなので覚えないとだめですね。


レジストリでプログラムリソース文字列を参照した例


 この作業によって、リソース文字列をレジストリで使うことができることが確かめれたと思いますが、確かめるために作ったレジストリは不要なので、気が済んだら消しておきましょう。これで一つ知識が増えたね。

 

各種レジストリ設定・技術に戻る。