日本Delphi振興会 | Delphiはじめて物語 | Delphiつれづれ記 | Delphiリンク互助会 | Delphiアクセサリ |
Delphi壁の穴
その三:レジストリを覗く
ここではレジストリの操作方法をご紹介します。
目次
この中で特に重要なのが、TRegistryは「バイナリ」も「DWORD値」も扱えるが、TRegIniFileは扱えないということです。Registy.pasのソースコードを見れば分かると思いますが、RegIniFileでWriteIntegerするとき、すなわちレジストリに数値を書き込むときにはIntToStrを使って文字列に直してから書き込みます。反対にレジストリから数値を読むとき、ReadIntegerでは、StrToIntを使って文字列を数値に変換しているのです。TRegistryを使えば、数値はDWORD値として保存されます。これは良くも悪くもINIファイルの名残だと思いますが、自分で作ったアプリケーションの設定値を保存するのでしたら、数値が文字列に変換されてレジストリに書き込まれても特段問題はないので、簡単に書けるTRegIniFileを使うことをお勧めします。
しかし、レジストリ全般を扱うとなれば、DWORD値を読み込み、書き込むことが必要になってくるでしょう。そういうときにTRegistryの方を使えばいいのです。また、TRegIniFileは、読み込みたい値のあるキーを勝手に作ってしまう性質があります。自分で作ったアプリケーションの設定場所であるキーならば特に問題ないでしょうが、システム関連ともなれば勝手にキーを作るのは困りものです。TRegistryで必ず使うOpenKeyメソッドでは「キーがなければとにかく作る」と「キーがなければ作らない」の2種類を選択できるようになっています。
次に両者の基本的なコーディング方法をご紹介します。
(略)
{終了時に保存}
procedure TForm1.FormCloseQuery(Sender: TObject);
const
AppKey='\Software\MySoft';
var
RegIniFile:TRegIniFile;
begin
RegIniFile:=TRegIniFile.Create(AppKey);
with RegIniFile do
begin
try
WriteInteger('Window','Left',Left);
WriteInteger('Window','Top',Top);
WriteInteger('Window','Height',Height);
WriteInteger('Window','Width',Width);
finally
Free;
end;
end;
end;
数値を保存するときは「WriteInteger」、文字列は「WriteString」、論理値(True/False)は「WriteBool」を使います。
※FormCloseはアプリケーションを自分で終了させたときに発生するイベントですが、FormCloseQueryは、アプリケーションが起動しているときにWindowsが終了した場合にも、発生するところがFormCloseとの違いです。だからFormCloseQueryの方が確実に設定を保存できます。
次に、保存した設定内容を起動時に読み込んでみましょう。
数値を読み込むときは「ReadInteger」、文字列は「ReadString」、論理値(True/False)は「ReadBool」を使います。
関連づけの設定場所は、HKEY_CLASSES_ROOTの下にあります。レジストリエディタで見ればわかると思いますが、「.ini」のように拡張子の名前が付いたキーがずらっと並んでいます。
「inifile」キーを開くと「DefaultIcon」キーと「shell」キーがあり、「shell」キーを開いていくと、「command」キーがあります。「DefaultIcon」キーにファイルのアイコンを指定し、「command」キーにダブルクリックで起動するアプリケーションを指定します。
ちなみに、どうして「.ini」と「inifile」が分かれているかというと、例えば拡張子が「pas」のファイルを「ini」ファイルと同じアプリケーションで起動したい場合、「.pas」キーの値に「(標準) "inifile"」と指定すれば、pasファイルはiniファイルと同一のアプリケーションで起動できるようになるのです。「.htm」と「.html」には同じデータが入っているはずです。
アプリケーションの設定を保存するにはTRegIniFileを使いましたが、一般的にレジストリ全般をいじくるには、TRegistryを使います。ファイルの関連づけ設定にもこれを使います。例として拡張子を「epl」、関連づける名前を「example」とし、手続き LinkExt を記述します。
(略)
{ファイルの関連づけ}
procedure LinkExt;
const
CommandKey='\example\shell\open\command';
var
Reg:TRegistry;
begin
Reg:=TRegistry.Create;
with Reg do
begin
try
RootKey:=HKEY_CLASSES_ROOT; {ルートキーを指定}
OpenKey('\.epl',True); {.eplキーを作成して開く}
WriteString('','example'); {(標準)のデータにexampleを書き込む}
OpenKey('\example',True);
WriteString('','関連づけファイル'); {ファイルの種類を指定}
OpenKey('\example\DefaultIcon',True);
WriteString('',ParamStr(0)+',0'); {ファイルのアイコンを指定}
OpenKey(CommandKey,True); {commandキーを作成して開く}
WriteString('','"'+ParamStr(0)+'" "%1"'); {開くアプリケーション名を指定}
finally
Free;
end;
end;
//関連づけの変更をエクスプローラに反映させる
SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_FLUSH,nil,nil);
end;
●次に、アプリケーションをファイルの関連づけに対応させる方法をご紹介します。
関連づけやドラッグドロップ(以下D&Dと略す)を行うと、アプリケーションの第一パラメータにそのファイルのフルパスが渡されます。この第一パラメータを参照することで、ファイルを開くことが出来ます。
参照するにはParamStrを使います。ParamStrには、パラメータの値がすべて入っています。例えば「C:\Delphi 3\delphi.exe c:\Delphi 3\project1.dpr /p」では、ParamStr(0)に C:\Delphi~1\delphi.exe が、ParamStr(1)に c:\Delphi~1\project1.dprが、ParamStr(2)に /p が入っています。今回は第一パラメータが必要なので、ParamStr(1)を使います。例としてTMemoでファイルを開きましょう。
複数のファイルが選択されている場合は、ParamCountが役立ちます。ParamCountにはパラメータの数が入っているからです。
(略)
procedure NewsIdSetting;
const
News='\Software\Microsoft\Internet Mail and News';
var
Reg:TRegistry;
begin
Reg:=TRegistry.Create;
with Reg do
begin
try
RootKey:=HKEY_CURRENT_USER;
if OpenKey(News , False) then
WriteInteger('DoNotGenerateNewsMessageId' , 1);
finally
Free;
end;
end;
end;
使い方は、「Label1.Caption:=GetShellFolder(gsfRecent);」のようにします。
なお、APIを使うバージョンもあります(こちらの方が一般的でしょう)。
-----ここから------
レジストリファイルのインポートとエクスポート行います.
REGEDIT [/L:システム] [/R:ユーザー] ファイル名1
/L:システム------SYSTEM.DAT ファイルの位置を指定します.
----ここまで-------
例えば、HKEY_CURRENT_USER以下を「User.reg」に保存するには、
とDOSプロンプトから打ち込めばいいことになります。詳しくは、Regedit.exeを適当なテキストエディタで開いてみて下さい。
これをDelphiで行うには、
のようにします。
#ちなみに、REGファイルの中身を「レジストリ スクリプト」と呼ぶようです。試しに適当なファイルの拡張子を「.reg」に変えてダブルクリックしてみて下さい。「...指定されたファイルはレジストリ スクリプトではありません。...」という内容のエラーメッセージが出てきます。ほんとにそう呼ぶのかは分かりませんけどね。
DeleteKeyは指定したキーの下にあるサブキーも一緒に削除します。だからcccキーも削除されます。しかし、cccキーはOpenKeyによって開かれているので、削除できません。そのため、aaaキーを削除しようとしても無効になってしまうのです(文法エラーにはならない)。
なお、現在開いているキー以外のキーを削除する場合は、CloseKeyする必要はありません。
現在開いているキー(カレントキー)は「\Software\TestApp」なので、その下にあるキーは上記のようにして消すことが出来ます。しかし、カレントキーよりも上にあるキーを消すには、カレントキー自体の移動が必要です。その場合は、やはりTRegistryにキャストしてOpenKeyメソッドを使います。例としてTestApp自体を消してみましょう。
こうすれば、従前のキーをきれいさっぱり消して、新しくキーを作成し直すことが出来るわけです。
Delphi壁の穴
Delphiを覗く
システムを覗く
アプリケーションを覗く
一番上へ
・レジストリ操作の基本を知る。
Delphiは、レジストリの操作をするためのユニット「Registry」を提供しています。レジストリを操作するにはこのユニットをuses節に追加する必要があります。Registryユニットは、レジストリ操作のために2つのクラスを用意しています。「TRegistry」と「TRegIniFile」です。両者の違いを以下にまとめます。
機能 TRegistry TRegIniFile
用途 システム全般を操作 アプリケーションの設定を保存
長所
短所
TRegistry TRegIniFile
procedure TForm1.Create(Sender: TObject);
const
{データが入っているキーを指定}
AppKey='\Software\Test\Setting';
var
Reg:TRegistry;
begin
//Registryオブジェクトを作成
Reg:=TRegistry.Create;
with Reg do
begin
try
RootKey:=HKEY_CURRENT_USER;
{キーを開く。第2引数をTrueにするとキーがなければ作る}
if OpenKey(AppKey,True) then
begin
//データ読み込み。
{TRegistryという名前の文字列データを取得}
Label1.Caption:=ReadString('TRegistry');
try
{Valueという名前の DWORDデータを取得}
SpinEdit1.Value:=ReadInteger('Value');
//Valueが存在しない場合に備え、例外処理を行っておく
except
SpinEdit1.Value:=0;
end;
end;
finally
//Registryオブジェクトを解放。
{何があっても解放できるように必ずtry..finallyでくくる。}
{Freeするとき、CloseKeyも同時になされる}
Free;
end;
end;
end;
procedure TForm1.Create(Sender: TObject);
const
{データが入っているキーの1つ上のキーを指定}
AppKey='\Software\Test';
var
RegIni:TRegIniFile;
begin
//RegIniFileオブジェクトを作成
RegIni:=TRegIniFile.Create(AppKey);
with RegIni do
begin
try
RootKey:=HKEY_CURRENT_USER;
//データ読み込み。ここでデータが入っているキー(Setting)を指定する
{Stringデータを取得}
Label1.Caption:=ReadString('Setting','TRegistry','');
{Integerデータを取得。例外処理は不要。Value がなければ0が代入される}
SpinEdit1.Value:=ReadInteger('Setting',Value',0);
finally
//RegIniFileオブジェクトを解放。
{何があっても解放できるように必ずtry..finallyでくくる。}
{Freeするとき、CloseKeyも同時になされる}
Free;
end;
end;
end;
・レジストリにアプリケーションの設定を保存する。
アプリケーションの設定保存場所は、HKEY_CURRENT_USER\Software の下と決まっています。TRegIniFileを使えば簡単に設定を保存できます。
例として、Softwareの下にMySoftというキーを作り、さらにその下にWindowキーを作って、フォームの位置と大きさを保存してみましょう。
uses ..... , Registry; {uses節に追加}
かっこ内には、(' 保存先のキー ',' 保存するデータの名前 ',保存するデータ); のように書きます。
{設定を読み込む}
procedure TForm1.FormCreate(Sender: TObject);
const
AppKey='\Software\MySoft';
var
RegIniFile:TRegIniFile;
begin
RegIniFile:=TRegIniFile.Create(AppKey);
with RegIniFile do
begin
try
Left:=ReadInteger('Window','Left',0);
Top:=ReadInteger('Window','Top',0);
Height:=ReadInteger('Window','Height',300);
Width:=ReadInteger('Window','Width',385);
finally
Free;
end;
end;
end;
かっこ内には、(' 読込先のキー ',' 読み込むデータの名前 ',デフォルト値); のように書きます。デフォルト値は読み込むデータがない場合に使われます。
「ReadInteger('Window','Left',0);」は、WindowキーにあるLeftという名前に入っているデータを読み出します。
・レジストリにファイルの関連づけを設定する。
自分で作ったソフトが独自の拡張子を持つファイルを扱う場合、そのファイルをダブルクリックで開けたら便利です。そのためには、レジストリに関連づけを設定しなければなりません。以下にその方法をご紹介します。
「.ini」キーを開いてみると、右側に「(標準) "inifile"」のように表示されます。「inifile」が重要です。下の方のキーをさらに見ていくと、「inifile」という名前のキーがあるはずです。
uses ..... , Registry, ShlObj; {uses節に追加}
ここで注意しなければならないのは、TRegIniFileのときのWriteStringとTRegistryのWriteStringは、パラメータが違うことです。TRegIniFileでは、(' 保存先のキー ',' 保存するデータの名前 ',保存するデータ); でしたが、TRegistryでは保存先のキーはすでにOpenKeyで指定されているので、(' 保存するデータの名前 ',保存するデータ); となります。ちなみに、ReadStringでも同様のことがいえます。
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Lines.LoadFromFile(ParamStr(1));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
for i:=1 to ParamCount do
begin
{開く処理 - ParamStr(i)を使う}
end;
end;
・レジストリにDWORD値を記録させる
TRegistryのWriteIntegerを使います。ここで重要なのは、TRegistryを使うことです。TRegIniFileだと、文字列に変換して記録されてしまいます。
uses ..... , Registry; {uses節に追加}
・レジストリにバイナリ値を記録させる
TRegistryのWriteBinaryDataを使います。ここで重要なのは、TRegistryを使うことです。
procedure TForm1.Button1Click(Sender: TObject);
const
FsKey='\SOFTWARE\Microsoft\Windows\CurrentVersion\FS Templates\';
var
Reg:TRegistry;
NameCache,PathCache:integer;
begin
Reg:=TRegistry.Create;
with Reg do
begin
try
RootKey:=HKEY_LOCAL_MACHINE;
OpenKey(Fskey+'Mobile',True);
NameCache:=337; {51 01 00 00}
PathCache:=16; {10 00 00 00}
WriteBinaryData('NameCache',NameCache,4);
WriteBinaryData('PathCache',PathCache,4);
OpenKey(Fskey+'Server',True);
NameCache:=2729; {a9 0a 00 00}
PathCache:=64; {40 00 00 00}
WriteBinaryData('NameCache',NameCache,4);
WriteBinaryData('PathCache',PathCache,4);
finally
Free;
end;
end;
end;
・各種のシェルフォルダを得る(レジストリ版)。
シェルフォルダというのは、Windows\ 以下にある、シェルに関するフォルダのことです。これらの情報はレジストリに記録されているので、それを読み込んでやれば得ることが出来ます。そのような関数を作ってみました。
uses Windows.....Registry;
type
TShellFolder=(gsfDesktop,gsfFavorites,gsfFonts,gsfNetHood,
gsfPersonal,gsfPrograms,gsfRecent,gsfSendTo,
gsfStartMenu,gsfStartUp,gsfTemplates);
(略)
{各種シェルフォルダを得る}
function GetShellFolder(Kind: TShellFolder):string;
const
FolderKey='\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders';
Folder:array[TShellFolder] of string =
('Desktop','Favorites','Fonts','NetHood','Personal',
'Programs','Recent','SendTo','Start Menu','Startup',
'Templates');
var
Reg:TRegistry;
begin
Reg:=TRegistry.Create;
with Reg do
begin
try
RootKey:=HKEY_CURRENT_USER;
if OpenKey(FolderKey,False) then
Result:=ReadString(Folder[Kind])+'\'
else Result:='';
finally
Free;
end;
end;
end;
・REGファイルを作る。
レジストリの内容を保存するには、TRegistryのSaveKeyを使いますが、これで作られたファイルはバイナリファイルで、いわゆる「.reg」を拡張子とするファイルとは違います。普通はバイナリファイルの方でいいのですが、レジストリをいじるアプリを作った場合に、ユーザーにRegファイルをダブルクリックさせてレジストリを復旧させるような時には、Regファイルの方が便利です。
しかし、Regファイルを直接作るAPIなどは存在しません。Regファイルを作るのは実はレジストリエディタ自身の機能なのです。コマンドラインからパラメータを指定することでRegファイルを作成できます。以下にパラメータを示します。
REGEDIT [/L:システム] [/R:ユーザー] /C ファイル名2
REGEDIT [/L:システム] [/R:ユーザー] /E ファイル名3 [レジストリパス]
/R:ユーザー------USER.DAT ファイルの位置を指定します.
ファイル名1------レジストリにインポートするファイル(複数可)を指定します.
/C ファイル名2---レジストリを作成するためのファイルを指定します.
/E ファイル名3---レジストリをエクスポートするファイルを指定します.
レジストリパス---エクスポートを開始するレジストリキー指定します.
(指定がなければ, レジストリ全体をエクスポートします.)Regedit /E User.reg HKEY_CURRENT_USER
uses Windows,......,ShellAPI; {ShellAPIを追加}
(略)
procedure TForm1.Button1Click(Sender: TObject);
begin
ShellExecute(Handle,'Open','Regedit.exe',
'/E User.reg HKEY_CURRENT_USER','',SW_SHOW);
end;
・TRegistryでDeleteKeyできない。
例えば以下のような場合は、DeleteKeyできません。
procedure TForm1.Button1Click(Sender: TObject);
var
Reg:TRegistry;
begin
Reg:=TRegistry.Create;
with Reg do
begin
try
RootKey:=HKEY_LOCAL_MACHINE;
OpenKey('\aaa\bbb\ccc',True); {cccキーを開く}
WriteString('Gojuon','aiueo'); {値を書き込む}
DeleteKey('\aaa'); {aaaキー以下を削除}
finally
Free;
end;
end;
end;
この場合は、DeleteKeyする前に、明示的にキーをクローズしてやる必要があります。そのためには、CloseKeyを使います。
procedure TForm1.Button1Click(Sender: TObject);
var
Reg:TRegistry;
begin
Reg:=TRegistry.Create;
with Reg do
begin
try
RootKey:=HKEY_LOCAL_MACHINE;
OpenKey('\aaa\bbb\ccc',True);
WriteString('Gojuon','aiueo');
CloseKey; {現在開いているキーを閉じる}
DeleteKey('\aaa'); {aaaキー以下を削除できる}
finally
Free;
end;
end;
end;
・TRegIniFileでキーを丸ごと削除する
キーを削除するにはDeleteKeyを使うのですが、TRegIniFileのDeleteKeyはなぜかキーの中にあるデータを削除する仕様になっています。このため、キーを丸ごと削除するにはTRegistryのDeleteKeyを使うしかありません。
そこで登場するのがキャストです。TRegIniFileはTRegistryを元にして作られているので、TRegistryの各メソッドを呼び出して使うことが出来ます。そのためにキャストを使います。
例として、「HKEY_CURRENT_USER\Software\TestApp」にある「TestKey」を削除してみましょう。
procedure TForm1.Button1Click(Sender: TObject);
var
RegIni: TRegIniFile;
begin
RegIni:=TRegIniFile.Create('\Software\TestApp');
with RegIni do
begin
try
TRegistry(RegIni).DeleteKey('TestKey'); //キャストしてキーを削除
finally
Free;
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
RegIni: TRegIniFile;
begin
RegIni:=TRegIniFile.Create('\Software\TestApp');
with RegIni do
begin
try
TRegistry(RegIni).OpenKey('\Software',True); //キャストしてカレントキーを移動
TRegistry(RegIni).DeleteKey('TestApp'); //キャストしてキーを削除
TRegistry(RegIni).OpenKey('\Software\TestApp',True); //新しくカレントキーを作成
finally
Free;
end;
end;
end;
Delphi壁の穴 | Delphiを覗く | システムを覗く | アプリケーションを覗く |
リンクは日本Delphi振興会から張ってください。