コントロールパネルにアイコンを追加する
1.はじめに
Windowsのコントロールパネルを開くと、複数のアイコンが並んでいる。
例えば、こんな感じだ。
Windows NT 4.0

Windows XP

バージョンや機種・インストールされているアプリケーションの種類などによって、その内容は様々に変わりうる。中には、明らかにWindowsの持ち物と思われるものもあれば、逆に、どう見てもサードパーティにより提供されていると思われるアイコンもある。
ということはつまり、このアイコンは、自分で作って組み込むことができるということを意味している。であれば、オリジナルのものを作って組み入れてみようと思うのは人間としての正常な欲求である。違うか?
ということでこのページでは、Windowsのコントロールパネルにオリジナルのアイコンを追加する方法について解説する。
2.するべきこと
簡潔に言うならコントロールパネルのアイコンは、誰だか知らないが恐らくはエクスプローラが、所定の場所に格納された「CPlAppletという関数をエクスポートするDLL」を読み込むことによって表示している。
つまり、「CPlAppletという関数をエクスポートするDLL」が、エクスプローラか何か知らない奴に対して、コントロールパネルに表示するアイコンの情報と、それがダブルクリックされたときに行うべき機能を提供していると言うことだ。
だから、そのCPlAppletという関数を自分で実装して、それをDLLにして、所定の方法でインストールしてやれば、コントロールパネルに好きな機能を持った好きなアイコンを追加することができるようになる。
3.CPlApplet
CPlAppletという関数は、下記のようなプロトタイプを持っている。
LONG CPlApplet(
HWND hwndCPl,
UINT uMsg,
LONG lParam1,
LONG lParam2
);
いつかどこかで見たことがあるような関数。
この関数に対して、どこかの誰かが下記のようなメッセージを送りつけてくるから、それぞれのメッセージを適当に捌いて処理するような機能を実装してあげればいい。
3.1 CPL_INIT
DLLがロードされた直後に、このメッセージが送られてくる。
何かすることがあるなら、ここで然るべき処理を行えばいい。何もないなら、何もする必要はない。
なお、このメッセージの処理が正常に終了した場合には、CPlApplet関数の戻り値はTRUEでなければならない。0を返すと、コントロールパネルにアイコンを表示してくれなくなる。
3.2 CPL_GETCOUNT
CPL_INITの後に送られてくる。
このDLLが、コントロールパネルにいくつのアイコンを表示したいのかを戻り値として返してやる。ごく普通に、一種類のダイアログボックスを表示したいだけであれば、1を返してやればいい。
3.3 CPL_INQUIRE
CPL_GETCOUNTの後に送られてくる。
コントロールパネルに表示するアイコンの情報を返してやる。このメッセージが送られてくる場合、CPlApplet関数の引数lParam2は、CPLINFOという構造体のアドレスになっているから、その構造体に然るべき値を設定してやる。
CPLINFOは下記のような構造体である。
typedef struct tagCPLINFO {
int idIcon;
int idName;
int idInfo;
LONG lData;
} CPLINFO;
3.3.1 idIcon
コントロールパネルに表示するアイコンの、リソースのIDを設定する。
3.3.2 idName
コントロールパネル中のアイコンの下に表示する名前を定義した、リソースのIDを設定する。
3.3.3 idInfo
コントロールパネルを詳細表示にした場合に表示される、「説明」のカラムに表示する文字列を定義した、リソースのIDを設定する。
3.3.4 lData
CPL_DBLCLKとCPL_STOPのメッセージが送られてくるとき、CPlApplet関数の引数lParam2に、このlDataに指定された値が設定される。
システム側ではこの値を直接使用することはなく、アプリケーションが勝手に使っていいらしい。
3.4 CPL_NEWINQUIRE
CPL_INQUIREと同じようなものだが、CPL_NEWINQUIREメッセージの応答として返した情報の方が優先的に使用される。
ただMSDNには、CPL_INQUIREの方が性能的に有利だから、CPL_INQUIREの処理だけを行って、CPL_NEWINQUIREは無視しろと書いてある。
一応説明しておくと、CPL_NEWINQUIREメッセージが送られてくるとき、lParam2にはNEWCPLINFO構造体のアドレス値が設定される。だから、そのNEWCPLINFO構想対の各メンバに適切な値を設定してやればいいことになる。
NEWCPLINFO構造体は下記のような構造となっている。
typedef struct tagNEWCPLINFO {
DWORD dwSize;
DWORD dwFlags;
DWORD dwHelpContext;
LONG lData;
HICON hIcon;
TCHAR szName[32];
TCHAR szInfo[64];
TCHAR szHelpFile[128];
} NEWCPLINFO;
3.4.1 dwSize
NEWCPLINFO構造体のサイズ、すなわちsizeof( NEWCPLINFO )の値を設定してやる。
3.4.2 dwFlags
使ってないらしい。無視されると書いてある。
3.4.3 dwHelpContex
これも使っていないらしい。無視されると書いてある。
3.4.4 lData
CPL_DBLCLKとCPL_STOPのメッセージが送られてくるとき、CPlApplet関数の引数lParam2に、このlDataに指定された値が設定される。
システム側ではこの値を直接使用することはなく、アプリケーションが勝手に使っていいらしい。
3.4.5 hIcon
コントロールパネルに表示するアイコンのハンドルを指定する。
CPLINFO::idIconだとリソースのIDを指定すればよかったのだが、NEWCPLINFO::hIconの場合は自分でアイコンを読み込んで、ハンドルを取得してやらなければならない。
3.4.6 szName
コントロールパネル中のアイコンの下に表示する名前を設定する。
3.4.7 szInfo
コントロールパネルを詳細表示にしたときに表示される、「説明」のカラムに表示する説明文の文字列を設定する。
3.4.8 szHelpFile
これも使っていないらしい。無視されると書いてある。
3.5 CPL_SELECT
MSDNには書いてあるが、送られてくることはないらしい。
3.6 CPL_DBLCLK
このメッセージは、コントロールパネルに表示されたアイコンがダブルクリックされたときに送られてくる。
このメッセージを受け取ったときに、普通にダイアログボックスを表示してやればいい。また、関数の制御はダイアログボックスが閉じられたときに返せばいいので、MFCであればCDialog::DoModal()を使うと、簡単に実装できる。
処理が終わったら、0でも返しておけばよろしい。
3.7 CPL_STOP
ダイアログボックスが閉じられるときに送られてくる。何かすることがあればすればいいし、何もすることがないなら、何もする必要はないらしい。
3.8 CPL_EXIT
DLLが解放されるとき、つまりFreeLibrary関数によりDLLがアンロードされるときに、このメッセージが送られてくる。何かすることがあるなら、ここでしかるべき処理を行う。何もないなら、何もする必要はない。
3.9 CPL_STARTWPARAMS
Windows 2000以降から追加された。
CPL_DBLCLKと似たような奴で、ユーザがアイコンを選択したときに送られてくる。プログラムとしては、このタイミングでダイアログボックスを表示してやれば良いらしい。
なお、このメッセージが送られてくる場合は、lParam1にはサブプログラム番号が、lParam2には文字列の拡張情報が渡されるらしい。
4.実装
以上の説明を基に、コントロールパネルのアイコンを実装してみることにする。
とりあえずここでは、Win NT 4.0上のVisual Studio 6.0を使っている。ずいぶん、前時代的な気がしなくもないが、基本的なところは環境が変わっても同じはず。
4.1 DLLを作る
とりあえず横着をするために、MFCを利用するDLLを作るものとする。


4.2 CPlApplet関数の作成
cpltest.cppファイルに、下記の記述を追記する
・・・・・・
#include "stdafx.h"
#include "Cpl.h" // 必要な定義が記述されている
#include "cpltest.h"
・・・・・・
CCpltestApp theApp;
LONG APIENTRY CPlApplet(
HWND hwndCPl,
UINT uMsg,
LONG lParam1,
LONG lParam2
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
switch ( uMsg ) {
default:
break;
}
return 0;
}
|
4.3 送られてくるメッセージを処理する
ここままではswitch文の中身が空で、何の役にも立たないため、各メッセージを処理するロジックを実装してやる必要がある。
4.3.1 CPL_INIT
ここでは特にすることはないので、とりあえず1を返しておく。
4.3.2 CPL_GETCOUNT
表示したいアイコンの個数を返す。とりあえずここでは1を返しておく。
case CPL_GETCOUNT:
return 1;
|
4.3.3 CPL_INQUIRE
このメッセージは、CPL_GETCOUNTの時に返した値の数だけ送られてくるのだが、ここでは固定的に1を返しているため、細かいことは気にしないものとする。とりあえず、CPLINFO構造体に値を設定してやればいい。
だがその前に、構造体に設定するためのリソースの定義を行ってやる。
アイコン

ストリングテーブル

そして、定義したリソースを構造体に設定してやる。
case CPL_INQUIRE:
((CPLINFO*)lParam2)->idIcon = IDI_ICON1;
((CPLINFO*)lParam2)->idName = IDS_STRING1;
((CPLINFO*)lParam2)->idInfo = IDS_STRING2;
((CPLINFO*)lParam2)->lData = 0;
|
4.3.4 CPL_NEWINQUIRE
することはないから無視する。
case CPL_NEWINQUIRE:
return 0;
|
4.3.5 CPL_SELECT
送られてくることもないはずだし、とりあえず無視する。
case CPL_SELECT:
return 0;
|
4.3.5 CPL_DBLCLK
MFCで普通にダイアログボックスを定義して、DoModalを呼び出してやればいい。
ダイアログの追加



cpltest.cppにヘッダファイルをインクルード
#include "stdafx.h"
#include "Cpl.h"
#include "cpltest.h"
#include "CplDlg.h"
|
CPlApplet関数のswitch文に、CPL_DBLCLKメッセージを処理する記述を追記。
case CPL_DBLCLK:
{
CCplDlg dlg;
dlg.DoModal();
}
return 0;
|
4.3.6 CPL_STOP
することはないから無視。
4.3.7 CPL_EXIT
することはないから無視。
4.4 CPlApplet関数のエクスポート
作成したCPlApplet関数をエクスポートする必要があるため、defファイルに以下の記述を追記する。
・・・・・・
EXPORTS
; 明示的なエクスポートはここへ記述できます
CPlApplet
|
4.5 コンパイル
うまくコンパイルが通ることを神に祈る。祈りが通じればcpltest.dllファイルが生成されるはずである。
5.インストール
作成したDLLをインストールして、コントロールパネルにアイコンとして表示させるには、以下の方法がある。
5.1 拡張子をcplにして、system32のフォルダに格納する
読んで字のごとく、system32のフォルダに格納してやる。

5.2 レジストリに設定する
HKEY_CURRENT_USER\Control Panel\MMCPLに値を追加する。
名前は何でもいいらしい。文字列の値として、DLLのファイル名を指定する。

うまくいけば、コントロールパネルを開いたときに、新しいアイコンが表示されるはず。
Windows NT 4.0

Windows XP

もっとも、ちゃんとアイコンを書いていないから、真っ白なままだが。
でもって、このアイコンをダブルクリックすれば、下記の様な虚しいダイアログボックスが表示される。

一応、上記の説明で作ったプログラムを公開しておく。
cpltest.zip 12KB
6.複数のアイコンを表示する
CPL_GETCOUNTメッセージの戻り値として、2以上の値を返せば、1つのDLLで複数個のアイコンを表示させることが可能となる。
またその場合、CPL_INQUIRE・CPL_NEWINQUIRE・CPL_DBLCLK・CPL_STOPの各メッセージは、CPL_GETCOUNTで返した値の数だけメッセージが送信されてくる。
さらに、そのときlParam1には、当該のメッセージがどのアイコンに対するものなのかを表すインデックス値が指定される。すなわち、CPL_GETCOUNTで2を返した場合、CPL_INQUIRE・CPL_NEWINQUIRE・CPL_DBLCLK・CPL_STOPの各メッセージが、lParam1が0の場合と1の場合の2回ずつ送られてくることになる。
だから、上記の各メッセージを処理する際に、lParam1の値を見て、それぞれのアイコンに対する処理を行うようにしてあげれば、1つのDLLでアイコンを2つ表示することが可能となる。
プログラムにすると下記のようになる。
switch ( uMsg ) {
・・・・・・
case CPL_GETCOUNT:
return 2; // アイコンを2つ表示する
case CPL_INQUIRE:
switch ( lParam1 ) {
case 0:
// 一つ目のアイコンの情報を設定する
break;
case 1:
// 二つ目のアイコンの情報を設定する
break;
}
return 0;
case CPL_DBLCLK:
switch ( lParam1 ) {
case 0:
// 1つ目のアイコンに対応する処理を行う
break;
case 1:
// 2つ目のアイコンに対応する処理を行う
break;
}
return 0:
・・・・・・
}
|
上記の要領で、アイコンを1つ表示させると、下記のようになる。

余り意味はないが、とりあえずアイコンを2つ表示させるプログラムも公開しておく。
cpltest2.zip 13KB
7.最後に
存外、普通のアプリケーションプログラムでは、コントロールパネルにアイコンを追加しなければならない要件というのは無いようだが、まぁ、好きならやってみるのも良いのではないだろうか。
もっとも、あんまり細かい芸を出し過ぎると、うざったがれることになりかねないがな。
|