〜 グラフィック 〜
クリップボードから画像を取得 (要GDI32.DLL, USER32.DLL)

クリップボードに格納されているビットマップデータをHSPウィンドウに取り込むサンプルです。
クリップボードとは、様々なデータ形式のコピー情報を保持しておく場所のことで、
主な手順として、はじめにビットマップデータが格納されているかを確認し、
ビットマップならクリップボードを開き、クリップボードのデータとビットマップオブジェクト情報を取得。
デバイスコンテキストハンドルからメモリデバイスコンテキストを作成して、
ビットマップオブジェクトをデバイスコンテキストに選択すれば、HSPウィンドウに画像を転送して完了。
ただし、処理は以上で終わりではなく、使い終われば元の状態に戻しておくのが暗黙のルール。
デバイスコンテキストに選択したビットマップオブジェクトを元のグラフィックオブジェクトに戻し、
作成したメモリデバイスコンテキストの削除と、開いたクリップボードを解放してください。
解放しないと他のアプリケーションからクリップボードにアクセスできない事態になってしまいます。
必ず、終了後の処理まで行うようにしてください。

具体的には、次のAPI関数を順次呼び出していく形となります。
クリップボードに特定のデータ形式が入っているか調べるのはAPI関数IsClipboardFormatAvailable。
様々なデータ形式が存在しますが、以下の定数値を利用することが出来ます。
0x0001CF_TEXT各行は復帰改行(CR-LF)コード、終端はNULL文字で終わるANSIテキスト形式のデータ
0x0002CF_BITMAPビットマップデータ
0x0003CF_METAFILEPICTメタファイル画像形式
0x0004CF_SYLKMicrosoftシンボリックリンク形式のデータ
0x0005CF_DIFSoftware Arts 社の DIF データ交換形式
0x0006CF_TIFFTIFF形式の画像データ
0x0007CF_OEMTEXTOEM文字セットの文字を持つテキスト形式データ
0x0008CF_DIBBITMAPINFO構造体とビット配列からなるビットマップデータ
0x0009CF_PALETTEカラーパレットのハンドル
0x000ACF_PENDATAペン拡張機能のためのデータ
0x000BCF_RIFFRIFF形式の音声データ
0x000CCF_WAVEWAVE形式の音声データ
0x000DCF_UNICODETEXT各行は復帰改行(CR-LF)コード、終端はNULL文字で終わるUnicodeテキスト形式のデータ
0x000ECF_ENHMETAFILE拡張メタファイルのデータ
0x000FCF_HDROPファイルドロップ形式
0x0010CF_LOCALEテキストデータのロケールIDハンドル
0x0011CF_DIBV5CF_DIBのWindows2000以降版?
0x0080CF_OWNERDISPLAYオーナーがクリップボードビューアの表示と更新を行なわねばならないオーナー表示形式
0x0081CF_DSPTEXTプライベートな形式のテキストデータ
0x0082CF_DSPBITMAPプライベートな形式のビットマップデータ
0x0083CF_DSPMETAFILEPICTプライベートな形式のメタファイル画像表示形式データ
0x008ECF_DSPENHMETAFILEプライベートな形式の拡張メタファイルデータ
0x0200CF_PRIVATEFIRSTオーナーが明示的に解放しなければならないプライベートなクリップボード形式
0x02FFCF_PRIVATELASTオーナーが明示的に解放しなければならないプライベートなクリップボード形式
0x0300CF_GDIOBJFIRSTGDIオブジェクトによって表現されるアプリケーション定義のクリップボード形式
0x03FFCF_GDIOBJLASTGDIオブジェクトによって表現されるアプリケーション定義のクリップボード形式
上記でCF_BITMAPが入っていれば、API関数OpenClipboardでクリップボードを開きます。 引数にはオーナーである自分(hwnd)を指定しましょう。 もし、他のアプリケーションが使用していたり、過去に解放し忘れていると開くことが出来ません。 無事に開けたら、クリップボードから画像データをAPI関数GetClipboardDataで取得します。 引数に取得するデータ形式を指定すればクリップボードオブジェクトのハンドルが返りますが、 指定したデータ形式が存在しない場合、ハンドルではなく0が返る様になっているので、 初めの特定の形式が入っているかの確認処理を飛ばして、結果が0なら中断するやり方でもいいと思います。 その場合、データ形式を問わず必ずオープンするので、閉じ忘れないように注意しなければなりません。 さて、無事にクリップボードオブジェクトハンドルが取得できたなら、 API関数GetObjectの引数に指定して、グラフィックオブジェクト情報を取得しましょう。 24バイトのビットマップ構造体を取得しますので、1要素4バイトの数値配列を6要素分確保しておき、 GetObjectの引数に構造体の先頭アドレスを指定します。 尚、構造体は以下のようになっています、参照する際の参考にどうぞ。
typedef struct BITMAP {
	DWORD   bmType;		// 0
	DWORD   bmWidth;	// 横幅
	DWORD   bmHeight;	// 高さ
	DWORD   bmWidthBytes;	// 1行の幅のバイト数
	WORD   bmPlanes;	// カラープレーン
	WORD   bmBitsPixel;	// ピクセルあたりのカラービット数
	LPVOID bmBits;		// ピクセルビットを指すポインタ
}
上記の処理よりも先であっても構いませんが、HSPウィンドウのデバイスコンテキストに関連するデバイスと 互換性のあるメモリデバイスコンテキストをAPI関数CreateCompatibleDCで作成しておきます。 そして、API関数SelectObjectを使ってデバイスコンテキストのビットマップオブジェクトとして GetObjectで取得したグラフィックスオブジェクトを選択すれば準備完了です。 API関数BitBltでクリップボード内ビットマップデータをHSPウィンドウに転送します。 コピー方法は通常のコピー以外も可能ですが、ココではそのまま引っ張ってくるだけにします。 その他のコピーモード(ラスタオペレーション)やBitBltの基本についてはコチラを参照してください。 画像の転送が終われば即座にAPI関数CloseClipboardでクリップボードを解放してあげます。 そして、API関数DeleteDCで作成したメモリデバイスコンテキストも解放するのですが、 SelectObjectでビットマップオブジェクトにクリップボードのグラフィックスオブジェクトを選択したので、 解放する前に先にコレを元のビットマップオブジェクトに戻しておきましょう。 解放するのなら戻すもクソもないとは思うのですが、古いOSだとメモリデバイスコンテキストを解放しても 新たなグラフィックスオブジェクトはそのまま残ってしまうようですので注意してください。 …で、元のグラフィックスオブジェクトに戻すには、SelectObjectで変更する際、 関数の戻り値として以前のオブジェクトハンドルが返るのでソレを退避しておき、 再度SelectObjectでこの退避しておいたハンドルを指定してあげると良いです。

clipgetg
[パラメータなし]クリップボードから画像をロードするだけのため、パラメータは必要ない。
尚、カレントウィンドウのカレントポジションを基点に描画する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
	ll_libload user, "user32.dll"
	ll_getproc OpenClipboard, "OpenClipboard", user
	ll_getproc GetClipboardData, "GetClipboardData", user
	ll_getproc CloseClipboard, "CloseClipboard", user
	ll_libload gdi,  "gdi32.dll"
	ll_getproc GetObject, "GetObjectA",gdi
	ll_getproc CreateCompatibleDC, "CreateCompatibleDC", gdi
	ll_getproc SelectObject, "SelectObject", gdi
	ll_getproc BitBlt, "BitBlt", gdi
	ll_getproc DeleteDC, "DeleteDC", gdi

#module
#deffunc clipgetg
	mref stt, 64
	mref bmscr, 67
	stt = 1
	prm = bmscr.13 // hwnd
	ll_callfunc prm, 1, OpenClipboard@ : ll_ret i // クリップボードを開く
	if i = 0 : stt = 1 : return // 開けなかったら終了
	prm = 2
	ll_callfunc prm, 1, GetClipboardData@ : ll_ret i.1 // クリップボードから画像(2:CF_BITMAP)取得
	if i.1 = 0 {
		ll_callfnv CloseClipboard@ // 取得できなければ終了
		stt = 2
		return
	}
	// ビットマップオブジェクト情報取得(BITMAP構造体24byte)
	dim bmp, 6
	prm = i.1, 24
	ll_getptr bmp : ll_ret prm.2
	ll_callfunc prm, 3, GetObject@ : ll_ret i
	if i = 0 {
		ll_callfnv CloseClipboard@ // 取得できなければ終了
		return
	}
	// メモリデバイスコンテキストを作成
	prm = bmscr.4 // hdc
	ll_callfunc prm, 1, CreateCompatibleDC@ : ll_ret i.3
	// ビットマップオブジェクトを選択(旧オブジェクトは退避しておく)
	prm = i.3, i.1
	ll_callfunc prm, 2, SelectObject@ : ll_ret i.2
	// 画像情報をコピー
	ginfo 6
	if bmp.1 > prmx : i.4 = prmx : else : i.4 = bmp.1
	if bmp.2 > prmy : i.5 = prmy : else : i.5 = bmp.2
	prm = bmscr.4, csrx, csry, i.4, i.5, i.3, 0, 0, 0x00CC0020 // SRCCOPY
	ll_callfunc prm, 9, BitBlt@
	redraw 1
	// 終了処理
	prm = i.3, i.2
	ll_callfunc prm, 2, SelectObject@ // オブジェクトを元に戻す
	ll_callfunc i.3, 1, DeleteDC@ // メモリデバイスコンテキストを削除
	ll_callfnv CloseClipboard@ // クリップボードを閉じる
	stt = 0
	return
#global

	pos 50, 50 : clipgetg // 画像取得
	if stat : dialog "クリップボードの取得に失敗しました。" : end
	stop

clipgetg
[パラメータなし]クリップボードから画像をロードするだけのため、パラメータは必要ない。
尚、カレントウィンドウのカレントポジションを基点に描画する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#uselib "user32.dll"
#func  global OpenClipboard "OpenClipboard" int
#cfunc global GetClipboardData "GetClipboardData" int
#func  global CloseClipboard "CloseClipboard"
#uselib "gdi32.dll"
#func  global CreateCompatibleDC "CreateCompatibleDC" int
#cfunc global GetObject "GetObjectA" int, int, var
#func  global SelectObject "SelectObject" int, int
#func  global BitBlt "BitBlt" int, int, int, int, int, int, int, int, int
#func  global DeleteDC "DeleteDC" int

#module
#deffunc clipgetg local i
	#define newBmp	i.0
	#define oldBmp	i.1
	#define memhdc	i.2
	#define sizex	i.3
	#define sizey	i.4
	OpenClipboard hwnd // クリップボードを開く
	if stat = 0 : return 1 // 開けなかったら終了
	newBmp = GetClipboardData(2) // クリップボードから画像(2:CF_BITMAP)取得
	if newBmp = 0 {
		CloseClipboard // 取得できなければ終了
		return 1
	}
	// ビットマップオブジェクト情報取得(BITMAP構造体24byte)
	dim bmp, 6
	if GetObject(newBmp, 24, bmp) = 0 {
		CloseClipboard // 取得できなければ終了
		return 2
	}
	// メモリデバイスコンテキストを作成
	CreateCompatibleDC hdc
	memhdc = stat
	// ビットマップオブジェクトを選択(旧オブジェクトは退避しておく)
	SelectObject memhdc, newBmp
	oldBmp = stat
	// 画像情報をコピー
	if bmp.1 > ginfo_sx : sizex = ginfo_sx : else : sizex = bmp.1
	if bmp.2 > ginfo_sy : sizey = ginfo_sy : else : sizey = bmp.2
	BitBlt hdc, ginfo_cx, ginfo_cy, sizex, sizey, memhdc, , , 0x00CC0020 // SRCCOPY
	redraw 1
	// 終了処理
	SelectObject memhdc, oldBmp // オブジェクトを元に戻す
	DeleteDC memhdc // メモリデバイスコンテキストを削除
	CloseClipboard // クリップボードを閉じる
	return 0
#global

	pos 50, 50 : clipgetg // 画像取得
	if stat : dialog "クリップボードの取得に失敗しました。" : end