Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2021年09月29日] [更新 2021年09月29日] Delphi 一般・その他
先頭が @ の文字列は文字列のリソース
動作確認等 Windows 10 ビルド 19042 + Delphi XE5(UP2) Pro VCL-32
[整理番号 - 1100]







01_先頭が @ の文字列は文字列のリソース


レジストリに,先頭が @ の文字列データがあります.これは,文字列のリソースを意味する文字列です.Windows API の SHLoadIndirectString 関数を使用すれば,リソースとしての文字列を取り出せます.
先頭が @ の文字列を間接文字列とも言います.



図1
DLL から文字列のリソースを取り出す

リスト1
先頭が @ の文字列は文字列のリソース
  function SHLoadIndirectString(pszSource, psuOutBuf: PWideChar; const ccOutBuf:
     UINT; var ppvReserved: Pointer): HRESULT; stdcall; external 'ShLwApi.dll';
  function GetDirectStr(ArgText: WideString): string;

var
  Form1: TForm1;

implementation

{$R *.DFM}

//=============================================================================
//  先頭が @ の文字列は文字列のリソース
//  DLL 内の文字列リソースを取り出す例
//  Windows API の SHLoadIndirectString 関数を使用して取得できる
//
//  取得した文字列は,必ずしもテキストとは限らない
//  画像ファイル,音楽ファイル等,他のオブジェクトのパス名のこともある
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LRegItem : string;
  LResText : string;
begin
  Memo1.Lines.Clear;

  LRegItem := '@%SystemRoot%\system32\shell32.dll,-31361';
  LResText := GetDirectStr(LRegItem);
  Memo1.Lines.Add(LResText);
end;

//-----------------------------------------------------------------------------
//  SHLoadIndirectString 関数を利用するための関数
//-----------------------------------------------------------------------------
function GetDirectStr(ArgText: WideString): string;
var
  LBuffer  : array [0..4095] of WideChar;
  LPointer : Pointer;
begin
  Result := '';
  if ArgText = '' then Exit;

  FillChar(LBuffer[0], SizeOf(LBuffer), #0);
  if SHLoadIndirectString(PWideChar(ArgText),
                          LBuffer,
                          Length(Lbuffer),
                          LPointer) = S_OK then begin
    Result := Lbuffer;
  end;
end;




02_「DLL のパス名,数字」形式の文字列


先頭に @ がない,以下のような文字列データがあります.この場合,ほとんどアイコン画像のリソースを意味します.文字列の最初の部分がリソースを格納している DLL 等のファイル名です.カンマの後の数字はリソースの ID 値です.
CSV (カンマ区切り) 文字列になっていますから,分解して Windows API の ExtractIcon 関数の引数に渡せばアイコンのハンドルが取得できます.ExtractIcon 関数の引数には,環境変数も使用可能です.


%systemRoot%\system32\shell32.dll,-13
C:\Windows\system32\shell32.dll,-13


図2
DLL からアイコン画像を取り出す

リスト2
「DLL のパス名,数字」形式の文字列は,主にいアイコン画像のリソースを意味する
implementation

uses
  System.StrUtils,
  Winapi.ShellAPI;

{$R *.DFM}

//=============================================================================
//  「DLL のパス名,数字」形式の文字列
//  アイコン画像のリソースを意味する
//  例 :
//    %systemRoot%\system32\shell32.dll,-13
//    C:\Windows\system32\shell32.dll,-13
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LRegItem  : string;
  LPos      : Integer;
  LFilePath : string;
  LResID    : Integer;
  LIcon     : TIcon;
begin
  Image1.Picture.Assign(nil);
  LRegItem := '%systemRoot%\system32\shell32.dll,-13';

  LPos := Pos(',', LRegItem);
  LFilePath := Copy(LRegItem, 1, LPos - 1);
  LResID    := Abs(StrToInt(Copy(LRegItem, LPos + 1, Length(LRegItem))));

  LIcon := TIcon.Create;
  try
    LIcon.Handle :=  ExtractIcon(hInstance, PChar(LFilePath), LResID);
    Image1.Picture.Assign(LIcon);
  finally
    FreeAndNil(LIcon);
  end;
end;

//=============================================================================
//  「DLL のパス名,数字」形式の文字列
//  アイコン画像のリソースを意味する
//  例 :
//    %systemRoot%\system32\shell32.dll,-13
//    C:\Windows\system32\shell32.dll,-13
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LRegItem  : string;
  LStrList  : TStringList;
  LFilePath : string;
  LResID    : Integer;
  LIcon     : TIcon;
begin
  Image1.Picture.Assign(nil);
  LRegItem := '%systemRoot%\system32\shell32.dll,-13';

  LStrList := TStringList.Create;
  LIcon := TIcon.Create;
  try
    LStrList.Text := ReplaceText(LRegItem, ',-', sLineBreak);
    LFilePath := LStrList[0];
    LResID    := StrToInt(LStrList[1]);

    LIcon.Handle :=  ExtractIcon(hInstance, PChar(LFilePath), LResID);
    Image1.Picture.Assign(LIcon);
  finally
    FreeAndNil(LIcon);
    FreeAndNil(LStrList);
  end;
end;


ExtractIcon 関数の第 3 引数の値を -1 にすると,DLL 内のアイコンの数を知ることががきます.



図3
DLL 内のアイコン数を調べる

implementation

uses
  Winapi.ShellAPI;

{$R *.DFM}

//=============================================================================
//  DLL 内のアイコンの数を取得
//  RT_GROUP_ICON リソースの数
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LFilePath : string;
  LIconCnt  : Integer;
begin
  LFilePath := '%systemRoot%\system32\shell32.dll';

  LIconCnt :=  ExtractIcon(hInstance, PChar(LFilePath), Cardinal(-1));
  MessageBox(Handle, PChar(IntToStr(LIconCnt)), 'アイコン数', MB_ICONINFORMATION);
end;


[備考]
ExtractIcon 関数の説明には,取得したアイコンのハンドルを DestroyIcon 関数で解放するように書いてありますが,TIcon.Handle に代入した場合は必要ありません.TIcon が処理します.