第4回 クリップボード その1
BTMemoに限らず、たいていのアプリケーションはクリップボードを介して相互にデータを交換することができます。
というか、そのために用意されている仕組みがクリップボードです。
ここでは、クリップボードの使い方をお伝えします。
(1)プレーンテキストをクリップボードに登録する
まず、クリップボードへデータを登録する手順を兼ねまして、プレーンテキストをクリップボードへ登録する方法です。
//クリップボードに格納するデータです。ここでは例としてリテラル文字列を使用します。 char
szSrcData[] = "この文字列をクリップボードに登録します" //(A)クリップデータへ格納するデータは共有メモリに格納する必要があります。 // 必要なだけの共有メモリを獲得してそこにデータをコピーします int
len = strlen(szSrcData)+1; HGLOBAL
hData = (HGLOBAL)::GlobalAlloc(GHND, (DWORD)len); char
*pData = (char *)::GlobalLock(hData); strcpy(pData,
szSrcData); ::GlobalUnlock(hData); //(B)クリップボードをオープンします。 ::OpenClipboard(NULL); //(C)今クリップボードに入っているデータを廃棄します。 ::EmptyClipboard(); //(D)クリップボードへグローバルメモリを登録する if
(::SetClipboardData(CF_TEXT, hData) == NULL) { //
登録失敗の場合は、自分で共有メモリを開放する必要があります。 ::GlobalFree(hData); } //(E)クリップボードをクローズする ::CloseClipboard(); −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− (B)(C)(E)は、おまじないみたいなものですので説明は省きます。 私が思うに、クリップボードを扱う際の主題は(A)と(D)です。 まず(D)ですが、クリップボードに登録するデータを格納した共有メモリのハンドルと、 その共有メモリ内に入っているデータの種類を示すクリップボードフォーマットをを指定します。 上記例では、クリップボードフォーマットに
CF_TEXT を使用していますがこれは、 ・共有メモリにはプレーンテキスト(シフトJIS)が格納されている ・共有メモリの先頭から文字列が始まりヌル文字で終わる と言うことを意味しています。 なお、登録が成功した場合、登録したハンドルの所有権はクリップボードに移ります。 プログラムでハンドルを廃棄したり、データを変更するような事は厳禁です。 次に(A)ですが、(D)で
CF_TEXT を指定するために、それに合致したデータを作りこんでいるわけです。 |
(2)クリップボードフォーマット
クリップボードフォーマットには、CF_TEXTの様にあらかじめ用途の決められているものがあります。
BTMemoでは他にCF_HDROPやCF_BITMAPというクリップボードフォーマットを使用しています。
CF_HDROPは、エクスプローラ等でファイルをコピーした際に使用されているフォーマットです。
CF_BITMAPは、ペイントブラシなどで、画像をコピーした際に使用されているフォーマットです。
さらに、プログラムが自分専用のクリップボードフォーマット(番号)をOSから割り当ててもらうことができます。
//
BTMemo用のクリップボードフォーマットの割り当てを得る int
CF_TAD = ::RegisterClipboardFormat("CF_BURUTURI_DATA_BUS"); −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− プログラムに固有の文字列をキーワードとします。キーワードが最初に使われたとき、本当に割り当てが行われ、 キーワードにが既に使われていれば、最初に割り当てられたのと同じものが返却されます。 したがって、誰が最初かなんて事は気にしなくても良いのです。 BTMemo以外のプログラムでも上記と同じキーワードを指定してクリップボードフォーマットの割り当てを得れば、 BTMemoとクリップボードを介してデータを交換することができます。 共有メモリ内のデータフォーマットは、BTMemoのファイルフォーマットとほとんど同じです。 (カレンダーのソースにサンプルがあります。興味があればそちらをご覧下さい) |
上記と同じ事がBTMemo以外のプログラムにも当てはまります。
//
インターネットエクスプローラがURLをクリップボードへ格納する際のクリップボードフォーマットを得るには int
CF_URL = ::RegisterClipboardFormat(CFSTR_SHELLURL); // CFSTR_SHELLURLはマクロで、文字列定数が宣言されてます −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− このクリップボードフォーマットを使用すれば、インターネットエクスプローラが登録したURLをクリップボードから取得できます。 共有メモリ内のデータフォーマットはCF_TEXTと同じで単なる文字列です。 正確にいうと、このクリップボードフォーマットでクリップボードからデータを得れるかどうか未確認です。 しかしドラッグ&ドロップ(クリップボードと同じようにクリップボードフォーマットと共有メモリを使用してデータ交換します)では データ交換できます。 |
(3)クリップボードフォーマットが異なるデータを同時にクリップボードに登録する
//(A)さまざまなクリップボードフォーマット用のデータを用意します。 HGLOBAL
hText = GetTextData(); //
プレーンテキストのデータを共有メモリに格納し、そのハンドルを返却する関数を仮定 HGLOBAL
hMemo = GetBTMemoData();
// BTMemo独自形式のデータを共有メモリに格納し、そのハンドルを返却する関数を仮定 //(B)クリップボードをオープンします。 ::OpenClipboard(NULL); //(C)今クリップボードに入っているデータを廃棄します。 ::EmptyClipboard(); //(D)クリップボードへグローバルメモリを登録する ::SetClipboardData(CF_TEXT,
hText) ; //
プレーンテキストのデータを登録します ::SetClipboardData(CF_TAD
, hMemo) ; //
BTMemo独自形式のデータを登録します。 //(E)クリップボードをクローズする ::CloseClipboard(); −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− クリップボードからデータを取り出すプログラムが、登録されているクリップボードフォーマットを見て、自分が扱えるデータだけを持っていくことになります。 BTMemo以外のプログラムはBTMemo独自形式のデータは使用せず、プレーンテキストだけを持っていくでしょう。 BTMemoは、まずBTMemo独自形式の有無を調べ、有ればそれを最優先して取り出します。それが無ければプレーンテキストを処理します。 |
(4)CF_HDROP形式でクリップボードに登録するデータを作成する
カレンダーからドラッグ&ドロップでBTMemoにリンクを作成するときに使用してます。
//
パス名からCF_HDROP形式のデータを得る HGLOBAL
GetClipData_HDROP(char *pszPathName) { //
メモリを獲得しクリップボードデータを作成 HGLOBAL
hData = (HGLOBAL)::GlobalAlloc(GHND, (DWORD)sizeof(DRAGDATA)); if
(hData == NULL) { return
NULL; } DRAGDATA
*pData = (DRAGDATA *)::GlobalLock(hData); pData->df.pFiles
= sizeof(DROPFILES); //
変数名はポインタですが、メモリの先頭からのバイト位置です strcpy(pData->szPathName,
pszPathName); //
複数のファイルを登録したい場合は、続けてパス名を登録すればよかったと思うのですが… //
正確なところは失念してしまいました ::GlobalUnlock(hData); return
hData; } −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− カレンダーのソースから抜粋してきました。 クリップボードの処理でもドラッグ&ドロップの処理でもデータの作り方は同じです。 |