国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

使用OLE拖放不同程序間的數據

2019-11-18 18:30:21
字體:
來源:轉載
供稿:網友

使用OLE拖放不同程序間的數據

(OLE Drag and Drop)

難度:★★★☆☆
先行知識:Delphi / 接口 / Win32 / OLE or COM
 
從一個程序拖動數據到另一個程序(典型的情況是拖動文本)已經不是什么新鮮事了,很多共享軟件都支持這個功能(比如說著名的FlashGet、netants等的浮動窗口功能)。作者一直想在自己的軟件中實現這個功能,經過一段時間的資料搜索,有了部分的了解,但這些文檔大多數使用C++描述。于是,好東西(也算不上好好的吧J)不敢獨享,經過整理我將自己用delphi的實現方法寫出來,并簡單的講解一下OLE Drag and Drop機制。
所謂OLE Drag and Drop不用翻譯大家一看就能知道它的意思了,它使不同的程序(或同一個程序)通過相互拖動數據來進行交互成為可能。 在這方面windows為我們在后面做了很復雜的工作,幸運的是我們不用擔心它的復雜性,windows已經為我們提供了兩個相當關鍵的接口:IDropSource、IDropTarget,我們只用實現這兩個接口便可以方便的實現OLE Drag and Drop,前者由允許拖放自己數據的數據源程序實現,后者由允許接收拖放數據的數據目標程序所實現。在本文中,我們只討論后者,因為我們只希望接收來自其它程序拖放過來的數據,而前者已經被大多數程序實現了(如IE、windows幫助系統等,如果想了解更多關于IDropSource的實現請參看win32 sdk幫助文件)。
接下來我們簡單的了解一下windows是怎樣在后面實現數據拖放的,然后我們實現IDropTarget的一個例子程序(關于程序中的api和格式會在出現的時候給予說明)。Windows在后臺調用了一個重要的DoDragDrop函數來檢測接口和調用有我們實現的接口方法,下面是這個函數工作時大概的步驟:
·當我們開始向可以接收數據的窗體拖動數據時,DoDragDrop首先檢查鼠標下的窗體是否被注冊為可以接收的窗體(通過RegisterDragDrop api來注冊,該函數有兩個參數,第一個為要注冊的窗體的句柄,第2個為指向我們實現IDropTarget的類的一個對象指針,在我們的窗體不需要再接收任何拖動過來的數據時使用RevokeDragDrop來解除注冊,它只有一個參數,就是欲解除的窗體句柄,另外重要的一點是要成功的調用這些函數,我們必須在程序開始時使用OleInitialize(nil)在結束時調用OleUninitialize以便初始化OLE library。)
·如果窗體可以接收拖動,DoDragDrop便調用IDropTarget接口的DragEnter方法,該方法通過一個引用參數返回一個拖動的效果dwEffect,它可以有不同的取值(通過檢查IDataObject來決定),你可以在幫助中找到這些值,其中有表示復制、剪切等的操作(指對于實現IDropSource的程序),具體的你還會在下文的代碼中看到。然后DoDragDrop通過調用IDropSource::GiveFeedback來將dwEffect傳遞給IDropSource。
·接下來DoDragDrop根據鼠標的狀態調用諸如IDropTarget接口的DragOver、DragLeave方法,整個過程是在循環中不斷的檢測鼠標的狀態來實現的,如果這時你改變了拖動目標它會再次檢測新的目標并重復上面的過程,如果你在鍵盤上同時按住了其它的鍵,它會調用IDropSource::QueryContinueDrag并在改變了鍵盤狀態碼(你可以通過DragEnter、DragOvert中的grfKeyState參數來檢測改值,并根據它做相應的工作)后繼續重復上面的過程。
·當我們最后松開鼠標后DoDragDrop將調用IDropTarget的Drop方法,它最后一次返回dwEffect,最后根據dwEffect我們可以在這個方法中得到IDataObject中的數據,一次完整的拖放操作就完成了。下面的圖說明一次拖放操作的過程:
上面說了這么多,其實都是windows在后臺為我們所做的工作,我們只是大概的了解一下這個過程,下面我們通過一個例子來實現一個可以接受文本的memo,窗體中只有一個Tmemo,請注意代碼中的注釋。我們先來看看在程序主窗口創建和撤消時需要做的一些必要的初始化和結束操作:
constructor TForm1.Create(AOwner: TComponent);
begin
  inherited Create(AOWner);
  OleInitialize(nil);
  DragAndDropOLE:=TDragAndDropOLE.Create;
  // TDragAndDropOLE便是我們要實現IDropTarget接口的類
end;
 
destructor TForm1.Destroy;
begin
  DragAndDropOLE.Free;
  OleUninitialize;
  inherited;
end;
下面我們來看看關鍵的TDragAndDropOLE的實現,首先他應該實現IunKnown接口,這是一個基本的接口用來實現引用計數,熟悉COM的朋友應該都知道這個接口及其實現方法,下面只給出實現它的代碼不做詳細說明,主要要注意的是IDropTarget的實現方法:
首先是TDragAndDropOLE的聲明部分:
type
  TDragAndDropOLE=Class(TObject,IUnknown,IDropTarget)
  PRivate
   CanDrop:HResult;
   fe:TFormatEtc;//數據的格式,在實現部分給出詳細說明
   FRefCount:integer;//引用計數
  protected
   { Iunkown }
   function _AddRef:integer;stdcall;
   function _Release:integer;stdcall;
   function QueryInterface(const IID:TGUID;out Obj):HResult;stdcall;
   { IdropTarget }
   function DragEnter(const dataObj: IDataObject; grfKeyState: Longint;
      pt: TPoint; var dwEffect: Longint): HResult;stdcall;
   function DragOver(grfKeyState: Longint; pt: TPoint;var dwEffect: Longint):HResult;stdcall;
   function DragLeave: HResult;stdcall;
   function Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint;
    var dwEffect: Longint): HResult; stdcall;
  public
   constructor Create;
   destructor Destroy;override;
  end;
下面是實現部分,首先初始化部分:
constructor TDragAndDropOLE.Create;
begin
  FRefCount:=0;
  RegisterDragDrop(Form1.Memo1.Handle,self);//上文提到的函數
end;
 
destructor TDragAndDropOLE.Destroy;
begin
  RevokeDragDrop(Form1.Memo1.Handle);
  inherited;
end;
接下來實現Iunknown,不再做詳細說明:
function TDragAndDropOLE._AddRef: integer;
begin
 result:=InterLockedDecrement(FRefCount);
 if Result=0 then Destroy;
end;
 
function TDragAndDropOLE._Release: integer;
begin
 result:=InterLockedIncrement(FRefCount);
end;
 
function TDragAndDropOLE.QueryInterface(const IID: TGUID;
  out Obj): HResult;
begin
 if GetInterface(IID,Obj) then
  result:=S_OK
 else result:=E_NOINTERFACE;
end;
最重要的IDropTarget實現:
function TDragAndDropOLE.DragEnter(const dataObj: IDataObject;
  grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult;
begin
 result:=E_FAIL;
 CanDrop:=E_Fail;
 if assigned(dataObj) then
 begin
  with fe do
  begin
   cfFormat:=CF_TEXT;
   ptd:=nil;
   dwaspect:=DVASPECT_CONTENT;
   lindex:=-1;
   tymed:=TYMED_HGLOBAL;
  end;
  //大家從上面看到的fe是一種我們處理內存數據時常用的轉換格式
  //這里它表示將數據格式作為文字(cfFormat),并將其存入一塊
  //全局的內存區域(tymed:=TYMED_HGLOBAL),更多的格式請在win32
  //幫助中搜索TFormatEtc
  CanDrop:=dataObj.QueryGetData(fe);//按照fe指定的格式檢查數據
  result:=CanDrop;
  if not Failed(result) then
   dwEffect:=DROPEFFECT_COPY
  else dwEffect:=DROPEFFECT_NONE;
  //注意這里我們設置了dwEffect,更多的取值請查看win32幫助
 end;
end;
 
function TDragAndDropOLE.DragLeave: HResult;
begin
 result:=S_OK;
end;
 
function TDragAndDropOLE.DragOver(grfKeyState: Integer; pt: TPoint;
  var dwEffect: Integer): HResult;
begin
 result:=S_OK;
 //我們不需要在這里做其余的操作,當然你可以根據自己的需要完成自己的方法
end;
 
function TDragAndDropOLE.Drop(const dataObj: IDataObject;
  grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult;
var
 medium:stgMedium;
 hData:HGLOBAL;
begin
 result:=E_Fail;
 if not Failed(CanDrop) then
 begin
   result:=dataObj.GetData(fe,medium);
   //按照fe的格式將數據存入內存的一塊全局區域,注意medium
   hData:=HGLOBAL(GlobalLock(medium.hGlobal));
   //GlobalLock鎖定這塊區域,并返回指向它的指針
   Form1.Memo1.Text:=pchar(hData);
   GlobalUnlock(hData);//接觸鎖定
   GlobalFree(hData);//釋放
 end;
end;
現在我們可以測試它了。本文只是大概的介紹了一下OLE Drag and Drop,只要仔細研究,大家可以實現更復雜的操作。 

上一篇:數據錄入時自動復制原記錄

下一篇:win32調試API學習心得(三)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網友關注

主站蜘蛛池模板: 通辽市| 理塘县| 伊吾县| 屏东县| 荥阳市| 扎赉特旗| 峨眉山市| 虞城县| 秀山| 甘德县| 木兰县| 无棣县| 威信县| 蒙城县| 南昌县| 常熟市| SHOW| 景洪市| 孟州市| 克山县| 宁安市| 江阴市| 乐亭县| 临洮县| 黄浦区| 夏邑县| 綦江县| 墨江| 桐柏县| 亚东县| 包头市| 龙山县| 洛川县| 鹿泉市| 乌拉特后旗| 利津县| 富平县| 余姚市| 荥经县| 格尔木市| 苍南县|