レガシー Windows API(概要)について

ここで紹介しているAPIは、Windows95、Windows NT3.5時代のAPI群であり、最新のAPIは含まれていないことに注しして欲しい。なお、当時の解説書は現在よりもより詳細に解説しているため、参考になるはずである。

  • レイアウトを変換する際、崩れているページがあります。
  • 概要およびSampleコードはありますが、APIの解説はありません。

ご要望があれば旧版のWin32 API(HELP形式)をお譲りします。問い合わせフォームより申し込みください。

Windows API メタファイルの概要

Microsoft(R) Windows(TM) 用のアプリケーションは、 メタファイルとビットマップの2種類のグラフィック ツールを使って画像を格納できます。ビットマップについて詳しくは、 ビットマップの概要を参照してください。ここでは、 メタファイルについて説明します。

「メタファイル」とは、 画像をデバイスに依存しない形式で格納する構造体の集合です。デバイスに依存しないことは、 メタファイルとビットマップの違いの1つです。メタファイルでは、 ビットマップとは異なり、 デバイスに依存しないことが保証されています。たとえば、 アプリケーションがVGAディスプレイで2x2インチの画像を作成し、 その画像をメタファイルに格納すると、 画像を300dpiのレーザー プリンタで印刷したり、 ネットワークでコピーして8514/Aディスプレイでほかのアプリケーションを使って表示しても、 画像の寸法はもとのままです。しかし、 メタファイルには欠点もあります。通常、 メタファイルの描画はビットマップよりも低速です。このため、 高速な描画を必要とし、 デバイスに依存してもかまわないときは、 メタファイルではなくビットマップを使ってください。

次に示すトピックでは、 Win32のメタファイルについて説明しています。

拡張形式メタファイル

拡張メタファイル レコード

拡張メタファイルの操作

Windows形式メタファイル

拡張メタファイルの作成

拡張メタファイルの画像の表示と格納

拡張メタファイルのオープンと内容の表示

拡張メタファイルの編集

メタファイル関数

メタファイルは、 内部的には、 「メタファイル レコード」と呼ばれる可変長構造体の配列です。メタファイルの最初のレコードは、 画像が作成されたデバイスの解像度や画像の寸法など、 一般的な情報を示します。メタファイルの大部分を構成するこれ以外のレコードは、 画像を描画するのに必要なグラフィック デバイス インターフェイス関数に対応しています。このレコードは、 特別なメタファイル デバイス コンテキストを作成してから、 メタファイルに格納されます。画像を作成するのに必要な描画操作には、 必ずこのDCを使います。Windowsは、 メタファイルDCに対応するGDI関数を処理するとき、 関数を適切なデータに変換し、 そのデータをレコードに格納してメタファイルに付加します。

画像が完成し、 最後のレコードをメタファイルに格納したら、 クリップボードを使ってほかのアプリケーションに渡したり、 ファイルへの埋め込みやディスクへの格納、 繰り返し再生などを行うことができます。メタファイルを再生するとき、 メタファイルのレコードはデバイス コマンドに変換され、 適切なデバイスがそのコマンドを処理します。

メタファイルには、 拡張メタファイルとWindowsメタファイルの2種類があります。「拡張メタファイル」は、 Win32アプリケーション プログラミング インターフェイス (API) を使って作成したアプリケーションで使われます。拡張形式は、 ヘッダー、 GDIオブジェクトのハンドルのテーブル、 プライベート パレット、 メタファイル レコードの配列で構成されます。拡張メタファイルによって、 デバイスにまったく依存しないようにできます (拡張メタファイルに格納されている画像は、 特定の瞬間のビデオ ディスプレイの「スナップショット」のようなものです。プリンタやプロッタ、 デスクトップ、 Win32アプリケーションのクライアントなど、 表示される場所が変わっても、 この

「スナップショット」の寸法は変化しません)。

「Windowsメタファイル」は、 Windowsバージョン3.xのアプリケーション プログラミング インターフェイス (API) を使って作成したアプリケーションで使われます。Windows形式は、 ヘッダーと、 メタファイル レコードの配列で構成されます。Windows形式メタファイルの機能は限られているため、 ほとんど使われません。WindowsメタファイルAPIは、 Windowsバージョン3.xで動作するように作成されているアプリケーションとの下位互換性を保つためにサポートされています。

 

 

拡張形式メタファイル

(新しいパス関数や座標変換関数などの) Win32 GDI関数を使って作成した画像を格納するには、 拡張メタファイルを使うことができます。拡張メタファイル形式はWin32アプリケーション プログラミング インターフェイス (API) で標準化されているため、 この形式で格納した画像は、 ほかのアプリケーションにコピーできます。また、 画像はデバイスにまったく依存しないため、 どのデバイスでも画像の形や比率は変わりません。

 

 

拡張メタファイル レコード

「拡張メタファイル」は、 レコードの配列です。メタファイル レコードは、 可変長のENHMETARECORD構造体です。この構造体は、 レコードの種類と長さを示し、 レコードの種類によって異なる追加データを含みます。

拡張メタファイルの最初のレコードは、 常に拡張メタファイル ヘッダーです。ヘッダーは、 次の情報を示します。

・ メタファイルのサイズ (バイト単位)

・ 画像の枠の寸法 (デバイス単位)

・ 画像の枠の寸法 (0.01ミリメートル単位)

・ メタファイルのレコード数

・ 省略可能なテキスト記述へのオフセット

・ 省略可能なパレットのサイズ

・ 元のデバイスの解像度 (ピクセル単位)

・ 元のデバイスの解像度 (ミリメートル単位)

 

ヘッダー レコードの後には、 省略可能なテキスト記述やパレットを置くことができます。テキスト記述は、 画像を記述し、 制作者の名前や作成日付などをリストします。パレットは、 拡張メタファイルの作成に使われた色を示します。その後のレコードは、 画像を作成するのに使われたGDI関数を示します。次の16進出力は、 SetMapMode関数を呼び出して生成したレコードを示しています。

 

0000 0011 0000 000C 0000 0004

0x00000011は、 レコードの種類を示しています (METADEF.Hで定義されている

EMR_SETMAPMODE定数に対応しています)。0x0000000Cは、 レコードのバイト単位の長さを示しています。0x00000004は、 マッピング モードを示しています (WINGDI.Hで定義されているMM_LOENGLISH定数に対応しています)。

 

 

拡張メタファイルの操作

拡張メタファイルを作成するには、 適切な引数を指定してCreateEnhMetaFile関数を呼び出します。Win32 APIは、 この引数を使って、 画像の寸法の管理や、 メタファイルをディスクとメモリのどちらに格納するかの判断などを行います。

出力デバイス間で画像の寸法を維持するため、 Win32 APIは、 参照デバイスの解像度を必要とします。「参照デバイス」とは、 画像を最初に表示したときのデバイスで、 「参照DC」とは、 参照デバイスに関連付けられているデバイス コンテキスト (DC) です。CreateEnhMetaFile関数を呼び出すときは、 このDCを識別するハンドルを指定してください。このハンドルを取得するには、 GetDC関数かCreateDC関数を呼び出してください。

通常、 アプリケーションは画像を恒久的に格納するため、 ディスクに格納される拡張メタファイルを作成します。しかし、 場合によっては、 ディスクに格納する必要はありません。たとえば、 グラフ描画機能を持つワード プロセッサ アプリケーションでは、 ユーザー定義のグラフを拡張メタファイルとしてメモリに格納し、 その拡張メタファイルのビットをメモリからユーザーのドキュメント ファイルにコピーできます。メタファイルをディスクに恒久的に格納しなければならないアプリケーションは、 CreateEnhMetaFile関数にファイル名を指定しなければなりません。ファイル名を指定しなければ、 Windowsは、 自動的にメタファイルを一時ファイルとして扱い、 メモリに格納します。

メタファイルには、 画像に関する情報、 制作者、 作成日時などに関する情報を示す省略可能なテキスト記述を付加できます。[ファイルを開く]ダイアログ ボックスでこれらの情報とメタファイルのないように関する情報を表示すれば、 ユーザーが適切なファイルを選択するのに役立ちます。テキスト記述を付加するには、 CreateEnhMetaFile関数を呼び出すときにテキスト記述文字列を指すポインタを渡してください。

CreateEnhMetaFile関数は、 正常に終了すると、 特別なデバイス コンテキストを識別するハンドルを返します。メタファイルDCは、 出力デバイスではなく関連するファイルについて一意です。Windowsは、 メタファイルDCを識別するハンドルを受け取るGDI関数を処理するとき、 GDI関数を拡張メタファイル レコードに変換し、 そのレコードをメタファイルの最後に付加します。

画像が完成し、 最後のレコードを拡張メタファイルに付加したら、 CloseEnhMetaFile関数を呼び出してファイルをクローズしてください。この関数は、 特別なメタファイルDCをクローズして削除し、 拡張メタファイルを識別するハンドルを返します。このハンドルは、 次に示す作業を行うのに使います。

・ 拡張メタファイルに格納された画像の表示

・ 拡張メタファイルのコピーの作成

・ 拡張メタファイルの各レコードの列挙、 編集、 コピー

・ 拡張メタファイルに格納されている省略可能なテキスト記述の取得

・ 拡張メタファイル ヘッダーのコピーの取得

・ 拡張メタファイルのバイナリ版の取得

・ 省略可能なパレットの色の列挙

・ 拡張メタファイルからWindows形式メタファイルへの変換

 

場合によっては、 ユーザーが元のファイルを変更できるようにする前に、 ファイルの一時バックアップ (複製) コピーを作成することがあります。拡張メタファイルのバックアップ コピーを作成するには、 拡張メタファイルを識別するハンドルと新しいファイルの名前を示すテキスト文字列を指すポインタを指定して、 CopyEnhMetaFile関数を呼び出します。

通常、 描画アプリケーションやCADアプリケーションでは、 拡張メタファイルに格納されている画像を編集する手段が必要になります。拡張メタファイルの編集は複雑な作業ですが、 EnumEnhMetaFile関数をほかのWin32関数を組み合わせることによってこの作業を実現できます。アプリケーションは、 EnumEnhMetaFile関数と関連するコールバック関数を利用することによって、 拡張メタファイルの個々のレコードを処理できます。

また、 [ファイルを開く]ダイアログ ボックスで、 拡張メタファイルのファイル名とともに省略可能なテキスト記述を表示する場合もあります。テキスト記述文字列が拡張メタファイルに存在するかどうかを調べるには、 メタファイル ヘッダーを取得し、 そのメンバを調べます。メタファイル ヘッダーを取得するには、 GetEnhMetaFileHeader関数を使います。文字列が存在すれば、 GetEnhMetaFileDescription関数を呼び出して文字列を取得できます。

メタファイルのコピーを作成するには、 GetEnhMetaFileBits関数を呼び出します。しかし、 コピーを作成するには、 ファイルのサイズを指定しなければなりません。ファイルのサイズを取得するには、 GetEnhMetaFileHeader関数を呼び出して、 適切なメンバの値を調べてください。

さまざまな出力デバイスで画像の色が一貫して表示されるようにするには、 CreatePalette関数を呼び出して、 論理パレットを拡張メタファイルに格納してください。この拡張メタファイルに格納されている画像を表示するには、 このパレットを取得し、 画像を表示する前にRealizePalette関数を呼び出してください。拡張メタファイルにパレットが格納されているかを調べるには、 メタファイル ヘッダーを取得して、 適切なメンバを調べてください。パレットが存在すれば、 GetEnhMetaFilePaletteEntries関数を呼び出して論理パレットを取得してください。

 

 

Windows形式メタファイル

Win32 APIは、 Windowsバージョン3.x用に作成されたアプリケーションとの互換性を維持するため、 Windowsメタファイル形式をサポートしています。Windowsメタファイル形式の制限を次に示します。

・ Windows形式メタファイルは、 アプリケーションやデバイスに依存します。この形式では、 アプリケーションのマッピング モードやデバイス解像度を変更すると、 メタファイルの画像のイメージに影響があります。

・ Windows形式メタファイルには、 元の画像の寸法、 画像を作成したときのデバイスの解像度、 省略可能なテキスト記述、 省略可能なパレットなどを記述する情報ヘッダーがありません。

・ Windows形式メタファイルはスケール変更できません。

・ Windows形式メタファイルに関連付けられているメタファイル デバイス コンテキストを問い合わせることはできません (つまり、 アプリケーションは、 デバイス解像度データやフォント メトリックスなどを取得できません)。

 

Windows形式メタファイルを拡張形式メタファイルに変換するには、 GetWinMetaFileBits関数を呼び出してWindows形式メタファイルからデータを取得し、 SetWinMetaFileBits関数を呼び出して、 そのデータを拡張形式メタファイルに変換してください。

Win32アプリケーションを開発する場合は、 Windows形式の関数を使わずに、 拡張形式の関数を使ってください。

 

 

 

メタファイルの使用

ここでは、 次に示すタスクを実行する方法を説明します。

・ ディスクに格納する拡張メタファイルの作成

拡張メタファイルの画像の表示と格納

拡張メタファイルのオープンと内容の表示

拡張メタファイルの編集

 

 

 

拡張メタファイルの作成

ここでは、 拡張メタファイルを作成し、 ユーザーが指定したファイル名でディスクに格納する例を示します。

この例では、 アプリケーション ウィンドウのデバイス コンテキストを参照DCとして使っています (Windowsは、 このデバイスの解像度データを拡張メタファイルのヘッダーに格納します)。このDCを識別するハンドルを取得するには、 GetDC関数を呼び出します。

画像の枠の寸法は、 アプリケーションのクライアント領域の寸法を使って定義します。GetClientRect関数が返した長方形の寸法を使って、 デバイス単位を0.01メートル単位に変換し、 変換した値をCreateEnhMetaFile関数に渡します。

新しい拡張メタファイルのファイル名をユーザーが指定できるようにするには、 [ファイル名を付けて保存]コモン ダイアログ ボックスを表示します。このダイアログ ボックスで取得したファイル名に拡張子.EMFを付加して、 CreateEnhMetaFile関数に渡します。

また、 拡張メタファイル ヘッダーには、 画像のテキスト記述を埋め込みます。この記述は、 アプリケーションのリソース ファイルの文字列テーブルでリソースとして指定されています。しかし、 実際のアプリケーションでは、 この文字列はコモン ダイアログ ボックスのカスタム コントロールで取得するか、 テキスト記述用のダイアログ ボックスを別に表示して取得してください。

 

/* Obtain a handle to a reference DC. */

hdcRef = GetDC(hWnd);

/*
* Determine the picture frame dimensions.
* iWidthMM is the display width in millimeters.
* iHeightMM is the display height in millimeters.
* iWidthPels is the display width in pixels.
* iHeightPels is the display height in pixels
*/

iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE);
iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE);
iWidthPels = GetDeviceCaps(hdcRef, HORZRES);
iHeightPels = GetDeviceCaps(hdcRef, VERTRES);

/*
* Use iWidthMM, iWidthPels, iHeightMM, and
* iHeightPels to determine the number of
* .01-millimeter units per pixel in the x-
* and y-directions.
*/


iMMPerPelX = (iWidthMM * 100)/iWidthPels;
iMMPerPelY = (iHeightMM * 100)/iHeightPels;


/*
* Retrieve the coordinates of the client
* rectangle, in pixels.
*/

GetClientRect(hWnd, &rect);

/* Convert client coordinates to .01-mm units. */

rect.left = rect.left * iMMPerPelX;
rect.top = rect.top * iMMPerPelY;
rect.right = rect.right * iMMPerPelX;
rect.bottom = rect.bottom * iMMPerPelY;

/* Load the filename filter from the string table. */

LoadString(hInst, IDS_FILTERSTRING,
(LPSTR)szFilter, sizeof(szFilter));

/*
* Replace the '%' separators that are embedded
* between the strings in the string-table entry
* with '\0'
*/

for (i=0; szFilter[i]!='\0'; i++)
if (szFilter[i] == '%')
szFilter[i] = '\0';

/* Load the dialog title string from the table. */

LoadString(hInst, IDS_TITLESTRING,
(LPSTR)szTitle, sizeof(szTitle));


/* Initialize the OPENFILENAME members. */

szFile[0] = '\0';

Ofn.lStructSize = sizeof(OPENFILENAME);
Ofn.hwndOwner = hWnd;
Ofn.lpstrFilter = szFilter;
Ofn.lpstrFile= szFile;
Ofn.nMaxFile = sizeof(szFile);
Ofn.lpstrFileTitle = szFileTitle;
Ofn.nMaxFileTitle = sizeof(szFileTitle);
Ofn.lpstrInitialDir = (LPSTR)NULL;
Ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
Ofn.lpstrTitle = szTitle;

/*
* Display the Filename common dialog box. The
* filename specified by the user is passed
* to the CreateMetaFile function and used to
* store the metafile on disk.
*/

GetSaveFileName(&Ofn);

/* Load the description from the string table. */

LoadString(hInst, IDS_DESCRIPTIONSTRING,
(LPSTR)szDescription, sizeof(szDescription));

/*
* Replace the '%' string separators that are
* embedded between strings in the string-table
* entry with '\0'
*/

for (i=0; szDescription[i]!='\0'; i++)
if (szDescription[i] == '%')
szDescription[i] = '\0';

/* Create the metafile DC. */

hdcMeta = CreateEnhMetaFile(hdcRef,
(LPTSTR) Ofn.lpstrFile,
&rect, (LPSTR)szDescription);

if (!hdcMeta)
errhandler("CreateEnhMetaFile", hWnd);

/* Release the reference DC. */

ReleaseDC(hWnd, hdcRef);

 

 

拡張メタファイルの画像の表示と格納

ここでは、 画像の作成と、 対応するレコードのメタファイルへの格納のコード例を示します。GetDC関数は、 ディスプレイ デバイス コンテキストを取得します。画像は、 直線や円弧、 長方形などの画像の構成要素を描画するGDI関数をこのDCハンドルを使って呼び出すことによって作成します。上記の例のように、 アプリケーションは、 拡張メタファイルを作成し、 ディスプレイ デバイスに画像を描画したときと同じGDI関数をもう一度呼び出して、 拡張メタファイルにレコードを格納します。しかし、 GDI関数を2回目に呼び出すときは、 1回目の呼び出しで使ったディスプレイDCではなくメタファイルDCを識別するハンドルを指定してください。

 

void DrawOrStore(HWND hwnd, HDC hdcMeta, HDC hdcDisplay)
{

RECT rect;
HDC hDC;
int fnMapModeOld;
HBRUSH hbrOld;

/* Draw it to the display DC or store it in the metafile DC. */

if (hdcMeta)
hDC = hdcMeta;
else
hDC = hdcDisplay;

/* Set the mapping mode in the DC. */

fnMapModeOld = SetMapMode(hDC, MM_LOENGLISH);

/* Find the midpoint of the client area. */

GetClientRect(hwnd, (LPRECT)&rect);
DPtoLP(hDC, (LPPOINT)&rect, 2);

/* Select a gray brush. */

hbrOld = SelectObject(hDC, GetStockObject(GRAY_BRUSH));

/* Draw an circle with an one inch raduis. */

Ellipse(hDC, (rect.right/2 - 100), (rect.bottom/2 + 100),
(rect.right/2 + 100), (rect.bottom/2 - 100));

.
. /* Perform remaining drawing and clean-up operations. */
.

}

 

 

拡張メタファイルのオープンと内容の表示

ここでは、 ディスクに格納されている拡張メタファイルをオープンし、 その画像をクライアント領域に表示するコード例を示します。

この例では、 [ファイルを開く]コモン ダイアログ ボックスを使って、 既存のファイルのリストから拡張メタファイルをユーザーが選択できるようにしています。選択されたファイルの名前は、 GetEnhMetaFile関数に渡します。この関数は、 ファイルを識別するハンドルを返します。画像を表示するには、 このハンドルをPlayEnhMetaFile関数に渡します。

 

LoadString(hInst, IDS_FILTERSTRING,
(LPSTR)szFilter, sizeof(szFilter));

/*
* Replace occurrences of '%' string separator
* with '\0'
*/

for (i=0; szFilter[i]!='\0'; i++)
if (szFilter[i] == '%')
szFilter[i] = '\0';

LoadString(hInst, IDS_DEFEXTSTRING,
(LPSTR)szDefExt, sizeof(szFilter));


/*
* Use the OpenFilename common dialog box
* to obtain the desired filename.
*/

szFile[0] = '\0';
Ofn.lStructSize = sizeof(OPENFILENAME);
Ofn.hwndOwner = hWnd;
Ofn.lpstrFilter = szFilter;
Ofn.lpstrCustomFilter = (LPSTR)NULL;
Ofn.nMaxCustFilter = 0L;
Ofn.nFilterIndex = 1L;
Ofn.lpstrFile = szFile;
Ofn.nMaxFile = sizeof(szFile);
Ofn.lpstrFileTitle = szFileTitle;
Ofn.nMaxFileTitle = sizeof(szFileTitle);
Ofn.lpstrInitialDir = (LPSTR) NULL;
Ofn.lpstrTitle = (LPSTR)NULL;
Ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
Ofn.nFileOffset = 0;
Ofn.nFileExtension = 0;
Ofn.lpstrDefExt = szDefExt;

GetOpenFileName(&Ofn);

/* Open the metafile. */

hemf = GetEnhMetaFile(Ofn.lpstrFile);

/* Retrieve a handle to a window DC. */

hDC = GetDC(hWnd);

/* Retrieve the client rectangle dimensions. */

GetClientRect(hWnd, &rct);

/* Draw the picture. */

PlayEnhMetaFile(hDC, hemf, &rct);

/* Release the metafile handle. */

DeleteEnhMetaFile(hemf);

/* Release the window DC. */

ReleaseDC(hWnd, hDC);

 

 

拡張メタファイルの編集

拡張メタファイルに格納されている画像を編集するには、 次に示す作業を行わなければなりません。

1. ヒット テストを使ってカーソル座標を調べ、 ユーザーが変更しようとしているオブジェクト (直線、 円弧、 長方形、 だ円、 多角形、 特殊な図形など) の位置を取得します。

2. その座標を論理 (ワールド) 単位に変換します。

3. EnumEnhMetaFile関数を呼び出して、 各メタファイル レコードを調べます。

4. レコードがGDI描画関数に対応しているか調べます。

5. レコードが描画関数に対応していれば、 ユーザーが指定した座標に交差する直線や円弧、 だ円などのグラフィック要素に対応するレコードに格納されている座標を調べます。

6. ユーザーが変更しようとするオブジェクトに対応するレコードが見つかったら、 元のレコードに対応するオブジェクトを画面上で消去します。

7. オブジェクトに対応するレコードを指すポインタを保存して、 そのレコードをメタファイルから削除します。

8. ユーザーがオブジェクトを再描画したり再配置できるようにします。

9. 新しいオブジェクトを描画するのに使ったGDI関数を、 拡張メタファイルのレコードに変換します。

10. レコードを拡張メタファイルに格納します。

 

 

 

メタファイル関数

拡張形式メタファイルに関する関数を次に示します。

CloseEnhMetaFile

CopyEnhMetaFile

CreateEnhMetaFile

DeleteEnhMetaFile

EnhMetaFileProc

EnumEnhMetaFile

GdiComment

GetEnhMetaFile

GetEnhMetaFileBits

GetEnhMetaFileDescription

GetEnhMetaFileHeader

GetEnhMetaFilePaletteEntries

GetWinMetaFileBits

PlayEnhMetaFile

PlayEnhMetaFileRecord

SetEnhMetaFileBits

SetWinMetaFileBits

Windows形式メタファイルとの互換性を保つために用意されている関数を次に示します。

CloseMetaFile

CopyMetaFile

CreateMetaFile

DeleteMetaFile

EnumMetaFile

EnumMetaFileProc

GetMetaFile

GetMetaFileBitsEx

PlayMetaFile

PlayMetaFileRecord

SetMetaFileBitsEx

 

 

▲ページトップに戻る

【本を読んでもよくらからない】 … 個別指導でわかりやすくお教えします