DragDrop.pas 74 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005
  1. unit DragDrop;
  2. {
  3. Description
  4. ===========
  5. TDragDrop is a component for OLE drag-and-drop operations. The component
  6. is able to make successor components of TWinControl to the source AND
  7. target of drag-and-drop operations.
  8. Disclaimer
  9. ==========
  10. The author disclaims all warranties, expressed or implied, including,
  11. without limitation, the warranties of merchantability and of fitness
  12. for any purpose. The author assumes no liability for damages, direct or
  13. consequential, which may result from the use of this component/unit.
  14. Restrictions on Using the Unit / Component
  15. ==========================================
  16. This unit/component is copyright 1998 by Dieter Steinwedel. ALL RIGHTS
  17. ARE RESERVED BY DIETER STEINWEDEL. You are allowed to use it freely
  18. subject to the following restrictions:
  19. • You are not allowed delete or alter the author's name and
  20. copyright in any manner
  21. • You are not allowed to publish a copy, modified version or
  22. compilation neither for payment in any kind nor freely
  23. • You are allowed to create a link to the download in the WWW
  24. • These restrictions and terms apply to you as long as until
  25. I alter them. Changes can found on my homepage
  26. }
  27. {$ALIGN ON}
  28. {$ASSERTIONS OFF}
  29. {$BOOLEVAL OFF}
  30. {$DENYPACKAGEUNIT OFF}
  31. {$EXTENDEDSYNTAX ON}
  32. {$HINTS ON}
  33. {$IMPORTEDDATA ON}
  34. {$LONGSTRINGS ON}
  35. {$OPTIMIZATION ON}
  36. {$TYPEDADDRESS OFF}
  37. {$TYPEINFO OFF}
  38. {$WARNINGS ON}
  39. {$WARN SYMBOL_DEPRECATED OFF}
  40. interface
  41. uses
  42. SysUtils, Windows, Classes, Controls, Forms, ShellApi,
  43. Menus, Messages, Graphics, ActiveX, ExtCtrls, Grids;
  44. {MP}(*$HPPEMIT '#include <oleidl.h>'*)
  45. // Available drop effects by the system:
  46. // (redefined, so need not to type "ActiveX" in the uses clause of your units )
  47. const
  48. DROPEFFECT_None = ActiveX.DROPEFFECT_None;
  49. DROPEFFECT_Copy = ActiveX.DROPEFFECT_Copy;
  50. DROPEFFECT_Move = ActiveX.DROPEFFECT_Move;
  51. DROPEFFECT_Link = ActiveX.DROPEFFECT_Link;
  52. DROPEFFECT_Scroll = ActiveX.DROPEFFECT_Scroll;
  53. TYMED_HGLOBAL = ActiveX.TYMED_HGLOBAL;
  54. TYMED_FILE = ActiveX.TYMED_FILE;
  55. TYMED_ISTREAM = ActiveX.TYMED_ISTREAM;
  56. TYMED_ISTORAGE = ActiveX.TYMED_ISTORAGE;
  57. TYMED_GDI = ActiveX.TYMED_GDI;
  58. TYMED_MFPICT = ActiveX.TYMED_MFPICT;
  59. TYMED_ENHMF = ActiveX.TYMED_ENHMF;
  60. TYMED_NULL = ActiveX.TYMED_NULL;
  61. DefaultCursor = 0;
  62. type
  63. IEnumFormatEtc = ActiveX.IEnumFormatEtc;
  64. IDataObject = ActiveX.IDataObject;
  65. TFormatEtc = ActiveX.TFormatEtc;
  66. TStgMedium = ActiveX.TStgMedium;
  67. TDropEffect = (deCopy, deMove, deLink);
  68. TDragResult = (drInvalid, drCancelled, drCopy, drMove, drLink);
  69. TDropEffectSet = set of TDropEffect;
  70. TDragDetectStatus = (ddsNone, ddsLeft, ddsRight, ddsCancelled, ddsDrag);
  71. TRenderDataOn = (rdoEnter, rdoEnterAndDropSync, rdoEnterAndDropAsync, rdoDropSync, rdoDropAsync, rdoNever);
  72. TSrcCompatibilityCheck = (CheckLindex, CheckdwAspect);
  73. TSrcCompatibilityCheckSet = set of TSrcCompatibilityCheck;
  74. TScrollInterval = 1..10000;
  75. TScrollDirection = (sdUp, sdDown, sdLeft, sdRight);
  76. // event handlers ...
  77. TOnDragEnter = procedure(DataObj: IDataObject; grfKeyState: LongInt; pt: TPoint;
  78. var dwEffect: LongInt; var Accept: Boolean) of object;
  79. TOnDragLeave = procedure of object;
  80. TOnDragOver = procedure(grfKeyState: LongInt; pt: TPoint; var dwEffect: LongInt) of object;
  81. TOnDrop = procedure(DataObj: IDataObject; grfKeyState: LongInt; pt: TPoint; var dwEffect: LongInt) of object;
  82. TOnQueryContinueDrag = procedure(fEscapePressed: BOOL; grfKeyState: LongInt; var Result: HResult) of object;
  83. TOnGiveFeedback = procedure(dwEffect: LongInt; var Result: HResult) of object;
  84. TOnDragDetect = procedure(grfKeyState: LongInt; DetectStart, pt: TPoint; DragDetectStatus: TDragDetectStatus) of object;
  85. TOnProcessDropped = procedure(Sender: TObject; grfKeyState: LongInt; pt: TPoint; dwEffect: LongInt) of object;
  86. TOnBeforeScrolling = procedure(Sender: TObject; pt: TPoint; var Interval: TScrollInterval;
  87. ScrollDirection: TScrollDirection; var ScrollPage: Boolean) of object;
  88. TOnMenuPopup = procedure(Sender: TObject; AMenu: HMenu; DataObj: IDataObject;
  89. AMinCustCmd: Integer; grfKeyState: LongInt; pt: TPoint) of object;
  90. TOnMenuExecCmd = procedure(Sender: TObject; AMenu: HMenu; DataObj: IDataObject;
  91. Command: Integer; var dwEffect: LongInt; var Succeeded: Boolean) of object;
  92. TOnMenuDestroy = procedure(Sender: TObject; AMenu: HMenu) of object;
  93. TFormatEtcArray = array of TFormatEtc;
  94. // list classes ...
  95. TFormatEtcList = class
  96. private
  97. FCount: Integer;
  98. FList: TFormatEtcArray;
  99. function Get(Index: Integer): TFormatEtc;
  100. procedure Put(Index: Integer; Item: TFormatEtc);
  101. public
  102. constructor Create;
  103. destructor Destroy; override;
  104. function Add(Item: TFormatEtc): Integer;
  105. procedure Clear;
  106. procedure Delete(Index: Integer);
  107. function Clone: TFormatEtcList;
  108. property Count: Integer read FCount;
  109. property Items[Index: Integer]: TFormatEtc read Get write Put;
  110. end;
  111. // inherited classes ...
  112. TDDInterfacedObject = class(TInterfacedObject)
  113. public
  114. function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  115. function _AddRef: Integer; stdcall;
  116. function _Release: Integer; stdcall;
  117. end;
  118. TEnumFormatEtc = class(TDDInterfacedObject, IEnumFormatEtc)
  119. protected
  120. FFormatEtcList: TFormatEtcList;
  121. FIndex: Integer;
  122. public
  123. constructor Create(FormatEtcList: TFormatEtcList);
  124. destructor Destroy; override;
  125. function Next(celt: LongInt; out elt; pceltFetched: PLongInt): HResult; stdcall;
  126. function Skip(celt: LongInt): HResult; stdcall;
  127. function Reset: HResult; stdcall;
  128. function Clone(out Enum: IEnumFormatEtc): HResult; stdcall;
  129. end;
  130. TDataObject = class(TDDInterfacedObject, IDataObject)
  131. protected
  132. FFormatEtcList: TFormatEtcList;
  133. FCheckLindex: Boolean;
  134. FCheckdwAspect: Boolean;
  135. public
  136. constructor Create;
  137. destructor Destroy; override;
  138. function GetData(const formatetcIn: TFormatEtc; out medium: TStgMedium): HResult; stdcall;
  139. function GetDataHere(const formatetc: TFormatEtc; out medium: TStgMedium): HResult; stdcall;
  140. function QueryGetData(const formatetc: TFormatEtc): HResult; stdcall;
  141. function GetCanonicalFormatEtc(const formatetc: TFormatEtc; out formatetcOut: TFormatEtc): HResult; stdcall;
  142. function SetData(const formatetc: TFormatEtc; var medium: TStgMedium; fRelease: BOOL): HResult; stdcall;
  143. function EnumFormatEtc(dwDirection: LongInt; out enumFormatEtc: IEnumFormatEtc): HResult; stdcall;
  144. function DAdvise(const formatetc: TFormatEtc; advf: LongInt;
  145. const advSink: IAdviseSink; out dwConnection: LongInt): HResult; stdcall;
  146. function DUnadvise(dwConnection: LongInt): HResult; stdcall;
  147. function EnumDAdvise(out enumAdvise: IEnumStatData): HResult; stdcall;
  148. function RenderData(FormatEtc:TFormatEtc; var StgMedium: TStgMedium): HResult; virtual; abstract;
  149. protected
  150. function AllowData(FormatEtc: TFormatEtc): Boolean; virtual;
  151. end;
  152. // forward declaration, because TDropSource and TDropTarget uses this class ...
  153. TDragDrop = class;
  154. TDropSource = class(TDDInterfacedObject, IDropSource)
  155. private
  156. FOwner: TDragDrop;
  157. public
  158. constructor Create(AOwner: TDragDrop);
  159. destructor Destroy; override;
  160. function QueryContinueDrag(fEscapePressed: BOOL; grfKeyState: LongInt): HResult; stdcall;
  161. function GiveFeedback(dwEffect: LongInt): HResult; stdcall;
  162. end;
  163. TDropTarget = class(TDDInterfacedObject, IDropTarget)
  164. private
  165. FAccept: Boolean;
  166. HorzStartTimer: TTimer;
  167. HorzScrollTimer: TTimer;
  168. VertStartTimer: TTimer;
  169. VertScrollTimer: TTimer;
  170. FVScrollCode: Integer;
  171. FHScrollCode: Integer;
  172. procedure InitScroll(VerticalScroll: Boolean; ScrollCode: Integer);
  173. procedure TermScroll(VerticalScroll: Boolean);
  174. procedure DetermineScrollDir(VertScrolling: Boolean; var ScrollCode: Integer);
  175. procedure OnStartTimer(Sender: TObject);
  176. procedure OnScrollTimer(Sender: TObject);
  177. protected
  178. FOwner: TDragDrop;
  179. procedure SuggestDropEffect(grfKeyState: LongInt; var dwEffect: LongInt); virtual;
  180. procedure AcceptDataObject(DataObj: IDataObject; var Accept:Boolean); virtual;
  181. procedure RenderDropped(DataObj: IDataObject; grfKeyState: LongInt; pt: TPoint; var dwEffect: LongInt); virtual;
  182. public
  183. constructor Create(AOwner: TDragDrop);
  184. destructor Destroy; override;
  185. function DragEnter(const dataObj: IDataObject; grfKeyState: LongInt; pt: TPoint; var dwEffect: LongInt): HResult; stdcall;
  186. function DragOver(grfKeyState: LongInt; pt: TPoint; var dwEffect: LongInt): HResult; stdcall;
  187. function DragLeave: HResult; stdcall;
  188. function Drop(const dataObj: IDataObject; grfKeyState: LongInt; pt: TPoint; var dwEffect: LongInt): HResult; stdcall;
  189. end;
  190. // custom properties
  191. TScrollDetectArea = class(TPersistent)
  192. private
  193. FControl: TPersistent;
  194. FMargin: Word;
  195. FRange: Word;
  196. FOnChange: TNotifyEvent;
  197. procedure SetValue(Index: Integer; Value: Word);
  198. protected
  199. procedure Change; dynamic;
  200. procedure AssignTo(Dest: TPersistent); override;
  201. property Control: TPersistent read FControl;
  202. public
  203. constructor Create(Control: TPersistent);
  204. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  205. published
  206. property Margin: Word index 0 read FMargin write SetValue default 0;
  207. property Range: Word index 1 read FRange write SetValue default 10;
  208. end;
  209. TScrollDetectOptions = class(TPersistent)
  210. private
  211. FControl: TDragDrop;
  212. FScrollDelay: TScrollInterval;
  213. FStartDelay: TScrollInterval;
  214. FLeft: TScrollDetectArea;
  215. FTop: TScrollDetectArea;
  216. FRight: TScrollDetectArea;
  217. FBottom: TScrollDetectArea;
  218. FOnChange: TNotifyEvent;
  219. FHorzScrolling: Boolean;
  220. FVertScrolling: Boolean;
  221. FHorzPageScroll: Boolean;
  222. FVertPageScroll: Boolean;
  223. procedure SetValue(Index: Integer; Value: TScrollInterval);
  224. protected
  225. procedure Change; dynamic;
  226. procedure AssignTo(Dest: TPersistent); override;
  227. property Control: TDragDrop read FControl;
  228. public
  229. constructor Create(Control: TDragDrop);
  230. destructor Destroy; override;
  231. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  232. published
  233. property ScrollDelay: TScrollInterval index 0 read FScrollDelay write SetValue default 100;
  234. property StartDelay: TScrollInterval index 1 read FStartDelay write SetValue default 750;
  235. property AreaLeft: TScrollDetectArea read FLeft write FLeft;
  236. property AreaTop: TScrollDetectArea read FTop write FTop;
  237. property AreaRight: TScrollDetectArea read FRight write FRight;
  238. property AreaBottom: TScrollDetectArea read FBottom write FBottom;
  239. property HorzScrolling: Boolean read FHorzScrolling write FHorzScrolling default False;
  240. property VertScrolling: Boolean read FVertScrolling write FVertScrolling default False;
  241. property HorzPageScroll: Boolean read FHorzPageScroll write FHorzPageScroll default False;
  242. property VertPageScroll: Boolean read FVertPageScroll write FVertPageScroll default False;
  243. end;
  244. // *THE* pseudo-visual Component
  245. TDragDrop = class(TComponent)
  246. private
  247. FAutoDetectDnD: Boolean;
  248. FDragDetectDelta: Byte;
  249. FAcceptOwnDnD: Boolean;
  250. FBTF: Boolean;
  251. FContextMenu: Boolean;
  252. FDragDropControl: TWinControl;
  253. FRegistered: Boolean;
  254. FOwnerIsSource: Boolean;
  255. FShowPopUpMenu: Boolean;
  256. FTargetEffectsSet: TDropEffectSet;
  257. FTargetEffects: LongInt;
  258. FOnQueryContinueDrag: TOnQueryContinueDrag;
  259. FOnGiveFeedback: TOnGiveFeedback;
  260. FOnDragEnter: TOnDragEnter;
  261. FOnDragLeave: TOnDragLeave;
  262. FOnDragOver: TOnDragOver;
  263. FOnDrop: TOnDrop;
  264. FSourceEffectsSet: TDropEffectSet;
  265. FSourceEffects: LongInt;
  266. FOnProcessDropped: TOnProcessDropped;
  267. OldWndProc: Pointer;
  268. WndProcPtr: Pointer;
  269. FOnDragDetect: TOnDragDetect;
  270. FDragDetectStatus: TDragDetectStatus;
  271. FDragDetectStart: TPoint;
  272. FRenderDataOn: TRenderDataOn;
  273. FDataObj: IDataObject;
  274. FgrfKeyState: LongInt;
  275. Fpt: TPoint;
  276. FdwEffect: LongInt;
  277. FCHCopy: HCursor;
  278. FCHMove: HCursor;
  279. FCHLink: HCursor;
  280. FCHScrollCopy: HCursor;
  281. FCHScrollMove: HCursor;
  282. FCHScrollLink: HCursor;
  283. FMessageHooked: Boolean;
  284. FAvailableDropEffects: LongInt;
  285. FTargetScrolling: Integer;
  286. FSrcCompatibilityCheck: TSrcCompatibilityCheckSet;
  287. FScrollDetectOptions: TScrollDetectOptions;
  288. FOnBeforeScrolling: TOnBeforeScrolling;
  289. FOnAfterScrolling: TNotifyEvent;
  290. FPressedButton: Integer;
  291. FInternalSource: TDragDrop;
  292. FOnMenuPopup: TOnMenuPopup;
  293. FOnMenuExecCmd: TOnMenuExecCmd;
  294. FOnMenuDestroy: TOnMenuDestroy;
  295. FOnMenuSucceeded: TOnProcessDropped;
  296. FOnDropHandlerSucceeded: TOnProcessDropped;
  297. procedure WndMethod(var Msg: TMessage);
  298. procedure SetDragDropControl(WinControl: TWinControl);
  299. procedure SetSourceEffects(Values: TDropEffectSet);
  300. procedure SetTargetEffects(Values: TDropEffectSet);
  301. protected
  302. FDropTarget: TDropTarget;
  303. procedure Loaded; override;
  304. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  305. function CreateDataObject: TDataObject; virtual; abstract;
  306. procedure DoMenuPopup(Sender: TObject; AMenu: HMenu; DataObj: IDataObject;
  307. AMinCustCmd: Integer; grfKeyState: LongInt; pt: TPoint); virtual;
  308. function DoMenuExecCmd(Sender: TObject; AMenu: HMenu; DataObj: IDataObject;
  309. Command: Integer; var dwEffect: LongInt): Boolean; virtual;
  310. procedure DoMenuDestroy(Sender: TObject; AMenu: HMenu); virtual;
  311. function DropHandler(const dataObj: IDataObject; grfKeyState: LongInt;
  312. pt: TPoint; var dwEffect: LongInt): Boolean; virtual;
  313. property OnDropHandlerSucceeded: TOnProcessDropped read FOnDropHandlerSucceeded write FOnDropHandlerSucceeded;
  314. public
  315. constructor Create(AOwner: TComponent); override;
  316. destructor Destroy; override;
  317. function RegisterTarget: Boolean;
  318. function UnRegisterTarget: Boolean;
  319. procedure HookMessageHandler;
  320. procedure UnhookMessageHandler(ForceUnhook: Boolean);
  321. function ExecuteOperation(DataObject: TDataObject): TDragResult;
  322. function Execute: TDragResult;
  323. function CopyToClipboard: Boolean; virtual;
  324. function GetFromClipboard: Boolean; virtual;
  325. procedure StartDnDDetection(Button: TMouseButton); virtual;
  326. property OwnerIsSource:Boolean read FOwnerIsSource;
  327. property Registered: Boolean read FRegistered default False;
  328. property CHCopy: HCursor read FCHCopy write FCHCopy default DefaultCursor;
  329. property CHMove: HCursor read FCHMove write FCHMove default DefaultCursor;
  330. property CHLink: HCursor read FCHLink write FCHLink default DefaultCursor;
  331. property CHScrollCopy: HCursor read FCHScrollCopy write FCHScrollCopy default DefaultCursor;
  332. property CHScrollMove: HCursor read FCHScrollMove write FCHScrollMove default DefaultCursor;
  333. property CHScrollLink: HCursor read FCHScrollLink write FCHScrollLink default DefaultCursor;
  334. property DragDetectStatus: TDragDetectStatus read FDragDetectStatus;
  335. property AvailableDropEffects: LongInt read FAvailableDropEffects;
  336. property InternalSource: TDragDrop read FInternalSource;
  337. published
  338. property AcceptOwnDnD: Boolean read FAcceptOwnDnD write FAcceptOwnDnD;
  339. property AutoDetectDnD: Boolean read FAutoDetectDnD write FAutoDetectDnD;
  340. property BringToFront: Boolean read FBTF write FBTF;
  341. property DragDetectDelta: Byte read FDragDetectDelta write FDragDetectDelta default 10;
  342. property DragDropControl: TWinControl read FDragDropControl write SetDragDropControl;
  343. property RenderDataOn: TRenderDataOn read FRenderDataOn write FRenderDataOn default rdoDropSync;
  344. property ScrollDetectOptions: TScrollDetectOptions read FScrollDetectOptions write FScrollDetectOptions;
  345. property SourceCompatibility: TSrcCompatibilityCheckSet read FSrcCompatibilityCheck write FSrcCompatibilityCheck;
  346. property SourceEffects: TDropEffectSet read FSourceEffectsSet write SetSourceEffects;
  347. property TargetPopupMenu: Boolean read FShowPopUpMenu write FShowPopUpMenu;
  348. property TargetEffects: TDropEffectSet read FTargetEffectsSet write SetTargetEffects;
  349. property OnAfterScrolling: TNotifyEvent read FOnAfterScrolling write FOnAfterScrolling;
  350. property OnBeforeScrolling: TOnBeforeScrolling read FOnBeforeScrolling write FOnBeforeScrolling;
  351. property OnDragDetect: TOnDragDetect read FOnDragDetect write FOnDragDetect;
  352. property OnDragEnter: TOnDragEnter read FOnDragEnter write FOnDragEnter;
  353. property OnDragLeave: TOnDragLeave read FOnDragLeave write FOnDragLeave;
  354. property OnDragOver: TOnDragOver read FOnDragOver write FOnDragOver;
  355. property OnDrop: TOnDrop read FOnDrop write FOnDrop;
  356. property OnQueryContinueDrag: TOnQueryContinueDrag read FOnQueryContinueDrag write FOnQueryContinueDrag;
  357. property OnGiveFeedback: TOnGiveFeedback read FOnGiveFeedback write FOnGiveFeedback;
  358. property OnProcessDropped: TOnProcessDropped read FOnProcessDropped write FOnProcessDropped;
  359. property OnMenuPopup: TOnMenuPopup read FOnMenuPopup write FOnMenuPopup;
  360. property OnMenuExecCmd: TOnMenuExecCmd read FOnMenuExecCmd write FOnMenuExecCmd;
  361. property OnMenuDestroy: TOnMenuDestroy read FOnMenuDestroy write FOnMenuDestroy;
  362. property OnMenuSucceeded: TOnProcessDropped read FOnMenuSucceeded write FOnMenuSucceeded;
  363. end;
  364. procedure Register;
  365. resourcestring
  366. MICopyStr = '&Copy Here';
  367. MIMoveStr = '&Move Here';
  368. MILinkStr = '&Shortcut(s) Create Here';
  369. MIAbortStr = '&Abort';
  370. implementation
  371. const
  372. CmdAbort = 0;
  373. CmdMove = 1;
  374. CmdCopy = 2;
  375. CmdLink = 3;
  376. CmdSeparator = 4;
  377. MinCustCmd = 10;
  378. var
  379. DDM_ProcessDropped: DWord; // Never change its value
  380. MouseHookHandle: HHook;
  381. MouseHookDragDrop: TDragDrop;
  382. GInternalSource: TDragDrop;
  383. function MouseHookProc(Code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT; stdcall;
  384. var
  385. MouseHookStruct: TMouseHookStruct;
  386. grfKeyState: LongInt;
  387. begin
  388. Result := CallNextHookEx(MouseHookHandle, Code, wParam, lParam);
  389. if not Assigned(MouseHookDragDrop) then
  390. begin
  391. UnHookWindowsHookEx(MouseHookHandle);
  392. MouseHookHandle := 0;
  393. end
  394. else
  395. with MouseHookDragDrop do
  396. begin
  397. MouseHookStruct := TMouseHookStruct(Pointer(lparam)^);
  398. if ((FDragDetectStatus = ddsRight) and (wParam = WM_LBUTTONDOWN)) or
  399. ((FDragDetectStatus = ddsLeft) and (wParam = WM_RBUTTONDOWN)) then
  400. begin
  401. FPressedButton := 2;
  402. FDragDetectStatus := ddsCancelled;
  403. if Assigned(FOnDragDetect) then
  404. begin
  405. if HiWord(DWord(GetKeyState(VK_SHIFT))) <> 0 then grfKeyState:=MK_SHIFT
  406. else grfKeyState := 0;
  407. if HiWord(DWord(GetKeyState(VK_CONTROL))) <> 0 then
  408. grfKeyState := grfKeyState or MK_CONTROL;
  409. FOnDragDetect(grfKeyState,
  410. FDragDropControl.ScreenToClient(FDragDetectStart),
  411. FDragDropControl.ScreenToClient(MouseHookStruct.pt),
  412. FDragDetectStatus);
  413. end;
  414. exit;
  415. end;
  416. if ((wParam = WM_LBUTTONDOWN) or (wParam = WM_RBUTTONDOWN)) and
  417. (FDragDetectStatus = ddsCancelled) then
  418. begin
  419. FPressedButton:=2;
  420. exit;
  421. end;
  422. if (FDragDetectStatus = ddsCancelled) and
  423. ((wParam = WM_LBUTTONUP) or (wParam = WM_RBUTTONUP)) then
  424. begin
  425. Dec(FPressedButton);
  426. if FPressedButton <= 0 then
  427. begin
  428. UnHookWindowsHookEx(MouseHookHandle);
  429. MouseHookHandle := 0;
  430. FDragDetectStatus := ddsNone;
  431. if Assigned(FOnDragDetect) then
  432. begin
  433. if HiWord(DWord(GetKeyState(VK_SHIFT))) <> 0 then grfKeyState := MK_SHIFT
  434. else grfKeyState := 0;
  435. if HiWord(DWord(GetKeyState(VK_CONTROL))) <> 0 then
  436. grfKeyState := grfKeyState or MK_CONTROL;
  437. FOnDragDetect(grfKeyState,
  438. FDragDropControl.ScreenToClient(FDragDetectStart),
  439. FDragDropControl.ScreenToClient(MouseHookStruct.pt),
  440. FDragDetectStatus);
  441. end;
  442. end;
  443. exit;
  444. end;
  445. if ((FDragDetectStatus = ddsRight) and (wParam = WM_RBUTTONUP)) or
  446. ((FDragDetectStatus = ddsLeft) and (wParam = WM_LBUTTONUP)) then
  447. begin
  448. UnHookWindowsHookEx(MouseHookHandle);
  449. MouseHookHandle := 0;
  450. FDragDetectStatus := ddsNone;
  451. if Assigned(FOnDragDetect) then
  452. begin
  453. if HiWord(DWord(GetKeyState(VK_SHIFT))) <> 0 then grfKeyState := MK_SHIFT
  454. else grfKeyState := 0;
  455. if HiWord(DWord(GetKeyState(VK_CONTROL))) <> 0 then
  456. grfKeyState := grfKeyState or MK_CONTROL;
  457. FOnDragDetect(grfKeyState,
  458. FDragDropControl.ScreenToClient(FDragDetectStart),
  459. FDragDropControl.ScreenToClient(MouseHookStruct.pt),
  460. FDragDetectStatus);
  461. end;
  462. exit;
  463. end;
  464. if ((Abs(FDragDetectStart.X - MouseHookStruct.pt.x) > DragDetectDelta) or
  465. (Abs(FDragDetectStart.Y - MouseHookStruct.pt.y) > DragDetectDelta)) and
  466. ((FDragDetectStatus = ddsRight) or (FDragDetectStatus = ddsLeft)) then
  467. begin
  468. FDragDetectStatus := ddsDrag;
  469. UnHookWindowsHookEx(MouseHookHandle);
  470. MouseHookHandle := 0;
  471. if Assigned(FOnDragDetect) then
  472. begin
  473. if HiWord(DWord(GetKeyState(VK_SHIFT))) <> 0 then grfKeyState := MK_SHIFT
  474. else grfKeyState := 0;
  475. if HiWord(DWord(GetKeyState(VK_CONTROL))) <> 0 then
  476. grfKeyState := grfKeyState or MK_CONTROL;
  477. FOnDragDetect(grfKeyState,
  478. FDragDropControl.ScreenToClient(FDragDetectStart),
  479. FDragDropControl.ScreenToClient(MouseHookStruct.pt),
  480. FDragDetectStatus);
  481. end;
  482. if FDragDetectStatus<>ddsNone then
  483. begin
  484. FDragDetectStatus := ddsNone;
  485. if Assigned(FOnDragDetect) then
  486. begin
  487. if HiWord(DWord(GetKeyState(VK_SHIFT))) <> 0 then grfKeyState:=MK_SHIFT
  488. else grfKeyState := 0;
  489. if HiWord(DWord(GetKeyState(VK_CONTROL))) <> 0 then
  490. grfKeyState := grfKeyState or MK_CONTROL;
  491. FOnDragDetect(grfKeyState,
  492. FDragDropControl.ScreenToClient(FDragDetectStart),
  493. FDragDropControl.ScreenToClient(MouseHookStruct.pt),
  494. FDragDetectStatus);
  495. end;
  496. end;
  497. end;
  498. end;
  499. end;
  500. // TFormatEtcList --------------------------------------------------------------
  501. constructor TFormatEtcList.Create;
  502. begin
  503. inherited;
  504. FCount := 0;
  505. SetLength(FList, 0);
  506. end;
  507. destructor TFormatEtcList.Destroy;
  508. begin
  509. if (FCount > 0) and (FList <> nil) then SetLength(FList, 0);
  510. inherited;
  511. end;
  512. function TFormatEtcList.Get(Index: Integer): TFormatEtc;
  513. begin
  514. if (Index >= FCount) or (FList = nil) then raise EListError.Create('Invalid item index')
  515. else Result := FList[Index];
  516. end;
  517. procedure TFormatEtcList.Put(Index: Integer; Item: TFormatEtc);
  518. begin
  519. if (Index >= FCount) or (FList = nil) then raise EListError.Create('Invalid item index')
  520. else FList[Index] := Item;
  521. end;
  522. function TFormatEtcList.Add(Item: TFormatEtc): Integer;
  523. begin
  524. SetLength(FList, Succ(FCount));
  525. FList[FCount] := Item;
  526. Result := FCount;
  527. Inc(FCount);
  528. end;
  529. procedure TFormatEtcList.Clear;
  530. begin
  531. SetLength(Flist, 0);
  532. FCount := 0;
  533. end;
  534. function TFormatEtcList.Clone: TFormatEtcList;
  535. var
  536. FEL: TFormatEtcList;
  537. begin
  538. FEL := TFormatEtcList.Create;
  539. if FList <> nil then
  540. begin
  541. SetLength(FEL.FList, FCount);
  542. CopyMemory(FEL.FList, FList, FCount * SizeOf(TFormatEtc));
  543. FEL.FCount:=FCount;
  544. end;
  545. Result := FEL;
  546. end;
  547. procedure TFormatEtcList.Delete(Index: Integer);
  548. var
  549. MoveCount: Integer;
  550. begin
  551. if (Index >= FCount) or (FList = nil) then raise EListError.Create('Invalid item index')
  552. else
  553. begin
  554. MoveCount := FCount-Index-1;
  555. System.Move(FList[Index+1], FList[Index], MoveCount * SizeOf(TFormatEtc));
  556. Dec(FCount);
  557. SetLength(FList, FCount);
  558. end;
  559. end;
  560. // TDDInterfacedObject ---------------------------------------------------------
  561. function TDDInterfacedObject.QueryInterface(const IID: TGUID; out Obj): HResult;
  562. begin
  563. Result := inherited QueryInterface(IID, Obj);
  564. end;
  565. function TDDInterfacedObject._AddRef: Integer;
  566. begin
  567. Result := inherited _AddRef;
  568. end;
  569. function TDDInterfacedObject._Release: Integer;
  570. begin
  571. Result := inherited _Release;
  572. end;
  573. // TEnumFormatEtc --------------------------------------------------------------
  574. constructor TEnumFormatEtc.Create(FormatEtcList: TFormatEtcList);
  575. begin
  576. inherited Create;
  577. _AddRef;
  578. FFormatEtcList := FormatEtcList;
  579. end;
  580. destructor TEnumFormatEtc.Destroy;
  581. begin
  582. if Assigned(FFormatEtcList) then FFormatEtcList.Free;
  583. inherited;
  584. end;
  585. function TEnumFormatEtc.Next(celt: LongInt; out elt; pceltFetched: PLongint): HResult;
  586. var
  587. CopyCount: Integer;
  588. begin
  589. Result := S_False;
  590. if pceltFetched <> nil then pceltFetched^ := 0;
  591. if (celt <= 0) or (FFormatEtcList.Count = 0) or (FIndex >= FFormatEtcList.Count) or
  592. ((pceltFetched = nil) and (celt <> 1)) then
  593. begin
  594. // noop
  595. end
  596. else
  597. begin
  598. CopyCount := FFormatEtcList.Count - FIndex;
  599. if celt < CopyCount then CopyCount := celt;
  600. if pceltFetched <> nil then pceltFetched^ := CopyCount;
  601. CopyMemory(@TFormatEtc(elt), @TFormatEtc(FFormatEtcList.FList[FIndex]), CopyCount * SizeOf(TFormatEtc));
  602. Inc(FIndex, CopyCount);
  603. Result := S_OK;
  604. end;
  605. end;
  606. function TEnumFormatEtc.Skip(celt: LongInt): HResult;
  607. begin
  608. if FIndex + celt <= FFormatEtcList.Count then
  609. begin
  610. Inc(FIndex, celt);
  611. Result := S_Ok;
  612. end
  613. else Result := S_False;
  614. end;
  615. function TEnumFormatEtc.Reset: HResult;
  616. begin
  617. FIndex := 0;
  618. Result := S_OK;
  619. end;
  620. function TEnumFormatEtc.Clone(out Enum: IEnumFormatEtc): HResult;
  621. begin
  622. Result := S_OK;
  623. try
  624. Enum := TEnumFormatEtc.Create(FFormatEtcList);
  625. TEnumFormatEtc(Enum).FIndex := FIndex;
  626. except
  627. Result := E_Fail;
  628. end;
  629. end;
  630. // TDataObject -----------------------------------------------------------------
  631. constructor TDataObject.Create;
  632. begin
  633. inherited;
  634. _AddRef;
  635. FFormatEtcList := TFormatEtcList.Create;
  636. end;
  637. destructor TDataObject.Destroy;
  638. begin
  639. FFormatEtcList.Free;
  640. inherited;
  641. end;
  642. function TDataObject.GetData(const formatetcIn: TFormatEtc; out medium: TStgMedium): HResult;
  643. var
  644. i: Integer;
  645. Cursor: TCursor;
  646. begin
  647. try
  648. if FFormatEtcList.Count>0 then
  649. begin
  650. for i := 0 to FFormatEtcList.Count - 1 do
  651. begin
  652. if ((formatetcIn.tymed and FFormatEtcList.Items[i].tymed) <> 0) and
  653. ((not FCheckLindex) or (FCheckLindex and (formatetcIn.lindex = FFormatEtcList.Items[i].lindex))) and
  654. ((not FCheckdwAspect) or (FCheckdwAspect and (formatetcIn.dwAspect = FFormatEtcList.Items[i].dwAspect))) and
  655. (formatetcIn.cfFormat = FFormatEtcList.Items[i].cfFormat) then
  656. begin
  657. Cursor := Screen.Cursor;
  658. try
  659. Screen.Cursor := crHourglass;
  660. Result := RenderData(formatetcIn, medium);
  661. finally
  662. Screen.Cursor := Cursor;
  663. end;
  664. exit;
  665. end;
  666. end;
  667. end;
  668. Result := DV_E_FormatEtc;
  669. except
  670. medium.HGlobal := 0;
  671. Result := E_Fail;
  672. end;
  673. end;
  674. function TDataObject.GetDataHere(const formatetc: TFormatEtc; out medium: TStgMedium): HResult;
  675. begin
  676. Result := E_NOTIMPL;
  677. end;
  678. function TDataObject.GetCanonicalFormatEtc(const formatetc: TFormatEtc; out formatetcOut: TFormatEtc): HResult;
  679. begin
  680. Result := E_NOTIMPL;
  681. end;
  682. function TDataObject.QueryGetData(const formatetc: TFormatEtc): HResult;
  683. const
  684. DVError: array[0..3] of HResult = (DV_E_FORMATETC, DV_E_TYMED, DV_E_DVASPECT, DV_E_LINDEX);
  685. var
  686. i, j: Integer;
  687. begin
  688. j := 0;
  689. if (FFormatEtcList.Count>0) and AllowData(FormatEtc) then
  690. begin
  691. for i := 0 to FFormatEtcList.Count - 1 do
  692. begin
  693. if FormatEtc.cfFormat = FFormatEtcList.Items[i].cfFormat then
  694. begin
  695. if (FormatEtc.tymed and FFormatEtcList.Items[i].tymed) <> 0 then
  696. begin
  697. if FormatEtc.dwAspect = FFormatEtcList.Items[i].dwAspect then
  698. begin
  699. if FormatEtc.lindex = FFormatEtcList.Items[i].lindex then
  700. begin
  701. Result := S_OK;
  702. exit;
  703. end
  704. else
  705. if j < 3 then j := 3;
  706. end
  707. else
  708. if j < 2 then j := 2;
  709. end
  710. else
  711. if j < 1 then j := 1;
  712. end;
  713. end;
  714. end;
  715. Result := DVError[j];
  716. end;
  717. function TDataObject.AllowData(FormatEtc: TFormatEtc): Boolean;
  718. begin
  719. Result := True;
  720. end;
  721. function TDataObject.EnumFormatEtc(dwDirection: LongInt; out enumFormatEtc: IEnumFormatEtc): HResult;
  722. begin
  723. Result := E_Fail;
  724. if dwDirection = DATADIR_GET then
  725. begin
  726. EnumFormatEtc := TEnumFormatEtc.Create(FFormatEtcList.Clone);
  727. Result := S_OK;
  728. end
  729. else EnumFormatEtc := nil;
  730. if EnumFormatEtc = nil then Result := OLE_S_USEREG;
  731. end;
  732. function TDataObject.SetData(const formatetc: TFormatEtc; var medium: TStgMedium; fRelease: BOOL): HResult;
  733. var
  734. i: Integer;
  735. AddData: Boolean;
  736. begin
  737. Result := E_Fail;
  738. if not FRelease then
  739. begin
  740. AddData := True;
  741. if FFormatEtcList.Count>0 then
  742. begin
  743. for i := 0 to FFormatEtcList.Count - 1 do
  744. begin
  745. if FFormatEtcList.Items[i].cfFormat = FormatEtc.cfFormat then
  746. begin
  747. AddData := False;
  748. FFormatEtcList.Items[i] := FormatEtc;
  749. end;
  750. end;
  751. end;
  752. if AddData then
  753. begin
  754. FFormatEtcList.Add(FormatEtc);
  755. end;
  756. end;
  757. end;
  758. function TDataObject.DAdvise(
  759. const formatetc: TFormatEtc; advf: LongInt; const advSink: IAdviseSink; out dwConnection: LongInt): HResult;
  760. begin
  761. Result := E_NOTIMPL;
  762. end;
  763. function TDataObject.DUnadvise(dwConnection: LongInt): HResult; stdcall;
  764. begin
  765. Result := E_NOTIMPL;
  766. end;
  767. function TDataObject.EnumDAdvise(out enumAdvise: IEnumStatData): HResult;
  768. begin
  769. Result := OLE_E_AdviseNotSupported;
  770. end;
  771. // TDropSource methods ---------------------------------------------------------
  772. constructor TDropSource.Create(AOwner: TDragDrop);
  773. begin
  774. inherited Create;
  775. _AddRef;
  776. FOwner := AOwner;
  777. end;
  778. destructor TDropSource.Destroy;
  779. begin
  780. inherited;
  781. end;
  782. function TDropSource.QueryContinueDrag(fEscapePressed: BOOL; grfKeyState: LongInt): HResult; stdcall;
  783. // Determines whether a drag-and-drop operation should be continued, cancelled,
  784. // or completed. You do not call this method directly. The OLE DoDragDrop function
  785. // calls this method during a drag-and-drop operation.
  786. begin
  787. // Abort drag-and-drop?
  788. if (((grfKeyState and MK_LBUTTON) <> 0) and
  789. ((grfKeyState and MK_RBUTTON) <> 0)) or fEscapePressed then
  790. begin
  791. Result := DRAGDROP_S_CANCEL;
  792. FOwner.FOwnerIsSource := False;
  793. end
  794. // Finish drag-and-drop?
  795. else if (((grfKeyState and MK_LBUTTON) = 0) and
  796. ((grfKeyState and MK_RBUTTON) = 0)) then
  797. begin
  798. Result := DRAGDROP_S_DROP;
  799. end
  800. else
  801. begin
  802. Result := S_OK;
  803. end;
  804. if Assigned(FOwner.FOnQueryContinueDrag) then
  805. begin
  806. FOwner.FOnQueryContinueDrag(fEscapePressed, grfKeyState, Result);
  807. end;
  808. end;
  809. function TDropSource.GiveFeedback(dwEffect: LongInt): HResult; stdcall;
  810. // Enables a source application to give visual feedback to its end user
  811. // during a drag-and-drop operation by providing the DoDragDrop function
  812. // with an enumeration value specifying the visual effect.
  813. var
  814. HC: HCursor;
  815. begin
  816. if Assigned(FOwner.FOnGiveFeedback) then FOwner.FOnGiveFeedback(dwEffect,Result);
  817. if dwEffect and DROPEFFECT_Scroll <> 0 then
  818. begin
  819. if dwEffect and DROPEFFECT_Link <> 0 then HC := FOwner.FCHScrollLink
  820. else
  821. if dwEffect and DROPEFFECT_Move <> 0 then HC := FOwner.FCHScrollMove
  822. else
  823. if dwEffect and DROPEFFECT_Copy <> 0 then HC := FOwner.FCHScrollCopy
  824. else HC := DefaultCursor;
  825. end
  826. else
  827. begin
  828. if dwEffect and DROPEFFECT_Link <> 0 then HC := FOwner.FCHLink
  829. else
  830. if dwEffect and DROPEFFECT_Move <> 0 then HC := FOwner.FCHMove
  831. else
  832. if dwEffect and DROPEFFECT_Copy <> 0 then HC := FOwner.FCHCopy
  833. else HC := DefaultCursor;
  834. end;
  835. if HC = DefaultCursor then
  836. begin
  837. Result := DRAGDROP_S_USEDEFAULTCURSORS
  838. end
  839. else
  840. begin
  841. Result := S_Ok;
  842. Windows.SetCursor(HC);
  843. end;
  844. end;
  845. // TDropTarget interface -------------------------------------------------------
  846. constructor TDropTarget.Create(AOwner: TDragDrop);
  847. begin
  848. inherited Create;
  849. FOwner:=AOwner;
  850. _AddRef;
  851. HorzStartTimer:=TTimer.Create(FOwner);
  852. HorzStartTimer.Enabled:=False;
  853. HorzStartTimer.OnTimer:=OnStartTimer;
  854. HorzScrollTimer:=TTimer.Create(FOwner);
  855. HorzScrollTimer.Enabled:=False;
  856. HorzScrollTimer.OnTimer:=OnScrollTimer;
  857. VertStartTimer:=TTimer.Create(FOwner);
  858. VertStartTimer.Enabled:=False;
  859. VertStartTimer.OnTimer:=OnStartTimer;
  860. VertScrollTimer:=TTimer.Create(FOwner);
  861. VertScrollTimer.Enabled:=False;
  862. VertScrollTimer.OnTimer:=OnScrollTimer;
  863. FVScrollCode:=0;
  864. FHScrollCode:=0;
  865. end;
  866. destructor TDropTarget.Destroy;
  867. begin
  868. HorzStartTimer.Free;
  869. HorzScrollTimer.Free;
  870. VertStartTimer.Free;
  871. VertScrollTimer.Free;
  872. inherited Destroy;
  873. end;
  874. procedure TDropTarget.InitScroll(VerticalScroll:Boolean; ScrollCode:Integer);
  875. begin
  876. TermScroll(VerticalScroll);
  877. if VerticalScroll then
  878. begin
  879. VertStartTimer.Interval:=FOwner.FScrollDetectOptions.FStartDelay;
  880. VertStartTimer.Enabled:=True;
  881. FVScrollCode:=ScrollCode;
  882. end
  883. else
  884. begin
  885. HorzStartTimer.Interval:=FOwner.FScrollDetectOptions.FStartDelay;
  886. HorzStartTimer.Enabled:=True;
  887. FHScrollCode:=ScrollCode;
  888. end;
  889. end;
  890. procedure TDropTarget.TermScroll(VerticalScroll:Boolean);
  891. begin
  892. if VerticalScroll then
  893. begin
  894. VertStartTimer.Enabled:=False;
  895. if VertScrollTimer.Enabled then
  896. sendmessage(FOwner.DragDropControl.handle,WM_VScroll,SB_ENDSCROLL,0);
  897. VertScrollTimer.Enabled:=False;
  898. FVScrollCode:=0;
  899. end
  900. else
  901. begin
  902. HorzStartTimer.Enabled:=False;
  903. if HorzScrollTimer.Enabled then
  904. sendmessage(FOwner.DragDropControl.handle,WM_HScroll,SB_ENDSCROLL,0);
  905. HorzScrollTimer.Enabled:=False;
  906. FHScrollCode:=0;
  907. end;
  908. end;
  909. procedure TDropTarget.DetermineScrollDir(VertScrolling:Boolean;
  910. var ScrollCode:Integer);
  911. var p1m,p1r,p2m,p2r:Integer;
  912. ptmc:TPoint;
  913. SCROLLINFO:TSCROLLINFO;
  914. begin
  915. GetCursorPos(ptmc);
  916. ptmc:=FOwner.DragDropControl.ScreenToClient(ptmc);
  917. if VertScrolling then
  918. begin
  919. // Checking vertical scroll areas ...
  920. // If the vertical scroll areas intersect, we don't allow scrolling
  921. p1m:=FOwner.FScrollDetectOptions.AreaTop.Margin;
  922. p1r:=p1m+FOwner.ScrollDetectOptions.AreaTop.Range;
  923. p2m:=FOwner.DragDropControl.ClientHeight-1-
  924. FOwner.ScrollDetectOptions.AreaBottom.Margin;
  925. p2r:=p2m-FOwner.ScrollDetectOptions.AreaBottom.Range;
  926. if (p1r<p2r) then
  927. begin
  928. if (p1m<=ptmc.y) and (p1r>=ptmc.y) then ScrollCode:=1
  929. else if (p2m>=ptmc.y) and (p2r<=ptmc.y) then ScrollCode:=2
  930. else ScrollCode:=0;
  931. if ScrollCode>0 then
  932. begin
  933. ScrollInfo.cbSize := Sizeof(ScrollInfo);
  934. ScrollInfo.FMask:=SIF_PAGE or SIF_POS or SIF_RANGE;
  935. if GetScrollInfo(FOwner.DragDropControl.Handle,SB_VERT,
  936. ScrollInfo) then
  937. begin
  938. if ScrollInfo.nPage>0 then dec(ScrollInfo.nPage);
  939. if ((ScrollCode=1) and (ScrollInfo.nPos<=ScrollInfo.nMin)) or
  940. ((ScrollCode=2) and
  941. (ScrollInfo.nPos>=ScrollInfo.nMax-Integer(ScrollInfo.nPage))) then
  942. ScrollCode:=0;
  943. end
  944. else ScrollCode:=0;
  945. end;
  946. end
  947. else ScrollCode:=0;
  948. end
  949. else
  950. begin
  951. // Checking horizontal scroll areas ...
  952. // If the horizontal scroll areas intersect, we don't allow scrolling
  953. p1m:=FOwner.FScrollDetectOptions.AreaLeft.Margin;
  954. p1r:=p1m+FOwner.ScrollDetectOptions.AreaLeft.Range;
  955. p2m:=FOwner.DragDropControl.ClientWidth-1-
  956. FOwner.ScrollDetectOptions.AreaRight.Margin;
  957. p2r:=p2m-FOwner.ScrollDetectOptions.AreaRight.Range;
  958. if (p1r<p2r) then
  959. begin
  960. if (p1m<=ptmc.x) and (p1r>=ptmc.x) then ScrollCode:=1
  961. else if (p2m>=ptmc.x) and (p2r<=ptmc.x) then ScrollCode:=2
  962. else ScrollCode:=0;
  963. if ScrollCode>0 then
  964. begin
  965. ScrollInfo.cbSize := Sizeof(ScrollInfo);
  966. ScrollInfo.FMask:=SIF_PAGE or SIF_POS or SIF_RANGE;
  967. if GetScrollInfo(FOwner.DragDropControl.Handle,SB_Horz,
  968. ScrollInfo) then
  969. begin
  970. if ScrollInfo.nPage>0 then dec(ScrollInfo.nPage);
  971. if ((ScrollCode=1) and (ScrollInfo.nPos<=ScrollInfo.nMin)) or
  972. ((ScrollCode=2) and
  973. (ScrollInfo.nPos>=ScrollInfo.nMax-Integer(ScrollInfo.nPage))) then
  974. ScrollCode:=0;
  975. end
  976. else ScrollCode:=0;
  977. end;
  978. end
  979. else ScrollCode:=0;
  980. end;
  981. end;
  982. procedure TDropTarget.OnStartTimer(Sender: TObject);
  983. begin
  984. if Sender=HorzStartTimer then
  985. begin
  986. HorzStartTimer.Enabled:=False;
  987. HorzScrollTimer.Interval:=FOwner.FScrollDetectOptions.FScrollDelay;
  988. OnScrollTimer(HorzScrollTimer);
  989. HorzScrollTimer.Enabled:=True;
  990. end
  991. else
  992. begin
  993. VertStartTimer.Enabled:=False;
  994. VertScrollTimer.Interval:=FOwner.FScrollDetectOptions.FScrollDelay;
  995. OnScrollTimer(VertScrollTimer);
  996. VertScrollTimer.Enabled:=True;
  997. end;
  998. end;
  999. procedure TDropTarget.OnScrollTimer(Sender: TObject);
  1000. var ScrollPage:Boolean;
  1001. pt:TPoint;
  1002. Interval:TScrollInterval;
  1003. ScrollCode,SCWParam:Integer;
  1004. begin
  1005. Interval:=FOwner.FScrollDetectOptions.FScrollDelay;
  1006. if Sender=VertScrollTimer then
  1007. begin
  1008. if FOwner.FScrollDetectOptions.FVertScrolling then
  1009. begin
  1010. DetermineScrollDir(True,ScrollCode);
  1011. if ScrollCode>0 then
  1012. begin
  1013. if ((VertStartTimer.Enabled=False) and (VertScrollTimer.Enabled=False)) or
  1014. (FVScrollCode<>ScrollCode) then InitScroll(True,ScrollCode)
  1015. else
  1016. begin
  1017. ScrollPage:=FOwner.FScrollDetectOptions.FVertPageScroll;
  1018. if assigned(FOwner.FOnBeforeScrolling) then
  1019. begin
  1020. GetCursorPos(pt);
  1021. pt:=FOwner.DragDropControl.ScreenToClient(pt);
  1022. if FVScrollCode=1 then FOwner.FOnBeforeScrolling(FOwner, pt,
  1023. Interval, sdUp, ScrollPage)
  1024. else FOwner.FOnBeforeScrolling(FOwner, pt, Interval, sdDown,
  1025. ScrollPage);
  1026. end;
  1027. if ScrollPage then
  1028. begin
  1029. if FVScrollCode=1 then SCWParam:=SB_PAGEUP
  1030. else SCWParam:=SB_PAGEDOWN;
  1031. end
  1032. else
  1033. begin
  1034. if FVScrollCode=1 then SCWParam:=SB_LINEUP
  1035. else SCWParam:=SB_LINEDOWN;
  1036. end;
  1037. sendmessage(FOwner.DragDropControl.handle,WM_VScroll,SCWParam,0);
  1038. if assigned(FOwner.FOnAfterScrolling) then
  1039. FOwner.FOnAfterScrolling(FOwner);
  1040. VertScrollTimer.Interval:=Interval;
  1041. end;
  1042. end
  1043. else if FVScrollCode<>0 then TermScroll(True);
  1044. end
  1045. else if FVScrollCode<>0 then TermScroll(True);
  1046. end
  1047. else
  1048. begin
  1049. if FOwner.FScrollDetectOptions.FHorzScrolling then
  1050. begin
  1051. DetermineScrollDir(False,ScrollCode);
  1052. if ScrollCode>0 then
  1053. begin
  1054. if ((HorzStartTimer.Enabled=False) and (HorzScrollTimer.Enabled=False)) or
  1055. (FHScrollCode<>ScrollCode) then InitScroll(False,ScrollCode)
  1056. else
  1057. begin
  1058. ScrollPage:=FOwner.FScrollDetectOptions.FHorzPageScroll;
  1059. if assigned(FOwner.FOnBeforeScrolling) then
  1060. begin
  1061. GetCursorPos(pt);
  1062. pt:=FOwner.DragDropControl.ScreenToClient(pt);
  1063. if FHScrollCode=1 then FOwner.FOnBeforeScrolling(FOwner, pt,
  1064. Interval, sdLeft, ScrollPage)
  1065. else FOwner.FOnBeforeScrolling(FOwner, pt, Interval, sdRight,
  1066. ScrollPage);
  1067. end;
  1068. if ScrollPage then
  1069. begin
  1070. if FHScrollCode=1 then SCWParam:=SB_PAGELEFT
  1071. else SCWParam:=SB_PAGERIGHT;
  1072. end
  1073. else
  1074. begin
  1075. if FHScrollCode=1 then SCWParam:=SB_LINELEFT
  1076. else SCWParam:=SB_LINERIGHT;
  1077. end;
  1078. sendmessage(FOwner.DragDropControl.handle,WM_HScroll,SCWParam,0);
  1079. HorzScrollTimer.Interval:=Interval;
  1080. end;
  1081. end
  1082. else if FHScrollCode<>0 then TermScroll(False);
  1083. end
  1084. else if FHScrollCode<>0 then TermScroll(False);
  1085. end;
  1086. end;
  1087. procedure TDropTarget.SuggestDropEffect(grfKeyState: LongInt; var dwEffect: LongInt);
  1088. begin
  1089. if (FOwner.FAcceptOwnDnD=False) and
  1090. (FOwner.FOwnerIsSource) then dwEffect:=DropEffect_None
  1091. else if (grfKeyState and MK_CONTROL=0) and (grfKeyState and MK_SHIFT<>0) and
  1092. (FOwner.FTargetEffects and DropEffect_Move<>0) then
  1093. dwEffect:=DropEffect_Move
  1094. else if (grfKeyState and MK_CONTROL<>0) and
  1095. (grfKeyState and MK_SHIFT<>0) and
  1096. (FOwner.FTargetEffects and DropEffect_Link<>0) then
  1097. dwEffect:=DropEffect_Link
  1098. else if (deCopy in FOwner.FTargetEffectsSet) and
  1099. (dwEffect and DropEffect_Copy<>0) then
  1100. dwEffect:=DropEffect_Copy
  1101. else if (deMove in FOwner.FTargetEffectsSet) and
  1102. (dwEffect and DropEffect_Move<>0) then
  1103. dwEffect:=DropEffect_Move
  1104. else if (deLink in FOwner.FTargetEffectsSet) and
  1105. (dwEffect and DropEffect_Link<>0) then
  1106. dwEffect:=DropEffect_Link
  1107. else dwEffect:=DropEffect_None;
  1108. if FOwner.FTargetScrolling<>0 then dwEffect:=dwEffect or Integer(DropEffect_Scroll);
  1109. end;
  1110. procedure TDropTarget.AcceptDataObject(DataObj: IDataObject; var Accept:Boolean);
  1111. begin
  1112. Accept:=True;
  1113. end;
  1114. function TDropTarget.DragEnter(const dataObj: IDataObject; grfKeyState: LongInt;
  1115. pt: TPoint; var dwEffect: LongInt): HResult;
  1116. // Is called if the d&d-mouse cursor moves ON (one call only) the TargeTWinControl. Here,
  1117. // you influence if a drop can be accepted and the drop's effect if accepted.
  1118. begin
  1119. TDragDrop(FOwner).FInternalSource:=GInternalSource;
  1120. FOwner.FAvailableDropEffects:=dwEffect;
  1121. FOwner.FContextMenu:=grfKeyState and mk_rbutton<>0;
  1122. if (FOwner.RenderDataOn=rdoEnter) or (FOwner.RenderDataOn=rdoEnterAndDropSync) or
  1123. (FOwner.RenderDataOn=rdoEnterAndDropAsync) then
  1124. RenderDropped(DataObj, grfKeyState, pt, dwEffect);
  1125. SuggestDropEffect(grfKeyState,dwEffect);
  1126. AcceptDataObject(DataObj, FAccept);
  1127. if Assigned(FOwner.OnDragEnter) then
  1128. FOwner.OnDragEnter(DataObj, grfKeyState,
  1129. FOwner.FDragDropControl.ScreenToClient(pt), dwEffect, FAccept);
  1130. if ((FOwner.FAcceptOwnDnD=False) and (FOwner.FOwnerIsSource)) or
  1131. (FAccept=False) then dwEffect:=DropEffect_None;
  1132. Result:= NOERROR;
  1133. end;
  1134. function TDropTarget.DragOver(grfKeyState: LongInt; pt: TPoint;
  1135. var dwEffect: LongInt): HResult;
  1136. // Is called if the mouse cursor moves OVER (called on every mouse move) the
  1137. // TargeTWinControl. Even here may you influence if a drop can be accepted and the
  1138. // drop's effect if accepted. Because this function is very often called YOUR
  1139. // function should be very efficient programmed.
  1140. var ScrollCode:Integer;
  1141. begin
  1142. if FOwner.FScrollDetectOptions.FVertScrolling then
  1143. begin
  1144. DetermineScrollDir(True,ScrollCode);
  1145. if ScrollCode>0 then
  1146. begin
  1147. if ((VertStartTimer.Enabled=False) and (VertScrollTimer.Enabled=False)) or
  1148. (FVScrollCode<>ScrollCode) then InitScroll(True,ScrollCode);
  1149. end
  1150. else if FVScrollCode<>0 then TermScroll(True);
  1151. end
  1152. else if FVScrollCode<>0 then TermScroll(True);
  1153. if FOwner.FScrollDetectOptions.FHorzScrolling then
  1154. begin
  1155. DetermineScrollDir(False,ScrollCode);
  1156. if ScrollCode>0 then
  1157. begin
  1158. if ((HorzStartTimer.Enabled=False) and (HorzScrollTimer.Enabled=False)) or
  1159. (FHScrollCode<>ScrollCode) then InitScroll(False,ScrollCode);
  1160. end
  1161. else if FHScrollCode<>0 then TermScroll(False);
  1162. end
  1163. else if FHScrollCode<>0 then TermScroll(False);
  1164. if FAccept=False then dwEffect:=DropEffect_None;
  1165. SuggestDropEffect(grfKeyState,dwEffect);
  1166. if Assigned(FOwner.OnDragOver) then
  1167. FOwner.OnDragOver(grfKeyState, FOwner.FDragDropControl.ScreenToClient(pt),
  1168. dwEffect);
  1169. if ((FOwner.FAcceptOwnDnD=False) and (FOwner.FOwnerIsSource)) or
  1170. (FAccept=False) then dwEffect:=DropEffect_None;
  1171. Result:=NOERROR;
  1172. end;
  1173. function TDropTarget.DragLeave: HResult;
  1174. // Removes target feedback and releases the data object.
  1175. begin
  1176. TDragDrop(FOwner).FInternalSource:=nil;
  1177. if Assigned(FOwner.OnDragLeave) then FOwner.OnDragLeave;
  1178. FOwner.FAvailableDropEffects:=0;
  1179. Result:=NOERROR;
  1180. TermScroll(True);
  1181. TermScroll(False);
  1182. end;
  1183. function TDropTarget.Drop(const DataObj: IDataObject; grfKeyState: LongInt; pt: TPoint;
  1184. var dwEffect: LongInt): HResult;
  1185. // Instructs drop target to handle the datas which are dropped on it.
  1186. var Menu:HMenu;
  1187. Cmd:Cardinal;
  1188. mcursor:TCursor;
  1189. KeyState:Integer;
  1190. function BuildMenuItemInfo(ACaption:string; ShowDefault:Boolean;
  1191. ACommand:UInt; ASeparator:Boolean):TMenuItemInfo;
  1192. begin
  1193. with Result do
  1194. begin
  1195. // cbSize:=SizeOf(MenuItemInfo);
  1196. cbSize:=44; //Required for Windows95
  1197. fMask:=MIIM_ID or MIIM_STATE or MIIM_TYPE;
  1198. if ASeparator then fType:=MFT_SEPARATOR
  1199. else fType:=MFT_STRING;
  1200. if ShowDefault then fState:=MFS_ENABLED or MFS_Default
  1201. else fState:=MFS_ENABLED;
  1202. wID:=ACommand;
  1203. hSubMenu:=0;
  1204. hbmpChecked:=0;
  1205. hbmpUnchecked:=0;
  1206. dwTypeData:=PChar(ACaption);
  1207. end;
  1208. end;
  1209. begin
  1210. Result:=E_Fail;
  1211. if FOwner.FContextMenu then KeyState:=grfKeyState or MK_RButton
  1212. else KeyState:=grfKeyState or MK_LButton;
  1213. if FAccept then SuggestDropEffect(KeyState,dwEffect)
  1214. else dwEffect:=DropEffect_None;
  1215. if assigned(FOwner.OnDragOver) then
  1216. FOwner.OnDragOver(KeyState, FOwner.FDragDropControl.ScreenToClient(pt),
  1217. dwEffect);
  1218. if ((FOwner.FAcceptOwnDnD=False) and (FOwner.FOwnerIsSource)) or
  1219. (FAccept=False) then dwEffect:=DropEffect_None;
  1220. TermScroll(True);
  1221. TermScroll(False);
  1222. if (FOwner.DropHandler(DataObj, KeyState, pt, dwEffect)=False) then
  1223. begin
  1224. // Show popup menu?
  1225. if FOwner.FContextMenu and FOwner.FShowPopupMenu and (dwEffect<>DropEffect_None) then
  1226. begin
  1227. Menu:=CreatePopupMenu;
  1228. if (deMove in FOwner.FTargetEffectsSet) and
  1229. (FOwner.FAvailableDropEffects and DropEffect_Move<>0) then
  1230. InsertMenuItem(Menu, DWORD(-1), True,
  1231. BuildMenuItemInfo(MIMoveStr, dwEffect and DropEffect_Move<>0,
  1232. CmdMove, False));
  1233. if (deCopy in FOwner.FTargetEffectsSet) and
  1234. (FOwner.FAvailableDropEffects and DropEffect_Copy<>0) then
  1235. InsertMenuItem(Menu, DWORD(-1), True,
  1236. BuildMenuItemInfo(MICopyStr, dwEffect and DropEffect_Copy<>0,
  1237. CmdCopy, False));
  1238. if (deLink in FOwner.FTargetEffectsSet) and
  1239. (FOwner.FAvailableDropEffects and DropEffect_Link<>0) then
  1240. InsertMenuItem(Menu, DWORD(-1), True,
  1241. BuildMenuItemInfo(MILinkStr, dwEffect and DropEffect_Link<>0,
  1242. CmdLink, False));
  1243. InsertMenuItem(Menu, DWORD(-1), True,
  1244. BuildMenuItemInfo('-', False, CmdSeparator, True));
  1245. InsertMenuItem(Menu, DWORD(-1), True,
  1246. BuildMenuItemInfo(MIAbortStr, False, CmdAbort, False));
  1247. // Add custom-menuitems ...
  1248. FOwner.DoMenuPopup(self, Menu, DataObj, MinCustCmd, KeyState, pt);
  1249. try
  1250. dwEffect:=DROPEFFECT_None;
  1251. Cmd:=Cardinal(TrackPopupMenuEx(Menu, TPM_LEFTALIGN or TPM_RIGHTBUTTON or TPM_RETURNCMD,
  1252. pt.x, pt.y, FOwner.DragDropControl.Handle, nil));
  1253. case Cmd of
  1254. CmdMove: dwEffect:=DROPEFFECT_Move;
  1255. CmdCopy: dwEffect:=DROPEFFECT_Copy;
  1256. CmdLink: dwEffect:=DROPEFFECT_Link;
  1257. CmdSeparator, CmdAbort:
  1258. dwEffect:=DROPEFFECT_None;
  1259. else // custom-menuitem was selected ...
  1260. begin
  1261. dwEffect:=DROPEFFECT_None;
  1262. if FOwner.DoMenuExecCmd(self, Menu, DataObj, Cmd, dwEffect) and
  1263. assigned(FOwner.FOnMenuSucceeded) then
  1264. FOwner.FOnMenuSucceeded(self, KeyState,
  1265. FOwner.FDragDropControl.ScreenToClient(pt), dwEffect);
  1266. end;
  1267. end;
  1268. finally
  1269. FOwner.DoMenuDestroy(Self, Menu);
  1270. DestroyMenu(Menu);
  1271. end;
  1272. end;
  1273. if assigned(FOwner.OnDrop) then
  1274. FOwner.OnDrop(DataObj, KeyState,
  1275. FOwner.FDragDropControl.ScreenToClient(pt), dwEffect);
  1276. if dwEffect<>DROPEFFECT_None then
  1277. begin
  1278. if FOwner.FBTF Then
  1279. SetForegroundWindow((FOwner.Owner As TWinControl).Handle);
  1280. TDragDrop(FOwner).FdwEffect:=dwEffect;
  1281. TDragDrop(FOwner).FgrfKeyState:=KeyState;
  1282. TDragDrop(FOwner).Fpt:=pt;
  1283. if (FOwner.RenderDataOn=rdoDropAsync) or
  1284. (FOwner.RenderDataOn=rdoEnterAndDropAsync) then
  1285. begin
  1286. TDragDrop(FOwner).FDataObj:=DataObj;
  1287. DataObj._AddRef;
  1288. end
  1289. else if (FOwner.RenderDataOn=rdoDropSync) or
  1290. (FOwner.RenderDataOn=rdoEnterAndDropSync) then
  1291. begin
  1292. // Set hourglass-cursor
  1293. mcursor:=Screen.Cursor;
  1294. Screen.Cursor:=crHourGlass;
  1295. try
  1296. RenderDropped(DataObj, KeyState, pt, dwEffect);
  1297. finally
  1298. // Set old cursor
  1299. Screen.Cursor:=mcursor;
  1300. end;
  1301. end;
  1302. PostMessage(FOwner.DragDropControl.Handle,DDM_ProcessDropped,0,0);
  1303. Result:=NOERROR;
  1304. end
  1305. else TDragDrop(FOwner).FInternalSource:=nil;
  1306. end
  1307. else
  1308. begin
  1309. TDragDrop(FOwner).FInternalSource:=nil;
  1310. if assigned(FOwner.FOnDropHandlerSucceeded) then
  1311. FOwner.FOnDropHandlerSucceeded(self, KeyState,
  1312. FOwner.FDragDropControl.ScreenToClient(pt), dwEffect);
  1313. end;
  1314. end;
  1315. procedure TDropTarget.RenderDropped(DataObj: IDataObject; grfKeyState: LongInt;
  1316. pt: TPoint; var dwEffect: LongInt);
  1317. begin
  1318. // override, if you need ...
  1319. end;
  1320. // TScrollDetectArea methods ---------------------------------------------------
  1321. constructor TScrollDetectArea.Create(Control: TPersistent);
  1322. begin
  1323. inherited Create;
  1324. FControl:=Control;
  1325. end;
  1326. procedure TScrollDetectArea.AssignTo(Dest: TPersistent);
  1327. begin
  1328. if Dest is TScrollDetectArea then
  1329. with TScrollDetectArea(Dest) do
  1330. begin
  1331. FMargin:=Self.FMargin;
  1332. FRange:=Self.FRange;
  1333. Change;
  1334. end
  1335. else inherited AssignTo(Dest);
  1336. end;
  1337. procedure TScrollDetectArea.SetValue(Index: Integer;
  1338. Value: Word);
  1339. begin
  1340. case Index of
  1341. 0: if Value<>FMargin then
  1342. begin
  1343. FMargin:=Value;
  1344. Change;
  1345. end;
  1346. 1: if Value<>FRange then
  1347. begin
  1348. FRange:=Value;
  1349. Change;
  1350. end;
  1351. end;
  1352. end;
  1353. procedure TScrollDetectArea.Change;
  1354. begin
  1355. if Assigned(FOnChange) then FOnChange(Self);
  1356. end;
  1357. // TScrollDetectOptions methods -------------------------------------------------
  1358. constructor TScrollDetectOptions.Create(Control: TDragDrop);
  1359. begin
  1360. inherited Create;
  1361. FControl:=Control;
  1362. FScrollDelay:=100;
  1363. FStartDelay:=750;
  1364. FLeft:=TScrollDetectArea.Create(self);
  1365. FLeft.Margin:=0;
  1366. FLeft.Range:=10;
  1367. FLeft.OnChange:=FOnChange;
  1368. FTop:=TScrollDetectArea.Create(self);
  1369. FTop.Margin:=0;
  1370. FTop.Range:=10;
  1371. FTop.OnChange:=FOnChange;
  1372. FRight:=TScrollDetectArea.Create(self);
  1373. FRight.Margin:=0;
  1374. FRight.Range:=10;
  1375. FRight.OnChange:=FOnChange;
  1376. FBottom:=TScrollDetectArea.Create(self);
  1377. FBottom.Margin:=0;
  1378. FBottom.Range:=10;
  1379. FBottom.OnChange:=FOnChange;
  1380. FHorzScrolling:=False;
  1381. FVertScrolling:=False;
  1382. FHorzPageScroll:=False;
  1383. FVertPageScroll:=False;
  1384. end;
  1385. destructor TScrollDetectOptions.Destroy;
  1386. begin
  1387. FLeft.Free;
  1388. FTop.Free;
  1389. FRight.Free;
  1390. FBottom.Free;
  1391. inherited Destroy;
  1392. end;
  1393. procedure TScrollDetectOptions.AssignTo(Dest: TPersistent);
  1394. begin
  1395. if Dest is TScrollDetectOptions then
  1396. with TScrollDetectOptions(Dest) do
  1397. begin
  1398. FScrollDelay:=Self.FScrollDelay;
  1399. FStartDelay:=Self.FStartDelay;
  1400. FLeft.AssignTo(Self.FLeft);
  1401. FTop.AssignTo(Self.FTop);
  1402. FRight.AssignTo(Self.FRight);
  1403. FBottom.AssignTo(Self.FBottom);
  1404. Change;
  1405. end
  1406. else inherited AssignTo(Dest);
  1407. end;
  1408. procedure TScrollDetectOptions.SetValue(index:Integer; Value: TScrollInterval);
  1409. begin
  1410. if (Index=0) and (Value<>FScrollDelay) then
  1411. begin
  1412. FScrollDelay:=Value;
  1413. Change;
  1414. end;
  1415. if (Index=1) and (Value<>FStartDelay) then
  1416. begin
  1417. FStartDelay:=Value;
  1418. Change;
  1419. end;
  1420. end;
  1421. procedure TScrollDetectOptions.Change;
  1422. begin
  1423. if Assigned(FOnChange) then FOnChange(Self);
  1424. end;
  1425. // TDragDrop control ------------------------------------------------------
  1426. constructor TDragDrop.Create(AOwner: TComponent);
  1427. begin
  1428. inherited Create(AOwner);
  1429. FDropTarget:=TDropTarget.Create(Self);
  1430. FRegistered:=False;
  1431. FDragDropControl:=nil;
  1432. FBTF:=False;
  1433. FAcceptOwnDnD:=False;
  1434. FShowPopupMenu:=True;
  1435. FDragDetectDelta:=10;
  1436. FDragDetectStatus:=ddsNone;
  1437. FRenderDataOn:=rdoDropSync;
  1438. FCHCopy:=DefaultCursor;
  1439. FCHMove:=DefaultCursor;
  1440. FCHLink:=DefaultCursor;
  1441. FCHScrollCopy:=DefaultCursor;
  1442. FCHScrollMove:=DefaultCursor;
  1443. FCHScrollLink:=DefaultCursor;
  1444. FMessageHooked:=False;
  1445. FAvailableDropEffects:=0;
  1446. FTargetScrolling:=0;
  1447. FSrcCompatibilityCheck:=[CheckLindex, CheckdwAspect];
  1448. FScrollDetectOptions:=TScrollDetectOptions.Create(Self);
  1449. FInternalSource:=nil;
  1450. end;
  1451. destructor TDragDrop.Destroy;
  1452. begin
  1453. UnregisterTarget;
  1454. UnhookMessageHandler(True);
  1455. FDropTarget._Release;
  1456. FDropTarget:=nil;
  1457. FDragDropControl:=nil;
  1458. FScrollDetectOptions.Free;
  1459. inherited Destroy;
  1460. end;
  1461. procedure TDragDrop.WndMethod(var Msg: TMessage); // message-hook to receive DDM_ProcessDropped
  1462. var mcursor:TCursor;
  1463. begin
  1464. with Msg do
  1465. begin
  1466. Result:=CallWindowProc(OldWndProc, DragDropControl.Handle, Msg, wParam, LParam);
  1467. if (Msg=DDM_ProcessDropped) then
  1468. begin
  1469. if (RenderDataOn=rdoDropAsync) or (RenderDataOn=rdoEnterAndDropAsync) then
  1470. begin
  1471. // Set hourglass-cursor
  1472. mcursor:=Screen.Cursor;
  1473. Screen.Cursor:=crHourGlass;
  1474. try
  1475. FDropTarget.RenderDropped(FDataObj, FgrfKeyState, Fpt, FdwEffect);
  1476. FDataObj._Release;
  1477. finally
  1478. // Set old cursor
  1479. Screen.Cursor:=mcursor;
  1480. end;
  1481. end;
  1482. if assigned(FOnProcessDropped) then
  1483. FOnProcessDropped(self, FgrfKeyState,
  1484. FDragDropControl.ScreenToClient(Fpt), FdwEffect);
  1485. FAvailableDropEffects:=0;
  1486. FInternalSource:=nil;
  1487. end;
  1488. case Msg of
  1489. WM_Destroy:
  1490. begin
  1491. if FRegistered then
  1492. begin
  1493. CoLockObjectExternal(FDropTarget, False, False);
  1494. if (FDragDropControl.HandleAllocated=False) or
  1495. (FDragDropControl.HandleAllocated and
  1496. (RevokeDragDrop(FDragDropControl.Handle)=S_OK)) then
  1497. FRegistered:=False;
  1498. end;
  1499. FMessageHooked:=False;
  1500. end;
  1501. WM_LBUTTONDOWN, WM_RBUTTONDOWN:
  1502. begin
  1503. if FAutoDetectDnD and (FDragDetectStatus=ddsNone) and
  1504. (FSourceEffects<>0) then
  1505. begin
  1506. if Msg=WM_LBUTTONDOWN then FDragDetectStatus:=ddsLeft
  1507. else FDragDetectStatus:=ddsRight;
  1508. GetCursorPos(FDragDetectStart);
  1509. if assigned(FOnDragDetect) then
  1510. FOnDragDetect(wparam,
  1511. FDragDropControl.ScreenToClient(FDragDetectStart),
  1512. FDragDropControl.ScreenToClient(FDragDetectStart),
  1513. FDragDetectStatus);
  1514. if (MouseHookHandle<>0) then
  1515. begin // MouseHookProc is used by another component ...
  1516. UnHookWindowsHookEx(MouseHookHandle);
  1517. MouseHookHandle:=0;
  1518. if assigned(MouseHookDragDrop) then
  1519. begin
  1520. MouseHookDragDrop.FDragDetectStatus:=ddsNone;
  1521. if assigned(MouseHookDragDrop.FOnDragDetect) then
  1522. MouseHookDragDrop.FOnDragDetect(wparam,
  1523. MouseHookDragDrop.FDragDropControl.ScreenToClient(
  1524. MouseHookDragDrop.FDragDetectStart),
  1525. MouseHookDragDrop.FDragDropControl.ScreenToClient(
  1526. FDragDetectStart),
  1527. MouseHookDragDrop.FDragDetectStatus);
  1528. end;
  1529. end;
  1530. MouseHookDragDrop:=self;
  1531. MouseHookHandle:=SetWindowsHookEx(WH_MOUSE,MouseHookProc,LongWord(HInstance),0);
  1532. end;
  1533. end;
  1534. WM_HSCROLL:
  1535. if LOWORD(wParam)<>SB_ENDSCROLL then FTargetScrolling:=FTargetScrolling or 1
  1536. else FTargetScrolling:=FTargetScrolling and not 1;
  1537. WM_VSCROLL:
  1538. begin
  1539. if LOWORD(wParam)<>SB_ENDSCROLL then FTargetScrolling:=FTargetScrolling or 2
  1540. else FTargetScrolling:=FTargetScrolling and not 2;
  1541. end;
  1542. WM_MOUSEMOVE:
  1543. if (MouseHookHandle<>0) and (wParam and (MK_LBUTTON or MK_RBUTTON)=0) then
  1544. begin
  1545. UnHookWindowsHookEx(MouseHookHandle);
  1546. MouseHookHandle:=0;
  1547. if assigned(MouseHookDragDrop) then
  1548. begin
  1549. MouseHookDragDrop.FDragDetectStatus:=ddsNone;
  1550. if assigned(MouseHookDragDrop.FOnDragDetect) then
  1551. MouseHookDragDrop.FOnDragDetect(wparam,
  1552. MouseHookDragDrop.FDragDropControl.ScreenToClient(
  1553. MouseHookDragDrop.FDragDetectStart),
  1554. MouseHookDragDrop.FDragDropControl.ScreenToClient(
  1555. FDragDetectStart),
  1556. MouseHookDragDrop.FDragDetectStatus);
  1557. end;
  1558. MouseHookDragDrop:=nil;
  1559. end;
  1560. end;
  1561. end;
  1562. end;
  1563. procedure TDragDrop.StartDnDDetection(Button: TMouseButton);
  1564. var grfKeyState: LongInt;
  1565. begin
  1566. if Button=mbLeft then FDragDetectStatus:=ddsLeft
  1567. else if Button=mbRight then FDragDetectStatus:=ddsRight
  1568. else
  1569. begin
  1570. FDragDetectStatus:=ddsNone;
  1571. exit;
  1572. end;
  1573. GetCursorPos(FDragDetectStart);
  1574. if HiWord(DWord(GetKeyState(VK_SHIFT)))<>0 then grfKeyState:=MK_SHIFT
  1575. else grfKeyState:=0;
  1576. if HiWord(DWord(GetKeyState(VK_CONTROL)))<>0 then
  1577. grfKeyState:=grfKeyState or MK_CONTROL;
  1578. if (MouseHookHandle<>0) then
  1579. begin // MouseHookProc is used by another component ...
  1580. UnHookWindowsHookEx(MouseHookHandle);
  1581. MouseHookHandle:=0;
  1582. if assigned(MouseHookDragDrop) then
  1583. begin
  1584. MouseHookDragDrop.FDragDetectStatus:=ddsNone;
  1585. if assigned(MouseHookDragDrop.FOnDragDetect) then
  1586. MouseHookDragDrop.FOnDragDetect(grfKeyState,
  1587. MouseHookDragDrop.FDragDropControl.ScreenToClient(
  1588. MouseHookDragDrop.FDragDetectStart),
  1589. MouseHookDragDrop.FDragDropControl.ScreenToClient(FDragDetectStart),
  1590. MouseHookDragDrop.FDragDetectStatus);
  1591. end;
  1592. end;
  1593. MouseHookDragDrop:=self;
  1594. MouseHookHandle:=SetWindowsHookEx(WH_MOUSE,MouseHookProc,LongWord(HInstance),0);
  1595. if assigned(FOnDragDetect) then
  1596. FOnDragDetect(grfKeyState,
  1597. FDragDropControl.ScreenToClient(FDragDetectStart),
  1598. FDragDropControl.ScreenToClient(FDragDetectStart),
  1599. FDragDetectStatus);
  1600. end;
  1601. procedure TDragDrop.Loaded;
  1602. // Methode which is called if all components are created - now, we can register
  1603. // the target control for drag-and-drop operations
  1604. begin
  1605. inherited Loaded;
  1606. if (FDragDropControl<>nil) and (csDesigning in ComponentState=False) then RegisterTarget;
  1607. end;
  1608. procedure TDragDrop.Notification(AComponent: TComponent; Operation: TOperation);
  1609. begin
  1610. inherited Notification(AComponent,Operation);
  1611. if (AComponent=FDragDropControl) and (Operation=opRemove) then
  1612. begin
  1613. UnregisterTarget;
  1614. UnhookMessageHandler(True);
  1615. FDragDropControl:=nil;
  1616. end;
  1617. end;
  1618. function TDragDrop.RegisterTarget: Boolean;
  1619. // Methode for registering the DragDropControl for drag-and-drop oprations
  1620. begin
  1621. Result:=False;
  1622. try
  1623. HookMessageHandler;
  1624. finally
  1625. // nothing to do
  1626. end;
  1627. if (not FRegistered) and (FTargetEffects <> 0) and (FDragDropControl <> nil) then
  1628. begin
  1629. try
  1630. // CoLockObjectExternal crashes debugging intermittently in C++ Builder 2010
  1631. {$IFNDEF IDE}
  1632. // Ensure that drag-and-drop interface stays in memory
  1633. CoLockObjectExternal(FDropTarget, True, False);
  1634. {$ENDIF}
  1635. if RegisterDragDrop(FDragDropControl.Handle, IDropTarget(FDropTarget))=S_OK then
  1636. begin
  1637. Result:=True;
  1638. FRegistered:=True;
  1639. end;
  1640. except
  1641. Result:=False;
  1642. FRegistered:=False;
  1643. end;
  1644. end;
  1645. end;
  1646. function TDragDrop.UnRegisterTarget: Boolean;
  1647. begin
  1648. Result:=False;
  1649. if (FRegistered=False) or (FDragDropControl=nil) then exit;
  1650. try
  1651. UnHookMessageHandler(False);
  1652. CoLockObjectExternal(FDropTarget, False, False);
  1653. if (FDragDropControl.HandleAllocated=False) or
  1654. (FDragDropControl.HandleAllocated and
  1655. (RevokeDragDrop(FDragDropControl.Handle)=S_OK)) then
  1656. begin
  1657. FRegistered:=False;
  1658. Result:=True;
  1659. end;
  1660. except
  1661. end;
  1662. end;
  1663. procedure TDragDrop.HookMessageHandler;
  1664. begin
  1665. if (FDragDropControl=nil) or (FDragDropControl.Handle=0) then exit;
  1666. if (FMessageHooked=False) and ((FSourceEffects<>0) or (FTargetEffects<>0)) then
  1667. begin
  1668. WndProcPtr:=MakeObjectInstance(WndMethod);
  1669. OldWndProc:=Pointer(SetWindowLong(FDragDropControl.Handle, GWL_WNDPROC,
  1670. LongInt(WndProcPtr)));
  1671. FMessageHooked:=True;
  1672. end;
  1673. end;
  1674. procedure TDragDrop.UnhookMessageHandler(ForceUnhook:Boolean);
  1675. begin
  1676. if FMessageHooked and (ForceUnhook or ((FSourceEffects=0) and (FTargetEffects=0))) then
  1677. begin
  1678. begin
  1679. SetWindowLong(FDragDropControl.Handle, GWL_WNDPROC, LongInt(OldWndProc));
  1680. FreeObjectInstance(WndProcPtr);
  1681. WndProcPtr:=nil;
  1682. OldWndProc:=nil;
  1683. end;
  1684. FMessageHooked:=False;
  1685. end;
  1686. end;
  1687. procedure TDragDrop.DoMenuPopup(Sender: TObject; AMenu: HMenu; DataObj: IDataObject; AMinCustCmd:Integer;
  1688. grfKeyState: LongInt; pt: TPoint);
  1689. begin
  1690. if assigned(FOnMenuPopup) then
  1691. FOnMenuPopup(Sender, AMenu, DataObj, AMinCustCmd, grfKeyState,
  1692. FDragDropControl.ScreenToClient(pt));
  1693. end;
  1694. function TDragDrop.DoMenuExecCmd(Sender: TObject; AMenu: HMenu; DataObj:IDataObject;
  1695. Command:Integer; var dwEffect: LongInt):Boolean;
  1696. begin
  1697. Result:=False;
  1698. if assigned(FOnMenuExecCmd) then
  1699. FOnMenuExecCmd(Sender, AMenu, DataObj, Command, dwEffect, Result);
  1700. end;
  1701. procedure TDragDrop.DoMenuDestroy(Sender:TObject; AMenu: HMenu);
  1702. begin
  1703. if assigned(FOnMenuDestroy) then FOnMenuDestroy(Sender, AMenu);
  1704. end;
  1705. procedure TDragDrop.SetDragDropControl(WinControl: TWinControl);
  1706. begin
  1707. if WinControl<>FDragDropControl then
  1708. begin
  1709. if FRegistered and (csDesigning in ComponentState=False) then
  1710. begin
  1711. UnhookMessageHandler(True);
  1712. UnregisterTarget;
  1713. end;
  1714. FDragDropControl:=WinControl;
  1715. if (csDesigning in ComponentState=False) then RegisterTarget;
  1716. end;
  1717. end;
  1718. function TDragDrop.ExecuteOperation(DataObject:TDataObject): TDragResult;
  1719. var dwEffect: LongInt;
  1720. DropSource: TDropSource;
  1721. pt: tpoint;
  1722. grfKeyState:LongInt;
  1723. begin
  1724. Result:=drInvalid;
  1725. if (DataObject=nil) or (GInternalSource<>nil) then exit;
  1726. GInternalSource:=self;
  1727. if (FSourceEffects<>0) then
  1728. begin
  1729. if MouseHookHandle<>0 then
  1730. begin
  1731. UnHookWindowsHookEx(MouseHookHandle);
  1732. MouseHookHandle:=0;
  1733. end;
  1734. FDragDetectStatus:=ddsDrag;
  1735. DataObject.FCheckLindex:=CheckLindex in FSrcCompatibilityCheck;
  1736. DataObject.FCheckdwAspect:=CheckdwAspect in FSrcCompatibilityCheck;
  1737. try
  1738. FOwnerIsSource:=True;
  1739. try
  1740. DropSource:=TDropSource.Create(self);
  1741. try
  1742. if (DataObject<>nil) and (DragDropControl<>nil) and
  1743. (DoDragDrop(IDataObject(DataObject), DropSource,
  1744. FSourceEffects, dwEffect)=DRAGDROP_S_DROP) then
  1745. begin
  1746. case dwEffect and ((DropEffect_Copy or
  1747. DropEffect_Move or DropEffect_Link)) of
  1748. DropEffect_Copy: Result:=drCopy;
  1749. DropEffect_Move: Result:=drMove;
  1750. DropEffect_Link: Result:=drLink;
  1751. else
  1752. begin
  1753. {MP dropped on no-drop location or }
  1754. {cancelled by ddext after drop with move-effect}
  1755. Result:=drInvalid;
  1756. end;
  1757. end;
  1758. end
  1759. else
  1760. begin
  1761. {MP cancelled by user }
  1762. Result:=drCancelled;
  1763. end;
  1764. finally
  1765. DropSource._Release;
  1766. end;
  1767. except
  1768. Result:=drInvalid;
  1769. raise;
  1770. end;
  1771. finally
  1772. FOwnerIsSource:=False;
  1773. DataObject._Release;
  1774. end;
  1775. FDragDetectStatus:=ddsNone;
  1776. if assigned(FOnDragDetect) then
  1777. begin
  1778. GetCursorPos(pt);
  1779. if HiWord(DWord(GetKeyState(VK_SHIFT)))<>0 then grfKeyState:=MK_SHIFT
  1780. else grfKeyState:=0;
  1781. if HiWord(DWord(GetKeyState(VK_CONTROL)))<>0 then
  1782. grfKeyState:=grfKeyState or MK_CONTROL;
  1783. FOnDragDetect(grfKeyState,
  1784. FDragDropControl.ScreenToClient(FDragDetectStart),
  1785. FDragDropControl.ScreenToClient(pt), FDragDetectStatus);
  1786. end;
  1787. end
  1788. else
  1789. begin
  1790. FDragDetectStatus:=ddsNone;
  1791. Result:=drCancelled;
  1792. end;
  1793. GInternalSource:=nil;
  1794. end;
  1795. function TDragDrop.Execute: TDragResult;
  1796. begin
  1797. Result:=ExecuteOperation(CreateDataObject);
  1798. end;
  1799. procedure TDragDrop.SetSourceEffects(Values:TDropEffectSet);
  1800. begin
  1801. FSourceEffectsSet:=Values;
  1802. FSourceEffects:=0;
  1803. if deCopy in Values then inc(FSourceEffects,DROPEFFECT_COPY);
  1804. if deMove in Values then inc(FSourceEffects,DROPEFFECT_MOVE);
  1805. if deLink in Values then inc(FSourceEffects,DROPEFFECT_LINK);
  1806. if (csDesigning in ComponentState=False) and (csLoading in ComponentState=False) then
  1807. begin
  1808. if (csDesigning in ComponentState=False) and (FMessageHooked=False) and
  1809. (FSourceEffects<>0) then HookMessageHandler;
  1810. if (csDesigning in ComponentState=False) and (FMessageHooked=True) and
  1811. (FSourceEffects=0) then UnhookMessageHandler(False);
  1812. end;
  1813. end;
  1814. procedure TDragDrop.SetTargetEffects(Values:TDropEffectSet);
  1815. begin
  1816. FTargetEffectsSet:=Values;
  1817. FTargetEffects:=0;
  1818. if deCopy in Values then inc(FTargetEffects,DROPEFFECT_COPY);
  1819. if deMove in Values then inc(FTargetEffects,DROPEFFECT_MOVE);
  1820. if deLink in Values then inc(FTargetEffects,DROPEFFECT_LINK);
  1821. if (csDesigning in ComponentState=False) and (FRegistered=False) and
  1822. (FTargetEffects<>0) then RegisterTarget;
  1823. if (FRegistered=True) and (FTargetEffects=0) then
  1824. UnRegisterTarget;
  1825. end;
  1826. function TDragDrop.CopyToClipboard:Boolean;
  1827. var DataObject:IDataObject;
  1828. begin
  1829. Result:=False;
  1830. DataObject:=CreateDataObject;
  1831. if DataObject=nil then exit;
  1832. try
  1833. Result:=OLESetClipBoard(DataObject)=S_Ok;
  1834. finally
  1835. DataObject._Release;
  1836. end;
  1837. end;
  1838. function TDragDrop.GetFromClipboard:Boolean;
  1839. var DataObject:IDataObject;
  1840. pt:TPoint;
  1841. dwEffect:LongInt;
  1842. begin
  1843. Result:=OLEGetClipBoard(DataObject)=S_Ok;
  1844. if Result then
  1845. begin
  1846. pt.x:=-1;
  1847. pt.y:=-1;
  1848. dwEffect:=DropEffect_Copy;
  1849. FDropTarget.RenderDropped(DataObject, 0, pt, dwEffect);
  1850. end;
  1851. end;
  1852. function TDragDrop.DropHandler(const dataObj: IDataObject; grfKeyState: LongInt;
  1853. pt: TPoint; var dwEffect: LongInt): Boolean;
  1854. begin
  1855. Result:=False;
  1856. end;
  1857. // Register method -------------------------------------------------------------
  1858. procedure Register;
  1859. begin
  1860. RegisterComponents('DragDrop', [TDragDrop]);
  1861. end;
  1862. // initialize/de-initialize the ole libary -------------------------------------
  1863. initialization
  1864. OleInitialize(nil);
  1865. MouseHookHandle := 0;
  1866. GInternalSource := nil;
  1867. // to avoid mix ups
  1868. DDM_ProcessDropped := RegisterWindowMessage('DDM_ProcessDropped');
  1869. finalization
  1870. if MouseHookHandle <> 0 then UnHookWindowsHookEx(MouseHookHandle);
  1871. OleUninitialize;
  1872. end.