為解決這些問題,我開發了下面的程序。程序啟動時,以極小化方式運行。此時只要剪貼板中存入位圖,則自動彈出一個對話框請求用戶保存。如果用戶希望查看確認,則可以雙擊運行程序圖標,選擇相應按鈕,剪貼板中的位圖就會顯示在屏幕上。
部件關鍵屬性設計如下:
ClipSaveForm:
Caption=‘Save Bitmap in Clipboard '
Panel1:
Align = ' Top '
Image1:
Align = ' Client '
SaveDialog1:
FileEditStyle = fsEdit
FileName = '*.bmp'
Filter = 'Bitmap Files(*.bmp)|*.bmp|Any Files(*.*)|*.*'
InitialDir = 'c:\bmp'
Title = 'Save Bitmap'
程序主窗口是TForm派生類TClipSaveForm的實例。TClipSaveForm通過定義一些私有數據成員和過程,使響應和處理Windows的相應消息成為可能。下面是TClipSaveForm的類定義:
type
TClipSaveForm = class(TForm)
SaveDialog1: TSaveDialog;
Image1: TImage;
Panel1: TPanel;
Button1: TButton;
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure SpeedButton2Click(Sender: TObject);
private
{ Private declarations }
MyBitmap: TBitmap; { 保存截獲的位圖 }
View: Boolean; { 判斷是否顯示 }
NextViewerHandle: HWND; { 下一剪貼板觀察器的句柄 }
procedure WMDrawClipboard(var Msg:TWMDrawClipboard);
message WM_DRAWCLIPBOARD;
procedure WMChangeCBChain(var Msg:TWMChangeCBChain);
message WM_CHANGECBCHAIN;
{ 響應Windows的剪貼板消息 }
public
{ Public declarations }
end;
窗口創建時,把該窗口登錄為剪貼板觀察器,添加到剪貼板觀察器鏈中,同時進行變量、部件和剪貼板的初始化。
procedure TClipSaveForm.FormCreate(Sender: TObject);
begin
View := False;
SpeedButton2.Down := True;
MyBitmap := TBitmap.create;
try
MyBitmap.Width := 0;
MyBitmap.Height := 0 ;
except
Application.terminate;
end;
Clipboard.Clear;
NextViewerHandle := SetClipboardViewer(Handle);
end;
窗口關閉時,退出剪貼板觀察器鏈,並釋放內存:
procedure TClipSaveForm.FormDestroy(Sender: TObject);
begin
ChangeClipboardChain(Handle,NextViewerHandle);
MyBitmap.Free;
end;
在以上兩段程序中用到的兩個Windows API函數SetClipboardViewer和ChangeClipboardChain分別用於登錄和退出剪貼板觀察器鏈。
程序保存位圖的功能是在消息響應過程WMDrawClipboard中實現的。該過程在剪貼板內容有變化時被調用。
procedure TClipSaveForm.WMDrawClipboard(var Msg: TWMDrawClipboard);
var
FileName: String;
begin
If NextViewerHandle <> 0 then
SendMessage(NextViewerHandle,msg.Msg,0,0);
If ClipBoard.HasFormat(CF_BITMAP) then
begin
MyBitmap.Assign(Clipboard);
If SaveDialog1.Execute then
begin
FileName := SaveDialog1.FileName;
MyBitmap.SaveToFile(FileName);
end;
If View then
begin
WindowState := wsNormal;
Image1.Picture.Bitmap := MyBitmap;
end;
end;
Msg.Result := 0;
end;
程序首先判斷在剪貼板觀察器鏈中是否還存在下一個觀察器。如果有,則把消息傳遞下去,這是剪貼板觀察器程序的義務。而後判斷剪貼板上內容的格式是否為位圖。如是,則首先把剪貼板上內容保存到數據成員MyBitmap中,並激活一個文件保存對話框把位圖保存到文件中。如果View=True,則把窗口狀態(WindowState)設置為wsNormal,並把MyBitmap賦給Image部件的相應值,使用戶可以對剪貼板上的位圖進行觀察。