RVDragDrop.pas
上传用户:daoqigc
上传日期:2021-04-20
资源大小:2795k
文件大小:35k
源码类别:

RichEdit

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {       RichView                                        }
  4. {       Assistant classes for drag & drop.              }
  5. {       TRVDropTarget: implements IDropTarget           }
  6. {                                                       }
  7. {       Copyright (c) Sergey Tkachenko                  }
  8. {       svt@trichview.com                               }
  9. {       http://www.trichview.com                        }
  10. {                                                       }
  11. {*******************************************************}
  12. unit RVDragDrop;
  13. interface
  14. {$I RV_Defs.inc}
  15. uses SysUtils, Windows, ActiveX, Classes, Graphics,
  16.      RVStr, RVUni, RVScroll, ShlObj;
  17.   {$IFNDEF RVDONOTUSEDRAGDROP}
  18. {$IFDEF BCB}
  19. {$HPPEMIT 'DECLARE_DINTERFACE_TYPE(IDropTarget)'}
  20. {$HPPEMIT 'DECLARE_DINTERFACE_TYPE(IDropSource)'}
  21. {$HPPEMIT 'DECLARE_DINTERFACE_TYPE(IEnumFORMATETC)'}
  22. {$ENDIF}
  23.   
  24. type
  25.   { ----------------------------------------------------------------------------
  26.     TRVDropTarget: implementation of IDropTarget.
  27.     Used as TCustomRichViewEdit.FDropTarget
  28.   }
  29.   TRVDropTarget = class(TRVScrollerInternalIfcObject, IDropTarget)
  30.   private
  31.     FAccepted: Boolean;
  32.     function HasAcceptableFormats(const DataObj: IDataObject): Boolean;
  33.     function AllowMoving(KeyState: LongInt; Effect: LongInt): Boolean;
  34.     function GetEffect(KeyState: LongInt; Effect: LongInt): LongInt;
  35.     procedure FillFormatEtc(var FmtEtc: TFormatEtc; Format: Word);
  36.     function GetFiles(const Handle: HGlobal; Files: TStrings): Boolean;    
  37.   public
  38.     { IDropTarget }
  39.     function DragEnter(const DataObj: IDataObject; KeyState: Longint;
  40.       pt: TPoint; var Effect: Longint): HResult; stdcall;
  41.     function DragOver(KeyState: Longint; pt: TPoint;
  42.       var Effect: Longint): HResult; stdcall;
  43.     function DragLeave: HResult; stdcall;
  44.     function Drop(const DataObj: IDataObject; KeyState: Longint; pt: TPoint;
  45.       var Effect: Longint): HResult; stdcall;
  46.     { Get data as ... }
  47.     function GetMedium(const DataObj: IDataObject; Format: Word;
  48.       var StgMedium: TStgMedium): Boolean;
  49.     function GetAsStream(const DataObj: IDataObject; Format: Word): TMemoryStream;
  50.     function GetAsText(const DataObj: IDataObject; Format: Word;
  51.       var s: String): Boolean;
  52.     {$IFNDEF RVDONOTUSEUNICODE}
  53.     function GetAsTextW(const DataObj: IDataObject; var s: String): Boolean;
  54.     {$ENDIF}
  55.     function GetAsBitmap(const DataObj: IDataObject; TryDIBFirst: Boolean): TBitmap;
  56.     function GetAsMetafile(const DataObj: IDataObject): TMetafile;
  57.     function GetAsFiles(const DataObj: IDataObject): TStringList;
  58.     function HasFormat(const DataObj: IDataObject; Format: Word): Boolean;
  59.     { Other methods }
  60.     destructor Destroy; override;
  61.     function RegisterDragDropForOwner: Boolean;
  62.     procedure UnRegisterDragDropForOwner;
  63.   end;
  64.   { ----------------------------------------------------------------------------
  65.     TRVEnumFormatEtc: implementation of IEnumFormatEtc
  66.   }
  67.   TRVEnumFormatEtc = class(TInterfacedObject, IEnumFormatEtc)
  68.   private
  69.     FGraphic: TGraphic;
  70.     FIndex: Integer;
  71.     function GetCurFormat: Word;
  72.   public
  73.     constructor Create(Graphic: TGraphic; Index: Integer);
  74.     { IEnumFormatEtc }
  75.     function Next(Celt: LongInt; out Elt; PCeltFetched: PLongInt): HResult; stdcall;
  76.     function Skip(Celt: LongInt): HResult; stdcall;
  77.     function Reset: HResult; stdcall;
  78.     function Clone(out Enum: IEnumFormatEtc): HResult; stdcall;
  79.   end;
  80.   { ----------------------------------------------------------------------------
  81.     TRVDropSource: implementation of IDropSource and IDataObject.
  82.     Used as TCustomRichView.FDropSource.
  83.   }
  84.   TRVDropSource = class(TRVScrollerInternalIfcObject, IDropSource, IDataObject)
  85.   private
  86.     FMedium: TStgMedium;
  87.     FUseMedium: Boolean;
  88.     function IsAvailableFormat(Format: Word): Boolean;
  89.     function GetAsStream(Format: Word): TMemoryStream;
  90.     function GetAsHandle(Format: Word; var Handle: HGlobal): HResult;
  91.     function SaveToHandle(Format: Word; Handle: HGlobal): HResult;
  92.   public
  93.     { IDropSource }
  94.     function QueryContinueDrag(FEscapePressed: Bool;
  95.       KeyState: LongInt): HResult; stdcall;
  96.     function GiveFeedback(Effect: LongInt): HResult; stdcall;
  97.     { IDataObject }
  98.     function GetData(const FormatEtcIn: TFormatEtc;
  99.       out Medium: TStgMedium): HResult; stdcall;
  100.     function GetDataHere(const FormatEtcIn: TFormatEtc;
  101.       out Medium: TStgMedium): HResult; stdcall;
  102.     function QueryGetData(const FormatEtc: TFormatEtc): HResult; stdcall;
  103.     function GetCanonicalFormatEtc(const FormatEtc: TFormatEtc;
  104.       out FormatEtcOut: TFormatEtc): HResult; stdcall;
  105.     function SetData(const FormatEtc: TFormatEtc; var Medium: TStgMedium;
  106.       FRelease: Bool): HResult; stdcall;
  107.     function EnumFormatEtc(Direction: LongInt;
  108.       out EnumFormatEtc: IEnumFormatEtc): HResult; stdcall;
  109.     function DAdvise(const FormatEtc: TFormatEtc; advf: LongInt;
  110.       const advsink: IAdviseSink; out Connection: LongInt): HResult; stdcall;
  111.     function DUnadvise(Connection: LongInt): HResult; stdcall;
  112.     function EnumDAdvise(out EnumAdvise: IEnumStatData): HResult; stdcall;
  113.     { Other methods }
  114.     destructor Destroy; override;
  115.     function StoreData(Format: Word): Boolean;
  116.   end;
  117.   {$ENDIF}
  118. implementation
  119. {$IFNDEF RVDONOTUSEDRAGDROP}
  120. uses RichView, RVRVData, CRVData;
  121. {=============================== TRVDropTarget ================================}
  122. destructor TRVDropTarget.Destroy;
  123. begin
  124.   OwnerReleaseDropTargetObject;
  125.   inherited;
  126. end;
  127. {------------------------------------------------------------------------------}
  128. { DROPEFFECT_MOVE is possible                                                  }
  129. function TRVDropTarget.AllowMoving(KeyState, Effect: Integer): Boolean;
  130. begin
  131.   Result := ((KeyState and MK_CONTROL)=0) and ((Effect and DROPEFFECT_MOVE)<>0)
  132.     and TCustomRichView(FOwner).RVData.IsDragging;
  133. end;
  134. {------------------------------------------------------------------------------}
  135. function TRVDropTarget.GetEffect(KeyState: LongInt; Effect: LongInt): LongInt;
  136. begin
  137.   if AllowMoving(KeyState, Effect) then
  138.     Result := DROPEFFECT_MOVE
  139.   else if (Effect and DROPEFFECT_COPY)<>0 then
  140.     Result := DROPEFFECT_COPY
  141.   else
  142.     Result := DROPEFFECT_LINK;
  143. end;
  144. {------------------------------------------------------------------------------}
  145. { IDropTarget.DragEnter                                                        }
  146. function TRVDropTarget.DragEnter(const DataObj: IDataObject;
  147.   KeyState: Integer; pt: TPoint; var Effect: Integer): HResult;
  148. var PossibleEffect: Integer;
  149. begin
  150.   PossibleEffect := Effect;
  151.   pt := FOwner.ScreenToClient(pt);
  152.   FAccepted := False;
  153.   if HasAcceptableFormats(DataObj) then
  154.     Effect := GetEffect(KeyState, Effect)
  155.   else
  156.     Effect := DROPEFFECT_NONE;
  157.   CallOwnerDragEnterEvent(DataObj, KeyState, pt, PossibleEffect, Effect);
  158.   if Effect<>DROPEFFECT_NONE then begin
  159.     FAccepted := OwnerDragEnter(pt.X, pt.Y);
  160.     if not FAccepted then
  161.       Effect := DROPEFFECT_NONE;
  162.   end;
  163.   Result := S_OK;
  164. end;
  165. {------------------------------------------------------------------------------}
  166. { IDropTarget.DragOver                                                         }
  167. function TRVDropTarget.DragOver(KeyState: Integer; pt: TPoint;
  168.   var Effect: Integer): HResult;
  169. var PossibleEffect: Integer;
  170. begin
  171.   PossibleEffect := Effect;
  172.   pt := FOwner.ScreenToClient(pt);
  173.   if FAccepted and OwnerDragOver(pt.X, pt.Y) then begin
  174.     Effect := GetEffect(KeyState, Effect);
  175.     CallOwnerDragOverEvent(KeyState, pt, PossibleEffect, Effect);
  176.     end
  177.   else
  178.     Effect := DROPEFFECT_NONE;
  179.   Result := S_OK;
  180. end;
  181. {------------------------------------------------------------------------------}
  182. // IDropTarget.DragOver
  183. function TRVDropTarget.DragLeave: HResult;
  184. begin
  185.   OwnerDragLeave;
  186.   Result := S_OK;
  187. end;
  188. {------------------------------------------------------------------------------}
  189. // IDropTarget.Drop
  190. function TRVDropTarget.Drop(const DataObj: IDataObject;
  191.   KeyState: Integer; pt: TPoint; var Effect: Integer): HResult;
  192. var NewEffect: LongInt;
  193. begin
  194.   pt := FOwner.ScreenToClient(pt);
  195.   NewEffect := OwnerDrop(DataObj, AllowMoving(KeyState, Effect),
  196.     KeyState, pt, Effect);
  197.   if (NewEffect=DROPEFFECT_COPY) and ((Effect and DROPEFFECT_COPY)=0) then
  198.     Effect := DROPEFFECT_LINK
  199.   else
  200.     Effect := NewEffect;  
  201.   Result := S_OK;
  202. end;
  203. {------------------------------------------------------------------------------}
  204. { Returns true if DataObj contains one of: text, RVF, RTF, Bitmap...           }
  205. function TRVDropTarget.HasAcceptableFormats(const DataObj: IDataObject): Boolean;
  206. var  FormatEtc : IEnumFormatEtc;
  207.      Fmt : TFormatEtc;
  208.      s: String;
  209.      l: Integer;
  210. begin
  211.   Result := False;
  212.   if DataObj.EnumFormatEtc(DATADIR_GET, FormatEtc) = S_OK then
  213.     while FormatEtc.Next(1, Fmt, nil) = S_OK do begin
  214.       SetLength(s, 1000);
  215.       l := GetClipboardFormatName(Fmt.cfFormat, PChar(s), 1000);
  216.       SetLength(s, l);
  217.       if OwnerCanAcceptFormat(Fmt.cfFormat) then begin
  218.         Result := True;
  219.         //exit;
  220.       end;
  221.     end;
  222. end;
  223. {------------------------------------------------------------------------------}
  224. { Returns tymed value for the data format                                      }
  225. function GetTymed(Format: Word): LongInt;
  226. begin
  227.   case Format of
  228.     CF_BITMAP:
  229.       Result := TYMED_GDI;
  230.     CF_ENHMETAFILE:
  231.       Result := TYMED_ENHMF;
  232.     CF_METAFILEPICT:
  233.       Result := TYMED_MFPICT;
  234.     else
  235.       Result := TYMED_HGLOBAL;
  236.   end;
  237. end;
  238. {------------------------------------------------------------------------------}
  239. { Fills TFormatEtc for the given Format.                                       }
  240. procedure TRVDropTarget.FillFormatEtc(var FmtEtc: TFormatEtc; Format: Word);
  241. begin
  242.   FillChar(FmtEtc, sizeof(FmtEtc), 0);
  243.   FmtEtc.cfFormat := Format;
  244.   FmtEtc.dwAspect := DVASPECT_CONTENT;
  245.   FmtEtc.lindex := -1;
  246.   FmtEtc.tymed := GetTymed(Format);
  247. end;
  248. {------------------------------------------------------------------------------}
  249. { Returns true if DataObj contains Format                                      }
  250. function TRVDropTarget.HasFormat(const DataObj: IDataObject;
  251.   Format: Word): Boolean;
  252. var FmtEtc: TFormatEtc;
  253. begin
  254.   FillFormatEtc(FmtEtc, Format);
  255.   Result := DataObj.QueryGetData(FmtEtc)=S_OK;
  256. end;
  257. {------------------------------------------------------------------------------}
  258. { Returns StgMedium. The caller must call ReleaseStgMedium                     }
  259. function TRVDropTarget.GetMedium(const DataObj: IDataObject; Format: Word;
  260.   var StgMedium: TStgMedium): Boolean;
  261. var FmtEtc: TFormatEtc;  
  262. begin
  263.   FillChar(StgMedium, sizeof(StgMedium), 0);
  264.   FillFormatEtc(FmtEtc, Format);
  265.   Result := DataObj.GetData(FmtEtc, StgMedium)=S_OK;
  266. end;
  267. {------------------------------------------------------------------------------}
  268. { Creates stream, copies data to it. Returns nil if failed.                    }
  269. function TRVDropTarget.GetAsStream(const DataObj: IDataObject;
  270.   Format: Word): TMemoryStream;
  271. var FmtEtc: TFormatEtc;
  272.   StgMedium: TStgMedium;
  273.   ptr: Pointer;
  274.   Size: Integer;
  275. begin
  276.   FillChar(StgMedium, sizeof(StgMedium), 0);
  277.   FillFormatEtc(FmtEtc, Format);
  278.   Result := nil;
  279.   if DataObj.GetData(FmtEtc, StgMedium)<>S_OK then
  280.     exit;
  281.   if StgMedium.tymed=GetTymed(Format) then begin
  282.     ptr := GlobalLock(StgMedium.HGlobal);
  283.     Result := TMemoryStream.Create;
  284.     if Format<>CFRV_RVF then
  285.       Result.WriteBuffer(ptr^, GlobalSize(StgMedium.HGlobal))
  286.     else begin
  287.       if GlobalSize(StgMedium.HGlobal)<4 then
  288.         exit;
  289.       Size := PInteger(ptr)^;
  290.       Result.WriteBuffer((PChar(ptr)+sizeof(Integer))^, Size);
  291.     end;
  292.     Result.Position := 0;
  293.     GlobalUnlock(StgMedium.HGlobal);
  294.   end;
  295.   ReleaseStgMedium(StgMedium);
  296. end;
  297. {------------------------------------------------------------------------------}
  298. { Returns data as string.                                                      }
  299. function TRVDropTarget.GetAsText(const DataObj: IDataObject;
  300.   Format: Word; var s: String): Boolean;
  301. var Stream: TMemoryStream;
  302. begin
  303.   Stream := GetAsStream(DataObj, Format);
  304.   Result := Stream<>nil;
  305.   if Result then begin
  306.     s := StrPas(Stream.Memory);
  307.     Stream.Free;
  308.   end;
  309. end;
  310. {------------------------------------------------------------------------------}
  311. { Returns CF_UNICODETEXT data as "raw unicode" string.                         }
  312. {$IFNDEF RVDONOTUSEUNICODE}
  313. function TRVDropTarget.GetAsTextW(const DataObj: IDataObject;
  314.   var s: String): Boolean;
  315. var Stream: TMemoryStream;
  316.    Len: Integer;
  317.    Ptr: Pointer;
  318. begin
  319.   Stream := GetAsStream(DataObj, CF_UNICODETEXT);
  320.   Result := Stream<>nil;
  321.   if Result then begin
  322.     Len := Stream.Size;
  323.     SetLength(s, Len);
  324.     Stream.ReadBuffer(PChar(s)^, Len);
  325.     Stream.Free;
  326.     ptr := RVU_StrScanW(Pointer(s), 0, Length(s) div 2);
  327.     if ptr<>nil then
  328.       SetLength(s, PChar(ptr)-PChar(s));
  329.   end;
  330. end;
  331. {$ENDIF}
  332. {------------------------------------------------------------------------------}
  333. { Returns a number of colors in TBitmapInfoHeader                              }
  334. function GetDInColors(BitCount: Word): Integer;
  335. begin
  336.   case BitCount of
  337.     1, 4, 8: Result := 1 shl BitCount;
  338.   else
  339.     Result := 0;
  340.   end;
  341. end;
  342. {------------------------------------------------------------------------------}
  343. { Returns data as a bitmap. First tries to read CF_DIB. If failed, tries
  344.   CF_BITMAP. If failed, returns nil.                                           }
  345. function TRVDropTarget.GetAsBitmap(const DataObj: IDataObject;
  346.   TryDIBFirst: Boolean): TBitmap;
  347. var FmtEtc: TFormatEtc;
  348.   StgMedium: TStgMedium;
  349.   ColorCount: Integer;
  350.   bits:Pointer;
  351.   BI: PBitmapInfoHeader;
  352.   Handle: HBitmap;
  353.   DC: HDC;
  354. begin
  355.   // 1. CF_DIB
  356.   FillFormatEtc(FmtEtc, CF_DIB);
  357.   Result := nil;
  358.   if TryDIBFirst then begin
  359.     if DataObj.GetData(FmtEtc, StgMedium)<>S_OK then
  360.       exit;
  361.     if StgMedium.tymed=GetTymed(CF_DIB) then begin
  362.       BI := GlobalLock(StgMedium.hGlobal);
  363.       ColorCount := GetDInColors(BI.biBitCount);
  364.       Bits := Pointer(Longint(BI) + SizeOf(TBitmapInfoHeader) + ColorCount * SizeOf(TRGBQuad));
  365.       try
  366.         DC := GetDC(0);
  367.         try
  368.           Handle := CreateDIBitmap(DC, BI^, CBM_INIT, Bits, PBitmapInfo(BI)^, DIB_RGB_COLORS);
  369.           if Handle<>0 then begin
  370.              Result := TBitmap.Create;
  371.              Result.Handle := Handle;
  372.           end;
  373.         finally
  374.           ReleaseDC(0, DC);
  375.         end;
  376.       finally
  377.         GlobalUnlock(StgMedium.hGlobal);
  378.       end;
  379.     end;
  380.     ReleaseStgMedium(StgMedium);
  381.   end;
  382.   // 2. CF_BITMAP
  383.   if Result=nil then begin
  384.     FillFormatEtc(FmtEtc, CF_BITMAP);
  385.     Result := nil;
  386.     if DataObj.GetData(FmtEtc, StgMedium)<>S_OK then
  387.       exit;
  388.     if StgMedium.tymed=GetTymed(CF_BITMAP) then begin
  389.       Result := TBitmap.Create;
  390.       // Palette?
  391.       Result.LoadFromClipboardFormat(CF_BITMAP, StgMedium.hBitmap, 0);
  392.     end;
  393.     ReleaseStgMedium(StgMedium);
  394.   end;
  395. end;
  396. {------------------------------------------------------------------------------}
  397. { Returns data as a metafile (CF_ENHMETAFILE).
  398.   CF_METAFILEPICT is not supported yet.                                        }
  399. function TRVDropTarget.GetAsMetafile(const DataObj: IDataObject): TMetafile;
  400. var FmtEtc: TFormatEtc;
  401.   StgMedium: TStgMedium;
  402.   Handle: HEnhMetafile;
  403. begin
  404.   // 1. CF_ENHMETAFILE
  405.   FillFormatEtc(FmtEtc, CF_ENHMETAFILE);
  406.   Result := nil;
  407.   if DataObj.GetData(FmtEtc, StgMedium)<>S_OK then
  408.     exit;
  409.   if StgMedium.tymed=GetTymed(CF_ENHMETAFILE) then begin
  410.     Handle := CopyEnhMetaFile(StgMedium.hEnhMetaFile, nil);
  411.     if Handle<>0 then begin
  412.       Result := TMetafile.Create;
  413.       Result.Handle := Handle;
  414.     end;
  415.   end;
  416.   ReleaseStgMedium(StgMedium);
  417. end;
  418. {------------------------------------------------------------------------------}
  419. { Returns a list of files from the Handle of CF_HDROP format                   }
  420. function TRVDropTarget.GetFiles(const Handle: HGlobal;
  421.   Files: TStrings): Boolean;
  422. var
  423.   DropFiles: PDropFiles;
  424.   FileName: PChar;
  425. begin
  426.   Files.Clear;
  427.   DropFiles := PDropFiles(GlobalLock(Handle));
  428.   try
  429.     FileName := PChar(DropFiles) + DropFiles^.pFiles;
  430.     while (FileName^ <> #0) do begin
  431.       if (DropFiles^.fWide) then begin
  432.         Files.Add(PWideChar(FileName));
  433.         inc(FileName, (Length(PWideChar(FileName)) + 1) * 2);
  434.       end else
  435.       begin
  436.         Files.Add(Filename);
  437.         inc(FileName, Length(FileName) + 1);
  438.       end;
  439.     end;
  440.   finally
  441.     GlobalUnlock(Handle);
  442.   end;
  443.   Result := Files.count>0;
  444. end;
  445. {------------------------------------------------------------------------------}
  446. function TRVDropTarget.GetAsFiles(const DataObj: IDataObject): TStringList;
  447. var FmtEtc: TFormatEtc;
  448.   StgMedium: TStgMedium;
  449. begin
  450.   FillFormatEtc(FmtEtc, CF_HDROP);
  451.   Result := nil;
  452.   if DataObj.GetData(FmtEtc, StgMedium)<>S_OK then
  453.     exit;
  454.   if StgMedium.tymed=GetTymed(CF_HDROP) then begin
  455.     Result := TStringList.Create;
  456.     GetFiles(StgMedium.hGlobal, Result);
  457.   end;
  458.   ReleaseStgMedium(StgMedium);
  459. end;
  460. {------------------------------------------------------------------------------}
  461. { Allows owner to be a drop targer.                                            }
  462. function TRVDropTarget.RegisterDragDropForOwner: Boolean;
  463. begin
  464.   Result := FOwner.HandleAllocated and
  465.     (RegisterDragDrop(FOwner.Handle, Self as IDropTarget)=S_OK);
  466. end;
  467. {------------------------------------------------------------------------------}
  468. { Reverse to RegisterDragDropForOwner.                                         }
  469. procedure TRVDropTarget.UnRegisterDragDropForOwner;
  470. begin
  471.   if FOwner.HandleAllocated then
  472.     RevokeDragDrop(FOwner.Handle);
  473. end;
  474. {============================ TRVEnumFormatEtc ================================}
  475. function GetTymeds(Format: Word): LongInt;
  476. begin
  477.   case Format of
  478.     CF_BITMAP:
  479.       Result := TYMED_GDI;
  480.     CF_ENHMETAFILE:
  481.       Result := TYMED_ENHMF;
  482.     CF_METAFILEPICT:
  483.       Result := TYMED_MFPICT;
  484.     {$IFNDEF RVDONOTUSEUNICODE}
  485.     CF_UNICODETEXT:
  486.       Result := TYMED_HGLOBAL {or TYMED_ISTREAM};    
  487.     {$ENDIF}
  488.     CF_TEXT:
  489.       Result := TYMED_HGLOBAL {or TYMED_ISTREAM};
  490.     else
  491.       {$IFNDEF RVDONOTUSERVF}
  492.       if (Format=CFRV_RVF) then
  493.         Result := TYMED_HGLOBAL
  494.       else
  495.       {$ENDIF}
  496.       {$IFNDEF RVDONOTUSERTF}
  497.          if (Format=CFRV_RTF) then
  498.            Result := TYMED_HGLOBAL {or TYMED_ISTREAM}
  499.       else
  500.       {$ENDIF}      
  501.         Result := 0;
  502.   end;
  503. end;
  504. {------------------------------------------------------------------------------}
  505. constructor TRVEnumFormatEtc.Create(Graphic: TGraphic; Index: Integer);
  506. begin
  507.   inherited Create;
  508.   FGraphic := Graphic;
  509.   FIndex := Index;
  510. end;
  511. {------------------------------------------------------------------------------}
  512. function TRVEnumFormatEtc.GetCurFormat: Word;
  513. begin
  514.   case FIndex of
  515.     0:
  516.     {$IFNDEF RVDONOTUSERVF}
  517.       Result := CFRV_RVF;
  518.     {$ELSE}
  519.       Result := CF_TEXT;
  520.     {$ENDIF}
  521.     1:
  522.     {$IFNDEF RVDONOTUSERTF}
  523.       Result := CFRV_RTF;
  524.     {$ELSE}
  525.       Result := CF_TEXT;
  526.     {$ENDIF}
  527.     2:
  528.       Result := CF_TEXT;
  529.     3:
  530.    {$IFNDEF RVDONOTUSEUNICODE}
  531.       Result := CF_UNICODETEXT;
  532.     4:
  533.     {$ENDIF}
  534.       begin
  535.         if FGraphic=nil then
  536.           Result := 0
  537.         else if FGraphic is TBitmap then
  538.           Result := CF_BITMAP
  539.         else if FGraphic is TMetafile then
  540.           Result := CF_ENHMETAFILE
  541.         else
  542.           Result := 0;
  543.       end
  544.     else
  545.       Result := 0;
  546.   end;
  547. end;
  548. {------------------------------------------------------------------------------}
  549. type
  550.   TFormatList = array[0..255] of TFormatEtc;
  551.   PFormatList = ^TFormatList;
  552. { IEnumFormatEtc.Next                                                          }  
  553. function TRVEnumFormatEtc.Next(Celt: Integer; out Elt;
  554.   PCeltFetched: PLongInt): HResult;
  555. var
  556.   i: Integer;
  557.   Format: Word;
  558.   List: TFormatList absolute Elt;
  559. begin
  560.   i := 0;
  561.   while (i<Celt) do begin
  562.     Format := GetCurFormat;
  563.     if Format=0 then
  564.       break;
  565.     List[i].cfFormat := Format;
  566.     List[i].ptd := nil;
  567.     List[i].dwAspect := DVASPECT_CONTENT;
  568.     List[i].lindex := -1;
  569.     List[i].tymed := GetTymeds(Format);
  570.     Inc(FIndex);
  571.     Inc(i);
  572.   end;
  573.   if PCeltFetched<>nil then
  574.     PCeltFetched^ := i;
  575.   if i = Celt then
  576.     Result := S_OK
  577.   else
  578.     Result := S_FALSE;
  579. end;
  580. {------------------------------------------------------------------------------}
  581. { IEnumFormatEtc.Skip                                                          }
  582. function TRVEnumFormatEtc.Skip(Celt: Integer): HResult;
  583. var
  584.   i: Integer;
  585.   Format: Word;
  586. begin
  587.   i := 0;
  588.   while (i<Celt) do begin
  589.     Format := GetCurFormat;
  590.     if Format=0 then
  591.       break;
  592.     Inc(FIndex);
  593.     Inc(i);
  594.   end;
  595.   if i = Celt then
  596.     Result := S_OK
  597.   else
  598.     Result := S_FALSE;
  599. end;
  600. {------------------------------------------------------------------------------}
  601. { IEnumFormatEtc.Reset                                                         }
  602. function TRVEnumFormatEtc.Reset: HResult;
  603. begin
  604.   FIndex := 0;
  605.   Result := S_OK;
  606. end;
  607. {------------------------------------------------------------------------------}
  608. { IEnumFormatEtc.Clone                                                         }
  609. function TRVEnumFormatEtc.Clone(out Enum: IEnumFormatEtc): HResult;
  610. begin
  611.   Enum := TRVEnumFormatEtc.Create(FGraphic, FIndex);
  612.   Result := S_OK;
  613. end;
  614. {============================== TRVDropSource =================================}
  615. destructor TRVDropSource.Destroy;
  616. begin
  617.   TRichViewRVData(TCustomRichView(FOwner).RVData).FDropSource := nil;
  618.   if FUseMedium then
  619.     ReleaseStgMedium(FMedium);
  620.   inherited;
  621. end;
  622. {------------------------------------------------------------------------------}
  623. function TRVDropSource.IsAvailableFormat(Format: Word): Boolean;
  624. var Graphic: TGraphic;
  625. begin
  626.   Result :=
  627.     (Format=CF_TEXT)
  628.     {$IFNDEF RVDONOTUSEUNICODE}
  629.     or (Format=CF_UNICODETEXT)
  630.     {$ENDIF}
  631.     {$IFNDEF RVDONOTUSERVF}
  632.     or (Format=CFRV_RVF)
  633.     {$ENDIF}
  634.     {$IFNDEF RVDONOTUSERTF}
  635.     or (Format=CFRV_RTF)
  636.     {$ENDIF};
  637.   if not Result then begin
  638.     Graphic := TCustomRichView(FOwner).GetSelectedImage;
  639.     if Graphic is TBitmap then
  640.       Result := Format=CF_BITMAP
  641.     else if Graphic is TMetafile then
  642.       Result := Format=CF_ENHMETAFILE
  643.   end;
  644. end;
  645. {------------------------------------------------------------------------------}
  646. function TRVDropSource.GetAsStream(Format: Word): TMemoryStream;
  647. var Size: Integer;
  648. begin
  649.    Result := TMemoryStream.Create;
  650.    case Format of
  651.      CF_TEXT:
  652.        begin
  653.          TCustomRichView(FOwner).SaveTextToStream('', Result, 80, True, True);
  654.          Size := 0;
  655.          Result.WriteBuffer(Size, 1);
  656.        end;
  657.      {$IFNDEF RVDONOTUSEUNICODE}
  658.      CF_UNICODETEXT:
  659.        begin
  660.          TCustomRichView(FOwner).SaveTextToStreamW('', Result, 80, True, True);
  661.          Size := 0;
  662.          Result.WriteBuffer(Size, 2);
  663.        end;
  664.      {$ENDIF}
  665.      else
  666.        begin
  667.          {$IFNDEF RVDONOTUSERVF}
  668.          if Format=CFRV_RVF then begin
  669.            Size := 0;
  670.            Result.WriteBuffer(Size, sizeof(Size));
  671.            TCustomRichView(FOwner).SaveRVFToStream(Result, True);
  672.            Size := Result.Size-sizeof(Size);
  673.            Result.Position := 0;
  674.            Result.WriteBuffer(Size, sizeof(Size));
  675.            end
  676.          else
  677.          {$ENDIF}
  678.          {$IFNDEF RVDONOTUSERTF}
  679.          if Format=CFRV_RTF then
  680.            TCustomRichView(FOwner).SaveRTFToStream(Result, True)
  681.          else
  682.          {$ENDIF}
  683.          begin
  684.            Result.Free;
  685.            Result := nil;
  686.          end;
  687.        end;
  688.    end;
  689.    if Result<>nil then
  690.      Result.Position := 0;
  691. end;
  692. {------------------------------------------------------------------------------}
  693. function TRVDropSource.GetAsHandle(Format: Word; var Handle: HGlobal): HResult;
  694. var Stream: TMemoryStream;
  695.     ptr: Pointer;
  696. begin
  697.   Handle := 0;
  698.   Stream := GetAsStream(Format);
  699.   if Stream=nil then begin
  700.     Result := DV_E_FORMATETC;
  701.     exit;
  702.   end;
  703.   Handle := GlobalAlloc(GMEM_SHARE or GMEM_ZEROINIT, Stream.Size);
  704.   if Handle=0 then begin
  705.     Result := E_OUTOFMEMORY;
  706.     Stream.Free;
  707.     exit;
  708.   end;
  709.   ptr := GlobalLock(Handle);
  710.   Stream.ReadBuffer(ptr^, Stream.Size);
  711.   GlobalUnlock(Handle);
  712.   Stream.Free;
  713.   Result := S_OK;
  714. end;
  715. {------------------------------------------------------------------------------}
  716. function TRVDropSource.SaveToHandle(Format: Word; Handle: HGlobal): HResult;
  717. var Stream: TMemoryStream;
  718.     ptr: Pointer;
  719. begin
  720.   Stream := GetAsStream(Format);
  721.   if Stream=nil then begin
  722.     Result := DV_E_FORMATETC;
  723.     exit;
  724.   end;
  725.   if GlobalSize(Handle)<DWORD(Stream.Size) then begin
  726.     Result := STG_E_MEDIUMFULL;
  727.     Stream.Free;
  728.     exit;
  729.   end;
  730.   ptr := GlobalLock(Handle);
  731.   Stream.ReadBuffer(ptr^, Stream.Size);
  732.   GlobalUnlock(Handle);
  733.   Stream.Free;
  734.   Result := S_OK;
  735. end;
  736. {------------------------------------------------------------------------------}
  737. {
  738. function TRVDropSource.SaveToStream(Format: Word; const Stream: IStream): HResult;
  739. var LStream: TMemoryStream;
  740.     cb: LongInt;
  741. begin
  742.   LStream := GetAsStream(Format);
  743.   if LStream=nil then begin
  744.     Result := DV_E_FORMATETC;
  745.     exit;
  746.   end;
  747.   Result := Stream.Write(LStream.Memory, LStream.Size, @cb);
  748.   LStream.Free;
  749. end;
  750. }
  751. {------------------------------------------------------------------------------}
  752. { IDropSource.GiveFeedback                                                     }
  753. function TRVDropSource.GiveFeedback(Effect: Integer): HResult;
  754. begin
  755.   Result := DRAGDROP_S_USEDEFAULTCURSORS;
  756. end;
  757. {------------------------------------------------------------------------------}
  758. { IDropSource.QueryContinueDrag                                                }
  759. function TRVDropSource.QueryContinueDrag(FEscapePressed: Bool;
  760.   KeyState: Integer): HResult;
  761. begin
  762.   if (MK_LBUTTON and KeyState)<>0 then
  763.     TCustomRichView(FOwner).RVData.State :=
  764.       TCustomRichView(FOwner).RVData.State-[rvstDragDropCursorNotMoved];
  765.   if FEscapePressed then
  766.     Result := DRAGDROP_S_CANCEL
  767.   else if (MK_LBUTTON and KeyState)=0 then
  768.     Result := DRAGDROP_S_DROP
  769.   else
  770.     Result := S_OK;
  771. end;
  772. {------------------------------------------------------------------------------}
  773. { IDataObject.EnumFormatEtc                                                    }
  774. function TRVDropSource.EnumFormatEtc(Direction: Integer;
  775.   out EnumFormatEtc: IEnumFormatEtc): HResult;
  776. begin
  777.   case Direction of
  778.     DATADIR_GET:
  779.       begin
  780.         EnumFormatEtc := TRVEnumFormatEtc.Create(
  781.           TCustomRichView(FOwner).GetSelectedImage, 0) as IEnumFormatEtc;
  782.         Result := S_OK;
  783.       end;
  784.     DATADIR_SET:
  785.       Result := E_NOTIMPL;
  786.     else
  787.       Result := E_INVALIDARG;
  788.   end;
  789. end;
  790. {------------------------------------------------------------------------------}
  791. { Stores data as Format in FMedium. This medium will be used in the next call
  792.   of GetData. This method is used when dropping data to itself.                }
  793. function TRVDropSource.StoreData(Format: Word): Boolean;
  794. var FmtEtc: TFormatEtc;
  795. begin
  796.   FillChar(FmtEtc, sizeof(FmtEtc), 0);
  797.   FmtEtc.cfFormat := Format;
  798.   FmtEtc.dwAspect := DVASPECT_CONTENT;
  799.   FmtEtc.lindex := -1;
  800.   FmtEtc.tymed := GetTymed(Format);
  801.   FUseMedium := GetData(FmtEtc, FMedium)=S_OK;
  802.   Result := FUseMedium;
  803. end;
  804. {------------------------------------------------------------------------------}
  805. { IDataObject.GetData                                                          }
  806. function TRVDropSource.GetData(const FormatEtcIn: TFormatEtc;
  807.   out Medium: TStgMedium): HResult;
  808. var {StreamAdapter : TStreamAdapter;
  809.     Stream        : TStream;}
  810.     Format: Word;
  811.     Palette: HPalette;
  812.     Handle: THandle;
  813. begin
  814.   Medium.tymed := 0;
  815.   Medium.UnkForRelease := nil;
  816.   Medium.hGlobal := 0;
  817.   Medium.hBitmap := 0;
  818.   Medium.hMetaFilePict := 0;
  819.   Medium.hEnhMetaFile := 0;
  820.   Medium.stm := nil;
  821.   if FUseMedium then begin
  822.     Medium := FMedium;
  823.     FUseMedium := False;
  824.     Result := S_OK;
  825.     exit;
  826.   end;
  827.   if IsAvailableFormat(FormatEtcIn.cfFormat) then
  828.     if FormatEtcIn.dwAspect = DVASPECT_CONTENT then
  829.       if (FormatEtcIn.tymed and GetTymeds(FormatEtcIn.cfFormat))<>0 then begin
  830.         if (FormatEtcIn.cfFormat=CF_TEXT)
  831.            {$IFNDEF RVDONOTUSEUNICODE}
  832.            or (FormatEtcIn.cfFormat=CF_UNICODETEXT)
  833.            {$ENDIF}
  834.            {$IFNDEF RVDONOTUSERVF}
  835.            or (FormatEtcIn.cfFormat=CFRV_RVF)
  836.            {$ENDIF}
  837.            {$IFNDEF RVDONOTUSERTF}
  838.            or (FormatEtcIn.cfFormat=CFRV_RTF)
  839.            {$ENDIF} then begin
  840.           if ((FormatEtcIn.tymed and TYMED_HGLOBAL)=TYMED_HGLOBAL) then begin
  841.             Result := GetAsHandle(FormatEtcIn.cfFormat, Medium.HGlobal);
  842.             Medium.tymed := TYMED_HGLOBAL;
  843.             end
  844.           {else if (FormatEtcIn.tymed and TYMED_ISTREAM)=TYMED_ISTREAM then begin
  845.             Stream := GetAsStream(FormatEtcIn.cfFormat);
  846.             StreamAdapter := TStreamAdapter.Create(Stream, soOwned);
  847.             Medium.stm := Pointer(StreamAdapter as IStream);
  848.             Medium.tymed := TYMED_ISTREAM;
  849.             Medium.unkForRelease := Pointer(StreamAdapter as IUnknown);
  850.             Result := S_OK;
  851.             end}
  852.           else
  853.             Result := DV_E_TYMED;
  854.           end
  855.         else begin
  856.           case FormatEtcIn.cfFormat of
  857.             CF_BITMAP:
  858.               begin
  859.                 if TRichView(FOwner).GetSelectedImage is TBitmap then begin
  860.                   Format := 0;
  861.                   Handle := 0;
  862.                   TRichView(FOwner).GetSelectedImage.SaveToClipboardFormat(
  863.                     Format, Handle, Palette);
  864.                   if Format=CF_BITMAP then begin
  865.                     Medium.hBitmap := Handle;
  866.                     if (Palette <> 0) and (Palette <> SystemPalette16) then
  867.                       DeleteObject(Palette);
  868.                     Medium.tymed := TYMED_GDI;
  869.                     Result := S_OK;
  870.                     end
  871.                   else
  872.                     Result := DV_E_FORMATETC;
  873.                   end
  874.                 else
  875.                   Result := DV_E_FORMATETC;
  876.               end;
  877.             CF_ENHMETAFILE:
  878.               begin
  879.                 if TRichView(FOwner).GetSelectedImage is TMetafile then begin
  880.                   Format := 0;
  881.                   Handle := 0;
  882.                   TRichView(FOwner).GetSelectedImage.SaveToClipboardFormat(
  883.                     Format, Handle, Palette);
  884.                   if Format=CF_ENHMETAFILE then begin
  885.                     Medium.hEnhMetaFile := Handle;
  886.                     Medium.tymed := TYMED_ENHMF;
  887.                     Result := S_OK;
  888.                     end
  889.                   else
  890.                     Result := DV_E_FORMATETC;
  891.                   end
  892.                 else
  893.                   Result := DV_E_FORMATETC;
  894.               end;
  895.             else
  896.               Result := DV_E_FORMATETC;
  897.           end;
  898.         end
  899.         end
  900.       else
  901.         Result := DV_E_TYMED
  902.     else
  903.       Result := DV_E_DVASPECT
  904.   else
  905.     Result := DV_E_FORMATETC;
  906. end;
  907. {------------------------------------------------------------------------------}
  908. { IDataObject.GetDataHere                                                      }
  909. function TRVDropSource.GetDataHere(const FormatEtcIn: TFormatEtc;
  910.   out Medium: TStgMedium): HResult;
  911. begin
  912.   if IsAvailableFormat(FormatEtcIn.cfFormat) then
  913.     if FormatEtcIn.dwAspect = DVASPECT_CONTENT then
  914.       if (FormatEtcIn.tymed and GetTymeds(FormatEtcIn.cfFormat))<>0 then begin
  915.         if (FormatEtcIn.cfFormat=CF_TEXT)
  916.            {$IFNDEF RVDONOTUSERVF}
  917.            or (FormatEtcIn.cfFormat=CFRV_RVF)
  918.            {$ENDIF}
  919.            {$IFNDEF RVDONOTUSERTF}
  920.            or (FormatEtcIn.cfFormat=CFRV_RTF)
  921.            {$ENDIF} then begin
  922.           if (FormatEtcIn.tymed and TYMED_HGLOBAL)=TYMED_HGLOBAL then
  923.             Result := SaveToHandle(FormatEtcIn.cfFormat, Medium.HGlobal)
  924.           {else if (FormatEtcIn.tymed and TYMED_ISTREAM)=TYMED_ISTREAM then
  925.             Result := SaveToStream(FormatEtcIn.cfFormat, IStream(Medium.stm))}
  926.           else
  927.             Result := DV_E_TYMED;
  928.           end
  929.         else begin
  930.           Result := DV_E_FORMATETC;
  931.         end
  932.         end
  933.       else
  934.         Result := DV_E_TYMED
  935.     else
  936.       Result := DV_E_DVASPECT
  937.   else
  938.     Result := DV_E_FORMATETC;
  939. end;
  940. {------------------------------------------------------------------------------}
  941. { IDataObject.QueryGetData                                                     }
  942. function TRVDropSource.QueryGetData(const FormatEtc: TFormatEtc): HResult;
  943. begin
  944.   if FUseMedium then begin
  945.     Result := S_OK;
  946.     exit;
  947.   end;
  948.   if IsAvailableFormat(FormatEtc.cfFormat) then
  949.     if FormatEtc.dwAspect = DVASPECT_CONTENT then
  950.       if (FormatEtc.tymed and GetTymeds(FormatEtc.cfFormat))<>0 then
  951.         Result := S_OK
  952.       else
  953.         Result := DV_E_TYMED
  954.     else
  955.       Result := DV_E_DVASPECT
  956.   else
  957.     Result := DV_E_FORMATETC;
  958. end;
  959. {------------------------------------------------------------------------------}
  960. { IDataObject.GetCanonicalFormatEtc                                            }
  961. function TRVDropSource.GetCanonicalFormatEtc(const FormatEtc: TFormatEtc;
  962.   out FormatEtcOut: TFormatEtc): HResult;
  963. begin
  964.   FormatEtcOut.ptd := nil;
  965.   Result := E_NOTIMPL;
  966. end;
  967. {------------------------------------------------------------------------------}
  968. { IDataObject.SetData                                                          }
  969. function TRVDropSource.SetData(const FormatEtc: TFormatEtc;
  970.   var Medium: TStgMedium; FRelease: Bool): HResult;
  971. begin
  972.   Result := E_NOTIMPL;
  973. end;
  974. {------------------------------------------------------------------------------}
  975. { IDataObject.dAdvise                                                          }
  976. function TRVDropSource.DAdvise(const FormatEtc: TFormatEtc; advf: Integer;
  977.   const advsink: IAdviseSink; out Connection: Integer): HResult;
  978. begin
  979.   Result := OLE_E_ADVISENOTSUPPORTED;
  980. end;
  981. {------------------------------------------------------------------------------}
  982. { IDataObject.dUnadvise                                                        }
  983. function TRVDropSource.DUnadvise(Connection: Integer): HResult;
  984. begin
  985.   Result := OLE_E_ADVISENOTSUPPORTED;
  986. end;
  987. {------------------------------------------------------------------------------}
  988. { IDataObject.EnumdAdvise                                                      }
  989. function TRVDropSource.EnumDAdvise(out EnumAdvise: IEnumStatData): HResult;
  990. begin
  991.   Result := OLE_E_ADVISENOTSUPPORTED;
  992. end;
  993. {$ENDIF}
  994. end.