DragDrop.pas 68 KB

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