PageRenderTime 48ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/controls/olerichedit/KOLOleRE.pas

http://github.com/rofl0r/KOL
Pascal | 481 lines | 403 code | 48 blank | 30 comment | 22 complexity | 038ec26dc4cbd8bb19e137d4fd7f96b9 MD5 | raw file
  1. unit KOLOleRE;
  2. interface
  3. uses
  4. Windows, Messages, KOL;
  5. type
  6. PKOLOleRichEdit =^TKOLOleRichEdit;
  7. TKOLOleRichEdit = object(TControl)
  8. protected
  9. procedure CreateHandle;
  10. function GetDragOle: boolean;
  11. procedure SetDragOle(d: boolean);
  12. public
  13. destructor Destroy; virtual;
  14. function BitmapToRTF(pict: PBitmap): string;
  15. procedure HideFrames;
  16. property CanDragOle: boolean read GetDragOle write SetDragOle;
  17. end;
  18. function NewOLERichEdit( AParent: PControl; Options: TEditOptions ): PKOLOleRichEdit;
  19. implementation
  20. {$B-}
  21. uses
  22. ActiveX, KOLComObj;
  23. const
  24. {$EXTERNALSYM EM_GETOLEINTERFACE}
  25. EM_GETOLEINTERFACE = WM_USER + 60;
  26. type
  27. _charrange = record
  28. cpMin: Longint;
  29. cpMax: LongInt;
  30. end;
  31. {$EXTERNALSYM _charrange}
  32. TCharRange = _charrange;
  33. CHARRANGE = _charrange;
  34. {$EXTERNALSYM CHARRANGE}
  35. TREOBJECT = packed record
  36. cbStruct: DWORD; // Size of structure
  37. cp: longint; // Character position of object
  38. clsid: TCLSID; // Class ID of object
  39. oleobj: IOleObject; // OLE object interface
  40. stg: IStorage; // Associated storage interface
  41. olesite: IOLEClientSite; // Associated client site interface
  42. sizel: TSize; // Size of object (may be 0,0)
  43. dvaspect: DWORD; // Display aspect to use
  44. dwFlags: DWORD; // Object status flags
  45. dwUser: DWORD; // Dword for user's use
  46. end;
  47. IRichEditOle = interface(IUnknown)
  48. ['{00020D00-0000-0000-C000-000000000046}']
  49. function GetClientSite(out lplpolesite: IOLECLIENTSITE): HResult; stdcall;
  50. function GetObjectCount: longint; stdcall;
  51. function GetLinkCount: longint; stdcall;
  52. function GetObject(iob: longint; out reobject: TREOBJECT; dwFlags: DWORD): HRESULT; stdcall;
  53. function InsertObject(const reobject: TREOBJECT): HResult; stdcall;
  54. function ConvertObject(iob: longint; const clsidNew: TCLSID;
  55. lpStrUserTypeNew: POleStr): HRESULT; stdcall;
  56. function ActivateAs(const clsid, clsidAs: TCLSID): HRESULT; stdcall;
  57. function SetHostNames(lpstrContainerApp, lpstrContainerObj: POleStr): HRESULT; stdcall;
  58. function SetLinkAvailable(iob: longint; fAvailable: BOOL): HRESULT; stdcall;
  59. function SetDvaspect(iob: longint; dvaspect: DWORD): HRESULT; stdcall;
  60. function HandsOffStorage(iob: longint): HRESULT; stdcall;
  61. function SaveCompleted(iob: longint; stg: IStorage): HRESULT; stdcall;
  62. function InPlaceDeactivate: HRESULT; stdcall;
  63. function ContextSensitiveHelp(fEnterMode: BOOL): HRESULT; stdcall;
  64. function GetClipboardData(const chrg: TCharRange; reco: DWORD;
  65. out dataobj: IDataObject): HRESULT; stdcall;
  66. function ImportDataObject(dataobj: IDataObject; cf: TClipFormat;
  67. hMetaPict: HGLOBAL): HRESULT; stdcall;
  68. end;
  69. IRichEditOleCallback = interface(IUnknown)
  70. ['{00020D03-0000-0000-C000-000000000046}']
  71. function GetNewStorage: IStorage; safecall;
  72. procedure GetInPlaceContext(out Frame: IOleInPlaceFrame;
  73. out Doc: IOleInPlaceUIWindow; var FrameInfo: TOleInPlaceFrameInfo); safecall;
  74. procedure ShowContainerUI(fShow: Bool); safecall;
  75. procedure QueryInsertObject(const ClsID: TCLSID; Stg: IStorage; CP: Longint); safecall;
  76. procedure DeleteObject(OleObj: IOleObject); safecall;
  77. procedure QueryAcceptData(dataobj: IDataObject; var cfFormat: TClipFormat;
  78. reCO: DWord; fReally: Bool; hMetaPict: HGlobal); safecall;
  79. function ContextSensitiveHelp(fEnterMode: Bool): HResult; stdcall;
  80. function GetClipboardData(const ChRg: TCharRange; reCO: DWord; out DataObj: IDataObject): HResult; stdcall;
  81. procedure GetDragDropEffect(fDrag: Bool; grfKeyState: DWord;
  82. var dwEffect: DWord); safecall;
  83. procedure GetContextMenu(SelType: Word; OleObj: IOleObject;
  84. const ChRg: TCharRange; var Menu: HMenu); safecall;
  85. end;
  86. TRichEditOleCallback = class(TInterfacedObject, IRichEditOleCallback)
  87. private
  88. FOwner: PKOLOleRichEdit;
  89. protected
  90. { IRichEditOleCallback }
  91. function GetNewStorage: IStorage; safecall;
  92. procedure GetInPlaceContext(out Frame: IOleInPlaceFrame;
  93. out Doc: IOleInPlaceUIWindow; var FrameInfo: TOleInPlaceFrameInfo); safecall;
  94. procedure ShowContainerUI(fShow: Bool); safecall;
  95. procedure QueryInsertObject(const ClsID: TCLSID; Stg: IStorage; CP: Longint); safecall;
  96. procedure DeleteObject(OleObj: IOleObject); safecall;
  97. procedure QueryAcceptData(dataobj: IDataObject; var cfFormat: TClipFormat;
  98. reCO: DWord; fReally: Bool; hMetaPict: HGlobal); safecall;
  99. function ContextSensitiveHelp(fEnterMode: Bool): HResult; stdcall;
  100. function GetClipboardData(const ChRg: TCharRange; reCO: DWord; out DataObj: IDataObject): HResult; stdcall;
  101. procedure GetDragDropEffect(fDrag: Bool; grfKeyState: DWord;
  102. var dwEffect: DWord); safecall;
  103. procedure GetContextMenu(SelType: Word; OleObj: IOleObject;
  104. const ChRg: TCharRange; var Menu: HMenu); safecall;
  105. public
  106. constructor Create(Owner: PKOLOleRichEdit);
  107. destructor Destroy; override;
  108. end;
  109. PData =^TData;
  110. TData = record
  111. IOle: IRichEditOle;
  112. IBck: TRichEditOleCallback;
  113. Drag: boolean;
  114. end;
  115. const
  116. {$EXTERNALSYM EM_SETOLECALLBACK}
  117. EM_SETOLECALLBACK = WM_USER + 70;
  118. function NewOLERichEdit( AParent: PControl; Options: TEditOptions ): PKOLOleRichEdit;
  119. label exit;
  120. var p: PData;
  121. begin
  122. Result := PKOLOleRichEdit(KOL.NewRichEdit( AParent, Options ));
  123. new(p);
  124. FillChar(p^, SizeOf(p^), 0);
  125. Result.CustomData := p;
  126. Result.CreateWindow;
  127. Result.CreateHandle;
  128. Result.Perform(EM_GETOLEINTERFACE, 0, integer(@p.IOle));
  129. asm
  130. MOV EDX, offset @@new_call + 4
  131. MOV EDX, [EDX]
  132. ADD EDX, 12
  133. MOV [EBX], EDX
  134. jmp exit
  135. @@new_call:
  136. end;
  137. new( Result, CreateParented( AParent ) );
  138. exit:
  139. end;
  140. {$O-}
  141. destructor TKOLOleRichEdit.Destroy;
  142. var //I: TRichEditOleCallback;
  143. P: PData;
  144. begin
  145. P := CustomData;
  146. P.IBck._Release;
  147. Dispose(P);
  148. CustomData := nil;
  149. inherited;
  150. end;
  151. {$O+}
  152. procedure TKOLOleRichEdit.CreateHandle;
  153. var I: IRichEditOleCallback;
  154. T: TRichEditOleCallback;
  155. P: PData;
  156. begin
  157. inherited;
  158. T := TRichEditOleCallback.Create(@Self);
  159. I := T as IRichEditOleCallback;
  160. Perform(em_SetOleCallback, 0, Longint(I));
  161. P := CustomData;
  162. P.IBck := T;
  163. end;
  164. { TRichEditOleCallback }
  165. constructor TRichEditOleCallback.Create(Owner: PKOLOleRichEdit);
  166. begin
  167. inherited Create;
  168. FOwner := Owner;
  169. end;
  170. destructor TRichEditOleCallback.Destroy;
  171. //var Form: PControl;
  172. begin
  173. { Form := GetParentForm(FOwner);}
  174. { if Assigned(Form) and Assigned(Form.OleFormObject) then
  175. (Form.OleFormObject as IOleInPlaceUIWindow).SetActiveObject(nil, nil);}
  176. inherited;
  177. end;
  178. function TRichEditOleCallback.ContextSensitiveHelp(fEnterMode: Bool): HResult;
  179. begin
  180. Result := E_NOTIMPL
  181. end;
  182. procedure TRichEditOleCallback.DeleteObject(OleObj: IOleObject);
  183. begin
  184. OleObj.Close(OLECLOSE_NOSAVE);
  185. end;
  186. function TRichEditOleCallback.GetClipboardData(const ChRg: TCharRange; reCO: DWord; out DataObj: IDataObject): HResult;
  187. begin
  188. Result := E_NOTIMPL;
  189. end;
  190. procedure TRichEditOleCallback.GetContextMenu(SelType: Word;
  191. OleObj: IOleObject; const ChRg: TCharRange; var Menu: HMenu);
  192. begin
  193. Menu := 0
  194. end;
  195. procedure TRichEditOleCallback.GetDragDropEffect(fDrag: Bool;
  196. grfKeyState: DWord; var dwEffect: DWord);
  197. var p: PData;
  198. begin
  199. if fOwner <> nil then begin
  200. if fOwner.CustomData <> nil then begin
  201. p := fOwner.CustomData;
  202. if not p.Drag then begin
  203. dwEffect := 0;
  204. end;
  205. end;
  206. end;
  207. end;
  208. procedure TRichEditOleCallback.GetInPlaceContext(
  209. out Frame: IOleInPlaceFrame; out Doc: IOleInPlaceUIWindow;
  210. var FrameInfo: TOleInPlaceFrameInfo);
  211. var
  212. Form: PControl;
  213. begin
  214. //Get richedit's underlying form
  215. { Form := ValidParentForm(FOwner);}
  216. //Ensure there is a TOleForm object
  217. { if Form.OleFormObject = nil then
  218. TOleForm.Create(Form);}
  219. //Get relevant frame interface
  220. { Frame := Form.OleFormObject as IOleInPlaceFrame;}
  221. Doc := nil; //Document window is same as frame window
  222. FrameInfo.hWndFrame := 0; // Form.Handle;
  223. FrameInfo.fMDIApp := False;
  224. FrameInfo.hAccel := 0;
  225. FrameInfo.cAccelEntries := 0;
  226. end;
  227. function TRichEditOleCallback.GetNewStorage: IStorage;
  228. var
  229. LockBytes: ILockBytes;
  230. begin
  231. //Basically copied from TOleContainer.CreateStorage
  232. OleCheck(CreateILockBytesOnHGlobal(0, True, LockBytes));
  233. OleCheck(StgCreateDocfileOnILockBytes(LockBytes,
  234. STGM_READWRITE or STGM_SHARE_EXCLUSIVE or STGM_CREATE, 0, Result));
  235. end;
  236. procedure TRichEditOleCallback.QueryAcceptData(dataobj: IDataObject;
  237. var cfFormat: TClipFormat; reCO: DWord; fReally: Bool;
  238. hMetaPict: HGlobal);
  239. begin
  240. //Accept anything
  241. end;
  242. procedure TRichEditOleCallback.QueryInsertObject(const ClsID: TCLSID;
  243. Stg: IStorage; CP: Integer);
  244. begin
  245. //Accept anything
  246. end;
  247. procedure TRichEditOleCallback.ShowContainerUI(fShow: Bool);
  248. var
  249. Form: PControl;
  250. begin
  251. if fShow then
  252. begin
  253. { Form := GetParentForm(FOwner);}
  254. { if Assigned(Form) and Assigned(Form.Menu) then
  255. begin
  256. Form.Menu.SetOle2MenuHandle(0);
  257. (Form.OleFormObject as IVCLFrameForm).ClearBorderSpace
  258. end}
  259. end
  260. end;
  261. { TOleRichEdit }
  262. function BytesPerScanline(PixelsPerScanline, BitsPerPixel, Alignment: Longint): Longint;
  263. begin
  264. Dec(Alignment);
  265. Result := ((PixelsPerScanline * BitsPerPixel) + Alignment) and not Alignment;
  266. Result := Result div 8;
  267. end;
  268. procedure InitializeBitmapInfoHeader(Bitmap: HBITMAP; var BI: TBitmapInfoHeader;
  269. Colors: Integer);
  270. var
  271. DS: TDIBSection;
  272. Bytes: Integer;
  273. begin
  274. DS.dsbmih.biSize := 0;
  275. Bytes := GetObject(Bitmap, SizeOf(DS), @DS);
  276. if Bytes = 0 then {InvalidBitmap}
  277. else if (Bytes >= (sizeof(DS.dsbm) + sizeof(DS.dsbmih))) and
  278. (DS.dsbmih.biSize >= DWORD(sizeof(DS.dsbmih))) then
  279. BI := DS.dsbmih
  280. else
  281. begin
  282. FillChar(BI, sizeof(BI), 0);
  283. with BI, DS.dsbm do
  284. begin
  285. biSize := SizeOf(BI);
  286. biWidth := bmWidth;
  287. biHeight := bmHeight;
  288. end;
  289. end;
  290. case Colors of
  291. 2: BI.biBitCount := 1;
  292. 3..16:
  293. begin
  294. BI.biBitCount := 4;
  295. BI.biClrUsed := Colors;
  296. end;
  297. 17..256:
  298. begin
  299. BI.biBitCount := 8;
  300. BI.biClrUsed := Colors;
  301. end;
  302. else
  303. BI.biBitCount := DS.dsbm.bmBitsPixel * DS.dsbm.bmPlanes;
  304. end;
  305. BI.biPlanes := 1;
  306. if BI.biClrImportant > BI.biClrUsed then
  307. BI.biClrImportant := BI.biClrUsed;
  308. if BI.biSizeImage = 0 then
  309. BI.biSizeImage := BytesPerScanLine(BI.biWidth, BI.biBitCount, 32) * Abs(BI.biHeight);
  310. end;
  311. procedure InternalGetDIBSizes(Bitmap: HBITMAP; var InfoHeaderSize: DWORD;
  312. var ImageSize: DWORD; Colors: Integer);
  313. var
  314. BI: TBitmapInfoHeader;
  315. begin
  316. InitializeBitmapInfoHeader(Bitmap, BI, Colors);
  317. if BI.biBitCount > 8 then
  318. begin
  319. InfoHeaderSize := SizeOf(TBitmapInfoHeader);
  320. if (BI.biCompression and BI_BITFIELDS) <> 0 then
  321. Inc(InfoHeaderSize, 12);
  322. end
  323. else
  324. if BI.biClrUsed = 0 then
  325. InfoHeaderSize := SizeOf(TBitmapInfoHeader) +
  326. SizeOf(TRGBQuad) * (1 shl BI.biBitCount)
  327. else
  328. InfoHeaderSize := SizeOf(TBitmapInfoHeader) +
  329. SizeOf(TRGBQuad) * BI.biClrUsed;
  330. ImageSize := BI.biSizeImage;
  331. end;
  332. procedure GetDIBSizes(Bitmap: HBITMAP; var InfoHeaderSize: DWORD;
  333. var ImageSize: DWORD);
  334. begin
  335. InternalGetDIBSizes(Bitmap, InfoHeaderSize, ImageSize, 0);
  336. end;
  337. function InternalGetDIB(Bitmap: HBITMAP; Palette: HPALETTE;
  338. var BitmapInfo; var Bits; Colors: Integer): Boolean;
  339. var
  340. OldPal: HPALETTE;
  341. DC: HDC;
  342. begin
  343. InitializeBitmapInfoHeader(Bitmap, TBitmapInfoHeader(BitmapInfo), Colors);
  344. OldPal := 0;
  345. DC := CreateCompatibleDC(0);
  346. try
  347. if Palette <> 0 then
  348. begin
  349. OldPal := SelectPalette(DC, Palette, False);
  350. RealizePalette(DC);
  351. end;
  352. Result := GetDIBits(DC, Bitmap, 0, TBitmapInfoHeader(BitmapInfo).biHeight, @Bits,
  353. TBitmapInfo(BitmapInfo), DIB_RGB_COLORS) <> 0;
  354. finally
  355. if OldPal <> 0 then SelectPalette(DC, OldPal, False);
  356. DeleteDC(DC);
  357. end;
  358. end;
  359. function GetDIB(Bitmap: HBITMAP; Palette: HPALETTE; var BitmapInfo; var Bits): Boolean;
  360. begin
  361. Result := InternalGetDIB(Bitmap, Palette, BitmapInfo, Bits, 0);
  362. end;
  363. function TKOLOleRichEdit.BitmapToRTF(pict: PBitmap): string;
  364. var
  365. bi, bb, rtf: string;
  366. bis, bbs: Cardinal;
  367. achar: ShortString;
  368. hexpict: string;
  369. I: Integer;
  370. begin
  371. GetDIBSizes(pict.Handle, bis, bbs);
  372. SetLength(bi, bis);
  373. SetLength(bb, bbs);
  374. GetDIB(pict.Handle, {pict.Palette}0, PChar(bi)^, PChar(bb)^);
  375. rtf := '{\rtf1 {\pict\dibitmap ';
  376. SetLength(hexpict, (Length(bb) + Length(bi)) * 2);
  377. I := 2;
  378. for bis := 1 to Length(bi) do
  379. begin
  380. achar := Format('%x', [Integer(bi[bis])]);
  381. if Length(achar) = 1 then
  382. achar := '0' + achar;
  383. hexpict[I - 1] := achar[1];
  384. hexpict[I] := achar[2];
  385. Inc(I, 2);
  386. end;
  387. for bbs := 1 to Length(bb) do
  388. begin
  389. achar := Format('%x', [Integer(bb[bbs])]);
  390. if Length(achar) = 1 then
  391. achar := '0' + achar;
  392. hexpict[I - 1] := achar[1];
  393. hexpict[I] := achar[2];
  394. Inc(I, 2);
  395. end;
  396. rtf := rtf + hexpict + ' }}';
  397. Result := rtf;
  398. end;
  399. procedure TKOLOleRichEdit.HideFrames;
  400. var p: PData;
  401. i: integer;
  402. n: integer;
  403. o: TREOBJECT;
  404. begin
  405. p := CustomData;
  406. n := p.IOle.GetObjectCount;
  407. for i := n - 1 downto 0 do begin
  408. fillchar(o, sizeof(o), 0);
  409. o.cbStruct := sizeof(O);
  410. if p.IOle.GetObject(i, o, 7) = S_OK then begin
  411. o.dwFlags := 0;
  412. p.IOle.InsertObject(o);
  413. end;
  414. end;
  415. end;
  416. function TKOLOleRichEdit.GetDragOle;
  417. var p: PData;
  418. begin
  419. Result := False;
  420. if CustomData <> nil then begin
  421. p := CustomData;
  422. Result := p.Drag;
  423. end;
  424. end;
  425. procedure TKOLOleRichEdit.SetDragOle;
  426. var p: PData;
  427. begin
  428. if CustomData <> nil then begin
  429. p := CustomData;
  430. p.Drag := d;
  431. end;
  432. end;
  433. end.