DragDrop.pas 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959
  1. unit DragDrop;
  2. // -----------------------------------------------------------------------------
  3. // Project: Drag and Drop Component Suite
  4. // Module: DragDrop
  5. // Description: Implements base classes and utility functions.
  6. // Version: 4.0
  7. // Date: 18-MAY-2001
  8. // Target: Win32, Delphi 5-6
  9. // Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
  10. // Copyright © 1997-2001 Angus Johnson & Anders Melander
  11. // -----------------------------------------------------------------------------
  12. // TODO -oanme -cPortability : Replace all public use of HWND with THandle. BCB's HWND <> Delphi's HWND.
  13. {$include DragDrop.inc}
  14. interface
  15. uses
  16. Classes,
  17. Windows,
  18. ActiveX;
  19. {$IFDEF BCB}
  20. {$HPPEMIT '#ifndef NO_WIN32_LEAN_AND_MEAN'}
  21. {$HPPEMIT '"Error: The NO_WIN32_LEAN_AND_MEAN symbol must be defined in your projects conditional defines"'}
  22. {$HPPEMIT '#endif'}
  23. {$ENDIF}
  24. const
  25. DROPEFFECT_NONE = ActiveX.DROPEFFECT_NONE;
  26. DROPEFFECT_COPY = ActiveX.DROPEFFECT_COPY;
  27. DROPEFFECT_MOVE = ActiveX.DROPEFFECT_MOVE;
  28. DROPEFFECT_LINK = ActiveX.DROPEFFECT_LINK;
  29. DROPEFFECT_SCROLL = ActiveX.DROPEFFECT_SCROLL;
  30. type
  31. // TDragType enumerates the three possible drag/drop operations.
  32. TDragType = (dtCopy, dtMove, dtLink);
  33. TDragTypes = set of TDragType;
  34. type
  35. // TDataDirection is used by the clipboard format registration to specify
  36. // if the clipboard format should be listed in get (read) format enumerations,
  37. // set (write) format enumerations or both.
  38. // ddRead : Destination (IDropTarget) can read data from IDataObject.
  39. // ddWrite : Destination (IDropTarget) can write data to IDataObject.
  40. TDataDirection = (ddRead, ddWrite);
  41. TDataDirections = set of TDataDirection;
  42. const
  43. ddReadWrite = [ddRead, ddWrite];
  44. type
  45. // TConversionScope is used by the clipboard format registration to specify
  46. // if a clipboard format conversion is supported by the drop source, the drop
  47. // target or both.
  48. // ddSource : Conversion is valid for drop source (IDropSource).
  49. // ddTarget : Conversion is valid for drop target (IDropTarget).
  50. TConversionScope = (csSource, csTarget);
  51. TConversionScopes = set of TConversionScope;
  52. const
  53. csSourceTarget = [csSource, csTarget];
  54. // C++ Builder's declaration of IEnumFORMATETC is incorrect, so we must generate
  55. // the typedef for C++ Builder.
  56. {$IFDEF BCB}
  57. {$HPPEMIT 'typedef System::DelphiInterface<IEnumFORMATETC> _di_IEnumFORMATETC;' }
  58. {$ENDIF}
  59. ////////////////////////////////////////////////////////////////////////////////
  60. //
  61. // TInterfacedComponent
  62. //
  63. ////////////////////////////////////////////////////////////////////////////////
  64. // Top level base class for the drag/drop component hierachy.
  65. // Implements the IUnknown interface.
  66. // Corresponds to TInterfacedObject (see VCL on-line help), but descends from
  67. // TComponent instead of TObject.
  68. // Reference counting is disabled (_AddRef and _Release methods does nothing)
  69. // since the component life span is controlled by the component owner.
  70. ////////////////////////////////////////////////////////////////////////////////
  71. type
  72. TInterfacedComponent = class(TComponent, IUnknown)
  73. protected
  74. function QueryInterface(const IID: TGuid; out Obj): HRESULT;
  75. {$IFDEF VER13_PLUS} override; {$ELSE}
  76. {$IFDEF VER12_PLUS} reintroduce; {$ENDIF}{$ENDIF} stdcall;
  77. function _AddRef: Integer; stdcall;
  78. function _Release: Integer; stdcall;
  79. end;
  80. ////////////////////////////////////////////////////////////////////////////////
  81. //
  82. // TClipboardFormat
  83. //
  84. ////////////////////////////////////////////////////////////////////////////////
  85. // Abstract base class. Extracts or injects data of a specific low level format
  86. // from or to an IDataObject.
  87. ////////////////////////////////////////////////////////////////////////////////
  88. type
  89. TCustomDataFormat = class;
  90. TClipboardFormat = class(TObject)
  91. private
  92. FDataDirections: TDataDirections;
  93. FDataFormat: TCustomDataFormat;
  94. protected
  95. FFormatEtc: TFormatEtc;
  96. constructor CreateFormat(Atymed: Longint); virtual;
  97. constructor CreateFormatEtc(const AFormatEtc: TFormatEtc); virtual;
  98. { Extracts data from the specified medium }
  99. function DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean; virtual;
  100. { Transfer data to the specified medium }
  101. function DoSetData(const FormatEtcIn: TFormatEtc;
  102. var AMedium: TStgMedium): boolean; virtual;
  103. function GetClipboardFormat: TClipFormat; virtual;
  104. procedure SetClipboardFormat(Value: TClipFormat); virtual;
  105. function GetClipboardFormatName: string; virtual;
  106. procedure SetClipboardFormatName(const Value: string); virtual;
  107. procedure SetFormatEtc(const Value: TFormatEtc);
  108. public
  109. constructor Create; virtual; abstract;
  110. destructor Destroy; override;
  111. { Determines if the object can read from the specified data object }
  112. function HasValidFormats(ADataObject: IDataObject): boolean; virtual;
  113. { Determines if the object can read the specified format }
  114. function AcceptFormat(const AFormatEtc: TFormatEtc): boolean; virtual;
  115. { Extracts data from the specified IDataObject }
  116. function GetData(ADataObject: IDataObject): boolean; virtual;
  117. { Extracts data from the specified IDataObject via the specified medium }
  118. function GetDataFromMedium(ADataObject: IDataObject;
  119. var AMedium: TStgMedium): boolean; virtual;
  120. { Transfers data to the specified IDataObject }
  121. function SetData(ADataObject: IDataObject; const FormatEtcIn: TFormatEtc;
  122. var AMedium: TStgMedium): boolean; virtual;
  123. { Transfers data to the specified medium }
  124. function SetDataToMedium(const FormatEtcIn: TFormatEtc;
  125. var AMedium: TStgMedium): boolean;
  126. { Copies data from the specified source format to the object }
  127. function Assign(Source: TCustomDataFormat): boolean; virtual;
  128. { Copies data from the object to the specified target format }
  129. function AssignTo(Dest: TCustomDataFormat): boolean; virtual;
  130. { Clears the objects data }
  131. procedure Clear; virtual; abstract;
  132. { Returns true if object can supply data }
  133. function HasData: boolean; virtual;
  134. { Unregisters the clipboard format and all mappings involving it from the global database }
  135. class procedure UnregisterClipboardFormat;
  136. { Returns the clipboard format value }
  137. property ClipboardFormat: TClipFormat read GetClipboardFormat
  138. write SetClipboardFormat;
  139. { Returns the clipboard format name }
  140. property ClipboardFormatName: string read GetClipboardFormatName
  141. write SetClipboardFormatName;
  142. { Provides access to the objects format specification }
  143. property FormatEtc: TFormatEtc read FFormatEtc;
  144. { Specifies whether the format can read and write data }
  145. property DataDirections: TDataDirections read FDataDirections
  146. write FDataDirections;
  147. { Specifies the data format which owns and controls this clipboard format }
  148. property DataFormat: TCustomDataFormat read FDataFormat write FDataFormat;
  149. end;
  150. TClipboardFormatClass = class of TClipboardFormat;
  151. // TClipboardFormats
  152. // List of TClipboardFormat objects.
  153. TClipboardFormats = class(TObject)
  154. private
  155. FList: TList;
  156. FOwnsObjects: boolean;
  157. FDataFormat: TCustomDataFormat;
  158. protected
  159. function GetFormat(Index: integer): TClipboardFormat;
  160. function GetCount: integer;
  161. public
  162. constructor Create(ADataFormat: TCustomDataFormat; AOwnsObjects: boolean);
  163. destructor Destroy; override;
  164. procedure Clear;
  165. function Add(ClipboardFormat: TClipboardFormat): integer;
  166. function Contain(ClipboardFormatClass: TClipboardFormatClass): boolean;
  167. function FindFormat(ClipboardFormatClass: TClipboardFormatClass): TClipboardFormat;
  168. property Formats[Index: integer]: TClipboardFormat read GetFormat; default;
  169. property Count: integer read GetCount;
  170. property DataFormat: TCustomDataFormat read FDataFormat;
  171. end;
  172. ////////////////////////////////////////////////////////////////////////////////
  173. //
  174. // TDragDropComponent
  175. //
  176. ////////////////////////////////////////////////////////////////////////////////
  177. // Base class for drag/drop components.
  178. ////////////////////////////////////////////////////////////////////////////////
  179. TDataFormats = class;
  180. TDragDropComponent = class(TInterfacedComponent)
  181. private
  182. protected
  183. FDataFormats: TDataFormats;
  184. //: Only used by TCustomDropMultiSource and TCustomDropMultiTarget and
  185. // their descendants.
  186. property DataFormats: TDataFormats read FDataFormats;
  187. public
  188. end;
  189. ////////////////////////////////////////////////////////////////////////////////
  190. //
  191. // TCustomFormat
  192. //
  193. ////////////////////////////////////////////////////////////////////////////////
  194. // Abstract base class.
  195. // Renders the data of one or more TClipboardFormat objects to or from a
  196. // specific high level data format.
  197. ////////////////////////////////////////////////////////////////////////////////
  198. TCustomDataFormat = class(TObject)
  199. private
  200. FCompatibleFormats : TClipboardFormats;
  201. FFormatList : TDataFormats;
  202. FOwner : TDragDropComponent;
  203. FOnChanging : TNotifyEvent;
  204. protected
  205. { Determines if the object can accept data from the specified source format }
  206. function SupportsFormat(ClipboardFormat: TClipboardFormat): boolean;
  207. procedure DoOnChanging(Sender: TObject);
  208. procedure Changing; virtual;
  209. property FormatList: TDataFormats read FFormatList;
  210. public
  211. constructor Create(AOwner: TDragDropComponent); virtual;
  212. destructor Destroy; override;
  213. procedure Clear; virtual; abstract;
  214. { Copies data between the specified clipboard format to the object }
  215. function Assign(Source: TClipboardFormat): boolean; virtual;
  216. function AssignTo(Dest: TClipboardFormat): boolean; virtual;
  217. { Extracts data from the specified IDataObject }
  218. function GetData(DataObject: IDataObject): boolean; virtual;
  219. { Determines if the object contains *any* data }
  220. function HasData: boolean; virtual; abstract;
  221. { Determines if the object needs/can use *more* data }
  222. function NeedsData: boolean; virtual;
  223. { Determines if the object can read from the specified data object }
  224. function HasValidFormats(ADataObject: IDataObject): boolean; virtual;
  225. { Determines if the object can read the specified format }
  226. function AcceptFormat(const FormatEtc: TFormatEtc): boolean; virtual;
  227. { Registers the data format in the data format list }
  228. class procedure RegisterDataFormat;
  229. { Registers the specified clipboard format as being compatible with the data format }
  230. class procedure RegisterCompatibleFormat(ClipboardFormatClass: TClipboardFormatClass;
  231. Priority: integer {$ifdef VER12_PLUS} = 0 {$endif};
  232. ConversionScopes: TConversionScopes {$ifdef VER12_PLUS} = csSourceTarget {$endif};
  233. DataDirections: TDataDirections {$ifdef VER12_PLUS} = [ddRead] {$endif});
  234. { Unregisters the specified clipboard format from the compatibility list }
  235. class procedure UnregisterCompatibleFormat(ClipboardFormatClass: TClipboardFormatClass);
  236. { Unregisters data format and all mappings involving it from the global database }
  237. class procedure UnregisterDataFormat;
  238. { List of compatible source formats }
  239. property CompatibleFormats: TClipboardFormats read FCompatibleFormats;
  240. property Owner: TDragDropComponent read FOwner;
  241. property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
  242. // TODO : Add support for delayed rendering with DelayedRender property.
  243. end;
  244. // TDataFormats
  245. // List of TCustomDataFormat objects.
  246. TDataFormats = class(TObject)
  247. private
  248. FList: TList;
  249. protected
  250. function GetFormat(Index: integer): TCustomDataFormat;
  251. function GetCount: integer;
  252. public
  253. constructor Create;
  254. destructor Destroy; override;
  255. function Add(DataFormat: TCustomDataFormat): integer; virtual;
  256. function IndexOf(DataFormat: TCustomDataFormat): integer; virtual;
  257. procedure Remove(DataFormat: TCustomDataFormat); virtual;
  258. property Formats[Index: integer]: TCustomDataFormat read GetFormat; default;
  259. property Count: integer read GetCount;
  260. end;
  261. // TDataFormatClasses
  262. // List of TCustomDataFormat classes.
  263. TDataFormatClass = class of TCustomDataFormat;
  264. TDataFormatClasses = class(TObject)
  265. private
  266. FList: TList;
  267. protected
  268. function GetFormat(Index: integer): TDataFormatClass;
  269. function GetCount: integer;
  270. { Provides singleton access to the global data format database }
  271. class function Instance: TDataFormatClasses;
  272. public
  273. constructor Create;
  274. destructor Destroy; override;
  275. function Add(DataFormat: TDataFormatClass): integer; virtual;
  276. procedure Remove(DataFormat: TDataFormatClass); virtual;
  277. property Formats[Index: integer]: TDataFormatClass read GetFormat; default;
  278. property Count: integer read GetCount;
  279. end;
  280. // TDataFormatMap
  281. // Format conversion database. Contains mappings between TClipboardFormat
  282. // and TCustomDataFormat.
  283. // Used internally by TCustomDropMultiTarget and TCustomDropMultiSource.
  284. TDataFormatMap = class(TObject)
  285. FList: TList;
  286. protected
  287. function FindMap(DataFormatClass: TDataFormatClass; ClipboardFormatClass: TClipboardFormatClass): integer;
  288. procedure Sort;
  289. { Provides singleton access to the global format map database }
  290. class function Instance: TDataFormatMap;
  291. public
  292. constructor Create;
  293. destructor Destroy; override;
  294. procedure Add(DataFormatClass: TDataFormatClass;
  295. ClipboardFormatClass: TClipboardFormatClass;
  296. Priority: integer {$ifdef VER12_PLUS} = 0 {$endif};
  297. ConversionScopes: TConversionScopes {$ifdef VER12_PLUS} = csSourceTarget {$endif};
  298. DataDirections: TDataDirections {$ifdef VER12_PLUS} = [ddRead] {$endif});
  299. procedure Delete(DataFormatClass: TDataFormatClass;
  300. ClipboardFormatClass: TClipboardFormatClass);
  301. procedure DeleteByClipboardFormat(ClipboardFormatClass: TClipboardFormatClass);
  302. procedure DeleteByDataFormat(DataFormatClass: TDataFormatClass);
  303. procedure GetSourceByDataFormat(DataFormatClass: TDataFormatClass;
  304. ClipboardFormats: TClipboardFormats; ConversionScope: TConversionScope);
  305. function CanMap(DataFormatClass: TDataFormatClass;
  306. ClipboardFormatClass: TClipboardFormatClass): boolean;
  307. { Registers the specified format mapping }
  308. procedure RegisterFormatMap(DataFormatClass: TDataFormatClass;
  309. ClipboardFormatClass: TClipboardFormatClass;
  310. Priority: integer {$ifdef VER12_PLUS} = 0 {$endif};
  311. ConversionScopes: TConversionScopes {$ifdef VER12_PLUS} = csSourceTarget {$endif};
  312. DataDirections: TDataDirections {$ifdef VER12_PLUS} = [ddRead] {$endif});
  313. { Unregisters the specified format mapping }
  314. procedure UnregisterFormatMap(DataFormatClass: TDataFormatClass;
  315. ClipboardFormatClass: TClipboardFormatClass);
  316. end;
  317. ////////////////////////////////////////////////////////////////////////////////
  318. //
  319. // TDataFormatAdapter
  320. //
  321. ////////////////////////////////////////////////////////////////////////////////
  322. // Helper component used to add additional data formats to a drop source or
  323. // target at design time.
  324. // Requires that data formats have been registered with
  325. // TCustomDataFormat.RegisterDataFormat.
  326. ////////////////////////////////////////////////////////////////////////////////
  327. TDataFormatAdapter = class(TComponent)
  328. private
  329. FDragDropComponent: TDragDropComponent;
  330. FDataFormat: TCustomDataFormat;
  331. FDataFormatClass: TDataFormatClass;
  332. FEnabled: boolean;
  333. function GetDataFormatName: string;
  334. procedure SetDataFormatName(const Value: string);
  335. protected
  336. procedure SetDataFormatClass(const Value: TDataFormatClass);
  337. procedure SetDragDropComponent(const Value: TDragDropComponent);
  338. function GetEnabled: boolean;
  339. procedure SetEnabled(const Value: boolean);
  340. procedure Notification(AComponent: TComponent;
  341. Operation: TOperation); override;
  342. procedure Loaded; override;
  343. public
  344. destructor Destroy; override;
  345. property DataFormatClass: TDataFormatClass read FDataFormatClass
  346. write SetDataFormatClass;
  347. property DataFormat: TCustomDataFormat read FDataFormat;
  348. published
  349. property DragDropComponent: TDragDropComponent read FDragDropComponent
  350. write SetDragDropComponent;
  351. property DataFormatName: string read GetDataFormatName
  352. write SetDataFormatName;
  353. property Enabled: boolean read GetEnabled write SetEnabled;
  354. end;
  355. ////////////////////////////////////////////////////////////////////////////////
  356. //
  357. // Drag Drop helper interfaces
  358. //
  359. ////////////////////////////////////////////////////////////////////////////////
  360. // Requires Windows 2000 or later.
  361. ////////////////////////////////////////////////////////////////////////////////
  362. type
  363. PSHDRAGIMAGE = ^TSHDRAGIMAGE;
  364. {_$EXTERNALSYM _SHDRAGIMAGE}
  365. _SHDRAGIMAGE = packed record
  366. sizeDragImage: TSize; { The length and Width of the rendered image }
  367. ptOffset: TPoint; { The Offset from the mouse cursor to the upper left corner of the image }
  368. hbmpDragImage: HBitmap; { The Bitmap containing the rendered drag images }
  369. crColorKey: COLORREF; { The COLORREF that has been blitted to the background of the images }
  370. end;
  371. TSHDRAGIMAGE = _SHDRAGIMAGE;
  372. {_$EXTERNALSYM SHDRAGIMAGE}
  373. SHDRAGIMAGE = _SHDRAGIMAGE;
  374. const
  375. CLSID_DragDropHelper: TGUID = (
  376. D1:$4657278a; D2:$411b; D3:$11d2; D4:($83,$9a,$00,$c0,$4f,$d9,$18,$d0));
  377. SID_DragDropHelper = '{4657278A-411B-11d2-839A-00C04FD918D0}';
  378. const
  379. IID_IDropTargetHelper: TGUID = (
  380. D1:$4657278b; D2:$411b; D3:$11d2; D4:($83,$9a,$00,$c0,$4f,$d9,$18,$d0));
  381. SID_IDropTargetHelper = '{4657278B-411B-11d2-839A-00C04FD918D0}';
  382. type
  383. {_$HPPEMIT 'typedef DragDrop::DelphiInterface<IDropTargetHelper> _di_IDropTargetHelper;'}
  384. {_$EXTERNALSYM IDropTargetHelper}
  385. IDropTargetHelper = interface(IUnknown)
  386. [SID_IDropTargetHelper]
  387. function DragEnter(hwndTarget: HWND; const DataObj: IDataObject;
  388. var pt: TPoint; dwEffect: Longint): HResult; stdcall;
  389. function DragLeave: HResult; stdcall;
  390. function DragOver(var pt: TPoint; dwEffect: longInt): HResult; stdcall;
  391. function Drop(const DataObj: IDataObject; var pt: TPoint;
  392. dwEffect: longInt): HResult; stdcall;
  393. function Show(Show: BOOL): HResult; stdcall;
  394. end;
  395. const
  396. IID_IDragSourceHelper: TGUID = (
  397. D1:$de5bf786; D2:$477a; D3:$11d2; D4:($83,$9d,$00,$c0,$4f,$d9,$18,$d0));
  398. SID_IDragSourceHelper = '{DE5BF786-477A-11d2-839D-00C04FD918D0}';
  399. type
  400. {_$HPPEMIT 'typedef DragDrop::DelphiInterface<IDragSourceHelper> _di_IDragSourceHelper;'}
  401. {_$EXTERNALSYM IDragSourceHelper}
  402. IDragSourceHelper = interface(IUnknown)
  403. [SID_IDragSourceHelper]
  404. function InitializeFromBitmap(var shdi: TSHDRAGIMAGE;
  405. const DataObj: IDataObject): HResult; stdcall;
  406. function InitializeFromWindow(hwnd: HWND; var pt: TPoint;
  407. const DataObj: IDataObject): HResult; stdcall;
  408. end;
  409. ////////////////////////////////////////////////////////////////////////////////
  410. //
  411. // Async data transfer interfaces
  412. //
  413. ////////////////////////////////////////////////////////////////////////////////
  414. // Requires Windows 2000 or later.
  415. ////////////////////////////////////////////////////////////////////////////////
  416. const
  417. IID_IAsyncOperation: TGUID = (
  418. D1:$3D8B0590; D2:$F691; D3:$11D2; D4:($8E,$A9,$00,$60,$97,$DF,$5B,$D4));
  419. SID_IAsyncOperation = '{3D8B0590-F691-11D2-8EA9-006097DF5BD4}';
  420. type
  421. {_$HPPEMIT 'typedef DragDrop::DelphiInterface<IAsyncOperation> _di_IAsyncOperation;'}
  422. {_$EXTERNALSYM IAsyncOperation}
  423. IAsyncOperation = interface(IUnknown)
  424. [SID_IAsyncOperation]
  425. function SetAsyncMode(fDoOpAsync: BOOL): HResult; stdcall;
  426. function GetAsyncMode(out fDoOpAsync: BOOL): HResult; stdcall;
  427. function StartOperation(const pbcReserved: IBindCtx): HResult; stdcall;
  428. function InOperation(out pfInAsyncOp: BOOL): HResult; stdcall;
  429. function EndOperation(hResult: HRESULT; const pbcReserved: IBindCtx;
  430. dwEffects: DWORD): HResult; stdcall;
  431. end;
  432. ////////////////////////////////////////////////////////////////////////////////
  433. //
  434. // TRawClipboardFormat & TRawDataFormat
  435. //
  436. ////////////////////////////////////////////////////////////////////////////////
  437. // These clipboard and data format classes are special in that they don't
  438. // interpret the data in any way.
  439. // Their primary purpose is to enable the TCustomDropMultiSource class to accept
  440. // and store arbitrary (and unknown) data types. This is a requirement for
  441. // drag drop helper object support.
  442. ////////////////////////////////////////////////////////////////////////////////
  443. // The TRawDataFormat class does not perform any storage of data itself. Instead
  444. // it relies on the TRawClipboardFormat objects to store data.
  445. ////////////////////////////////////////////////////////////////////////////////
  446. TRawDataFormat = class(TCustomDataFormat)
  447. private
  448. FMedium: TStgMedium;
  449. protected
  450. public
  451. procedure Clear; override;
  452. function HasData: boolean; override;
  453. function NeedsData: boolean; override;
  454. property Medium: TStgMedium read FMedium write FMedium;
  455. end;
  456. TRawClipboardFormat = class(TClipboardFormat)
  457. private
  458. FMedium: TStgMedium;
  459. protected
  460. function DoGetData(ADataObject: IDataObject;
  461. const AMedium: TStgMedium): boolean; override;
  462. function DoSetData(const FormatEtcIn: TFormatEtc;
  463. var AMedium: TStgMedium): boolean; override;
  464. procedure SetClipboardFormatName(const Value: string); override;
  465. function GetClipboardFormat: TClipFormat; override;
  466. function GetString: string;
  467. procedure SetString(const Value: string);
  468. public
  469. constructor Create; override;
  470. constructor CreateFormatEtc(const AFormatEtc: TFormatEtc); override;
  471. function Assign(Source: TCustomDataFormat): boolean; override;
  472. function AssignTo(Dest: TCustomDataFormat): boolean; override;
  473. procedure Clear; override;
  474. // Methods to handle the corresponding TRawDataFormat functioinality.
  475. procedure ClearData;
  476. function HasData: boolean; override;
  477. function NeedsData: boolean;
  478. // All of these should be moved/mirrored in TRawDataFormat:
  479. procedure CopyFromStgMedium(const AMedium: TStgMedium);
  480. procedure CopyToStgMedium(var AMedium: TStgMedium);
  481. property AsString: string read GetString write SetString;
  482. property Medium: TStgMedium read FMedium write FMedium;
  483. end;
  484. ////////////////////////////////////////////////////////////////////////////////
  485. //
  486. // Utility functions
  487. //
  488. ////////////////////////////////////////////////////////////////////////////////
  489. function DropEffectToDragType(DropEffect: longInt; var DragType: TDragType): boolean;
  490. function DragTypesToDropEffect(DragTypes: TDragTypes): longint; // V4: New
  491. // Coordinate space conversion.
  492. function ClientPtToWindowPt(Handle: THandle; pt: TPoint): TPoint;
  493. // Replacement for KeysToShiftState.
  494. function KeysToShiftStatePlus(Keys: Word): TShiftState; // V4: New
  495. function ShiftStateToDropEffect(Shift: TShiftState; AllowedEffects: longint;
  496. Fallback: boolean): longint;
  497. // Replacement for the buggy DragDetect API function.
  498. function DragDetectPlus(Handle: THandle; p: TPoint): boolean; // V4: New
  499. // Wrapper for urlmon.CopyStgMedium.
  500. // Note: Only works with IE4 or later installed.
  501. function CopyStgMedium(const SrcMedium: TStgMedium; var DstMedium: TStgMedium): boolean;
  502. // Get the name of a clipboard format as a Delphi string.
  503. function GetClipboardFormatNameStr(Value: TClipFormat): string;
  504. // Raise last Windows API error as an exception.
  505. procedure _RaiseLastWin32Error;
  506. ////////////////////////////////////////////////////////////////////////////////
  507. //
  508. // Global variables
  509. //
  510. ////////////////////////////////////////////////////////////////////////////////
  511. var
  512. ShellMalloc: IMalloc;
  513. // Name of the IDE component palette page the drag drop components are
  514. // registered to
  515. var
  516. DragDropComponentPalettePage: string = 'DragDrop';
  517. ////////////////////////////////////////////////////////////////////////////////
  518. //
  519. // Misc drop target related constants
  520. //
  521. ////////////////////////////////////////////////////////////////////////////////
  522. // Drag Drop constants from ActiveX unit
  523. var
  524. // Default inset-width of the auto scroll hot zone.
  525. // Specified in pixels.
  526. // Not used! Instead the height of the target control's font is used.
  527. DragDropScrollInset: integer = DD_DEFSCROLLINSET; // 11
  528. // Default delay after entering the scroll zone, before scrolling starts.
  529. // Specified in milliseconds.
  530. DragDropScrollDelay: integer = DD_DEFSCROLLDELAY; // 50
  531. // Default scroll interval during auto scroll.
  532. // Specified in milliseconds.
  533. DragDropScrollInterval: integer = DD_DEFSCROLLINTERVAL; // 50
  534. // Default delay before dragging should start.
  535. // Specified in milliseconds.
  536. DragDropDragDelay: integer = DD_DEFDRAGDELAY; // 200
  537. // Default minimum distance (radius) before dragging should start.
  538. // Specified in pixels.
  539. // Not used! Instead the SM_CXDRAG and SM_CYDRAG system metrics are used.
  540. DragDropDragMinDistance: integer = DD_DEFDRAGMINDIST; // 2
  541. ////////////////////////////////////////////////////////////////////////////////
  542. //
  543. // Misc drag drop API related constants
  544. //
  545. ////////////////////////////////////////////////////////////////////////////////
  546. // The following DVASPECT constants are missing from some versions of Delphi and
  547. // C++ Builder.
  548. {$ifndef VER135_PLUS}
  549. const
  550. {$ifndef VER10_PLUS}
  551. DVASPECT_SHORTNAME = 2; // use for CF_HDROP to get short name version of file paths
  552. {$endif}
  553. DVASPECT_COPY = 3; // use to indicate format is a "Copy" of the data (FILECONTENTS, FILEDESCRIPTOR, etc)
  554. DVASPECT_LINK = 4; // use to indicate format is a "Shortcut" to the data (FILECONTENTS, FILEDESCRIPTOR, etc)
  555. {$endif}
  556. ////////////////////////////////////////////////////////////////////////////////
  557. //
  558. // Component registration
  559. //
  560. ////////////////////////////////////////////////////////////////////////////////
  561. procedure Register;
  562. (*******************************************************************************
  563. **
  564. ** IMPLEMENTATION
  565. **
  566. *******************************************************************************)
  567. implementation
  568. uses
  569. {$ifdef DEBUG}
  570. ComObj,
  571. {$endif}
  572. DropSource,
  573. DropTarget,
  574. DragDropFormats, // Used by TRawClipboardFormat
  575. Messages,
  576. ShlObj,
  577. MMSystem,
  578. SysUtils;
  579. resourcestring
  580. sImplementationRequired = 'Internal error: %s.%s needs implementation';
  581. sInvalidOwnerType = '%s is not a valid owner for %s. Owner must be derived from %s';
  582. sFormatNameReadOnly = '%s.ClipboardFormat is read-only';
  583. sNoCopyStgMedium = 'A required system function (URLMON.CopyStgMedium) was not available on this system. Operation aborted.';
  584. sBadConstructor = 'The %s class can not be instantiated with the default constructor';
  585. sUnregisteredDataFormat = 'The %s data format has not been registered by any of the used units';
  586. ////////////////////////////////////////////////////////////////////////////////
  587. //
  588. // Component registration
  589. //
  590. ////////////////////////////////////////////////////////////////////////////////
  591. procedure Register;
  592. begin
  593. RegisterComponents(DragDropComponentPalettePage, [TDataFormatAdapter]);
  594. end;
  595. ////////////////////////////////////////////////////////////////////////////////
  596. //
  597. // TInterfacedComponent
  598. //
  599. ////////////////////////////////////////////////////////////////////////////////
  600. function TInterfacedComponent.QueryInterface(const IID: TGuid; out Obj): HRESULT;
  601. {$ifdef DEBUG}
  602. function GuidToString(const IID: TGuid): string;
  603. var
  604. GUID: string;
  605. begin
  606. GUID := ComObj.GUIDToString(IID);
  607. Result := GetRegStringValue('Interface\'+GUID, '');
  608. if (Result = '') then
  609. Result := GUID;
  610. end;
  611. {$endif}
  612. begin
  613. {$ifdef VER12_PLUS}
  614. if GetInterface(IID, Obj) then
  615. Result := 0
  616. else if (VCLComObject <> nil) then
  617. Result := IVCLComObject(VCLComObject).QueryInterface(IID, Obj)
  618. else
  619. Result := E_NOINTERFACE;
  620. {$else}
  621. Result := inherited QueryInterface(IID, Obj);
  622. {$endif}
  623. {$ifdef DEBUG}
  624. OutputDebugString(PChar(format('%s.QueryInterface(%s): %d (%d)',
  625. [ClassName, GuidToString(IID), Result, ord(pointer(Obj) <> nil)])));
  626. {$endif}
  627. end;
  628. function TInterfacedComponent._AddRef: Integer;
  629. var
  630. Outer: IUnknown;
  631. begin
  632. // In case we are the inner object of an aggregation, we attempt to delegate
  633. // the reference counting to the outer object. We assume that the component
  634. // owner is the outer object.
  635. if (Owner <> nil) and (Owner.GetInterface(IUnknown, Outer)) then
  636. Result := Outer._AddRef
  637. else
  638. begin
  639. {$ifdef VER12_PLUS}
  640. inherited _AddRef;
  641. {$else}
  642. if (VCLComObject <> nil) then
  643. inherited _AddRef;
  644. {$endif}
  645. Result := -1;
  646. end;
  647. end;
  648. function TInterfacedComponent._Release: Integer;
  649. var
  650. Outer: IUnknown;
  651. begin
  652. // See _AddRef for comments.
  653. if (Owner <> nil) and (Owner.GetInterface(IUnknown, Outer)) then
  654. Result := Outer._Release
  655. else
  656. begin
  657. {$ifdef VER12_PLUS}
  658. inherited _Release;
  659. {$else}
  660. if (VCLComObject <> nil) then
  661. inherited _Release;
  662. {$endif}
  663. Result := -1;
  664. end;
  665. end;
  666. ////////////////////////////////////////////////////////////////////////////////
  667. //
  668. // TClipboardFormat
  669. //
  670. ////////////////////////////////////////////////////////////////////////////////
  671. destructor TClipboardFormat.Destroy;
  672. begin
  673. // Warning: Do not call Clear here. Descendant class has already
  674. // cleaned up and released resources!
  675. inherited Destroy;
  676. end;
  677. constructor TClipboardFormat.CreateFormat(Atymed: Longint);
  678. begin
  679. inherited Create;
  680. FDataDirections := [ddRead];
  681. FFormatEtc.cfFormat := ClipboardFormat;
  682. FFormatEtc.ptd := nil;
  683. FFormatEtc.dwAspect := DVASPECT_CONTENT;
  684. FFormatEtc.lindex := -1;
  685. FFormatEtc.tymed := Atymed;
  686. end;
  687. constructor TClipboardFormat.CreateFormatEtc(const AFormatEtc: TFormatEtc);
  688. begin
  689. inherited Create;
  690. FDataDirections := [ddRead];
  691. FFormatEtc := AFormatEtc;
  692. end;
  693. function TClipboardFormat.HasValidFormats(ADataObject: IDataObject): boolean;
  694. begin
  695. Result := (ADataObject.QueryGetData(FormatEtc) = S_OK);
  696. end;
  697. function TClipboardFormat.AcceptFormat(const AFormatEtc: TFormatEtc): boolean;
  698. begin
  699. Result := (AFormatEtc.cfFormat = FFormatEtc.cfFormat) and
  700. (AFormatEtc.ptd = nil) and
  701. (AFormatEtc.dwAspect = FFormatEtc.dwAspect) and
  702. (AFormatEtc.tymed AND FFormatEtc.tymed <> 0);
  703. end;
  704. function TClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
  705. begin
  706. Result := False;
  707. end;
  708. function TClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
  709. begin
  710. Result := False;
  711. end;
  712. function TClipboardFormat.DoGetData(ADataObject: IDataObject; const AMedium: TStgMedium): boolean;
  713. begin
  714. Result := False;
  715. end;
  716. function TClipboardFormat.DoSetData(const FormatEtcIn: TFormatEtc;
  717. var AMedium: TStgMedium): boolean;
  718. begin
  719. Result := False;
  720. end;
  721. function TClipboardFormat.GetData(ADataObject: IDataObject): boolean;
  722. var
  723. Medium : TStgMedium;
  724. begin
  725. Result := False;
  726. Clear;
  727. if (ADataObject.GetData(FFormatEtc, Medium) <> S_OK) then
  728. exit;
  729. Result := GetDataFromMedium(ADataObject, Medium);
  730. end;
  731. function TClipboardFormat.GetDataFromMedium(ADataObject: IDataObject;
  732. var AMedium: TStgMedium): boolean;
  733. begin
  734. Result := False;
  735. try
  736. Clear;
  737. if ((AMedium.tymed AND FFormatEtc.tymed) <> 0) then
  738. Result := DoGetData(ADataObject, AMedium);
  739. finally
  740. ReleaseStgMedium(AMedium);
  741. end;
  742. end;
  743. function TClipboardFormat.SetDataToMedium(const FormatEtcIn: TFormatEtc;
  744. var AMedium: TStgMedium): boolean;
  745. begin
  746. Result := False;
  747. FillChar(AMedium, SizeOf(AMedium), 0);
  748. if (FormatEtcIn.cfFormat <> FFormatEtc.cfFormat) or
  749. (FormatEtcIn.dwAspect <> FFormatEtc.dwAspect) or
  750. (FormatEtcIn.tymed and FFormatEtc.tymed = 0) then
  751. exit;
  752. // Call descendant to allocate medium and transfer data to it
  753. Result := DoSetData(FormatEtcIn, AMedium);
  754. end;
  755. function TClipboardFormat.SetData(ADataObject: IDataObject;
  756. const FormatEtcIn: TFormatEtc; var AMedium: TStgMedium): boolean;
  757. begin
  758. // Transfer data to medium
  759. Result := SetDataToMedium(FormatEtcIn, AMedium);
  760. // Call IDataObject to set data
  761. if (Result) then
  762. Result := (ADataObject.SetData(FormatEtc, AMedium, True) = S_OK);
  763. // If we didn't succeed in transfering ownership of the data medium to the
  764. // IDataObject, we must deallocate the medium ourselves.
  765. if (not Result) then
  766. ReleaseStgMedium(AMedium);
  767. end;
  768. class procedure TClipboardFormat.UnregisterClipboardFormat;
  769. begin
  770. TDataFormatMap.Instance.DeleteByClipboardFormat(Self);
  771. end;
  772. function TClipboardFormat.GetClipboardFormat: TClipFormat;
  773. begin
  774. // This should have been a virtual abstract class method, but this isn't supported by C++ Builder.
  775. raise Exception.CreateFmt(sImplementationRequired, [ClassName, 'GetClipboardFormat']);
  776. end;
  777. procedure TClipboardFormat.SetClipboardFormat(Value: TClipFormat);
  778. begin
  779. FFormatEtc.cfFormat := Value;
  780. end;
  781. function TClipboardFormat.GetClipboardFormatName: string;
  782. var
  783. Len : integer;
  784. begin
  785. SetLength(Result, 255); // 255 is just an artificial limit.
  786. Len := Windows.GetClipboardFormatName(GetClipboardFormat, PChar(Result), 255);
  787. SetLength(Result, Len);
  788. end;
  789. procedure TClipboardFormat.SetClipboardFormatName(const Value: string);
  790. begin
  791. raise Exception.CreateFmt(sFormatNameReadOnly, [ClassName]);
  792. end;
  793. function TClipboardFormat.HasData: boolean;
  794. begin
  795. // Descendant classes are not required to override this method, so by default
  796. // we just pretend that data is available. No harm is done by this.
  797. Result := True;
  798. end;
  799. procedure TClipboardFormat.SetFormatEtc(const Value: TFormatEtc);
  800. begin
  801. FFormatEtc := Value;
  802. end;
  803. ////////////////////////////////////////////////////////////////////////////////
  804. //
  805. // TClipboardFormats
  806. //
  807. ////////////////////////////////////////////////////////////////////////////////
  808. constructor TClipboardFormats.Create(ADataFormat: TCustomDataFormat;
  809. AOwnsObjects: boolean);
  810. begin
  811. inherited Create;
  812. FList := TList.Create;
  813. FDataFormat := ADataFormat;
  814. FOwnsObjects := AOwnsObjects;
  815. end;
  816. destructor TClipboardFormats.Destroy;
  817. begin
  818. Clear;
  819. FList.Free;
  820. inherited Destroy;
  821. end;
  822. function TClipboardFormats.Add(ClipboardFormat: TClipboardFormat): integer;
  823. begin
  824. Result := FList.Add(ClipboardFormat);
  825. if (FOwnsObjects) and (DataFormat <> nil) then
  826. ClipboardFormat.DataFormat := DataFormat;
  827. end;
  828. function TClipboardFormats.FindFormat(ClipboardFormatClass: TClipboardFormatClass): TClipboardFormat;
  829. var
  830. i : integer;
  831. begin
  832. // Search list for an object of the specified type
  833. for i := 0 to Count-1 do
  834. if (Formats[i].InheritsFrom(ClipboardFormatClass)) then
  835. begin
  836. Result := Formats[i];
  837. exit;
  838. end;
  839. Result := nil;
  840. end;
  841. function TClipboardFormats.Contain(ClipboardFormatClass: TClipboardFormatClass): boolean;
  842. begin
  843. Result := (FindFormat(ClipboardFormatClass) <> nil);
  844. end;
  845. function TClipboardFormats.GetCount: integer;
  846. begin
  847. Result := FList.Count;
  848. end;
  849. function TClipboardFormats.GetFormat(Index: integer): TClipboardFormat;
  850. begin
  851. Result := TClipboardFormat(FList[Index]);
  852. end;
  853. procedure TClipboardFormats.Clear;
  854. var
  855. i : integer;
  856. Format : TObject;
  857. begin
  858. if (FOwnsObjects) then
  859. // Empty list and delete all objects in it
  860. for i := Count-1 downto 0 do
  861. begin
  862. Format := Formats[i];
  863. FList.Delete(i);
  864. Format.Free;
  865. end;
  866. FList.Clear;
  867. end;
  868. ////////////////////////////////////////////////////////////////////////////////
  869. //
  870. // TCustomDataFormat
  871. //
  872. ////////////////////////////////////////////////////////////////////////////////
  873. constructor TCustomDataFormat.Create(AOwner: TDragDropComponent);
  874. var
  875. ConversionScope: TConversionScope;
  876. begin
  877. if (AOwner <> nil) then
  878. begin
  879. if (AOwner is TCustomDropMultiSource) then
  880. ConversionScope := csSource
  881. else if (AOwner is TCustomDropMultiTarget) then
  882. ConversionScope := csTarget
  883. else
  884. raise Exception.CreateFmt(sInvalidOwnerType, [AOwner.ClassName, ClassName,
  885. 'TCustomDropMultiSource or TCustomDropMultiTarget']);
  886. // Add object to owners list of data formats.
  887. FOwner := AOwner;
  888. end else
  889. // TODO : This sucks! All this ConversionScope stuff should be redesigned.
  890. ConversionScope := csTarget;
  891. FCompatibleFormats := TClipboardFormats.Create(Self, True);
  892. // Populate list with all the clipboard formats that have been registered as
  893. // compatible with this data format.
  894. TDataFormatMap.Instance.GetSourceByDataFormat(TDataFormatClass(ClassType),
  895. FCompatibleFormats, ConversionScope);
  896. if (FOwner <> nil) then
  897. FOwner.DataFormats.Add(Self);
  898. end;
  899. destructor TCustomDataFormat.Destroy;
  900. begin
  901. FCompatibleFormats.Free;
  902. // Remove object from owners list of target formats
  903. if (FOwner <> nil) then
  904. FOwner.DataFormats.Remove(Self);
  905. inherited Destroy;
  906. end;
  907. function TCustomDataFormat.Assign(Source: TClipboardFormat): boolean;
  908. begin
  909. // Called when derived class(es) couldn't convert from the source format.
  910. // Try to let source format convert to this format instead.
  911. Result := Source.AssignTo(Self);
  912. end;
  913. function TCustomDataFormat.AssignTo(Dest: TClipboardFormat): boolean;
  914. begin
  915. // Called when derived class(es) couldn't convert to the destination format.
  916. // Try to let destination format convert from this format instead.
  917. Result := Dest.Assign(Self);
  918. end;
  919. function TCustomDataFormat.GetData(DataObject: IDataObject): boolean;
  920. var
  921. i: integer;
  922. begin
  923. Result := False;
  924. i := 0;
  925. // Get data from each of our associated clipboard formats until we don't
  926. // need anymore data.
  927. while (NeedsData) and (i < CompatibleFormats.Count) do
  928. begin
  929. CompatibleFormats[i].Clear;
  930. if (CompatibleFormats[i].GetData(DataObject)) and
  931. (CompatibleFormats[i].HasData) then
  932. begin
  933. if (Assign(CompatibleFormats[i])) then
  934. begin
  935. // Once data has been sucessfully transfered to the TDataFormat object,
  936. // we clear the data in the TClipboardFormat object in order to conserve
  937. // resources.
  938. CompatibleFormats[i].Clear;
  939. Result := True;
  940. end;
  941. end;
  942. inc(i);
  943. end;
  944. end;
  945. function TCustomDataFormat.NeedsData: boolean;
  946. begin
  947. Result := not HasData;
  948. end;
  949. function TCustomDataFormat.HasValidFormats(ADataObject: IDataObject): boolean;
  950. var
  951. i: integer;
  952. begin
  953. // Determine if any of the registered clipboard formats can read from the
  954. // specified data object.
  955. Result := False;
  956. for i := 0 to CompatibleFormats.Count-1 do
  957. if (CompatibleFormats[i].HasValidFormats(ADataObject)) then
  958. begin
  959. Result := True;
  960. break;
  961. end;
  962. end;
  963. function TCustomDataFormat.AcceptFormat(const FormatEtc: TFormatEtc): boolean;
  964. var
  965. i: integer;
  966. begin
  967. // Determine if any of the registered clipboard formats can handle the
  968. // specified clipboard format.
  969. Result := False;
  970. for i := 0 to CompatibleFormats.Count-1 do
  971. if (CompatibleFormats[i].AcceptFormat(FormatEtc)) then
  972. begin
  973. Result := True;
  974. break;
  975. end;
  976. end;
  977. class procedure TCustomDataFormat.RegisterDataFormat;
  978. begin
  979. TDataFormatClasses.Instance.Add(Self);
  980. end;
  981. class procedure TCustomDataFormat.RegisterCompatibleFormat(ClipboardFormatClass: TClipboardFormatClass;
  982. Priority: integer; ConversionScopes: TConversionScopes;
  983. DataDirections: TDataDirections);
  984. begin
  985. // Register format mapping.
  986. TDataFormatMap.Instance.RegisterFormatMap(Self, ClipboardFormatClass,
  987. Priority, ConversionScopes, DataDirections);
  988. end;
  989. function TCustomDataFormat.SupportsFormat(ClipboardFormat: TClipboardFormat): boolean;
  990. begin
  991. Result := CompatibleFormats.Contain(TClipboardFormatClass(ClipboardFormat.ClassType));
  992. end;
  993. class procedure TCustomDataFormat.UnregisterCompatibleFormat(ClipboardFormatClass: TClipboardFormatClass);
  994. begin
  995. // Unregister format mapping
  996. TDataFormatMap.Instance.UnregisterFormatMap(Self, ClipboardFormatClass);
  997. end;
  998. class procedure TCustomDataFormat.UnregisterDataFormat;
  999. begin
  1000. TDataFormatMap.Instance.DeleteByDataFormat(Self);
  1001. TDataFormatClasses.Instance.Remove(Self);
  1002. end;
  1003. procedure TCustomDataFormat.DoOnChanging(Sender: TObject);
  1004. begin
  1005. Changing;
  1006. end;
  1007. procedure TCustomDataFormat.Changing;
  1008. begin
  1009. if (Assigned(OnChanging)) then
  1010. OnChanging(Self);
  1011. end;
  1012. ////////////////////////////////////////////////////////////////////////////////
  1013. //
  1014. // TDataFormats
  1015. //
  1016. ////////////////////////////////////////////////////////////////////////////////
  1017. function TDataFormats.Add(DataFormat: TCustomDataFormat): integer;
  1018. begin
  1019. Result := FList.IndexOf(DataFormat);
  1020. if (Result = -1) then
  1021. Result := FList.Add(DataFormat);
  1022. end;
  1023. constructor TDataFormats.Create;
  1024. begin
  1025. inherited Create;
  1026. FList := TList.Create;
  1027. end;
  1028. destructor TDataFormats.Destroy;
  1029. var
  1030. i: integer;
  1031. begin
  1032. for i := FList.Count-1 downto 0 do
  1033. Remove(TCustomDataFormat(FList[i]));
  1034. FList.Free;
  1035. inherited Destroy;
  1036. end;
  1037. function TDataFormats.GetCount: integer;
  1038. begin
  1039. Result := FList.Count;
  1040. end;
  1041. function TDataFormats.GetFormat(Index: integer): TCustomDataFormat;
  1042. begin
  1043. Result := TCustomDataFormat(FList[Index]);
  1044. end;
  1045. function TDataFormats.IndexOf(DataFormat: TCustomDataFormat): integer;
  1046. begin
  1047. Result := FList.IndexOf(DataFormat);
  1048. end;
  1049. procedure TDataFormats.Remove(DataFormat: TCustomDataFormat);
  1050. begin
  1051. FList.Remove(DataFormat);
  1052. end;
  1053. ////////////////////////////////////////////////////////////////////////////////
  1054. //
  1055. // TDataFormatClasses
  1056. //
  1057. ////////////////////////////////////////////////////////////////////////////////
  1058. function TDataFormatClasses.Add(DataFormat: TDataFormatClass): integer;
  1059. begin
  1060. Result := FList.IndexOf(DataFormat);
  1061. if (Result = -1) then
  1062. Result := FList.Add(DataFormat);
  1063. end;
  1064. constructor TDataFormatClasses.Create;
  1065. begin
  1066. inherited Create;
  1067. FList := TList.Create;
  1068. end;
  1069. destructor TDataFormatClasses.Destroy;
  1070. var
  1071. i: integer;
  1072. begin
  1073. for i := FList.Count-1 downto 0 do
  1074. Remove(TDataFormatClass(FList[i]));
  1075. FList.Free;
  1076. inherited Destroy;
  1077. end;
  1078. function TDataFormatClasses.GetCount: integer;
  1079. begin
  1080. Result := FList.Count;
  1081. end;
  1082. function TDataFormatClasses.GetFormat(Index: integer): TDataFormatClass;
  1083. begin
  1084. Result := TDataFormatClass(FList[Index]);
  1085. end;
  1086. var
  1087. FDataFormatClasses: TDataFormatClasses = nil;
  1088. class function TDataFormatClasses.Instance: TDataFormatClasses;
  1089. begin
  1090. if (FDataFormatClasses = nil) then
  1091. FDataFormatClasses := TDataFormatClasses.Create;
  1092. Result := FDataFormatClasses;
  1093. end;
  1094. procedure TDataFormatClasses.Remove(DataFormat: TDataFormatClass);
  1095. begin
  1096. FList.Remove(DataFormat);
  1097. end;
  1098. ////////////////////////////////////////////////////////////////////////////////
  1099. //
  1100. // TDataFormatMap
  1101. //
  1102. ////////////////////////////////////////////////////////////////////////////////
  1103. type
  1104. // TTargetFormat / TClipboardFormat association
  1105. TFormatMap = record
  1106. DataFormat: TDataFormatClass;
  1107. ClipboardFormat: TClipboardFormatClass;
  1108. Priority: integer;
  1109. ConversionScopes: TConversionScopes;
  1110. DataDirections: TDataDirections;
  1111. end;
  1112. PFormatMap = ^TFormatMap;
  1113. constructor TDataFormatMap.Create;
  1114. begin
  1115. inherited Create;
  1116. FList := TList.Create;
  1117. end;
  1118. destructor TDataFormatMap.Destroy;
  1119. var
  1120. i : integer;
  1121. begin
  1122. // Zap any mapings which hasn't been unregistered
  1123. // yet (actually an error condition)
  1124. for i := FList.Count-1 downto 0 do
  1125. Dispose(FList[i]);
  1126. FList.Free;
  1127. inherited Destroy;
  1128. end;
  1129. procedure TDataFormatMap.Sort;
  1130. var
  1131. i : integer;
  1132. NewMap : PFormatMap;
  1133. begin
  1134. // Note: We do not use the built-in Sort method of TList because
  1135. // we need to preserve the order in which the mappings were added.
  1136. // New mappings have higher precedence than old mappings (within the
  1137. // same priority).
  1138. // Preconditions:
  1139. // 1) The list is already sorted before a new mapping is added.
  1140. // 2) The new mapping is always added to the end of the list.
  1141. NewMap := PFormatMap(FList.Last);
  1142. // Scan the list for a map with the same TTargetFormat type
  1143. i := FList.Count-2;
  1144. while (i > 0) do
  1145. begin
  1146. if (PFormatMap(FList[i])^.DataFormat = NewMap^.DataFormat) then
  1147. begin
  1148. // Scan the list for a map with lower priority
  1149. repeat
  1150. if (PFormatMap(FList[i])^.Priority < NewMap^.Priority) then
  1151. begin
  1152. // Move the mapping to the new position
  1153. FList.Move(FList.Count-1, i+1);
  1154. exit;
  1155. end;
  1156. dec(i);
  1157. until (i < 0) or (PFormatMap(FList[i])^.DataFormat <> NewMap^.DataFormat);
  1158. // Move the mapping to the new position
  1159. FList.Move(FList.Count-1, i+1);
  1160. exit;
  1161. end;
  1162. dec(i);
  1163. end;
  1164. end;
  1165. procedure TDataFormatMap.Add(DataFormatClass: TDataFormatClass;
  1166. ClipboardFormatClass: TClipboardFormatClass; Priority: integer;
  1167. ConversionScopes: TConversionScopes; DataDirections: TDataDirections);
  1168. var
  1169. FormatMap : PFormatMap;
  1170. OldMap : integer;
  1171. begin
  1172. // Avoid duplicate mappings
  1173. OldMap := FindMap(DataFormatClass, ClipboardFormatClass);
  1174. if (OldMap = -1) then
  1175. begin
  1176. // Add new mapping...
  1177. New(FormatMap);
  1178. FList.Add(FormatMap);
  1179. FormatMap^.ConversionScopes := ConversionScopes;
  1180. FormatMap^.DataDirections := DataDirections;
  1181. end else
  1182. begin
  1183. // Replace old mapping...
  1184. FormatMap := FList[OldMap];
  1185. FList.Move(OldMap, FList.Count-1);
  1186. FormatMap^.ConversionScopes := FormatMap^.ConversionScopes + ConversionScopes;
  1187. FormatMap^.DataDirections := FormatMap^.DataDirections + DataDirections;
  1188. end;
  1189. FormatMap^.ClipboardFormat := ClipboardFormatClass;
  1190. FormatMap^.DataFormat := DataFormatClass;
  1191. FormatMap^.Priority := Priority;
  1192. // ...and sort list
  1193. Sort;
  1194. end;
  1195. function TDataFormatMap.CanMap(DataFormatClass: TDataFormatClass;
  1196. ClipboardFormatClass: TClipboardFormatClass): boolean;
  1197. begin
  1198. Result := (FindMap(DataFormatClass, ClipboardFormatClass) <> -1);
  1199. end;
  1200. procedure TDataFormatMap.Delete(DataFormatClass: TDataFormatClass;
  1201. ClipboardFormatClass: TClipboardFormatClass);
  1202. var
  1203. Index : integer;
  1204. begin
  1205. Index := FindMap(DataFormatClass, ClipboardFormatClass);
  1206. if (Index <> -1) then
  1207. begin
  1208. Dispose(FList[Index]);
  1209. FList.Delete(Index);
  1210. end;
  1211. end;
  1212. procedure TDataFormatMap.DeleteByClipboardFormat(ClipboardFormatClass: TClipboardFormatClass);
  1213. var
  1214. i : integer;
  1215. begin
  1216. // Delete all mappings associated with the specified clipboard format
  1217. for i := FList.Count-1 downto 0 do
  1218. if (PFormatMap(FList[i])^.ClipboardFormat.InheritsFrom(ClipboardFormatClass)) then
  1219. begin
  1220. Dispose(FList[i]);
  1221. FList.Delete(i);
  1222. end;
  1223. end;
  1224. procedure TDataFormatMap.DeleteByDataFormat(DataFormatClass: TDataFormatClass);
  1225. var
  1226. i : integer;
  1227. begin
  1228. // Delete all mappings associated with the specified target format
  1229. for i := FList.Count-1 downto 0 do
  1230. if (PFormatMap(FList[i])^.DataFormat.InheritsFrom(DataFormatClass)) then
  1231. begin
  1232. Dispose(FList[i]);
  1233. FList.Delete(i);
  1234. end;
  1235. end;
  1236. function TDataFormatMap.FindMap(DataFormatClass: TDataFormatClass;
  1237. ClipboardFormatClass: TClipboardFormatClass): integer;
  1238. var
  1239. i : integer;
  1240. begin
  1241. for i := 0 to FList.Count-1 do
  1242. if (PFormatMap(FList[i])^.DataFormat.InheritsFrom(DataFormatClass)) and
  1243. (PFormatMap(FList[i])^.ClipboardFormat.InheritsFrom(ClipboardFormatClass)) then
  1244. begin
  1245. Result := i;
  1246. exit;
  1247. end;
  1248. Result := -1;
  1249. end;
  1250. procedure TDataFormatMap.GetSourceByDataFormat(DataFormatClass: TDataFormatClass;
  1251. ClipboardFormats: TClipboardFormats; ConversionScope: TConversionScope);
  1252. var
  1253. i: integer;
  1254. ClipboardFormat: TClipboardFormat;
  1255. begin
  1256. // Clear the list...
  1257. ClipboardFormats.Clear;
  1258. // ...and populate it with *instances* of all the clipbard
  1259. // formats associated with the specified target format and
  1260. // registered with the specified data direction.
  1261. for i := 0 to FList.Count-1 do
  1262. if (ConversionScope in PFormatMap(FList[i])^.ConversionScopes) and
  1263. (PFormatMap(FList[i])^.DataFormat.InheritsFrom(DataFormatClass)) then
  1264. begin
  1265. ClipboardFormat := PFormatMap(FList[i])^.ClipboardFormat.Create;
  1266. ClipboardFormat.DataDirections := PFormatMap(FList[i])^.DataDirections;
  1267. ClipboardFormats.Add(ClipboardFormat);
  1268. end;
  1269. end;
  1270. procedure TDataFormatMap.RegisterFormatMap(DataFormatClass: TDataFormatClass;
  1271. ClipboardFormatClass: TClipboardFormatClass; Priority: integer;
  1272. ConversionScopes: TConversionScopes; DataDirections: TDataDirections);
  1273. begin
  1274. Add(DataFormatClass, ClipboardFormatClass, Priority, ConversionScopes,
  1275. DataDirections);
  1276. end;
  1277. procedure TDataFormatMap.UnregisterFormatMap(DataFormatClass: TDataFormatClass;
  1278. ClipboardFormatClass: TClipboardFormatClass);
  1279. begin
  1280. Delete(DataFormatClass, ClipboardFormatClass);
  1281. end;
  1282. var
  1283. FDataFormatMap: TDataFormatMap = nil;
  1284. class function TDataFormatMap.Instance: TDataFormatMap;
  1285. begin
  1286. if (FDataFormatMap = nil) then
  1287. FDataFormatMap := TDataFormatMap.Create;
  1288. Result := FDataFormatMap;
  1289. end;
  1290. ////////////////////////////////////////////////////////////////////////////////
  1291. //
  1292. // TDataFormatAdapter
  1293. //
  1294. ////////////////////////////////////////////////////////////////////////////////
  1295. destructor TDataFormatAdapter.Destroy;
  1296. begin
  1297. inherited Destroy;
  1298. end;
  1299. function TDataFormatAdapter.GetDataFormatName: string;
  1300. begin
  1301. if Assigned(FDataFormatClass) then
  1302. Result := FDataFormatClass.ClassName
  1303. else
  1304. Result := '';
  1305. end;
  1306. function TDataFormatAdapter.GetEnabled: boolean;
  1307. begin
  1308. if (csDesigning in ComponentState) then
  1309. Result := FEnabled
  1310. else
  1311. Result := Assigned(FDataFormat) and Assigned(FDataFormatClass);
  1312. end;
  1313. procedure TDataFormatAdapter.Loaded;
  1314. begin
  1315. inherited;
  1316. if (FEnabled) then
  1317. Enabled := True;
  1318. end;
  1319. procedure TDataFormatAdapter.Notification(AComponent: TComponent;
  1320. Operation: TOperation);
  1321. begin
  1322. if (Operation = opRemove) and (AComponent = FDragDropComponent) then
  1323. DragDropComponent := nil;
  1324. inherited;
  1325. end;
  1326. procedure TDataFormatAdapter.SetDataFormatClass(const Value: TDataFormatClass);
  1327. begin
  1328. if (Value <> FDataFormatClass) then
  1329. begin
  1330. if not(csLoading in ComponentState) then
  1331. Enabled := False;
  1332. FDataFormatClass := Value;
  1333. end;
  1334. end;
  1335. procedure TDataFormatAdapter.SetDataFormatName(const Value: string);
  1336. var
  1337. i: integer;
  1338. ADataFormatClass: TDataFormatClass;
  1339. begin
  1340. ADataFormatClass := nil;
  1341. if (Value <> '') then
  1342. begin
  1343. for i := 0 to TDataFormatClasses.Instance.Count-1 do
  1344. if (AnsiCompareText(TDataFormatClasses.Instance[i].ClassName, Value) = 0) then
  1345. begin
  1346. ADataFormatClass := TDataFormatClasses.Instance[i];
  1347. break;
  1348. end;
  1349. if (ADataFormatClass = nil) then
  1350. raise Exception.CreateFmt(sUnregisteredDataFormat, [Value]);
  1351. end;
  1352. DataFormatClass := ADataFormatClass;
  1353. end;
  1354. procedure TDataFormatAdapter.SetDragDropComponent(const Value: TDragDropComponent);
  1355. begin
  1356. if (Value <> FDragDropComponent) then
  1357. begin
  1358. if not(csLoading in ComponentState) then
  1359. Enabled := False;
  1360. if (FDragDropComponent <> nil) then
  1361. FDragDropComponent.RemoveFreeNotification(Self);
  1362. FDragDropComponent := Value;
  1363. if (Value <> nil) then
  1364. Value.FreeNotification(Self);
  1365. end;
  1366. end;
  1367. procedure TDataFormatAdapter.SetEnabled(const Value: boolean);
  1368. begin
  1369. if (csLoading in ComponentState) then
  1370. begin
  1371. FEnabled := Value;
  1372. end else
  1373. if (csDesigning in ComponentState) then
  1374. begin
  1375. FEnabled := Value and Assigned(FDragDropComponent) and
  1376. Assigned(FDataFormatClass);
  1377. end else
  1378. if (Value) then
  1379. begin
  1380. if (Assigned(FDragDropComponent)) and (Assigned(FDataFormatClass)) and
  1381. (not Assigned(FDataFormat)) then
  1382. FDataFormat := FDataFormatClass.Create(FDragDropComponent);
  1383. end else
  1384. begin
  1385. if Assigned(FDataFormat) then
  1386. begin
  1387. if Assigned(FDragDropComponent) and
  1388. (FDragDropComponent.DataFormats.IndexOf(FDataFormat) <> -1) then
  1389. FDataFormat.Free;
  1390. FDataFormat := nil;
  1391. end;
  1392. end;
  1393. end;
  1394. ////////////////////////////////////////////////////////////////////////////////
  1395. //
  1396. // TRawClipboardFormat
  1397. //
  1398. ////////////////////////////////////////////////////////////////////////////////
  1399. constructor TRawClipboardFormat.Create;
  1400. begin
  1401. // Yeah, it's a hack but blame Borland for making TObject.Create public!
  1402. raise Exception.CreateFmt(sBadConstructor, [ClassName]);
  1403. end;
  1404. constructor TRawClipboardFormat.CreateFormatEtc(const AFormatEtc: TFormatEtc);
  1405. begin
  1406. inherited CreateFormatEtc(AFormatEtc);
  1407. end;
  1408. procedure TRawClipboardFormat.SetClipboardFormatName(const Value: string);
  1409. begin
  1410. ClipboardFormat := RegisterClipboardFormat(PChar(Value));
  1411. end;
  1412. function TRawClipboardFormat.GetClipboardFormat: TClipFormat;
  1413. begin
  1414. Result := FFormatEtc.cfFormat;
  1415. end;
  1416. function TRawClipboardFormat.Assign(Source: TCustomDataFormat): boolean;
  1417. begin
  1418. if (Source is TRawDataFormat) then
  1419. begin
  1420. Result := True;
  1421. end else
  1422. Result := inherited Assign(Source);
  1423. end;
  1424. function TRawClipboardFormat.AssignTo(Dest: TCustomDataFormat): boolean;
  1425. begin
  1426. if (Dest is TRawDataFormat) then
  1427. begin
  1428. Result := True;
  1429. end else
  1430. Result := inherited AssignTo(Dest);
  1431. end;
  1432. procedure TRawClipboardFormat.Clear;
  1433. begin
  1434. // Since TRawDataFormat performs storage for TRawDataFormat we only allow
  1435. // TRawDataFormat to clear. To accomplish this TRawDataFormat ignores calls to
  1436. // the clear method and instead introduces the ClearData method.
  1437. end;
  1438. procedure TRawClipboardFormat.ClearData;
  1439. begin
  1440. ReleaseStgMedium(FMedium);
  1441. FillChar(FMedium, SizeOf(FMedium), 0);
  1442. end;
  1443. function TRawClipboardFormat.HasData: boolean;
  1444. begin
  1445. Result := (FMedium.tymed <> TYMED_NULL);
  1446. end;
  1447. function TRawClipboardFormat.NeedsData: boolean;
  1448. begin
  1449. Result := (FMedium.tymed = TYMED_NULL);
  1450. end;
  1451. procedure TRawClipboardFormat.CopyFromStgMedium(const AMedium: TStgMedium);
  1452. begin
  1453. CopyStgMedium(AMedium, FMedium);
  1454. end;
  1455. procedure TRawClipboardFormat.CopyToStgMedium(var AMedium: TStgMedium);
  1456. begin
  1457. CopyStgMedium(FMedium, AMedium);
  1458. end;
  1459. function TRawClipboardFormat.DoGetData(ADataObject: IDataObject;
  1460. const AMedium: TStgMedium): boolean;
  1461. begin
  1462. Result := CopyStgMedium(AMedium, FMedium);
  1463. end;
  1464. function TRawClipboardFormat.DoSetData(const FormatEtcIn: TFormatEtc;
  1465. var AMedium: TStgMedium): boolean;
  1466. begin
  1467. Result := CopyStgMedium(FMedium, AMedium);
  1468. end;
  1469. function TRawClipboardFormat.GetString: string;
  1470. begin
  1471. with TTextClipboardFormat.Create do
  1472. try
  1473. if GetDataFromMedium(nil, FMedium) then
  1474. Result := Text
  1475. else
  1476. Result := '';
  1477. finally
  1478. Free;
  1479. end;
  1480. end;
  1481. procedure TRawClipboardFormat.SetString(const Value: string);
  1482. begin
  1483. with TTextClipboardFormat.Create do
  1484. try
  1485. Text := Value;
  1486. SetDataToMedium(FormatEtc, FMedium);
  1487. finally
  1488. Free;
  1489. end;
  1490. end;
  1491. ////////////////////////////////////////////////////////////////////////////////
  1492. //
  1493. // TRawDataFormat
  1494. //
  1495. ////////////////////////////////////////////////////////////////////////////////
  1496. procedure TRawDataFormat.Clear;
  1497. var
  1498. i: integer;
  1499. begin
  1500. Changing;
  1501. for i := 0 to CompatibleFormats.Count-1 do
  1502. TRawClipboardFormat(CompatibleFormats[i]).ClearData;
  1503. end;
  1504. function TRawDataFormat.HasData: boolean;
  1505. var
  1506. i: integer;
  1507. begin
  1508. i := 0;
  1509. Result := False;
  1510. while (not Result) and (i < CompatibleFormats.Count) do
  1511. begin
  1512. Result := TRawClipboardFormat(CompatibleFormats[i]).HasData;
  1513. inc(i);
  1514. end;
  1515. end;
  1516. function TRawDataFormat.NeedsData: boolean;
  1517. var
  1518. i: integer;
  1519. begin
  1520. i := 0;
  1521. Result := False;
  1522. while (not Result) and (i < CompatibleFormats.Count) do
  1523. begin
  1524. Result := TRawClipboardFormat(CompatibleFormats[i]).NeedsData;
  1525. inc(i);
  1526. end;
  1527. end;
  1528. ////////////////////////////////////////////////////////////////////////////////
  1529. //
  1530. // Utility functions
  1531. //
  1532. ////////////////////////////////////////////////////////////////////////////////
  1533. procedure _RaiseLastWin32Error;
  1534. begin
  1535. {$ifdef VER14_PLUS}
  1536. RaiseLastOSError;
  1537. {$else}
  1538. RaiseLastWin32Error;
  1539. {$endif}
  1540. end;
  1541. function DropEffectToDragType(DropEffect: longInt; var DragType: TDragType): boolean;
  1542. begin
  1543. Result := True;
  1544. if ((DropEffect and DROPEFFECT_COPY) <> 0) then
  1545. DragType := dtCopy
  1546. else
  1547. if ((DropEffect and DROPEFFECT_MOVE) <> 0) then
  1548. DragType := dtMove
  1549. else
  1550. if ((DropEffect and DROPEFFECT_LINK) <> 0) then
  1551. DragType := dtLink
  1552. else
  1553. begin
  1554. DragType := dtCopy;
  1555. Result := False;
  1556. end;
  1557. end;
  1558. function DragTypesToDropEffect(DragTypes: TDragTypes): longint;
  1559. begin
  1560. Result := DROPEFFECT_NONE;
  1561. if (dtCopy in DragTypes) then
  1562. Result := Result OR DROPEFFECT_COPY;
  1563. if (dtMove in DragTypes) then
  1564. Result := Result OR DROPEFFECT_MOVE;
  1565. if (dtLink in DragTypes) then
  1566. Result := Result OR DROPEFFECT_LINK;
  1567. end;
  1568. // Replacement for the buggy DragDetect API function.
  1569. function DragDetectPlus(Handle: THandle; p: TPoint): boolean;
  1570. var
  1571. DragRect: TRect;
  1572. Msg: TMsg;
  1573. StartTime: DWORD;
  1574. OldCapture: HWND;
  1575. begin
  1576. Result := False;
  1577. if (not ClientToScreen(Handle, p)) then
  1578. exit;
  1579. // Calculate the drag rect. If the mouse leaves this rect while the
  1580. // mouse button is pressed, a drag is detected.
  1581. DragRect.TopLeft := p;
  1582. DragRect.BottomRight := p;
  1583. InflateRect(DragRect, GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG));
  1584. StartTime := TimeGetTime;
  1585. // Capture the mouse so that we will receive mouse messages even after the
  1586. // mouse leaves the control rect.
  1587. OldCapture := SetCapture(Handle);
  1588. try
  1589. // Abort if we failed to capture the mouse.
  1590. if (GetCapture <> Handle) then
  1591. exit;
  1592. while (not Result) do
  1593. begin
  1594. // Detect if all mouse buttons are up (might mean that we missed a
  1595. // MW_?BUTTONUP message).
  1596. if (GetAsyncKeyState(VK_LBUTTON) AND $8000 = 0) and
  1597. (GetAsyncKeyState(VK_RBUTTON) AND $8000 = 0) then
  1598. break;
  1599. if (PeekMessage(Msg, Handle, 0,0, PM_REMOVE)) then
  1600. begin
  1601. case (Msg.message) of
  1602. WM_MOUSEMOVE:
  1603. // Mouse were moved. Check if we are still within the drag rect...
  1604. Result := (not PtInRect(DragRect, Msg.pt)) and
  1605. // ... and that the minimum time has elapsed.
  1606. // Note that we ignore time warp (wrap around) and that Msg.Time
  1607. // might be smaller than StartTime.
  1608. (Msg.time >= StartTime + DWORD(DragDropDragDelay));
  1609. WM_RBUTTONUP,
  1610. WM_LBUTTONUP,
  1611. WM_CANCELMODE:
  1612. // Mouse button were released, escape were pressed or some other
  1613. // operation cancelled our mouse capture.
  1614. break;
  1615. WM_QUIT:
  1616. // Application is shutting down. Get out of here fast.
  1617. exit;
  1618. else
  1619. TranslateMessage(Msg);
  1620. DispatchMessage(Msg);
  1621. end;
  1622. end else
  1623. Sleep(0);
  1624. end;
  1625. finally
  1626. ReleaseCapture;
  1627. // Restore previous capture.
  1628. if (OldCapture <> 0) then
  1629. SetCapture(OldCapture);
  1630. end;
  1631. end;
  1632. function ClientPtToWindowPt(Handle: THandle; pt: TPoint): TPoint;
  1633. var
  1634. Rect: TRect;
  1635. begin
  1636. ClientToScreen(Handle, pt);
  1637. GetWindowRect(Handle, Rect);
  1638. Result.X := pt.X - Rect.Left;
  1639. Result.Y := pt.Y - Rect.Top;
  1640. end;
  1641. const
  1642. // Note: The definition of MK_ALT is missing from the current Delphi (D5)
  1643. // declarations. Hopefully Delphi 6 will fix this.
  1644. MK_ALT = $20;
  1645. function KeysToShiftStatePlus(Keys: Word): TShiftState;
  1646. begin
  1647. Result := [];
  1648. if (Keys and MK_SHIFT <> 0) then
  1649. Include(Result, ssShift);
  1650. if (Keys and MK_CONTROL <> 0) then
  1651. Include(Result, ssCtrl);
  1652. if (Keys and MK_LBUTTON <> 0) then
  1653. Include(Result, ssLeft);
  1654. if (Keys and MK_RBUTTON <> 0) then
  1655. Include(Result, ssRight);
  1656. if (Keys and MK_MBUTTON <> 0) then
  1657. Include(Result, ssMiddle);
  1658. if (Keys and MK_ALT <> 0) then
  1659. Include(Result, ssMiddle);
  1660. end;
  1661. function ShiftStateToDropEffect(Shift: TShiftState; AllowedEffects: longint;
  1662. Fallback: boolean): longint;
  1663. begin
  1664. // As we're only interested in ssShift & ssCtrl here,
  1665. // mouse button states are screened out.
  1666. Shift := Shift * [ssShift, ssCtrl];
  1667. Result := DROPEFFECT_NONE;
  1668. if (Shift = [ssShift, ssCtrl]) then
  1669. begin
  1670. if (AllowedEffects AND DROPEFFECT_LINK <> 0) then
  1671. Result := DROPEFFECT_LINK;
  1672. end else
  1673. if (Shift = [ssCtrl]) then
  1674. begin
  1675. if (AllowedEffects AND DROPEFFECT_COPY <> 0) then
  1676. Result := DROPEFFECT_COPY;
  1677. end else
  1678. begin
  1679. if (AllowedEffects AND DROPEFFECT_MOVE <> 0) then
  1680. Result := DROPEFFECT_MOVE;
  1681. end;
  1682. // Fall back to defaults if the shift-states specified an
  1683. // unavailable drop effect.
  1684. if (Result = DROPEFFECT_NONE) and (Fallback) then
  1685. begin
  1686. if (AllowedEffects AND DROPEFFECT_COPY <> 0) then
  1687. Result := DROPEFFECT_COPY
  1688. else if (AllowedEffects AND DROPEFFECT_MOVE <> 0) then
  1689. Result := DROPEFFECT_MOVE
  1690. else if (AllowedEffects AND DROPEFFECT_LINK <> 0) then
  1691. Result := DROPEFFECT_LINK;
  1692. end;
  1693. end;
  1694. var
  1695. URLMONDLL: THandle = 0;
  1696. _CopyStgMedium: function(const cstgmedSrc: TStgMedium; var stgmedDest: TStgMedium): HResult; stdcall = nil;
  1697. function CopyStgMedium(const SrcMedium: TStgMedium; var DstMedium: TStgMedium): boolean;
  1698. begin
  1699. // Copy the medium via the URLMON CopyStgMedium function. This should be safe
  1700. // since this function is only called when the drag drop helper object is
  1701. // used and the drag drop helper object is only supported on Windows 2000
  1702. // and later.
  1703. // URLMON.CopyStgMedium requires IE4 or later.
  1704. // An alternative approach would be to use OleDuplicateData, but based on a
  1705. // disassembly of urlmon.dll, CopyStgMedium seems to do a lot more than
  1706. // OleDuplicateData.
  1707. if (URLMONDLL = 0) then
  1708. begin
  1709. URLMONDLL := LoadLibrary('URLMON.DLL');
  1710. if (URLMONDLL <> 0) then
  1711. @_CopyStgMedium := GetProcAddress(URLMONDLL, 'CopyStgMedium');
  1712. end;
  1713. if (@_CopyStgMedium = nil) then
  1714. raise Exception.Create(sNoCopyStgMedium);
  1715. Result := (_CopyStgMedium(SrcMedium, DstMedium) = S_OK);
  1716. end;
  1717. function GetClipboardFormatNameStr(Value: TClipFormat): string;
  1718. var
  1719. len: integer;
  1720. begin
  1721. Setlength(Result, 255);
  1722. len := GetClipboardFormatName(Value, PChar(Result), 255);
  1723. SetLength(Result, len);
  1724. end;
  1725. ////////////////////////////////////////////////////////////////////////////////
  1726. //
  1727. // Initialization/Finalization
  1728. //
  1729. ////////////////////////////////////////////////////////////////////////////////
  1730. initialization
  1731. OleInitialize(nil);
  1732. ShGetMalloc(ShellMalloc);
  1733. GetClipboardFormatNameStr(0);
  1734. finalization
  1735. if (FDataFormatMap <> nil) then
  1736. begin
  1737. FDataFormatMap.Free;
  1738. FDataFormatMap := nil;
  1739. end;
  1740. if (FDataFormatClasses <> nil) then
  1741. begin
  1742. FDataFormatClasses.Free;
  1743. FDataFormatClasses := nil;
  1744. end;
  1745. ShellMalloc := nil;
  1746. OleUninitialize;
  1747. end.