Skip to content

Instantly share code, notes, and snippets.

@rkennedy
Created December 15, 2011 17:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rkennedy/1482014 to your computer and use it in GitHub Desktop.
Save rkennedy/1482014 to your computer and use it in GitHub Desktop.
Using the windowsless RTF control from Delphi: http://www.cs.wisc.edu/~rkennedy/windowless-rtf
// Demonstration of using TOM.pas, the windowless rich-edit control, and
// the text object model
// http://www.cs.wisc.edu/~rkennedy/windowless-rtf
// Copyright © 2003-2006 Rob Kennedy. Some rights reserved.
// For license information, see http://www.cs.wisc.edu/~rkennedy/license
unit RTFPaint;
interface
uses Windows, Graphics;
// The RTF parameter should be a string containing a full RTF document. It
// will not work if it is just an RTF fragment.
procedure DrawRTF(Canvas: TCanvas; const RTF: string; const Rect: TRect; const Transparent, WordWrap: Boolean);
implementation
uses SysUtils, ComObj, ActiveX, RichEdit, Messages, TOM;
function StrCpyN(dest: PChar; const src: PChar; cchMax: Integer): PChar; stdcall; external 'shlwapi.dll' name 'StrCpyNA';
function StrCpyNA(dest: PAnsiChar; const src: PAnsiChar; cchMax: Integer): PAnsiChar; stdcall; external 'shlwapi.dll';
function StrCpyNW(dest: PWideChar; const src: PWideChar; cchMax: Integer): PWideChar; stdcall; external 'shlwapi.dll';
type
TDrawRTFTextHost = class(TTextHostImpl)
private
FDefaultCharFormat: PCharFormatW;
FDefaultParaFormat: PParaFormat;
FRect: TRect;
FTransparent, FWordWrap: Boolean;
protected
// TTextHostImpl
function TxGetClientRect(out prc: TRect): HResult; override;
function TxGetCharFormat(out ppCF: PCharFormatW): HResult; override;
function TxGetParaFormat(out ppPF: PParaFormat): HResult; override;
function TxGetBackStyle(out pstyle: TTxtBackStyle): HResult; override;
function OnTxCharFormatChange(const pcf: TCharFormatW): HResult; override;
function OnTxParaFormatChange(const ppf: TParaFormat): HResult; override;
function TxGetPropertyBits(dwMask: DWord; out pdwBits: DWord): HResult; override;
function TxNotify(iNotify: DWord; pv: Pointer): HResult; override;
public
constructor Create(const ARect: TRect; const ATransparent, AWordWrap: Boolean);
destructor Destroy; override;
end;
PCookie = ^TCookie;
TCookie = record
dwSize, dwCount: Cardinal;
Text: PChar;
end;
function EditStreamInCallback(dwCookie: Longint; pbBuff: PByte; cb: Longint; var pcb: Longint): Longint; stdcall;
var
Cookie: PCookie;
begin
Result := 0;
Cookie := PCookie(dwCookie);
if Cookie.dwSize - Cookie.dwCount < Cardinal(cb) then pcb := Cookie.dwSize - Cookie.dwCount
else pcb := cb;
if pcb <= 0 then exit;
CopyMemory(pbBuff, Cookie.Text, pcb);
Inc(Cookie.dwCount, pcb);
Inc(Cookie.Text, pcb);
end;
procedure DrawRTF(Canvas: TCanvas; const RTF: string; const Rect: TRect; const Transparent, WordWrap: Boolean);
var
Host: ITextHost;
Unknown: IUnknown;
Services: ITextServices;
HostImpl: TTextHostImpl;
Stream: TEditStream;
Cookie: TCookie;
res: Integer;
begin
HostImpl := TDrawRTFTextHost.Create(Rect, Transparent, WordWrap);
Host := CreateTextHost(HostImpl);
OleCheck(CreateTextServices(nil, Host, Unknown));
Services := Unknown as ITextServices;
Unknown := nil;
PatchTextServices(Services);
Cookie.dwCount := 0;
Cookie.dwSize := Length(RTF);
Cookie.Text := PChar(RTF);
Stream.dwCookie := Integer(@Cookie);
Stream.dwError := 0;
Stream.pfnCallback := EditStreamInCallback;
OleCheck(Services.TxSendMessage(em_StreamIn, sf_RTF or sff_PlainRTF, lParam(@Stream), res));
OleCheck(Services.TxDraw(dvAspect_Content, 0, nil, nil, Canvas.Handle, 0, Rect, PRect(nil)^, PRect(nil)^, nil, 0, txtView_Inactive));
Services := nil;
Host := nil;
end;
{ TDrawRTFTextHost }
constructor TDrawRTFTextHost.Create(const ARect: TRect; const ATransparent, AWordWrap: Boolean);
begin
inherited Create;
FRect := ARect;
FTransparent := ATransparent;
FWordWrap := AWordWrap;
GetMem(FDefaultCharFormat, SizeOf(FDefaultCharFormat^));
FillChar(FDefaultCharFormat^, SizeOf(FDefaultCharFormat^), 0);
FDefaultCharFormat.cbSize := SizeOf(FDefaultCharFormat^);
Cardinal(FDefaultCharFormat.dwMask) := cfm_Bold or cfm_Charset or {cfm_Color or} cfm_Face or cfm_Italic or cfm_Offset or cfm_Protected or {cfm_Size or} cfm_Strikeout or cfm_Underline;
FDefaultCharFormat.dwEffects := 0;
FDefaultCharFormat.yHeight := 8 * 20;
FDefaultCharFormat.crTextColor := ColorToRGB(clBlack);
FDefaultCharFormat.bCharSet := Default_Charset;
FDefaultCharFormat.bPitchAndFamily := Default_Pitch or ff_DontCare;
StrCpyNW(FDefaultCharFormat.szFaceName, 'Tahoma', SizeOf(FDefaultCharFormat.szFaceName) div SizeOf(FDefaultCharFormat.szFaceName[0]));
GetMem(FDefaultParaFormat, SizeOf(FDefaultParaFormat^));
FillChar(FDefaultParaFormat^, SizeOf(FDefaultParaFormat^), 0);
FDefaultParaFormat.cbSize := SizeOf(FDefaultParaFormat^);
FDefaultParaFormat.dwMask := pfm_All;
FDefaultParaFormat.wAlignment := pfa_Left;
FDefaultParaFormat.cTabCount := 1;
FDefaultParaFormat.rgxTabs[0] := lDefaultTab;
end;
destructor TDrawRTFTextHost.Destroy;
begin
FreeMem(FDefaultCharFormat);
FreeMem(FDefaultParaFormat);
inherited;
end;
function TDrawRTFTextHost.OnTxCharFormatChange(const pcf: TCharFormatW): HResult;
var
NewCharFormat: PCharFormatW;
begin
try
GetMem(NewCharFormat, pcf.cbSize);
Move(pcf, NewCharFormat^, pcf.cbSize);
FreeMem(FDefaultCharFormat);
PCharFormatW(FDefaultCharFormat) := NewCharFormat;
Result := S_OK;
except
Result := E_Fail;
end;
end;
function TDrawRTFTextHost.OnTxParaFormatChange(const ppf: TParaFormat): HResult;
var
NewParaFormat: PParaFormat;
begin
try
GetMem(NewParaFormat, ppf.cbSize);
Move(ppf, NewParaFormat^, ppf.cbSize);
FreeMem(FDefaultParaFormat);
PParaFormat(FDefaultParaFormat) := NewParaFormat;
Result := S_OK;
except
Result := E_Fail;
end;
end;
function TDrawRTFTextHost.TxGetBackStyle(out pstyle: TTxtBackStyle): HResult;
begin
if FTransparent then
pstyle := txtBack_Transparent
else
pstyle := txtBack_Opaque;
Result := S_OK;
end;
function TDrawRTFTextHost.TxGetCharFormat(out ppCF: PCharFormatW): HResult;
begin
ppCF := PCharFormatW(FDefaultCharFormat);
Result := S_OK;
end;
function TDrawRTFTextHost.TxGetClientRect(out prc: TRect): HResult;
begin
prc := FRect;
Result := S_OK;
end;
function TDrawRTFTextHost.TxGetParaFormat(out ppPF: PParaFormat): HResult;
begin
ppPF := PParaFormat(FDefaultParaFormat);
Result := S_OK;
end;
function TDrawRTFTextHost.TxGetPropertyBits(dwMask: DWord; out pdwBits: DWord): HResult;
begin
pdwBits := txtBit_DisableDrag or txtBit_Multiline or txtBit_RichText;
if FWordWrap then
pdwBits := pdwBits or txtBit_WordWrap;
pdwBits := pdwBits and dwMask;
Result := S_OK;
end;
function TDrawRTFTextHost.TxNotify(iNotify: DWord; pv: Pointer): HResult;
begin
case iNotify of
en_Update: Result := S_OK;
else Result := inherited TxNotify(iNotify, pv);
end;
end;
end.
// Delphi interface unit for the windowless rich-edit control
// http://msdn.microsoft.com/library/en-us/shellcc/platform/commctls/richedit/windowlessricheditcontrols.asp
// Copyright © 2003-2006 Rob Kennedy. Some rights reserved.
// For license information, see http://www.cs.wisc.edu/~rkennedy/license
// This code was written using Delphi 5. It should not require any special
// features missing from previous versions, though, except for the obvious
// COM interface support. It should also work with later Delphi versions.
unit TOM;
interface
uses Windows, ActiveX, RichEdit, IMM;
const
// These GUIDs come from the following newsgroup message.
// 92gl2vcsn6ie92e71228cr2jkpvap9t6g6@4ax.com
// Re: ITextServices (Microsoft Text Object Model)
// comp.os.ms-windows.programmer.controls, comp.os.ms-windows.programmer.ole, comp.os.ms-windows.programmer.win32
// Frederic Marchal (badibulgator@free.fr)
// 2003-01-19 07:28:50 PST
// http://groups.google.com/groups?selm=92gl2vcsn6ie92e71228cr2jkpvap9t6g6%404ax.com
SID_ITextHost = '{c5bdd8d0-d26e-11ce-a89e-00aa006cadc5}';
SID_ITextServices = '{8d33f740-cf58-11ce-a89d-00aa006cadc5}';
IID_ITextHost: TGUID = SID_ITextHost;
IID_ITextServices: TGUID = SID_ITextServices;
// The following declarations are based on the contents of the TextServ.h
// Windows SDK header file as of 26 March 2003.
type
// These pointer types are missing from Borland's declarations.
PCharFormat = ^TCharFormat;
PCharFormatA = ^TCharFormatA;
PCharFormatW = ^TCharFormatW;
PParaFormat = ^TParaFormat;
TSizeL = TSize;
TRectL = TRect;
// For the en_RequestResize notification message
PReqResize = ^TReqResize;
TReqResize = packed record
nmhdr: TNMHdr;
rc: TRect;
end;
const
txtBit_RichText = 1;
txtBit_Multiline = 2;
txtBit_ReadOnly = 4;
txtBit_ShowAccelerator = 8;
txtBit_UsePassword = $10;
txtBit_HideSelection = $20;
txtBit_SaveSelection = $40;
txtBit_AutoWordSel = $80;
txtBit_Vertical = $100;
txtBit_SelBarChange = $200;
txtBit_WordWrap = $400;
txtBit_AllowBeep = $800;
txtBit_DisableDrag = $1000;
txtBit_ViewInsetChange = $2000;
txtBit_BackStyleChange = $4000;
txtBit_MaxLengthChange = $8000;
txtBit_ScrollBarChange = $10000;
txtBit_CharFormatChange = $20000;
txtBit_ParaFormatChange = $40000;
txtBit_ExtentChange = $80000;
txtBit_ClientRectChange = $100000;
txtBit_UseCurrentBkg = $200000;
txtNS_FitToContent = 1;
txtNS_RoundToLine = 2;
type
{$MINENUMSIZE 4}
TTxtBackStyle = (txtBack_Transparent, txtBack_Opaque);
TTxtView = (txtView_Active, txtView_Inactive);
TTxDrawCallback = function(param: DWord): Bool; stdcall;
ITextServices = interface
[SID_ITextServices]
function TxSendMessage(msg: UInt; wParam: wParam; lParam: lParam; out plresult: lResult): HResult; stdcall;
function TxDraw(dwDrawAspect: DWord; lindex: LongInt; pvAspect: Pointer; ptd: PDVTargetDevice; hdcDraw, hicTargetDev: HDC; const lprcBounds, lprcWBounds: TRectL; const lprcUpdate: TRect; pfnContinue: TTxDrawCallback; dwContinue: DWord; lViewID: TTxtView): HResult; stdcall;
function TxGetHScroll(out plMin, plMax, plPos, plPage: LongInt; out pfEnabled: Bool): HResult; stdcall;
function TxGetVScroll(out plMin, plMax, plPos, plPage: LongInt; out pfEnabled: Bool): HResult; stdcall;
function OnTxSetCursor(dwDrawAspect: DWord; lindex: LongInt; pvAspect: Pointer; ptd: PDVTargetDevice; hdcDraw, hicTargetDev: HDC; const lprcClient: TRect; x, y: Integer): HResult; stdcall;
function TxQueryHitPoint(dwDrawAspect: DWord; lindex: LongInt; pvAspect: Pointer; ptd: PDVTargetDevice; hdcDraw, hicTargetDev: HDC; const lprcClient: TRect; x, y: Integer; out pHitResult: DWord): HResult; stdcall;
function OnTxInPlaceActivate(const prcClient: TRect): HResult; stdcall;
function OnTxInPlaceDeactivate: HResult; stdcall;
function OnTxUIActivate: HResult; stdcall;
function OnTxUIDeactivate: HResult; stdcall;
function TxGetText(out pbstrText: TBStr): HResult; stdcall;
function TxSetText(pszText: PWideChar): HResult; stdcall;
function TxGetCurTargetX(out px: LongInt): HResult; stdcall;
function TxGetBaselinePos(out pBaselinePos: LongInt): HResult; stdcall;
function TxGetNaturalSize(dwAspect: DWord; hdcDraw, hicTargetDev: HDC; ptd: PDVTargetDevice; dwMode: DWord; const psizelExtent: TSizeL; var pwidth, pheight: LongInt): HResult; stdcall;
function TxGetDropTarget(out ppDropTarget: IDropTarget): HResult; stdcall;
function OnTxPropertyBitsChange(dwMask, dwBits: DWord): HResult; stdcall;
function TxGetCachedSize(out pdwWidth, pdwHeight: DWord): HResult; stdcall;
end;
ITextHost = interface
[SID_ITextHost]
function TxGetDC: HDC; stdcall;
function TxReleaseDC(hdc: HDC): Integer; stdcall;
function TxShowScrollBar(fnBar: Integer; fShow: Bool): Bool; stdcall;
function TxEnableScrollBar(fuSBFlags, fuArrowFlags: Integer): Bool; stdcall;
function TxSetScrollRange(fnBar: Integer; nMinPos: LongInt; nMaxPos: Integer; fRedraw: Bool): Bool; stdcall;
function TxSetScrollPos(fnBar, nPos: Integer; fRedraw: Bool): Bool; stdcall;
procedure TxInvalidateRect(const prc: TRect; fMode: Bool); stdcall;
procedure TxViewChange(fUpdate: Bool); stdcall;
function TxCreateCaret(hbmp: hBitmap; xWidth, yHeight: Integer): Bool; stdcall;
function TxShowCaret(fShow: Bool): Bool; stdcall;
function TxSetCaretPos(x, y: Integer): Bool; stdcall;
function TxSetTimer(idTimer, uTimeout: UInt): Bool; stdcall;
procedure TxKillTimer(idTimer: UInt); stdcall;
procedure TxScrollWindowEx(dx, dy: Integer; const lprcScroll, lprcClip: TRect; hrgnUpdate: HRgn; fuScroll: UInt); stdcall;
procedure TxSetCapture(fCapture: Bool); stdcall;
procedure TxSetFocus; stdcall;
procedure TxSetCursor(hcur: hCursor; fText: Bool); stdcall;
function TxScreenToClient(var lppt: TPoint): Bool; stdcall;
function TxClientToScreen(var lppt: TPoint): Bool; stdcall;
function TxActivate(out lpOldState: LongInt): HResult; stdcall;
function TxDeactivate(lNewState: LongInt): HResult; stdcall;
function TxGetClientRect(out prc: TRect): HResult; stdcall;
function TxGetViewInset(out prc: TRect): HResult; stdcall;
function TxGetCharFormat(out ppCF: PCharFormatW): HResult; stdcall;
function TxGetParaFormat(out ppPF: PParaFormat): HResult; stdcall;
function TxGetSysColor(nIndex: Integer): TColorRef; stdcall;
function TxGetBackStyle(out pstyle: TTxtBackStyle): HResult; stdcall;
function TxGetMaxLength(out pLength: DWord): HResult; stdcall;
function TxGetScrollBars(out pdwScrollBar: DWord): HResult; stdcall;
function TxGetPasswordChar(out pch: {Wide}Char): HResult; stdcall;
function TxGetAcceleratorPos(out pcp: LongInt): HResult; stdcall;
function TxGetExtent(out lpExtent: TSizeL): HResult; stdcall;
function OnTxCharFormatChange(const pcf: TCharFormatW): HResult; stdcall;
function OnTxParaFormatChange(const ppf: TParaFormat): HResult; stdcall;
function TxGetPropertyBits(dwMask: DWord; out pdwBits: DWord): HResult; stdcall;
function TxNotify(iNotify: DWord; pv: Pointer): HResult; stdcall;
function TxImmGetContext: hIMC; stdcall;
procedure TxImmReleaseContext(himc: hIMC); stdcall;
function TxGetSelectionBarWidth(out lSelBarWidth: LongInt): HResult; stdcall;
end;
// TTextHostImpl is a helper class for implementors of the ITextHost
// interface in Delphi. It could have been declared as an actual
// implementor of ITextHost itself, but since it has to be wrapped by
// CreateTextHost anyway, I didn't want to have to deal with reference
// counting of a helper class and forwarding calls to IUnknown's methods.
// TTextHostImpl provides default implementations for most of the
// methods. Override them in descendents. TxGetPropertyBits is an
// abstract method since I could not decide on a suitable default return
// value. The layout of this class is important. The virtual-method table
// MUST have the same layout as the ITextHost method table. To use
// TTextHostImpl with a windowless rich-edit control, create an instance
// of a descendent and pass it to CreateTextHost (declared below).
// CreateTextHost takes ownership of the TTextHostImpl object; do not
// free it.
TTextHostImpl = class
public
function TxGetDC: HDC; virtual; stdcall;
function TxReleaseDC(hdc: HDC): Integer; virtual; stdcall;
function TxShowScrollBar(fnBar: Integer; fShow: Bool): Bool; virtual; stdcall;
function TxEnableScrollBar(fuSBFlags, fuArrowFlags: Integer): Bool; virtual; stdcall;
function TxSetScrollRange(fnBar: Integer; nMinPos: LongInt; nMaxPos: Integer; fRedraw: Bool): Bool; virtual; stdcall;
function TxSetScrollPos(fnBar, nPos: Integer; fRedraw: Bool): Bool; virtual; stdcall;
procedure TxInvalidateRect(const prc: TRect; fMode: Bool); virtual; stdcall;
procedure TxViewChange(fUpdate: Bool); virtual; stdcall;
function TxCreateCaret(hbmp: hBitmap; xWidth, yHeight: Integer): Bool; virtual; stdcall;
function TxShowCaret(fShow: Bool): Bool; virtual; stdcall;
function TxSetCaretPos(x, y: Integer): Bool; virtual; stdcall;
function TxSetTimer(idTimer, uTimeout: UInt): Bool; virtual; stdcall;
procedure TxKillTimer(idTimer: UInt); virtual; stdcall;
procedure TxScrollWindowEx(dx, dy: Integer; const lprcScroll, lprcClip: TRect; hrgnUpdate: HRgn; fuScroll: UInt); virtual; stdcall;
procedure TxSetCapture(fCapture: Bool); virtual; stdcall;
procedure TxSetFocus; virtual; stdcall;
procedure TxSetCursor(hcur: hCursor; fText: Bool); virtual; stdcall;
function TxScreenToClient(var lppt: TPoint): Bool; virtual; stdcall;
function TxClientToScreen(var lppt: TPoint): Bool; virtual; stdcall;
function TxActivate(out lpOldState: LongInt): HResult; virtual; stdcall;
function TxDeactivate(lNewState: LongInt): HResult; virtual; stdcall;
function TxGetClientRect(out prc: TRect): HResult; virtual; stdcall;
function TxGetViewInset(out prc: TRect): HResult; virtual; stdcall;
function TxGetCharFormat(out ppCF: PCharFormatW): HResult; virtual; stdcall;
function TxGetParaFormat(out ppPF: PParaFormat): HResult; virtual; stdcall;
function TxGetSysColor(nIndex: Integer): TColorRef; virtual; stdcall;
function TxGetBackStyle(out pstyle: TTxtBackStyle): HResult; virtual; stdcall;
function TxGetMaxLength(out pLength: DWord): HResult; virtual; stdcall;
function TxGetScrollBars(out pdwScrollBar: DWord): HResult; virtual; stdcall;
function TxGetPasswordChar(out pch: {Wide}Char): HResult; virtual; stdcall;
function TxGetAcceleratorPos(out pcp: LongInt): HResult; virtual; stdcall;
function TxGetExtent(out lpExtent: TSizeL): HResult; virtual; stdcall;
function OnTxCharFormatChange(const pcf: TCharFormatW): HResult; virtual; stdcall;
function OnTxParaFormatChange(const ppf: TParaFormat): HResult; virtual; stdcall;
function TxGetPropertyBits(dwMask: DWord; out pdwBits: DWord): HResult; virtual; stdcall; abstract;
function TxNotify(iNotify: DWord; pv: Pointer): HResult; virtual; stdcall;
function TxImmGetContext: hIMC; virtual; stdcall;
procedure TxImmReleaseContext(himc: hIMC); virtual; stdcall;
function TxGetSelectionBarWidth(out lSelBarWidth: LongInt): HResult; virtual; stdcall;
end;
// CreateTextHost wraps a TTextHostImpl instance and returns an ITextHost
// interface reference suitable for passing to CreateTextServices.
//
// Caution: Delphi code must NEVER call any functions using the returned
// interface, except for the methods introduced in IUnknown. The actual
// ITextHost methods use the thiscall calling convention, which Delphi
// doesn't understand. If you need to call those methods, call them via
// the original TTextHostImpl reference instead.
//
// See also: TTextHostImpl
function CreateTextHost(const Impl: TTextHostImpl): ITextHost;
// This is the API function, documented by Microsoft. See MSDN for details.
function CreateTextServices(punkOuter: IUnknown; pITextHost: ITextHost; out ppUnk): HResult; stdcall;
// PatchTextServices takes an ITextServices reference, as returned by
// CreateTextServices, and wraps it within a Delphi-compatible
// ITextServices implementation.
//
// Services
// [in,out] On entry, this parameter is a reference to an ITextServices
// object returned by CreateTextServices. On exit, it is a reference to a
// new ITextServices object suitable for use in Delphi.
//
// This function is necessary because the ITextServices interface is
// written to expect the thiscall calling convention, not the usual
// stdcall. Instead of passing Self as a regular variable on the stack, it
// is passed in the ECX register. PatchTextServices creates a wrapper
// object that fixes the stack layout for each function before forwarding
// the call to the original object.
//
// See also: CreateTextServices
procedure PatchTextServices(var Services: ITextServices);
implementation
uses SysUtils;
function CreateTextServices; external 'riched20.dll';
type
TQueryInterface = function(const This: IUnknown; const riid: TGUID; out ppvObj): HResult; stdcall;
// Many of the following routines are declared without any parameters or
// return types. This is because they must use the stdcall calling
// convention, but the compiler automatically adds prologue and epilogue
// code for all stdcall functions, even if it isn't strictly necessary.
// This is OK, though, since these functions are all implemented in
// assembler and they are never called by any Delphi code. They're always
// called via an interface reference, usually by the operating system.
type
PITextServicesMT = ^TITextServicesMT;
TITextServicesMT = packed record
// IUnknown
QueryInterface: TQueryInterface;
_AddRef,
_Release: TProcedure;
// ITextServices
TxSendMessage,
TxDraw,
TxGetHScroll,
TxGetVScroll,
OnTxSetCursor,
TxQueryHitPoint,
OnTxInPlaceActivate,
OnTxInPlaceDeactivate,
OnTxUIActivate,
OnTxUIDeactivate,
TxGetText,
TxSetText,
TxGetCurTargetX,
TxGetBaselinePos,
TxGetNaturalSize,
TxGetDropTarget,
OnTxPropertyBitsChange,
TxGetCachedSize: TProcedure;
end;
PITextServices = ^TITextServices;
TITextServices = packed record
MethodTable: PITextServicesMT;
Impl: ITextServices;
end;
function TextServices_QueryInterface(const This: IUnknown; const riid: TGUID; out ppvObj): HResult; stdcall;
begin
Result := PITextServices(This).Impl.QueryInterface(riid, ppvObj);
end;
procedure TextServices_AddRef; // (const This: IUnknown): ULong; stdcall;
{begin
Result := PITextServices(This).Impl._AddRef;}
asm
mov eax, [esp + 4]
mov eax, [eax].TITextServices.Impl
mov [esp + 4], eax
mov eax, [eax]
jmp dword ptr [eax].TITextServicesMT._AddRef
end;
procedure ReleaseTextServices(const Services: PITextServices);
// This procedure is not in assembler because Dispose requires compiler
// magic in order to include TypeInfo for a PITextServices pointer.
begin
Pointer(Services.Impl) := nil;
Dispose(Services);
end;
procedure TextServices_Release; // (const This: IUnknown): ULong; stdcall;
{begin
Result := PITextServices(This).Impl._Release;
if Result = 0 then ReleaseTextServices(PTextServices(This));}
asm
mov eax, [esp + 4]
mov eax, [eax].TITextServices.Impl
push eax
mov eax, [eax]
call dword ptr [eax].TITextServicesMT._Release
test eax, eax
jnz @@exit
mov eax, [esp + 4]
call ReleaseTextServices
xor eax, eax
@@exit:
ret 4
end;
// These stubs get called as stdcall methods. They translate the stack into
// a thiscall method. First, there is a breakpoint, which can be set or
// ignored when a method is patched. Next, we pop the return address into
// EDX. Then we pop the Self parameter that Delphi puts at the top of the
// stack. It's actually a PITextServices value. The real ITextServices
// implementor is expecting to find its instance reference in ECX when we
// call it, and that got stored in the Inst field of the TITextServices
// record by the PatchTextServices function. After we set ECX, we push the
// return address back onto the stack (note the PITextServices reference is
// *not* pushed back on). ECX points to the first entry of the
// implementor's VMT, so we add an offset to that pointer and jump to the
// address stored there.
procedure TextServices_TxSendMessage; // (msg: UInt; wParam: wParam; lParam: lParam; out plresult: lResult): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.TxSendMessage
end;
procedure TextServices_TxDraw; // (dwDrawAspect: DWord; lindex: LongInt; pvAspect: Pointer; ptd: PDVTargetDevice; hdcDraw, hicTargetDev: HDC; const lprcBounds, lprcWBounds: TRectL; const lprcUpdate: TRect; pfnContinue: TTxDrawCallback; dwContinue: DWord; lViewID: TTxtView): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.TxDraw
end;
procedure TextServices_TxGetHScroll; // (out plMin, plMax, plPos, plPage: LongInt; out pfEnabled: Bool): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.TxGetHScroll
end;
procedure TextServices_TxGetVScroll; // (out plMin, plMax, plPos, plPage: LongInt; out pfEnabled: Bool): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.TxGetVScroll
end;
procedure TextServices_OnTxSetCursor; // (dwDrawAspect: DWord; lindex: LongInt; pvAspect: Pointer; ptd: PDVTargetDevice; hdcDraw, hicTargetDev: HDC; const lprcClient: TRect; x, y: Integer): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.OnTxSetCursor
end;
procedure TextServices_TxQueryHitPoint; // (dwDrawAspect: DWord; lindex: LongInt; pvAspect: Pointer; ptd: PDVTargetDevice; hdcDraw, hicTargetDev: HDC; const lprcClient: TRect; x, y: Integer; out pHitResult: DWord): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.TxQueryHitPoint
end;
procedure TextServices_OnTxInPlaceActivate; // (const prcClient: TRect): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.OnTxInPlaceActivate
end;
procedure TextServices_OnTxInPlaceDeactivate; // : HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.OnTxInPlaceDeactivate
end;
procedure TextServices_OnTxUIActivate; // : HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.OnTxUIActivate
end;
procedure TextServices_OnTxUIDeactivate; // : HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.OnTxUIDeactivate
end;
procedure TextServices_TxGetText; // (out pbstrText: TBStr): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.TxGetText
end;
procedure TextServices_TxSetText; // (pszText: PWideChar): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.TxSetText
end;
procedure TextServices_TxGetCurTargetX; // (out px: LongInt): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.TxGetCurTargetX
end;
procedure TextServices_TxGetBaselinePos; // (out pBaselinePos: LongInt): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.TxGetBaselinePos
end;
procedure TextServices_TxGetNaturalSize; // (dwAspect: DWord; hdcDraw, hicTargetDev: HDC; ptd: PDVTargetDevice; dwMode: DWord; const psizelExtent: TSizeL; var pwidth, pheight: LongInt): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.TxGetNaturalSize
end;
procedure TextServices_TxGetDropTarget; // (out ppDropTarget: IDropTarget): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.TxGetDropTarget
end;
procedure TextServices_OnTxPropertyBitsChange; // (dwMask, dwBits: DWord): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.OnTxPropertyBitsChange
end;
procedure TextServices_TxGetCachedSize; // (out pdwWidth, pdwHeight: DWord): HResult; stdcall;
asm
pop edx // return address
pop eax
mov ecx, [eax].TITextServices.Impl
push edx // return address
mov eax, [ecx]
jmp dword ptr [eax].TITextServicesMT.TxGetCachedSize
end;
var
TextServicesMethodTable: TITextServicesMT = (
// IUnknown
QueryInterface: TextServices_QueryInterface;
_AddRef: TextServices_AddRef;
_Release: TextServices_Release;
// ITextServices
TxSendMessage: TextServices_TxSendMessage;
TxDraw: TextServices_TxDraw;
TxGetHScroll: TextServices_TxGetHScroll;
TxGetVScroll: TextServices_TxGetVScroll;
OnTxSetCursor: TextServices_OnTxSetCursor;
TxQueryHitPoint: TextServices_TxQueryHitPoint;
OnTxInPlaceActivate: TextServices_OnTxInPlaceActivate;
OnTxInPlaceDeactivate: TextServices_OnTxInPlaceDeactivate;
OnTxUIActivate: TextServices_OnTxUIActivate;
OnTxUIDeactivate: TextServices_OnTxUIDeactivate;
TxGetText: TextServices_TxGetText;
TxSetText: TextServices_TxSetText;
TxGetCurTargetX: TextServices_TxGetCurTargetX;
TxGetBaselinePos: TextServices_TxGetBaselinePos;
TxGetNaturalSize: TextServices_TxGetNaturalSize;
TxGetDropTarget: TextServices_TxGetDropTarget;
OnTxPropertyBitsChange: TextServices_OnTxPropertyBitsChange;
TxGetCachedSize: TextServices_TxGetCachedSize
);
type
PITextHostMT = ^TITextHostMT;
TITextHostMT = packed record
// IUnknown
QueryInterface: TQueryInterface;
_AddRef,
_Release: TProcedure;
// ITextHost
TxGetDC,
TxReleaseDC,
TxShowScrollBar,
TxEnableScrollBar,
TxSetScrollRange,
TxSetScrollPos,
TxInvalidateRect,
TxViewChange,
TxCreateCaret,
TxShowCaret,
TxSetCaretPos,
TxSetTimer,
TxKillTimer,
TxScrollWindowEx,
TxSetCapture,
TxSetFocus,
TxSetCursor,
TxScreenToClient,
TxClientToScreen,
TxActivate,
TxDeactivate,
TxGetClientRect,
TxGetViewInset,
TxGetCharFormat,
TxGetParaFormat,
TxGetSysColor,
TxGetBackStyle,
TxGetMaxLength,
TxGetScrollBars,
TxGetPasswordChar,
TxGetAcceleratorPos,
TxGetExtent,
OnTxCharFormatChange,
OnTxParaFormatChange,
TxGetPropertyBits,
TxNotify,
TxImmGetContext,
TxImmReleaseContext,
TxGetSelectionBarWidth: TProcedure;
end;
PITextHost = ^TITextHost;
TITextHost = record
MethodTable: PITextHostMT;
RefCount: Cardinal;
Impl: TTextHostImpl;
end;
function TextHost_QueryInterface(const This: IUnknown; const riid: TGUID; out ppvObj): HResult; stdcall;
begin
if IsEqualGUID(riid, IUnknown) or IsEqualGUID(riid, ITextHost) then begin
Pointer(ppvObj) := Pointer(This);
IUnknown(ppvObj)._AddRef;
Result := S_OK;
end else begin
Pointer(ppvObj) := nil;
Result := E_NoInterface;
end;
end;
procedure TextHost_AddRef; // (const This: IUnknown): ULong; stdcall;
{begin
Result := InterlockedIncrement(PITextHost(This).RefCount);}
asm
mov eax, [esp + 4]
lea eax, [eax].TITextHost.RefCount
push eax
call InterlockedIncrement
ret 4 // return from stdcall function
end;
procedure ReleaseTextHost(const Host: PITextHost);
begin
Host.Impl.Free;
Dispose(Host);
end;
procedure TextHost_Release; // (const This: IUnknown): ULong; stdcall;
{begin
Result := InterlockedDecrement(PITextHost(This).RefCount);
if Result = 0 then ReleaseTextHost(PITextHost(This));}
asm
mov eax, [esp + 4]
lea eax, [eax].TITextHost.RefCount
push eax
call InterlockedDecrement
test eax, eax
jnz @@exit
mov eax, [esp + 4]
call ReleaseTextHost
xor eax, eax
@@exit:
ret 4 // return from stdcall function
end;
// When these stubs get called, it is as thiscall methods. We translate it
// to a stdcall method and then jump to the Delphi object method that's
// implementing the interface. ECX refers to the PITextHost value that
// CreateTextHost returned as an ITextHost reference. Besides a pointer to
// a VMT of these method stubs, that record also contains a reference to
// the TTextHostImpl instance, eight bytes into the record. That reference
// gets stored in EAX and then pushed onto the stack underneath the return
// address. Then we fetch the address of the method being wrapped from the
// TTextHostImpl's VMT and jump to that method.
procedure TextHost_TxGetDC; // : HDC; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetDC]
end;
procedure TextHost_TxReleaseDC; // (hdc: HDC): Integer; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxReleaseDC]
end;
procedure TextHost_TxShowScrollBar; // (fnBar: Integer; fShow: Bool): Bool; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxShowScrollBar]
end;
procedure TextHost_TxEnableScrollBar; // (fuSBFlags, fuArrowFlags: Integer): Bool; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxEnableScrollBar]
end;
procedure TextHost_TxSetScrollRange; // (fnBar: Integer; nMinPos: LongInt; nMaxPos: Integer; fRedraw: Bool): Bool; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxSetScrollRange]
end;
procedure TextHost_TxSetScrollPos; // (fnBar, nPos: Integer; fRedraw: Bool): Bool; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxSetScrollPos]
end;
procedure TextHost_TxInvalidateRect; // (const prc: TRect; fMode: Bool); stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxInvalidateRect]
end;
procedure TextHost_TxViewChange; // (fUpdate: Bool); stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxViewChange]
end;
procedure TextHost_TxCreateCaret; // (hbmp: hBitmap; xWidth, yHeight: Integer): Bool; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxCreateCaret]
end;
procedure TextHost_TxShowCaret; // (fShow: Bool): Bool; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxShowCaret]
end;
procedure TextHost_TxSetCaretPos; // (x, y: Integer): Bool; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxSetCaretPos]
end;
procedure TextHost_TxSetTimer; // (idTimer, uTimeout: UInt): Bool; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxSetTimer]
end;
procedure TextHost_TxKillTimer; // (idTimer: UInt); stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxKillTimer]
end;
procedure TextHost_TxScrollWindowEx; // (dx, dy: Integer; const lprcScroll, lprcClip: TRect; hrgnUpdate: HRgn; fuScroll: UInt); stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxScrollWindowEx]
end;
procedure TextHost_TxSetCapture; // (fCapture: Bool); stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxSetCapture]
end;
procedure TextHost_TxSetFocus; // ; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxSetFocus]
end;
procedure TextHost_TxSetCursor; // (hcur: hCursor; fText: Bool); stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxSetCursor]
end;
procedure TextHost_TxScreenToClient; // (var lppt: TPoint): Bool; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxScreenToClient]
end;
procedure TextHost_TxClientToScreen; // (var lppt: TPoint): Bool; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxClientToScreen]
end;
procedure TextHost_TxActivate; // (out lpOldState: LongInt): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxActivate]
end;
procedure TextHost_TxDeactivate; // (lNewState: LongInt): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxDeactivate]
end;
procedure TextHost_TxGetClientRect; // (out prc: TRect): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetClientRect]
end;
procedure TextHost_TxGetViewInset; // (out prc: TRect): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetViewInset]
end;
procedure TextHost_TxGetCharFormat; // (out ppCF: PCharFormatW): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetCharFormat]
end;
procedure TextHost_TxGetParaFormat; // (out ppPF: PParaFormat): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetParaFormat]
end;
procedure TextHost_TxGetSysColor; // (nIndex: Integer): TColorRef; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetSysColor]
end;
procedure TextHost_TxGetBackStyle; // (out pstyle: TTxtBackStyle): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetBackStyle]
end;
procedure TextHost_TxGetMaxLength; // (out pLength: DWord): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetMaxLength]
end;
procedure TextHost_TxGetScrollBars; // (out pdwScrollBar: DWord): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetScrollBars]
end;
procedure TextHost_TxGetPasswordChar; // (out pch: {Wide}Char): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetPasswordChar]
end;
procedure TextHost_TxGetAcceleratorPos; // (out pcp: LongInt): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetAcceleratorPos]
end;
procedure TextHost_TxGetExtent; // (out lpExtent: TSizeL): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetExtent]
end;
procedure TextHost_OnTxCharFormatChange; // (const pcf: TCharFormatW): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.OnTxCharFormatChange]
end;
procedure TextHost_OnTxParaFormatChange; // (const ppf: TParaFormat): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.OnTxParaFormatChange]
end;
procedure TextHost_TxGetPropertyBits; // (dwMask: DWord; out pdwBits: DWord): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetPropertyBits]
end;
procedure TextHost_TxNotify; // (iNotify: DWord; pv: Pointer): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxNotify]
end;
procedure TextHost_TxImmGetContext; // : hIMC; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxImmGetContext]
end;
procedure TextHost_TxImmReleaseContext; // (himc: hIMC); stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxImmReleaseContext]
end;
procedure TextHost_TxGetSelectionBarWidth; // (out lSelBarWidth: LongInt): HResult; stdcall;
asm
pop edx // return address
mov eax, [ecx].TITextHost.Impl
push eax
push edx // return address
mov eax, [eax]
jmp dword ptr [eax + vmtoffset TTextHostImpl.TxGetSelectionBarWidth]
end;
var
TextHostMethodTable: TITextHostMT = (
// IUnknown
QueryInterface: TextHost_QueryInterface;
_AddRef: TextHost_AddRef;
_Release: TextHost_Release;
// ITextHost
TxGetDC: TextHost_TxGetDC;
TxReleaseDC: TextHost_TxReleaseDC;
TxShowScrollBar: TextHost_TxShowScrollBar;
TxEnableScrollBar: TextHost_TxEnableScrollBar;
TxSetScrollRange: TextHost_TxSetScrollRange;
TxSetScrollPos: TextHost_TxSetScrollPos;
TxInvalidateRect: TextHost_TxInvalidateRect;
TxViewChange: TextHost_TxViewChange;
TxCreateCaret: TextHost_TxCreateCaret;
TxShowCaret: TextHost_TxShowCaret;
TxSetCaretPos: TextHost_TxSetCaretPos;
TxSetTimer: TextHost_TxSetTimer;
TxKillTimer: TextHost_TxKillTimer;
TxScrollWindowEx: TextHost_TxScrollWindowEx;
TxSetCapture: TextHost_TxSetCapture;
TxSetFocus: TextHost_TxSetFocus;
TxSetCursor: TextHost_TxSetCursor;
TxScreenToClient: TextHost_TxScreenToClient;
TxClientToScreen: TextHost_TxClientToScreen;
TxActivate: TextHost_TxActivate;
TxDeactivate: TextHost_TxDeactivate;
TxGetClientRect: TextHost_TxGetClientRect;
TxGetViewInset: TextHost_TxGetViewInset;
TxGetCharFormat: TextHost_TxGetCharFormat;
TxGetParaFormat: TextHost_TxGetParaFormat;
TxGetSysColor: TextHost_TxGetSysColor;
TxGetBackStyle: TextHost_TxGetBackStyle;
TxGetMaxLength: TextHost_TxGetMaxLength;
TxGetScrollBars: TextHost_TxGetScrollBars;
TxGetPasswordChar: TextHost_TxGetPasswordChar;
TxGetAcceleratorPos: TextHost_TxGetAcceleratorPos;
TxGetExtent: TextHost_TxGetExtent;
OnTxCharFormatChange: TextHost_OnTxCharFormatChange;
OnTxParaFormatChange: TextHost_OnTxParaFormatChange;
TxGetPropertyBits: TextHost_TxGetPropertyBits;
TxNotify: TextHost_TxNotify;
TxImmGetContext: TextHost_TxImmGetContext;
TxImmReleaseContext: TextHost_TxImmReleaseContext;
TxGetSelectionBarWidth: TextHost_TxGetSelectionBarWidth;
);
procedure PatchTextServices(var Services: ITextServices);
var
NewServices: PITextServices;
begin
New(NewServices);
NewServices.MethodTable := @TextServicesMethodTable;
Pointer(NewServices.Impl) := Pointer(Services);
Pointer(Services) := NewServices;
end;
function CreateTextHost(const Impl: TTextHostImpl): ITextHost;
var
Obj: PITextHost;
begin
New(Obj);
Obj.MethodTable := @TextHostMethodTable;
Obj.RefCount := 0;
Obj.Impl := Impl;
Result := ITextHost(Obj);
end;
{ TTextHostImpl }
// The following is a generic implementation of the ITextHost interface.
// Many of the methods return E_Fail, but that's actually OK. The OS does
// not expect the text-services object to be fully functional.
function TTextHostImpl.OnTxCharFormatChange(const pcf: TCharFormatW): HResult;
begin
Result := E_Fail;
end;
function TTextHostImpl.OnTxParaFormatChange(const ppf: TParaFormat): HResult;
begin
Result := E_Fail;
end;
function TTextHostImpl.TxActivate(out lpOldState: Integer): HResult;
begin
Result := E_Fail;
end;
function TTextHostImpl.TxClientToScreen(var lppt: TPoint): Bool;
begin
Result := False;
end;
function TTextHostImpl.TxCreateCaret(hbmp: hBitmap; xWidth, yHeight: Integer): Bool;
begin
Result := False;
end;
function TTextHostImpl.TxDeactivate(lNewState: Integer): HResult;
begin
Result := E_Fail;
end;
function TTextHostImpl.TxEnableScrollBar(fuSBFlags, fuArrowFlags: Integer): Bool;
begin
Result := False;
end;
function TTextHostImpl.TxGetAcceleratorPos(out pcp: Integer): HResult;
begin
pcp := -1;
Result := S_OK;
end;
function TTextHostImpl.TxGetBackStyle(out pstyle: TTxtBackStyle): HResult;
begin
pstyle := txtBack_Transparent;
Result := S_OK;
end;
function TTextHostImpl.TxGetCharFormat(out ppCF: PCharFormatW): HResult;
begin
Result := E_NotImpl;
end;
function TTextHostImpl.TxGetClientRect(out prc: TRect): HResult;
begin
Result := E_Fail;
end;
function TTextHostImpl.TxGetDC: HDC;
begin
Result := 0;
end;
function TTextHostImpl.TxGetExtent(out lpExtent: TSizeL): HResult;
begin
Result := E_Fail;
end;
function TTextHostImpl.TxGetMaxLength(out pLength: DWord): HResult;
begin
pLength := Infinite;
Result := S_OK;
end;
function TTextHostImpl.TxGetParaFormat(out ppPF: PParaFormat): HResult;
begin
Result := E_NotImpl;
end;
function TTextHostImpl.TxGetPasswordChar(out pch: Char): HResult;
begin
Result := S_False;
end;
function TTextHostImpl.TxGetScrollBars(out pdwScrollBar: DWord): HResult;
begin
pdwScrollBar := 0;
Result := S_OK;
end;
function TTextHostImpl.TxGetSelectionBarWidth(out lSelBarWidth: Integer): HResult;
begin
lSelBarWidth := 0;
Result := S_OK;
end;
function TTextHostImpl.TxGetSysColor(nIndex: Integer): TColorRef;
begin
Result := GetSysColor(nIndex);
end;
function TTextHostImpl.TxGetViewInset(out prc: TRect): HResult;
begin
SetRect(prc, 0, 0, 0, 0);
Result := S_OK;
end;
function TTextHostImpl.TxImmGetContext: hIMC;
begin
Result := 0;
end;
procedure TTextHostImpl.TxImmReleaseContext(himc: hIMC);
begin
end;
procedure TTextHostImpl.TxInvalidateRect(const prc: TRect; fMode: Bool);
begin
end;
procedure TTextHostImpl.TxKillTimer(idTimer: UInt);
begin
end;
function TTextHostImpl.TxNotify(iNotify: DWord; pv: Pointer): HResult;
begin
Result := S_False;
end;
function TTextHostImpl.TxReleaseDC(hdc: HDC): Integer;
begin
Result := 0;
end;
function TTextHostImpl.TxScreenToClient(var lppt: TPoint): Bool;
begin
Result := False;
end;
procedure TTextHostImpl.TxScrollWindowEx(dx, dy: Integer; const lprcScroll, lprcClip: TRect; hrgnUpdate: HRgn; fuScroll: UInt);
begin
end;
procedure TTextHostImpl.TxSetCapture(fCapture: Bool);
begin
end;
function TTextHostImpl.TxSetCaretPos(x, y: Integer): Bool;
begin
Result := False;
end;
procedure TTextHostImpl.TxSetCursor(hcur: hCursor; fText: Bool);
begin
end;
procedure TTextHostImpl.TxSetFocus;
begin
end;
function TTextHostImpl.TxSetScrollPos(fnBar, nPos: Integer; fRedraw: Bool): Bool;
begin
Result := False;
end;
function TTextHostImpl.TxSetScrollRange(fnBar, nMinPos, nMaxPos: Integer; fRedraw: Bool): Bool;
begin
Result := False;
end;
function TTextHostImpl.TxSetTimer(idTimer, uTimeout: UInt): Bool;
begin
Result := False;
end;
function TTextHostImpl.TxShowCaret(fShow: Bool): Bool;
begin
Result := False;
end;
function TTextHostImpl.TxShowScrollBar(fnBar: Integer; fShow: Bool): Bool;
begin
Result := False;
end;
procedure TTextHostImpl.TxViewChange(fUpdate: Bool);
begin
end;
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment