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