![]()
Windowsを使っている以上は必ずお目にかかっているはずなので、アイコンが何かとはいまさら説明することもないと思いますが、デスクトップやタスクバー、各ウィンドウの左上など、至るところに表示されているビットマップイメージのことです。
Windowsでは、ユーザーが操作を視覚的に行なうことができるように、画面の表示にグラフィックスを多用し、マウスによって操作を行なうことができるGUI(グラフィカルユーザーインターフェース)が使われています。この中で、アイコンはファイルやフォルダ、ショートカット、アプリケーションなどを表すために使用され、これらをマウス操作することで対象を開いたり実行したりすることができるようになっているのです。
これらのアイコンの実際のデータは、アイコンリソースとして、実行可能ファイル(EXEやDLL)やアイコンファイル(.ICO)の中に含まれています。(『リソース』は広い意味ではプログラム実行時に資源とみなせるあらゆるものを指しますが、ここでは、狭い意味での、Windowsプログラムで使用されるメニュー、アイコン、カーソルなどのようなデータを指しています。)
今回はこれらのファイルからアイコンを読み込んで表示してみたいと思います。
Windows上では、GUIを構成するアイコンは、ユーザーオブジェクトの1つである『アイコンオブジェクト』として扱われます。したがって、プログラム中でアイコンを使用するためには、まずアイコンオブジェクトを作成してハンドルを取得し、そのアイコンオブジェクトを識別するハンドル(アイコンハンドル)をアイコン操作関数に渡さなくてはなりません。
アイコンオブジェクトを作成するための方法は何通りかあります。ビットマップイメージから直接作成する方法もありますが、今回は、実行可能ファイルにアイコンリソースとして含まれるアイコンや、アイコンファイル(.ico)に含まれているアイコンのデータを取り出して、そのデータからアイコンオブジェクトを作成する方法を説明しましょう。
ファイルにアイコンリソースとして含まれるアイコンからアイコンオブジェクトを作成するには ExtractIcon 関数または ExtractIconEx 関数を呼び出します。通常、ファイルに含まれるアイコンを1つだけ取り出してアイコンオブジェクトを作成したい場合には ExtractIcon 関数を使います。また、ファイルに含まれる複数のアイコンから複数のアイコンオブジェクトを一度に作成したい場合や、大きいアイコンではなく小さいアイコンのオブジェクトを作成したい場合には ExtractIconEx 関数を使います。
ここでは ExtractIconEx 関数について説明しましょう。
UINT ExtractIconExA(
PCTSTR pszFile, // ファイル名
UINT nIconIndex, // アイコンのインデックス
HICON *phIconLarge, // 大きなアイコンのハンドルを格納する変数
HICON *phIconSmall, // 小さなアイコンのハンドルを格納する変数
UINT nIcons // 取得するアイコンの数
);
pszFile パラメータにはアイコンリソースを持つファイルのファイル名を表す文字列のアドレスを、 nIconIndex パラメータと nIcons パラメータには取得を始めるアイコンのインデックスと取得する数をそれぞれ指定します。
アイコンはオブジェクトとして扱われるので、他のWindowsオブジェクトと同じようにハンドルで識別されます。これらを格納するための配列変数のアドレスを phIconLarge パラメータと phIconSmall パラメータに指定します。 phIconLarge パラメータには大きいアイコンのハンドルを格納するための配列変数のアドレスを、 phIconSmall パラメータには小さいアイコンのハンドルを格納するための配列変数のアドレスをそれぞれ指定します。また、大きいアイコンだけを取得したい場合には phIconSmall パラメータに 0 (NULL) を、小さいアイコンだけを取得したい場合には phIconLarge パラメータに 0 (NULL) を指定します。
ExtractIconEx 関数は、戻り値として、実際にハンドルが返されたアイコンの数を返します。また、 nIconIndex パラメータに -1 を、 phIconLarge パラメータと phIconSmall パラメータに 0 (NULL) を指定した場合は、戻り値として、指定されたファイルが持っているアイコンの数を返します。
今回はアイコンオブジェクトのイメージをウィンドウに描画してみます。
アイコンを描画するには DrawIconEx 関数を使います。
BOOL DrawIconEx(
HDC hDC, // デバイスコンテキスト
int x, // x座標
int y, // y座標
HICON hIcon, // アイコンまたはマウスカーソルハンドル
int width, // 幅
int height, // 高さ
UINT iStepAniCur, // フレームインデックス
HBRUSH hbrFlicker, // ブラシ
UINT uFlags // フラグ
);
hDC パラメータには描画先であるHSPウィンドウのデバイスコンテキストのハンドルを指定します。HSPウィンドウのデバイスコンテキストのハンドルは BMSCR 構造体から取得することができます。
hIcon パラメータには描画するアイコンのハンドルを指定し、 x パラメータと y パラメータにはカーソルを描画する位置を、 width パラメータと height パラメータには描画サイズをそれぞれ指定します。
今回は iStepAniCur パラメータと hbrFlicker パラメータには 0 を指定しておくことにし、 uFlags パラメータには 3 (DI_NORMAL) を指定します。
作成されたアイコンオブジェクトは、もうそれ以上使用することがないと分かった時点で削除する必要があります。一般に、アイコンオブジェクトを削除して、アイコンのために使用されていたメモリ領域を解放することを「アイコンを破棄する」と呼びます。アイコンを破棄するには、 DestroyIcon 関数を呼び出します。メモリリークを防ぐためにも、描画した後に破棄するようにしましょう。
BOOL DestroyIcon(
HICON hIcon // アイコンハンドル
);
hIcon パラメータには、破棄するアイコンのハンドルを指定します。
さて、実際にスクリプトを書いてみます。
#include "llmod.as"
#module ;######## アイコンオブジェクト操作モジュール ############
;===============================================================
; ファイルからアイコンオブジェクトを作成しハンドルを取得
; GetIconFromFile v1, s2, n3, n4
; v1 : アイコンハンドルを格納するための配列変数
; s2 : アイコンを持つファイルのファイル名
; n3 : アイコンのインデックス(-1のときアイコンの数取得)
; n4 : 取得するアイコンの数
; stat : 作成されたアイコンオブジェクトの数
;===============================================================
#deffunc GetIconFromFile val, str, int, int
mref ret, 16 ; ハンドルを格納する変数
mref setfilename, 33 ; ファイル名
mref index, 2 ; アイコンのインデックス
; (-1を指定するとアイコン数を取得)
mref num, 3 ; 取得するアイコンの数
sdim filename, 260
filename = setfilename ; いったん別の変数に移す
; アイコンオブジェクト作成
getptr pm.0, filename
pm.1 = index
if index != -1 {
getptr pm.2, ret ; 配列変数のアドレス
} else {
; ファイルが持つアイコンの数を取得する場合
pm.2 = 0
}
pm.3 = 0
pm.4 = num
dllproc "ExtractIconExA", pm, 5, D_SHELL@
if index == -1 {
ret = stat ; ファイルの持つアイコンの数
}
return
;===============================================================
; アイコンオブジェクトの描画中ウィンドウにイメージを描画
; DrawIcon n1, n2, n3, n4, n5
; n1 : アイコンハンドル
; n2 : x座標
; n3 : y座標
; n4 : 幅
; n4 : 高さ
;===============================================================
#deffunc DrawIcon int, int, int, int, int
mref hIcon, 0 ; アイコンハンドル
mref cx, 1 ; x座標
mref cy, 2 ; y座標
mref sx, 3 ; 幅
mref sy, 4 ; 高さ
mref bmscr, 67 ; 描画中ウィンドウのBMSCR構造体
;アイコンを描画
pm = bmscr.4, cx, cy, hIcon, sx, sy, 0, 0, 3
dllproc "DrawIconEx", pm, 9, D_USER@
return
;===============================================================
; アイコンを破棄
; DestroyIcon n1
; n1 : アイコンハンドル
;===============================================================
#deffunc DestroyIcon int
mref hIcon, 0 ; アイコンハンドル
; アイコンの破棄
pm = hIcon
dllproc "DestroyIcon", pm, 1, D_USER@
return
#global ;############# モジュール終わり ########################
; ファイル名を指定(DLL,EXE,ICO)
sdim fname, 260
fname = "shell32.dll"
; ファイルの持つアイコンの数を取得
GetIconFromFile num, fname, -1
if num == 0 {
mes "指定されたファイルはアイコンを持ちません"
stop
}
; アイコンハンドルの取得
dim hIcon, num
GetIconFromFile hIcon, fname, 0, num
; アイコンの描画
size = 32 ; 描画サイズ
numline = winx / size ; 1行に表示するアイコン数
repeat num
x = cnt \ numline * size
y = cnt / numline * size
DrawIcon hIcon.cnt, x, y, size, size
loop
redraw ; 実際の画面の反映させる
; アイコンハンドルの破棄
repeat num
DestroyIcon hIcon.cnt
loop
stop