DragDrop.pas 69 KB

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