DragDropBitmap.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. unit DragDropBitmap;
  2. {
  3. Description
  4. ===========
  5. TDragDropBitmap is a component for simple OLE drag-and-drop operations
  6. with bitmaps. The component is a child-class from TDragDrop.
  7. Disclaimer
  8. ==========
  9. The author disclaims all warranties, expressed or implied, including,
  10. without limitation, the warranties of merchantability and of fitness
  11. for any purpose. The author assumes no liability for damages, direct or
  12. consequential, which may result from the use of this component/unit.
  13. Restrictions on Using the Unit / Component
  14. ==========================================
  15. This unit/component is copyright 1998 by Dieter Steinwedel. ALL RIGHTS
  16. ARE RESERVED BY DIETER STEINWEDEL. You are allowed to use it freely
  17. subject to the following restrictions:
  18. • You are not allowed delete or alter the author's name and
  19. copyright in any manner
  20. • You are not allowed to publish a copy, modified version or
  21. compilation neither for payment in any kind nor freely
  22. • You are allowed to create a link to the download in the WWW
  23. • These restrictions and terms apply to you as long as until
  24. I alter them. Changes can found on my homepage
  25. Contact
  26. =======
  27. homepage: http://godard.oec.uni-osnabrueck.de/student_home/dsteinwe/delphi/DietersDelphiSite.htm
  28. }
  29. {$ALIGN ON}
  30. {$ASSERTIONS OFF}
  31. {$BOOLEVAL OFF}
  32. {$DENYPACKAGEUNIT OFF}
  33. {$EXTENDEDSYNTAX ON}
  34. {$HINTS ON}
  35. {$IMPORTEDDATA ON}
  36. {$LONGSTRINGS ON}
  37. {$OPTIMIZATION ON}
  38. {$TYPEDADDRESS OFF}
  39. {$TYPEINFO OFF}
  40. {$WARNINGS ON}
  41. interface
  42. uses DragDrop, Windows, Classes, SysUtils, ActiveX, Graphics, Controls, Forms;
  43. type
  44. TDataObjectBitmap = class(TDataObject)
  45. private
  46. DIBStream:TMemoryStream;
  47. public
  48. constructor Create(const Bitmap: TBitmap);
  49. destructor Destroy; override;
  50. function RenderData(FormatEtc:TFormatEtc;
  51. var StgMedium: TStgMedium):HResult; override;
  52. end;
  53. TDropTargetBitmap = class(TDropTarget)
  54. protected
  55. procedure AcceptDataObject(DataObj: IDataObject; var Accept:boolean); override;
  56. public
  57. constructor Create(AOwner: TDragDrop);
  58. destructor Destroy; override;
  59. procedure RenderDropped(DataObj: IDataObject; grfKeyState: Longint;
  60. pt: TPoint; var dwEffect: longint); override;
  61. end;
  62. TDragDropBitmap = class(TDragDrop)
  63. private
  64. FBitmap:TBitmap;
  65. procedure SetBitmap(Bitmap:TBitmap);
  66. protected
  67. function CreateDataObject:TDataObject; override;
  68. public
  69. constructor Create(AOwner: TComponent); override;
  70. destructor Destroy; override;
  71. property Bitmap: TBitmap read FBitmap write SetBitmap;
  72. end;
  73. procedure Register;
  74. implementation
  75. // some local functions --------------------------------------------------------
  76. {procedure CopyAsBitmap(Bitmap:TBitmap; DataPtr: PChar; DataSize:longint);
  77. var MemoryStream: TMemoryStream;
  78. BMF: TBitmapFileheader;
  79. begin
  80. ZeroMemory(@BMF, sizeof (TBitmapFileheader));
  81. BMF.bfType:=$4D42;
  82. MemoryStream:=TMemoryStream.Create;
  83. try
  84. MemoryStream.Write(BMF, sizeof (BMF));
  85. MemoryStream.Write(DataPtr^, DataSize);
  86. MemoryStream.Seek(0,0);
  87. Bitmap.LoadFromStream(MemoryStream);
  88. finally
  89. MemoryStream.Free;
  90. end;
  91. end;}
  92. procedure CopyAsBitmap(Bitmap:TBitmap; DataPtr: PChar; DataSize:longint);
  93. var BitmapInfoHeader: TBitmapInfoHeader;
  94. BitmapInfo: PBitmapInfo;
  95. Size: Word;
  96. Pal: HPALETTE;
  97. BitsMem: Pointer;
  98. Focus: HWND;
  99. DC: HDC;
  100. OldPal: HPALETTE;
  101. ImagePtr:pchar;
  102. ImageSize:DWord;
  103. function GetDInColors(BitCount: Word): Integer;
  104. begin
  105. case BitCount of
  106. 1, 4, 8: Result := 1 shl BitCount;
  107. else Result := 0;
  108. end;
  109. end;
  110. function PaletteFromW3DIB(const BI: TBitmapInfo): HPALETTE;
  111. var DstPal: PLogPalette;
  112. Colors, n: Integer;
  113. Size: Longint;
  114. DC: HDC;
  115. Focus: HWND;
  116. SysPalSize: Integer;
  117. I: Integer;
  118. begin
  119. Result := 0;
  120. { If the ClrUsed field of the header is non-zero, it means that we could
  121. have a short color table }
  122. with BI.bmiHeader do
  123. if biClrUsed <> 0 then Colors := biClrUsed
  124. else Colors := GetDInColors(biBitCount);
  125. if Colors <= 2 then Exit;
  126. Size := SizeOf(TLogPalette) + ((Colors - 1) * SizeOf(TPaletteEntry));
  127. DstPal := AllocMem(Size);
  128. try
  129. FillChar(DstPal^, Size, 0);
  130. with DstPal^ do
  131. begin
  132. palNumEntries := Colors;
  133. palVersion := $300;
  134. Focus := GetFocus;
  135. DC := GetDC(Focus);
  136. try
  137. SysPalSize := GetDeviceCaps(DC, SIZEPALETTE);
  138. if (Colors = 16) and (SysPalSize >= 16) then
  139. begin
  140. { Ignore the disk image of the palette for 16 color bitmaps use
  141. instead the first 8 and last 8 of the current system palette }
  142. GetSystemPaletteEntries(DC, 0, 8, palPalEntry);
  143. I := 8;
  144. GetSystemPaletteEntries(DC, SysPalSize - I, I, palPalEntry[I]);
  145. end
  146. else
  147. { Copy the palette for all others (i.e. 256 colors) }
  148. for N := 0 to Colors - 1 do
  149. begin
  150. palPalEntry[N].peRed := BI.bmiColors[N].rgbRed;
  151. palPalEntry[N].peGreen := BI.bmiColors[N].rgbGreen;
  152. palPalEntry[N].peBlue := BI.bmiColors[N].rgbBlue;
  153. palPalEntry[N].peFlags := 0;
  154. end;
  155. finally
  156. ReleaseDC(Focus, DC);
  157. end;
  158. end;
  159. Result := CreatePalette(DstPal^);
  160. finally
  161. FreeMem(DstPal, Size);
  162. end;
  163. end;
  164. begin
  165. ImagePtr:=DataPtr;
  166. ImageSize:=DataSize;
  167. CopyMemory(@BitmapInfoHeader,ImagePtr,SizeOf(TBitmapInfoHeader));
  168. ImagePtr:=ImagePtr+SizeOf(TBitmapInfoHeader);
  169. with BitmapInfoHeader do
  170. begin
  171. if biClrUsed = 0 then
  172. biClrUsed := GetDInColors(biBitCount);
  173. Size := biClrUsed * SizeOf(TRgbQuad);
  174. end;
  175. BitmapInfo := AllocMem(Size + SizeOf(TBitmapInfoHeader));
  176. try
  177. with BitmapInfo^ do
  178. begin
  179. bmiHeader := BitmapInfoHeader;
  180. CopyMemory(@bmiColors, ImagePtr,Size);
  181. ImagePtr:=ImagePtr+Size;
  182. { now we've got the color table. Create a palette from it }
  183. Pal := PaletteFromW3DIB(BitmapInfo^);
  184. { some applications do not fill in the SizeImage field in the header.
  185. (Actually the truth is more likely that some drivers do not fill the field
  186. in and the apps do not compensate for these buggy drivers.) Therefore, if
  187. this field is 0, we will compute the size. }
  188. with bmiHeader do
  189. begin
  190. Dec(ImageSize, SizeOf(TBitmapInfoHeader) + Size);
  191. if biSizeImage <> 0 then
  192. if biSizeImage < ImageSize then ImageSize := biSizeImage;
  193. BitsMem := AllocMem(ImageSize);
  194. try
  195. CopyMemory(BitsMem, ImagePtr,ImageSize);
  196. { we use the handle of the window with the focus (which, if this routine
  197. is called from a menu command, will be this window) in order to guarantee
  198. that the realized palette will have first priority on the system palette }
  199. Focus := GetFocus;
  200. DC := GetDC(Focus);
  201. if DC <>0 then
  202. try
  203. if Pal <> 0 then
  204. begin
  205. { select and realize our palette we have gotten the DC of the focus
  206. window just to make sure that all our colors are mapped }
  207. OldPal := SelectPalette(DC, Pal, False);
  208. RealizePalette(DC);
  209. end
  210. else OldPal := 0;
  211. try
  212. Bitmap.Handle:=CreateDIBitmap(DC, BitmapInfo^.bmiHeader, CBM_INIT, BitsMem,
  213. BitmapInfo^, DIB_RGB_COLORS);
  214. finally
  215. if OldPal <> 0 then
  216. SelectPalette(DC, OldPal, False);
  217. end;
  218. finally
  219. ReleaseDC(Focus, DC);
  220. end;
  221. finally
  222. FreeMem(BitsMem, ImageSize);
  223. end;
  224. end;
  225. end;
  226. finally
  227. FreeMem(BitmapInfo, Size + SizeOf(TBitmapInfoHeader));
  228. end;
  229. end;
  230. function WidthBytes(I: Longint): Longint;
  231. begin
  232. Result := ((I + 31) div 32) * 4;
  233. end;
  234. procedure InitializeBitmapInfoHeader(Bitmap: HBITMAP; var BI: TBitmapInfoHeader;
  235. Colors: Integer);
  236. var BM: Windows.TBitmap;
  237. begin
  238. GetObject(Bitmap, SizeOf(BM), @BM);
  239. with BI do
  240. begin
  241. biSize := SizeOf(BI);
  242. biWidth := BM.bmWidth;
  243. biHeight := BM.bmHeight;
  244. if Colors <> 0 then
  245. case Colors of
  246. 2: biBitCount := 1;
  247. 16: biBitCount := 4;
  248. 256: biBitCount := 8;
  249. end
  250. else biBitCount := BM.bmBitsPixel * BM.bmPlanes;
  251. biPlanes := 1;
  252. biXPelsPerMeter := 0;
  253. biYPelsPerMeter := 0;
  254. biClrUsed := 0;
  255. biClrImportant := 0;
  256. biCompression := BI_RGB;
  257. if biBitCount in [16, 32] then biBitCount := 24;
  258. biSizeImage := WidthBytes(biWidth * biBitCount) * biHeight;
  259. end;
  260. end;
  261. procedure InternalGetDIBSizes(Bitmap: HBITMAP; var InfoHeaderSize: Integer;
  262. var ImageSize: DWORD; Colors: Integer);
  263. var BI: TBitmapInfoHeader;
  264. begin
  265. InitializeBitmapInfoHeader(Bitmap, BI, Colors);
  266. with BI do
  267. begin
  268. if biBitCount=24 then InfoHeaderSize := SizeOf(TBitmapInfoHeader)
  269. else InfoHeaderSize := SizeOf(TBitmapInfoHeader) + SizeOf(TRGBQuad) *
  270. (1 shl biBitCount);
  271. end;
  272. ImageSize := BI.biSizeImage;
  273. end;
  274. function InternalGetDIB(Bitmap: HBITMAP; Palette: HPALETTE;
  275. var BitmapInfo; var Bits; Colors: Integer): Boolean;
  276. var OldPal: HPALETTE;
  277. Focus: HWND;
  278. DC: HDC;
  279. begin
  280. InitializeBitmapInfoHeader(Bitmap, TBitmapInfoHeader(BitmapInfo), Colors);
  281. OldPal := 0;
  282. Focus := GetFocus;
  283. DC := GetDC(Focus);
  284. try
  285. if Palette <> 0 then
  286. begin
  287. OldPal := SelectPalette(DC, Palette, False);
  288. RealizePalette(DC);
  289. end;
  290. Result := GetDIBits(DC, Bitmap, 0, TBitmapInfoHeader(BitmapInfo).biHeight,
  291. @Bits, TBitmapInfo(BitmapInfo), DIB_RGB_COLORS) <> 0;
  292. finally
  293. if OldPal <> 0 then SelectPalette(DC, OldPal, False);
  294. ReleaseDC(Focus, DC);
  295. end;
  296. end;
  297. procedure DIBFromBit(Stream: TMemoryStream; Src: HBITMAP;
  298. Pal: HPALETTE; Colors: Integer; var DIBHeader, DIBBits: Pointer);
  299. var HeaderSize: Integer;
  300. ImageSize: DWORD;
  301. begin
  302. if Src=0 then exit;
  303. InternalGetDIBSizes(Src, HeaderSize, ImageSize, Colors);
  304. Stream.SetSize(HeaderSize + integer(ImageSize));
  305. DIBHeader:=Stream.Memory;
  306. DIBBits:=Pointer(Longint(DIBHeader) + HeaderSize);
  307. InternalGetDIB(Src, Pal, DIBHeader^, DIBBits^, Colors);
  308. end;
  309. // TDataObjectBitmap -----------------------------------------------------------
  310. constructor TDataObjectBitmap.Create(const Bitmap: TBitmap);
  311. var FE:TFormatEtc;
  312. SM:TStgMedium;
  313. DIBHeader, DIBBits: Pointer;
  314. begin
  315. inherited Create;
  316. with FE do
  317. begin
  318. cfFormat:=CF_DIB;
  319. ptd:=nil;
  320. dwAspect:=DVASPECT_CONTENT;
  321. lindex:=-1;
  322. tymed:=TYMED_HGLOBAL;
  323. end;
  324. SetData(FE,SM,false);
  325. DIBStream:=TMemoryStream.Create;
  326. DIBFromBit(DIBStream, Bitmap.Handle, Bitmap.Palette,0,DIBHeader, DIBBits);
  327. // Don't release DIBHeader and DIBBits; both points to a position in the stream
  328. end;
  329. destructor TDataObjectBitmap.Destroy;
  330. begin
  331. DIBStream.free;
  332. inherited Destroy;
  333. end;
  334. function TDataObjectBitmap.RenderData(FormatEtc:TFormatEtc;
  335. var StgMedium: TStgMedium):HResult;
  336. var h: HGlobal;
  337. p:pointer;
  338. begin
  339. Result:=E_Fail;
  340. if FormatEtc.cfFormat=cf_DIB then
  341. begin
  342. h:=GlobalAlloc(GHND or GMEM_SHARE, DIBStream.Size);
  343. if h=0 then
  344. begin
  345. Result:=E_OUTOFMEMORY;
  346. exit;
  347. end;
  348. p:=globallock(h);
  349. DIBStream.Seek(0,0);
  350. DIBStream.Read(p^,DIBStream.Size);
  351. globalunlock(h);
  352. with StgMedium do
  353. begin
  354. tymed:=TYMED_HGLOBAL;
  355. hGlobal := h;
  356. unkForRelease := nil;
  357. end;
  358. Result:=S_OK;
  359. end;
  360. end;
  361. // TDropTargetBitmap -----------------------------------------------------------
  362. constructor TDropTargetBitmap.Create(AOwner: TDragDrop);
  363. begin
  364. inherited Create(AOwner);
  365. end;
  366. destructor TDropTargetBitmap.Destroy;
  367. begin
  368. inherited Destroy;
  369. end;
  370. procedure TDropTargetBitmap.AcceptDataObject(DataObj: IDataObject; var Accept:boolean);
  371. var FE:TFormatEtc;
  372. begin
  373. with FE do
  374. begin
  375. cfFormat:=cf_DIB;
  376. ptd:=nil;
  377. dwAspect:=DVASPECT_CONTENT;
  378. lindex:=-1;
  379. tymed:=TYMED_HGLOBAL;
  380. end;
  381. Accept:=DataObj.QueryGetData(FE)=S_OK;
  382. end;
  383. procedure TDropTargetBitmap.RenderDropped(DataObj: IDataObject; grfKeyState: Longint;
  384. pt: TPoint; var dwEffect: longint);
  385. var FE: TFormatEtc;
  386. SM: TStgMedium;
  387. DataSize: longint;
  388. DataPtr: pointer;
  389. begin
  390. with FE do
  391. begin
  392. cfFormat:=CF_DIB;
  393. ptd:=nil;
  394. dwAspect:=DVASPECT_CONTENT;
  395. lindex:=-1;
  396. tymed:=TYMED_HGLOBAL;
  397. end;
  398. if DataObj.GetData(FE,SM)=S_Ok then
  399. begin
  400. DataSize:=GlobalSize(SM.HGlobal);
  401. try
  402. DataPtr:=GlobalLock(SM.HGlobal);
  403. CopyAsBitmap(TDragDropBitmap(FOwner).FBitmap,DataPtr, DataSize);
  404. finally
  405. GlobalUnLock(SM.HGlobal);
  406. ReleaseStgMedium(SM);
  407. end;
  408. end;
  409. end;
  410. // TDragDropBitmap -------------------------------------------------------------
  411. constructor TDragDropBitmap.Create(AOwner: TComponent);
  412. begin
  413. inherited Create(AOwner);
  414. FBitmap:=TBitmap.Create;
  415. FDropTarget._Release;
  416. FDropTarget:=TDropTargetBitmap.Create(self);
  417. end;
  418. destructor TDragDropBitmap.Destroy;
  419. begin
  420. FBitmap.free;
  421. inherited destroy;
  422. end;
  423. procedure TDragDropBitmap.SetBitmap(Bitmap:TBitmap);
  424. var MS:TMemoryStream;
  425. begin
  426. // A little bit dirty but short ...
  427. MS:=TMemoryStream.Create;
  428. Bitmap.SaveToStream(MS);
  429. MS.Seek(0,0);
  430. FBitmap.LoadFromStream(MS);
  431. MS.Free;
  432. end;
  433. function TDragDropBitmap.CreateDataObject:TDataObject;
  434. begin
  435. if FBitmap.Empty=false then Result:=TDataObjectBitmap.Create(FBitmap)
  436. else Result:=nil;
  437. end;
  438. // Register --------------------------------------------------------------------
  439. procedure Register;
  440. begin
  441. {MP}RegisterComponents({'Shell32'}'DragDrop', [TDragDropBitmap]);
  442. end;
  443. end.