お世話になります。
クリップボードの内容(※)を待避し、一旦、クリップボードの内容を変更した後、
再度、待避した内容をクリップボードに戻したいです。
対象がすべてテキストであったら、現在の私の知識で可能ですが、
それ以外はどうしたらいいのか検討がつきません。
これを実現するにはどうしたらいいのでしょうか?
※…テキスト、画像、他
画像でビットマップに待避したなら
Clipboard.Assign(bmp);
という感じです。
ん〜、待避するのは、自分のアプリで作ったデータではなく、全てに共通で使用されているデータってことかね?
例えば、Excelでコピーしたデータを、自分のアプリで一端待避し、クリップボードを使用。
その後、Excelのデータを戻すようなイメージかな?
だとしたら、クリップボードに保存されている全てのフォーマット形式を取得し、
(たぶんできたと思うけど、やり方は他の人のレスを待とう(^^ゞ)
FileStreamもMemoryStreamでも全部保存して(クリップボードからStreamへの
読み書きはあったと思うけど)、クリア。
あとは、自アプリで好きなように使って、復元すればいいと思われる。
具体的なコードは・・・出せませんm(v_v)m
みなさん、ありがとう。
#通りすがり さん
>例えば、Excelでコピーしたデータを、自分のアプリで一端待避し、クリップボードを使用。
>その後、Excelのデータを戻すようなイメージかな?
その通りです。
テキスト、画像あたりならなんとかなりそうですが、
他の形式の場合はどうするのかが分からなかったのです。
具体的な目的は、
(あらゆるアプリで)テキストの範囲選択しているところをクリップボードに取り込みたいのです。
しかし、APIによるSendMessageでは「Edit」コンポーネントしか取れないと、
ネットで見ました。
ですので、キー押下メッセージ(CTRL+C)を送ることにより範囲選択しているところをクリップボードに取り込もうとしています。
記述漏れましました。追記です。
主目的がこれですので、
自アプリケーションでクリップボードの内容を使用した後、元に戻したいという訳です。
以前、全く同じことしました。
そのときのノウハウですが、エクセル等の一部のアプリはこの仕様では無理です。
クリップボードにポインタみたいなものを置いてたり、アプリ自体がクリップボードの変更を監視しているのは以外にありますからね。
完全対応はあきらめるが吉だとおもいます。
作ってみました。
細かいエラー対策はしていません。
procedure ClipBoardSaveToStream(Stream: TStream);
procedure ClipBoardLoadFromStream(Stream: TStream);
implementation
procedure ClipBoardSaveToStream(Stream: TStream);
var
hMem: THandle;//LongWord
uiFormatId: UINT;
dwSize: DWORD;
p: PCHAR;
begin
if OpenClipboard(0) then
begin
try
uiFormatId := EnumClipboardFormats(0);
while uiFormatId <> 0 do
begin
Stream.Write(uiFormatId, SizeOf(uiFormatId));
hMem := GetClipboardData(uiFormatId);
if hMem <> 0 then
begin
dwSize := GlobalSize(hMem);
Stream.Write(dwSize, SizeOf(dwSize));
p := GlobalLock(hMem);
Stream.Write(p^, dwSize);
GlobalUnlock(hMem);
end
else
begin
dwSize := 0;
Stream.Write(dwSize, SizeOf(dwSize));
end;
uiFormatId := EnumClipboardFormats(uiFormatId);
end;
finally
CloseClipboard;
end;
end;
end;
procedure ClipBoardLoadFromStream(Stream: TStream);
var
hMem: THandle;
uiFormatId: UINT;
dwSize: DWORD;
p: PCHAR;
begin
if OpenClipboard(0) then
begin
EmptyClipboard;
try
while Stream.Read(uiFormatId, SizeOf(uiFormatId)) = SizeOf(uiFormatId) do
begin
Stream.Read(dwSize, SizeOf(dwSize));
hMem := GlobalAlloc(GMEM_MOVEABLE, dwSize);
p := GlobalLock(hMem);
Stream.Read(p^, dwSize);
GlobalUnlock(hMem);
SetClipboardData(uiFormatId, hMem);
GlobalFree(hMem);
end;
finally
CloseClipboard;
end;
end;
end;
>にしのさん
遅延レンダリングの場合、このアプリにメッセージが届くことになりますね?
遅延レンダリングの場合、GetClipboardDataを呼び出した時点で、WM_RENDERFORMATが飛びませんか?
# 私の勘違いかも。
上のプロシージャでは、必ずメモリを確保してからSetClipboardDataを呼ぶので、このアプリがWM_RENDERFORMATを受け取ることはないと思います。
> GetClipboardDataを呼び出した時点で、WM_RENDERFORMATが飛びませんか?
おお、そうでした。すみません。
ママん さん、にしの さん、りおりお さん、ご親切にありがとうございます。
私のレベルではまだ理解不能な回答をいただいて、混乱気味で、正直断念しそうです。
しかし、せっかく教えていただいていますので、頑張って理解しようと思っています。
基本的なことをお伺いするようで、大変恐縮ですが、よろしくお願いいたします。
まず、にしの さんより提示していただいたソースを順次見ていきまして、
私が理解できなかったことです(というより、アホな私はそこから学ぶ必要があると・・・)
>procedure ClipBoardSaveToStream(Stream: TStream);
>(略)
> uiFormatId := EnumClipboardFormats(0);
ここでクリップボード内に存在するデータが持つデータ形式を列挙することは、
なんとなく分かったのですが、
> Stream.Write(uiFormatId, SizeOf(uiFormatId));
ここは何をしているのでしょうか?
(ヘルプを見ると、「Write メソッドは,ストリームにデータを書き込むための抽象メソッドを
導入します。」とありますが、なんとも理解不能でありまして)
また、とりあえず動かしながら理解を深めようと、
単純に、クリップボードの内容を待避してすぐ戻してみようと以下の処理を行ってみました、
うまく動きません。どのようのすればよろしいのでしょうか?
>procedure TForm1.Button1Click(Sender: TObject);
>var
> Stream1 : TStream;
>begin
> ClipBoardSaveToStream(Stream1);
> ClipBoardLoadFromStream(Stream1);
>
>end;
本当に低レベルな私ですが、どうかよろしくお願いいたしますm(_ _)m
> > Stream.Write(uiFormatId, SizeOf(uiFormatId));
> ここは何をしているのでしょうか?
> (ヘルプを見ると、「Write メソッドは,ストリームにデータを書き込むための抽象メソッドを
> 導入します。」とありますが、なんとも理解不能でありまして)
読んだそのままです。
uiFormatIdの内容をStreamに書き込みます。
TStreamは基底クラスなので、実装はその継承クラスがおこなっています。
Writeメソッドは、指定されたデータを「書き込む」というメソッドです。
この「書き込む」が抽象化されていて、たとえば
TMemoryStream・・・メモリに書き込む
TFileStream・・・ファイルに書き込む
というように、継承クラスの実装によって振る舞いが変わってきます。
> 単純に、クリップボードの内容を待避してすぐ戻してみようと以下の処理を行ってみました、
> うまく動きません。どのようのすればよろしいのでしょうか?
では、簡単な例を。
# ここでは、メモリに確保し、復元する方法。
1.TForm1の、Private宣言に、ms: TMemoryStream;を用意する。
{ Private宣言 }
ms: TMemoryStream;
2.TForm1のOnCreateイベントで、msのインスタンスを生成する。
ms := TMemoryStream.Create;
3.TForm1.のOnDestroyイベントで、msのインスタンスを破棄する。
ms.Free;
4.Button1のOnClickイベントで、クリップボードを待避する。
procedure TForm1.Button1Click(Sender: TObject);
begin
ms.Clear; //確保したMemoryStreamのクリア
ClipboardSaveToStream(ms); //待避
end;
5.Button2のOnClickイベントで、クリップボードを復元する。
procedure TForm1.Button2Click(Sender: TObject);
begin
ms.Seek(0, soFromBeginning); //MemoryStreamの巻き戻し
ClipboardLoadFromStream(ms); //復元
end;
にしの さん、ご丁寧な説明をありがとうございます。
テキスト文字、EXCELのセル、画像(ビットマップ)などで試したところ、
うまくいっています。
これから、自作のアプリに取り込んでみようと思います。
大変勉強になり、また、非常に助かりました。ありがとうございました。
ツイート | ![]() |