You are correct, It is for a class to use NumGet functions.
I got confused in the difference between map, arrays and objects.
I am trying to convert Class_RichEdit to V2.
It is hard to convert a large complicated script that you hardly understand and functions you have never used, but I can try ...
in the Class PF2, "." and ":" are used as keys, but I assume that "attr" and "addr" are more logical.
I think I have fixed the VarSetCapacity functions and added "ErrorLevel := " before Sendmessage functions to fix some V2 Errors, but the Classes still need to be fixed. the __Set function of the class returns the undefined var [tabs], I assume this is an error in the original code.
Code: Select all
; ======================================================================================================================
; Scriptname: Class_RichEdit.ahk
; Namespace: RichEdit
; Author: just me
; AHK Version: 2.0-a100-52515e2 (AHK_User: Trying to convert it to 2.0-beta.1)
; OS Version: Win 10 (x64)
; Function: The class provides some wrapper functions for rich edit controls (v4.1 Unicode).
; Change History:
; 0.2.00.02 2021-09-04/AHK_User - Trying to convert it to 2.0-beta.1
; 0.2.00.01 2018-11-13/oif2003 - Added support for onEvent(), .Value, and support for:readonly, upper/lowercase
; 0.2.00.00 2018-11-08/oif2003 - Updated for AutoHotkey v2
; 0.1.05.00 2015-04-14/just me - fixed LoadRTF() not closing the file after reading
; 0.1.04.00 2014-08-27/just me - fixed SetParaIndent() and changed indentation sample
; 0.1.03.00 2014-03-03/just me - added GetTextRange()
; 0.1.02.00 2013-12-01/just me - changed SetText() to handle RTF formatted text properly
; 0.1.01.00 2013-11-29/just me - bug fix -> GetSelText()
; 0.1.00.00 2013-11-17/just me - initial beta release
; Credits:
; corrupt for cRichEdit:
; http://www.autohotkey.com/board/topic/17869-crichedit-standard-richedit-control-for-autohotkey-scripts/
; jballi for HE_Print:
; http://www.autohotkey.com/board/topic/45513-function-he-print-wysiwyg-print-for-the-hiedit-control/
; majkinetor for Dlg:
; http://www.autohotkey.com/board/topic/15836-module-dlg-501/
; ======================================================================================================================
Class RichEdit {
; ===================================================================================================================
; Class variables - do not change !!!
; ===================================================================================================================
; RichEdit v4.1 (Unicode)
Static Class := "RICHEDIT50W"
; RichEdit v4.1 (Unicode)
Static DLL := "Msftedit.dll"
; DLL handle
Static Instance := DllCall("Kernel32.dll\LoadLibrary", "Str", RichEdit.DLL, "UPtr")
; Callback function handling RichEdit messages
Static SubclassCB := 0
; Number of controls/instances
Static Controls := 0
; ===================================================================================================================
; Instance variables and - do not change !!!
; ===================================================================================================================
DefFont := ""
; GUI Control Properties
Gui := ""
Hwnd := ""
ClassNN {
get {
return this.ctrl.ClassNN
}
set {
this.ctrl.ClassNN := value
}
}
Enabled {
get {
return this.ctrl.Enabled
}
set {
this.ctrl.Enabled := value
}
}
Focused {
get {
return this.ctrl.Focused
}
}
Name {
get {
return this.ctrl.Name
}
set {
this.ctrl.Name := value
}
}
Pos {
get {
return this.ctrl.Pos
}
}
Text {
get {
return this.GetText()
}
set {
this.SetText(value)
}
}
Type {
get {
return this.Type
}
}
Value {
get {
return this.GetText()
}
set {
this.SetText(value)
}
}
Visible {
get {
return this.ctrl.Visible
}
set {
this.ctrl.Visible := value
}
}
;GUI Control Methods
Move(Param*) {
return this.ctrl.Move(Param*)
}
Focus() {
return this.ctrl.Focus()
}
OnEvent(event := "", cbFunc := "", MaxThreads := 1) {
static AhkChangeEventRegistered := false
if event = "change"
this.onEventChangeCB := cbFunc
else if event = "focus"
this.onEventFocusCB := cbFunc
else if event = "losefocus"
this.onEventLoseFocusCB := cbFunc
else return false
if !AhkChangeEventRegistered {
r := this.SetEventMask("Change")
if isObject(cbFunc) && cbFunc.isBuiltIn != "" {
this.onEventFunc := cbFunc
OnMessage(0x111, (param*)=>this._onEventHandler(param*), MaxThreads)
}
else r := false
r := true, AhkChangeEventRegistered := true
}
return r
}
_onEventHandler(wparam, lparam, msg, sender) {
if msg == 0x111 {
change := (wparam & 0xf000000) // 0x1000000
if change != 4 && lparam == this.Hwnd {
if change == 3 && this.onEventChangeCB != ""
this.onEventChangeCB.Call(wparam, lparam, msg, sender)
else if change == 1 && this.onEventFocusCB != ""
this.onEventFocusCB.Call(wparam, lparam, msg, sender)
else if change == 2 && this.onEventLoseFocusCB != ""
this.onEventLoseFocusCB.Call(wparam, lparam, msg, sender)
}
}
}
Opt(param*) {
this.Options(param*)
}
Options(options := "", mode := "SET") {
static reOptionsList := { AUTOWORDSELECTION: 0x01, AUTOVSCROLL: 0x40, AUTOHSCROLL: 0x80
, NOHIDESEL: 0x100, READONLY: 0x800, WANTRETURN: 0x1000
, SAVESEL: 0x8000, SELECTIONBAR: 0x01000000, VERTICAL: 0x400000}
options := StrSplit(options, " ")
for _, v in options
if reOptionsList.HasKey(v)
reOptions .= v " "
else
_options .= v " "
this.ctrl.Options(_options)
this.SetOptions(Trim(reOptions, " `t`n`r"), mode)
}
; ===================================================================================================================
; CONSTRUCTOR
; ===================================================================================================================
__New(Gui, Options := "", DefaultText := "", MultiLine := True) {
Static WS_TABSTOP := 0x10000, WS_HSCROLL := 0x100000, WS_VSCROLL := 0x200000, WS_VISIBLE := 0x10000000
, WS_CHILD := 0x40000000, WS_BORDER := 0x800000
, WS_EX_CLIENTEDGE := 0x200, WS_EX_STATICEDGE := 0x20000
, ES_MULTILINE := 0x0004, ES_AUTOVSCROLL := 0x40, ES_AUTOHSCROLL := 0x80, ES_NOHIDESEL := 0x0100
, ES_WANTRETURN := 0x1000, ES_DISABLENOSCROLL := 0x2000, ES_SUNKEN := 0x4000, ES_SAVESEL := 0x8000
, ES_SELECTIONBAR := 0x1000000
;list of option keyword and [funcName*, param*] pairs. Where funcName is an array that stores the classes and method,
;ie : ["RichEdit, "CallBack", "someMethod"]; and param* is a variadic array of parameters to be passed
;We will call these at the end of the constructor to set options found in array reOptions
Static optionsList := Map("-WRAP", [["WordWrap"], [false]], "+WRAP", [["WordWrap"], [true]], "readonly", [["SetOptions"], ["readonly"]]
,"lowercase", [["SetStyles"], ["lowercase"]] ,"uppercase", [["SetStyles"], ["uppercase"]]) ;SetOptions(Options := ""SetStyles
; Do not instantiate instances of RichEdit
If (This.Base.HWND)
Return False
If !(Gui) {
ErrorLevel := "ERROR: Gui does not exist!"
Return False
}
this.gui := gui
; Load library if necessary
If (This.Base.Instance == 0) {
This.Base.Instance := DllCall("Kernel32.dll\LoadLibrary", "Str", This.Base.DLL, "UPtr")
If (ErrorLevel) {
ErrorLevel := "ERROR: Error loading " . This.Base.DLL . " - " . ErrorLevel
Return False
}
}
; Specify default styles & exstyles
Styles := WS_TABSTOP | WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL ;| WS_BORDER
If (MultiLine)
Styles |= WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL | ES_WANTRETURN ; | WS_HSCROLL
| ES_DISABLENOSCROLL | ES_SAVESEL ; | ES_SELECTIONBAR does not work properly
ExStyles := WS_EX_STATICEDGE
; Create the control
CtrlClass := This.Class
;separate standard AHK control options and RE options (which we will set at the end)
reOptions := [], ctrlOptions := []
_options := StrSplit(Options, " ")
for _, v in _options {
if optionsList.HasKey(v)
reOptions.Push(optionsList[v])
else
ctrlOptions.Push(v)
}
Options := ""
for k, v in ctrlOptions
Options .= (k == 1 ? "" : " ") v
ctrl := Gui.Add("Custom", "Class" CtrlClass " " Options " +" Styles " +E" ExStyles)
this.ctrl := ctrl
HWND := ctrl.hwnd
If (MultiLine) {
; Adjust the formatting rectangle for multiline controls to simulate a selection bar
; EM_GETRECT = 0xB2, EM_SETRECT = 0xB3
;v1 VarSetCapacity(RECT, 16, 0)
RECT := Buffer(16, 0)
SendMessage(0xB2, 0, &RECT, , "ahk_id" HWND)
NumPut(NumGet(RECT, 0, "Int") + 1, RECT, 0, "Int")
NumPut(NumGet(RECT, 4, "Int") + 2, RECT, 4, "Int")
SendMessage(0xB3, 0, &RECT, , "ahk_id" HWND)
; Set advanced typographic options
; EM_SETTYPOGRAPHYOPTIONS = 0x04CA (WM_USER + 202)
; TO_ADVANCEDTYPOGRAPHY = 1, TO_ADVANCEDLAYOUT = 8 ? not documented
SendMessage(0x04CA, 0x01, 0x01, , "ahk_id" HWND)
}
; Initialize control
; EM_SETLANGOPTIONS = 0x0478 (WM_USER + 120)
; IMF_AUTOKEYBOARD = 0x01, IMF_AUTOFONT = 0x02
SendMessage(0x0478, 0, 0x03, , "ahk_id" HWND)
; Subclass the control to get Tab key and prevent Esc from sending a WM_CLOSE message to the parent window.
; One of majkinetor's splendid discoveries!
; Initialize SubclassCB
If (This.Base.SubclassCB = 0)
This.Base.SubclassCB := CallbackCreate("RichEdit.SubclassProc")
DllCall("Comctl32.dll\SetWindowSubclass", "Ptr", HWND, "Ptr", This.Base.SubclassCB, "Ptr", HWND, "Ptr", 0)
This.HWND := HWND
This.DefFont := This.GetFont(1)
This.DefFont.Default := 1
; Correct AHK font size setting, if necessary
If (Round(This.DefFont.Size) != This.DefFont.Size) {
This.DefFont.Size := Round(This.DefFont.Size)
This.SetDefaultFont()
}
This.Base.Controls += 1
; Initialize the print margins
;This.GetMargins()
; Initialize the text limit
This.LimitText(2147483647)
;IRichEditOleCallback interface
;https://docs.microsoft.com/en-us/windows/desktop/api/richole/nn-richole-iricheditolecallback
this.Callback.SetOleCallback(hwnd)
;Setting options for RichEdit
;Conditional options / defaults
if MultiLine
this.WordWrap(true)
if DefaultText != ""
this.text := DefaultText
;RichEdit options
for _, v in reOptions
if v[1].Length() == 1
this[v[1][1]](v[2]*)
else {
obj := this, i := 1
while i < v[1].Length()
obj := obj[ v[1][i++] ]
obj[ v[1][i++] ](v[2]*)
}
}
class CallBack {
; Authors: just me & DigiDon
; Description: IRichEditOleCallback interface AHK implementation for the RichEdit control
Static ContextMenu := ""
makeContextMenu() {
ContextMenu := Menu() ; Simple context menu
ContextMenu.Add("&Copy", ()=>Send("^c"))
ContextMenu.Add("&Paste", ()=>Send("^v"))
ContextMenu.Add("Cu&t", ()=>Send("^x"))
ContextMenu.Add("Select &All", ()=>Send("^a"))
ContextMenu.Add("&Undo", ()=>Send("^z"))
ContextMenu.Add("&Redo", ()=>Send("^y"))
this.ContextMenu := ContextMenu
}
SetOleCallback(hwnd) {
static cb := RichEdit.Callback
static VTBL := [CallbackCreate((p1, p2, p3, p4) => cb.IREOleCB_QueryInterface(p1, p2, p3, p4))
, CallbackCreate((p1) => cb.IREOleCB_AddRef(p1))
, CallbackCreate((p1) => cb.IREOleCB_Release(p1))
, CallbackCreate((p1, p2) => cb.IREOleCB_GetNewStorage(p1, p2))
, CallbackCreate((p1, p2, p3, p4) => cb.IREOleCB_GetInPlaceContext(p1, p2, p3, p4))
, CallbackCreate((p1, p2) => cb.IREOleCB_ShowContainerUI(p1, p2))
, CallbackCreate((p1, p2, p3, p4) => cb.IREOleCB_QueryInsertObject(p1, p2, p3, p4))
, CallbackCreate((p1, p2) => cb.IREOleCB_DeleteObject(p1, p2))
, CallbackCreate((p1, p2, p3, p4, p5, p6) => cb.IREOleCB_QueryAcceptData(p1, p2, p3, p4, p5, p6))
, CallbackCreate((p1, p2) => cb.IREOleCB_ContextSensitiveHelp(p1, p2))
, CallbackCreate((p1, p2, p3, p4) => cb.IREOleCB_GetClipboardData(p1, p2, p3, p4))
, CallbackCreate((p1, p2, p3, p4) => cb.IREOleCB_GetDragDropEffect(p1, p2, p3, p4))
, CallbackCreate((p1, p2, p3, p4, p5) => cb.IREOleCB_GetContextMenu(p1, p2, p3, p4, p5))]
;this.RE_SetOleCallback(this.Hwnd)
HeapSize := A_PtrSize * 20 ; VTBL pointer + 13 method pointers + 4 unused pointers + reference count + HEAP handle
HeapOffset := A_PtrSize * 19 ; offset to store the heap handle within the heap
Heap := DllCall("HeapCreate", "UInt", 0x05, "Ptr", 0, "Ptr", 0, "UPtr")
IREOleCB := DllCall("HeapAlloc", "Ptr", Heap, "UInt", 0x08, "Ptr", HeapSize, "UPtr")
Addr := IREOleCB
Addr := NumPut(Addr + A_PtrSize, Addr + 0, "UPtr")
For Each, CB In VTBL
Addr := NumPut(CB, Addr + 0, "UPtr")
NumPut(Heap, IREOleCB + HeapOffset, "UPtr")
SendMessage( 0x0446 , 0, IREOleCB , , "ahk_id" HWND)
}
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_QueryInterface(IREOleCB, REFIID, &IFPtr) { ; IUnknown::QueryInterface
OutputDebug(A_ThisFunc)
Return 0 ; S_OK
}
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_AddRef(IREOleCB) { ; IUnknown::AddRef
Static RefOffset := A_PtrSize * 18
OutputDebug(A_ThisFunc)
NumPut(RefCount := NumGet(IREOleCB + RefOffset, "UInt") + 1, IREOleCB + RefOffset, "UInt")
Return RefCount
}
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_Release(IREOleCB) { ; IUnknown::Release
Static RefOffset := A_PtrSize * 18
, HeapOffset := A_PtrSize * 19
OutputDebug(A_ThisFunc)
NumPut(RefCount := NumGet(IREOleCB + RefOffset, "UInt") - 1, IREOleCB + RefOffset, "UInt")
If (RefCount = 0) {
Heap := NumGet(IREOleCB + HeapOffset, "UPtr")
DllCall("HeapDestroy", "Ptr", Heap)
}
Return RefCount
}
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_GetNewStorage(IREOleCB, IStoragePtr) { ; IRichEditOleCallback::GetNewStorage
OutputDebug(A_ThisFunc)
; msdn.microsoft.com/en-us/library/windows/desktop/aa378977(v=vs.85).aspx
If !(HR := DllCall("Ole32.dll\CreateILockBytesOnHGlobal", "Ptr", 0, "Int", 1, "PtrP", &ILockBytes)) {
; msdn.microsoft.com/en-us/library/windows/desktop/aa380324(v=vs.85).aspx
; STGM_READWRITE = 0x02, STGM_SHARE_EXCLUSIVE = 0x10, STGM_CREATE = 0x1000
If (HR := DllCall("Ole32.dll\StgCreateDocfileOnILockBytes", "Ptr", ILockBytes, "UInt", 0x1012, "UInt", 0, "PtrP", &IStorage))
ObjRelease(ILockBytes)
Else
NumPut(IStorage, IStoragePtr + 0, "UPtr")
}
Return HR
}
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_GetInPlaceContext(IREOleCB, Frame, Doc, FrameInfo) { ; IRichEditOleCallback::GetInPlaceContext - not implemented
OutputDebug(A_ThisFunc)
Return 0x80004001 ; E_NOTIMPL
}
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_ShowContainerUI(IREOleCB, Show) { ; IRichEditOleCallback::ShowContainerUI - not implemented
OutputDebug(A_ThisFunc)
Return 0x80004001 ; E_NOTIMPL
}
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_QueryInsertObject(IREOleCB, CLSID, STG, CP) { ; IRichEditOleCallback::QueryInsertObject - returns S_OK
OutputDebug(A_ThisFunc)
Return 0 ; S_OK
}
; --------------------------------------------------------------------------------------------------------------------------------
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_DeleteObject(IREOleCB, OleObj) { ; IRichEditOleCallback::DeleteObject - returns S_OK
OutputDebug(A_ThisFunc)
Return 0 ; S_OK
}
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_QueryAcceptData(IREOleCB, DataObj, Format, Operation, Really, MetaPic) { ; IRichEditOleCallback::QueryAcceptData - returns S_OK
OutputDebug(A_ThisFunc)
Return 0 ; S_OK
}
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_ContextSensitiveHelp(IREOleCB, EnterMode) { ; IRichEditOleCallback::ContextSensitiveHelp - not implemented
OutputDebug(A_ThisFunc)
Return 0x80004001 ; E_NOTIMPL
}
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_GetClipboardData(IREOleCB, CharRange, Operation, DataObj) { ; IRichEditOleCallback::GetClipboardData - not implemented
Return 0x80004001 ; E_NOTIMPL
}
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_GetDragDropEffect(IREOleCB, Drag, KeyState, Effect) { ; IRichEditOleCallback::GetDragDropEffect - returns S_OK
Return 0 ; S_OK
}
; --------------------------------------------------------------------------------------------------------------------------------
IREOleCB_GetContextMenu(IREOleCB, SelType, OleObj, CharRange, HMENU) { ; IRichEditOleCallback::GetContextMenu
if this.ContextMenu == ""
this.makeContextMenu()
; GCM_RIGHTMOUSEDROP = 0x8000
; OutputDebug(A_ThisFunc)
this.ContextMenu.Show()
If !(SelType & 0x8000) { ; indicates that a context menu for a right-mouse drag drop should be generated
MouseGetPos( , , &HGUI, &HRE, 2)
DllCall("PostMessage", "Ptr", HGUI, "UInt", 0x007B, "Ptr", HRE, "Ptr", -1)
}
Return 0
}
}
; ===================================================================================================================
; DESTRUCTOR
; ===================================================================================================================
__Delete() {
If (This.HWND) {
DllCall("Comctl32.dll\RemoveWindowSubclass", "Ptr", This.HWND, "Ptr", This.Base.SubclassCB, "Ptr", 0)
DllCall("User32.dll\DestroyWindow", "Ptr", This.HWND)
This.HWND := 0
This.Base.Controls -= 1
If (This.Base.Controls = 0) {
DllCall("Kernel32.dll\FreeLibrary", "Ptr", This.Base.Instance)
This.Base.Instance := 0
}
}
}
; ===================================================================================================================
; ===================================================================================================================
; INTERNAL CLASSES ==================================================================================================
; ===================================================================================================================
; ===================================================================================================================
Class CF2 { ; CHARFORMAT2 structure -> http://msdn.microsoft.com/en-us/library/bb787883(v=vs.85).aspx
__New() {
Static CF2_Size := 116
ObjRawSet(this, ":", {Mask: {O: 4, T: "UInt"}, Effects: {O: 8, T: "UInt"}
, Height: {O: 12, T: "Int"}, Offset: {O: 16, T: "Int"}
, TextColor: {O: 20, T: "Int"}, CharSet: {O: 24, T: "UChar"}
, PitchAndFamily: {O: 25, T: "UChar"}, FaceName: {O: 26, T: "Str32"}
, Weight: {O: 90, T: "UShort"}, Spacing: {O: 92, T: "Short"}
, BackColor: {O: 96, T: "UInt"}, LCID: {O: 100, T: "UInt"}
, Cookie: {O: 104, T: "UInt"}, Style: {O: 108, T: "Short"}
, Kerning: {O: 110, T: "UShort"}, UnderlineType: {O: 112, T: "UChar"}
, Animation: {O: 113, T: "UChar"}, RevAuthor: {O: 114, T: "UChar"}
, UnderlineColor: {O: 115, T: "UChar"}})
This.Push(".")
This.SetCapacity(".", CF2_Size)
Addr := This.GetAddress(".")
DllCall("Kernel32.dll\RtlZeroMemory", "Ptr", Addr, "Ptr", CF2_Size)
NumPut(CF2_Size, Addr + 0, 0, "UInt")
}
__Get(Name) {
Addr := This.GetAddress(".")
If (Name = "CF2")
Return Addr
If !This[":"].HasKey(Name)
Return ""
Attr := This[":"][Name]
If (Name != "FaceName")
Return NumGet(Addr + 0, Attr.O, Attr.T)
Return StrGet(Addr + Attr.O, 32)
}
__Set(Name, Value) {
Addr := This.GetAddress(".")
If !This[":"].HasKey(Name)
Return ""
Attr := This[":"][Name]
If (Name != "FaceName")
NumPut(Value, Addr + 0, Attr.O, Attr.T)
Else
StrPut(Value, Addr + Attr.O, 32)
Return Value
}
}
; -------------------------------------------------------------------------------------------------------------------
Class PF2 { ; PARAFORMAT2 structure -> http://msdn.microsoft.com/en-us/library/bb787942(v=vs.85).aspx
__New() {
Static PF2_Size := 188
ObjRawSet(this, ":", {Mask: {O: 4, T: "UInt"}, Numbering: {O: 8, T: "UShort"}
, StartIndent: {O: 12, T: "Int"}, RightIndent: {O: 16, T: "Int"}
, Offset: {O: 20, T: "Int"}, Alignment: {O: 24, T: "UShort"}
, TabCount: {O: 26, T: "UShort"}, Tabs: {O: 28, T: "UInt"}
, SpaceBefore: {O: 156, T: "Int"}, SpaceAfter: {O: 160, T: "Int"}
, LineSpacing: {O: 164, T: "Int"}, Style: {O: 168, T: "Short"}
, LineSpacingRule: {O: 170, T: "UChar"}, OutlineLevel: {O: 171, T: "UChar"}
, ShadingWeight: {O: 172, T: "UShort"}, ShadingStyle: {O: 174, T: "UShort"}
, NumberingStart: {O: 176, T: "UShort"}, NumberingStyle: {O: 178, T: "UShort"}
, NumberingTab: {O: 180, T: "UShort"}, BorderSpace: {O: 182, T: "UShort"}
, BorderWidth: {O: 184, T: "UShort"}, Borders: {O: 186, T: "UShort"}})
This.Push(".")
This.SetCapacity(".", PF2_Size)
Addr := This.GetAddress(".")
DllCall("Kernel32.dll\RtlZeroMemory", "Ptr", Addr, "Ptr", PF2_Size)
NumPut(PF2_Size, Addr + 0, 0, "UInt")
}
__Get(Name) {
Addr := This.GetAddress(".")
If (Name = "PF2")
Return Addr
If !This[":"].HasKey(Name)
Return ""
Attr := This[":"][Name]
If (Name != "Tabs")
Return NumGet(Addr + 0, Attr.O, Attr.T)
Tabs := []
Offset := Attr.O - 4
Loop 32
Tabs[A_Index] := NumGet(Addr + 0, Offset += 4, "UInt")
Return Tabs
}
__Set(Name, Value) {
Addr := This.GetAddress(".")
If !This[":"].HasKey(Name)
Return ""
Attr := This[":"][Name]
If (Name != "Tabs") {
NumPut(Value, Addr + 0, Attr.O, Attr.T)
Return Value
}
If !IsObject(Value)
Return ""
Offset := Attr.O - 4
For Each, Tab In Value
NumPut(Tab, Addr + 0, Offset += 4, "UInt")
Return Tabs
}
}
; ===================================================================================================================
; ===================================================================================================================
; PRIVATE METHODS ===================================================================================================
; ===================================================================================================================
; ===================================================================================================================
GetBGR(RGB) { ; Get numeric BGR value from numeric RGB value or HTML color name
Static HTML := {BLACK: 0x000000, SILVER: 0xC0C0C0, GRAY: 0x808080, WHITE: 0xFFFFFF
, MAROON: 0x000080, RED: 0x0000FF, PURPLE: 0x800080, FUCHSIA: 0xFF00FF
, GREEN: 0x008000, LIME: 0x00FF00, OLIVE: 0x008080, YELLOW: 0x00FFFF
, NAVY: 0x800000, BLUE: 0xFF0000, TEAL: 0x808000, AQUA: 0xFFFF00}
If HTML.HasKey(RGB)
Return HTML[RGB]
Return ((RGB & 0xFF0000) >> 16) + (RGB & 0x00FF00) + ((RGB & 0x0000FF) << 16)
}
; -------------------------------------------------------------------------------------------------------------------
GetRGB(BGR) { ; Get numeric RGB value from numeric BGR-Value
Return ((BGR & 0xFF0000) >> 16) + (BGR & 0x00FF00) + ((BGR & 0x0000FF) << 16)
}
; -------------------------------------------------------------------------------------------------------------------
GetMeasurement() { ; Get locale measurement (metric / inch)
; LOCALE_USER_DEFAULT = 0x0400, LOCALE_IMEASURE = 0x0D, LOCALE_RETURN_NUMBER = 0x20000000
Static Metric := 2.54 ; centimeters
, Inches := 1.00 ; inches
, Measurement := ""
, Len := 2 ;Changed
;Old , Len := A_IsUnicode ? 2 : 4
If (Measurement = "") {
;OldVarSetCapacity(LCD, 4, 0)
LCD := Buffer(4, 0)
DllCall("Kernel32.dll\GetLocaleInfo", "UInt", 0x400, "UInt", 0x2000000D, "Ptr", &LCD, "Int", Len)
Measurement := NumGet(LCD, 0, "UInt") ? Inches : Metric
}
Return Measurement
}
; -------------------------------------------------------------------------------------------------------------------
SubclassProc(M, W, L, I, R) { ; RichEdit subclassproc
; Left out first parameter HWND, will be found in "This" when called by system
; See -> http://msdn.microsoft.com/en-us/library/bb776774%28VS.85%29.aspx
If (M == 0x87) ; WM_GETDLGCODE
Return 4 ; DLGC_WANTALLKEYS
Return DllCall("Comctl32.dll\DefSubclassProc", "Ptr", This, "UInt", M, "Ptr", W, "Ptr", L)
}
; ===================================================================================================================
; ===================================================================================================================
; PUBLIC METHODS ====================================================================================================
; ===================================================================================================================
; ===================================================================================================================
; -------------------------------------------------------------------------------------------------------------------
; Methods to be used by advanced users only
; -------------------------------------------------------------------------------------------------------------------
GetCharFormat() { ; Retrieves the character formatting of the current selection.
; For details see http://msdn.microsoft.com/en-us/library/bb787883(v=vs.85).aspx.
; Returns a 'CF2' object containing the formatting settings.
; EM_GETCHARFORMAT = 0x043A
CF2 := New This.CF2
SendMessage(0x043A, 1, CF2.CF2, , "ahk_id " This.HWND)
Return (CF2.Mask ? CF2 : False)
}
; -------------------------------------------------------------------------------------------------------------------
SetCharFormat(CF2) { ; Sets character formatting of the current selection.
; For details see http://msdn.microsoft.com/en-us/library/bb787883(v=vs.85).aspx.
; CF2 : CF2 object like returned by GetCharFormat().
; EM_SETCHARFORMAT = 0x0444
ErrorLevel := SendMessage( 0x0444, 1, CF2.CF2, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
GetParaFormat() { ; Retrieves the paragraph formatting of the current selection.
; For details see http://msdn.microsoft.com/en-us/library/bb787942(v=vs.85).aspx.
; Returns a 'PF2' object containing the formatting settings.
; EM_GETPARAFORMAT = 0x043D
PF2 := New This.PF2
ErrorLevel := SendMessage(0x043D, 0, PF2.PF2, , "ahk_id " . This.HWND)
Return (PF2.Mask ? PF2 : False)
}
; -------------------------------------------------------------------------------------------------------------------
SetParaFormat(PF2) { ; Sets the paragraph formatting for the current selection.
; For details see http://msdn.microsoft.com/en-us/library/bb787942(v=vs.85).aspx.
; PF2 : PF2 object like returned by GetParaFormat().
; EM_SETPARAFORMAT = 0x0447
ErrorLevel := SendMessage(0x0447, 0, PF2.PF2, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
; Control specific
; -------------------------------------------------------------------------------------------------------------------
IsModified() { ; Has the control been modified?
; EM_GETMODIFY = 0xB8
ErrorLevel := SendMessage( 0xB8, 0, 0, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
SetModified(Modified := False) { ; Sets or clears the modification flag for an edit control.
; EM_SETMODIFY = 0xB9
ErrorLevel := SendMessage( 0xB9, !!Modified, 0, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
SetEventMask(Events := "") { ; Set the events which shall send notification codes control's owner
; Events : Array containing one or more of the keys defined in 'ENM'.
; For details see http://msdn.microsoft.com/en-us/library/bb774238(v=vs.85).aspx
; EM_SETEVENTMASK = 0x0445
Static ENM := {NONE: 0x00, CHANGE: 0x01, UPDATE: 0x02, SCROLL: 0x04, SCROLLEVENTS: 0x08, DRAGDROPDONE: 0x10
, PARAGRAPHEXPANDED: 0x20, PAGECHANGE: 0x40, KEYEVENTS: 0x010000, MOUSEEVENTS: 0x020000
, REQUESTRESIZE: 0x040000, SELCHANGE: 0x080000, DROPFILES: 0x100000, PROTECTED: 0x200000
, LINK: 0x04000000}
if Events is "Integer"
Mask := Events
else {
Mask := 0
Events := StrSplit(Events, " ")
for _, v in Events {
If ENM.HasKey(v) {
Mask := Mask | ENM[v]
}
Else
Return False
}
}
r := SendMessage(0x0445, 0, Mask, , "ahk_id " . This.HWND)
return r
}
; -------------------------------------------------------------------------------------------------------------------
; Loading and storing RTF format
; -------------------------------------------------------------------------------------------------------------------
GetRTF(Selection := False) { ; Gets the whole content of the control as rich text.
; Selection = False : whole contents (default)
; Selection = True : current selection
; EM_STREAMOUT = 0x044A
; SF_TEXT = 0x1, SF_RTF = 0x2, SF_RTFNOOBJS = 0x3, SF_UNICODE = 0x10, SF_USECODEPAGE = 0x0020
; SFF_PLAINRTF = 0x4000, SFF_SELECTION = 0x8000
; UTF-8 = 65001, UTF-16 = 1200
Static GetRTFCB := 0
Flags := 0x4022 | (1200 << 16) | (Selection ? 0x8000 : 0)
GetRTFCB := CallbackCreate("RichEdit.GetRTFProc")
;Old VarSetCapacity(ES, (A_PtrSize * 2) + 4, 0) ; EDITSTREAM structure
ES := Buffer((A_PtrSize * 2) + 4, 0) ; EDITSTREAM structure ;Changed
NumPut(This.HWND, ES, 0, "Ptr") ; dwCookie
NumPut(GetRTFCB, ES, A_PtrSize + 4, "Ptr") ; pfnCallback
SendMessage(0x044A, Flags, &ES, , "ahk_id " . This.HWND)
DllCall("Kernel32.dll\GlobalFree", "Ptr", GetRTFCB)
Return This.GetRTFProc("Get", 0, 0)
}
; -------------------------------------------------------------------------------------------------------------------
GetRTFProc(pbBuff, cb, pcb) { ; Callback procedure for GetRTF
; left out first parameter dwCookie, will be passed in "This" when called by system
Static RTF := ""
If (cb > 0) {
RTF .= StrGet(pbBuff, cb, "CP0")
Return 0
}
If (pbBuff = "Get") {
Out := RTF
;Old VarSetCapacity(RTF, 0)
VarSetStrCapacity(&RTF, 0) ; Changed
Return Out
}
Return 1
}
; -------------------------------------------------------------------------------------------------------------------
LoadRTF(FilePath, Selection := False) { ; Loads RTF file into the control.
; FilePath = file path
; Selection = False : whole contents (default)
; Selection = True : current selection
; EM_STREAMIN = 0x0449
; SF_TEXT = 0x1, SF_RTF = 0x2, SF_RTFNOOBJS = 0x3, SF_UNICODE = 0x10, SF_USECODEPAGE = 0x0020
; SFF_PLAINRTF = 0x4000, SFF_SELECTION = 0x8000
; UTF-16 = 1200
Static LoadRTFCB := CallbackCreate("RichEdit.LoadRTFProc")
Flags := 0x4002 | (Selection ? 0x8000 : 0) ; | (1200 << 16)
If !(File := FileOpen(FilePath, "r"))
Return False
;Old VarSetCapacity(ES, (A_PtrSize * 2) + 4, 0) ; EDITSTREAM structure
ES := Buffer((A_PtrSize * 2) + 4, 0) ; EDITSTREAM structure ;Changed
NumPut(File.__Handle, ES, 0, "Ptr") ; dwCookie
NumPut(LoadRTFCB, ES, A_PtrSize + 4, "Ptr") ; pfnCallback
ErrorLevel := SendMessage(0x0449, Flags, &ES, , "ahk_id " . This.HWND)
Result := ErrorLevel
File.Close()
Return Result
}
; -------------------------------------------------------------------------------------------------------------------
LoadRTFProc(pbBuff, cb, pcb) { ; Callback procedure for LoadRTF
; Left out first parameter dwCookie, will be passed in "This" when called by system
Return !DllCall("ReadFile", "Ptr", This, "Ptr", pbBuff, "UInt", cb, "Ptr", pcb, "Ptr", 0)
}
; -------------------------------------------------------------------------------------------------------------------
; Scrolling
; -------------------------------------------------------------------------------------------------------------------
GetScrollPos() { ; Obtains the current scroll position.
; Returns on object with keys 'X' and 'Y' containing the scroll position.
; EM_GETSCROLLPOS = 0x04DD
;Old VarSetCapacity(PT, 8, 0)
PT := Buffer(8, 0) ; Changed
SendMessage(0x04DD, 0, &PT, , "ahk_id " . This.HWND)
Return {X: NumGet(PT, 0, "Int"), Y: NumGet(PT, 4, "Int")}
}
; -------------------------------------------------------------------------------------------------------------------
SetScrollPos(X, Y) { ; Scrolls the contents of a rich edit control to the specified point.
; X : x-position to scroll to.
; Y : y-position to scroll to.
; EM_SETSCROLLPOS = 0x04DE
;Old VarSetCapacity(PT, 8, 0)
PT := Buffer(8, 0) ; Changed
NumPut(X, PT, 0, "Int")
NumPut(Y, PT, 4, "Int")
ErrorLevel := SendMessage(0x04DE, 0, &PT, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
ScrollCaret() { ; Scrolls the caret into view.
; EM_SCROLLCARET = 0x00B7
SendMessage(0x00B7, 0, 0, , "ahk_id " . This.HWND)
Return True
}
; -------------------------------------------------------------------------------------------------------------------
ShowScrollBar(SB, Mode := True) { ; Shows or hides one of the scroll bars of a rich edit control.
; SB : Identifies which scroll bar to display: horizontal or vertical.
; This parameter must be 1 (SB_VERT) or 0 (SB_HORZ).
; Mode : Specify TRUE to show the scroll bar and FALSE to hide it.
; EM_SHOWSCROLLBAR = 0x0460 (WM_USER + 96)
SendMessage(0x0460, SB, Mode, , "ahk_id " . This.HWND)
Return True
}
; -------------------------------------------------------------------------------------------------------------------
; Text and selection
; -------------------------------------------------------------------------------------------------------------------
RegExFunc(needle, function) {
if isObject(function) && function.isBuiltIn != "" {
textLen := this.GetTextLen(), text := this.GetText(), sp := 0, len := 1, match := []
while sp < textLen && sp := RegExMatch(text, needle, &m, sp + len)
len := m.len > 0 ? m.len : 1
, _match := SubStr(text, sp, m.Len)
, match.push(_match)
, function.Call(_match, sp, len)
return match
}
else
return false
}
FindText(Find, Mode := "") { ; Finds Unicode text within a rich edit control.
; Find : Text to search for.
; Mode : Optional array containing one or more of the keys specified in 'FR'.
; For details see http://msdn.microsoft.com/en-us/library/bb788013(v=vs.85).aspx.
; Returns True if the text was found; otherwise false.
; EM_FINDTEXTEXW = 0x047C, EM_SCROLLCARET = 0x00B7
Static FR:= {DOWN: 1, WHOLEWORD: 2, MATCHCASE: 4}
Flags := 0
if Mode != ""
For Each, Value In Mode
If FR.HasKey(Value)
Flags |= FR[Value]
Sel := This.GetSel()
Min := (Flags & FR.DOWN) ? Sel.E : Sel.S
Max := (Flags & FR.DOWN) ? -1 : 0
;Old VarSetCapacity(FTX, 16 + A_PtrSize, 0)
FTX := Buffer(16 + A_PtrSize, 0) ;Changed
NumPut(Min, FTX, 0, "Int")
NumPut(Max, FTX, 4, "Int")
NumPut(&Find, FTX, 8, "Ptr")
SendMessage(0x047C, Flags, &FTX, , "ahk_id " . This.HWND)
S := NumGet(FTX, 8 + A_PtrSize, "Int"), E := NumGet(FTX, 12 + A_PtrSize, "Int")
If (S = -1) && (E = -1)
Return False
This.SetSel(S, E)
This.ScrollCaret()
Return
}
; -------------------------------------------------------------------------------------------------------------------
GotoPos(pos) { ;Goto position
This.SetSel(pos, pos)
This.ScrollCaret()
}
; -------------------------------------------------------------------------------------------------------------------
FindWordBreak(CharPos, Mode := "Left") { ; Finds the next word break before or after the specified character position
; or retrieves information about the character at that position.
; CharPos : Character position.
; Mode : Can be one of the keys specified in 'WB'.
; Returns the character index of the word break or other values depending on 'Mode'.
; For details see http://msdn.microsoft.com/en-us/library/bb788018(v=vs.85).aspx.
; EM_FINDWORDBREAK = 0x044C (WM_USER + 76)
Static WB := {LEFT: 0, RIGHT: 1, ISDELIMITER: 2, CLASSIFY: 3, MOVEWORDLEFT: 4, MOVEWORDRIGHT: 5, LEFTBREAK: 6
, RIGHTBREAK: 7}
Option := WB.HasKey(Mode) ? WB[Mode] : 0
ErrorLevel := SendMessage(0x044C, Option, CharPos, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
GetSelText() { ; Retrieves the currently selected text as plain text.
; Returns selected text.
; EM_GETSELTEXT = 0x043E, EM_EXGETSEL = 0x0434
;Old VarSetCapacity(CR, 8, 0)
CR := Buffer(8, 0) ;Changed
SendMessage(0x0434, 0, &CR, , "ahk_id " . This.HWND)
L := NumGet(CR, 4, "Int") - NumGet(CR, 0, "Int") + 1
If (L > 1) {
;Old VarSetCapacity(Text, L * 2, 0)
Text := Buffer(L * 2, 0) ;Changed
SendMessage(0x043E, 0, &Text, , "ahk_id " . This.HWND)
VarSetStrCapacity(&Text, -1)
}
Return Text
}
; -------------------------------------------------------------------------------------------------------------------
GetSel() { ; Retrieves the starting and ending character positions of the selection in a rich edit control.
; Returns an object containing the keys S (start of selection) and E (end of selection)).
; EM_EXGETSEL = 0x0434
;Old VarSetCapacity(CR, 8, 0)
CR := Buffer(8, 0) ;Changed
SendMessage(0x0434, 0, &CR, , "ahk_id " . This.HWND)
Return {S: NumGet(CR, 0, "Int"), E: NumGet(CR, 4, "Int")}
}
; -------------------------------------------------------------------------------------------------------------------
GetText() { ; Gets the whole content of the control as plain text.
; EM_GETTEXTEX = 0x045E
Text := ""
If (Length := This.GetTextLen() * 2) {
;Old VarSetCapacity(GTX, (4 * 4) + (A_PtrSize * 2), 0) ; GETTEXTEX structure
GTX := Buffer((4 * 4) + (A_PtrSize * 2), 0) ; GETTEXTEX structure ; Changed
NumPut(Length + 2, GTX, 0, "UInt") ; cb
NumPut(1200, GTX, 8, "UInt") ; codepage = Unicode
;Old VarSetCapacity(Text, Length + 2, 0)
Text := Buffer(Length + 2, 0) ; Changed
SendMessage(0x045E, >X, &Text, , "ahk_id " . This.HWND)
;Old VarSetCapacity(Text, -1)
VarSetStrCapacity(&Text, -1) ;Changed
}
Return Text
}
; -------------------------------------------------------------------------------------------------------------------
GetTextLen() { ; Calculates text length in various ways.
; EM_GETTEXTLENGTHEX = 0x045F
;OldVarSetCapacity(GTL, 8, 0) ; GETTEXTLENGTHEX structure
GTL := Buffer(8, 0) ; GETTEXTLENGTHEX structure ; Changed
NumPut(1200, GTL, 4, "UInt") ; codepage = Unicode
return SendMessage(0x045F, >L, 0, , "ahk_id " . This.HWND)
}
; -------------------------------------------------------------------------------------------------------------------
GetTextRange(Min, Max) { ; Retrieves a specified range of characters from a rich edit control.
; Min : Character position index immediately preceding the first character in the range.
; Integer value to store as cpMin in the CHARRANGE structure.
; Max : Character position immediately following the last character in the range.
; Integer value to store as cpMax in the CHARRANGE structure.
; CHARRANGE -> http://msdn.microsoft.com/en-us/library/bb787885(v=vs.85).aspx
; EM_GETTEXTRANGE = 0x044B
If (Max <= Min)
Return ""
;Old VarSetCapacity(Text, (Max - Min) << !!A_IsUnicode, 0)
;Old VarSetCapacity(TEXTRANGE, 16, 0) ; TEXTRANGE Struktur
;Old Text := Buffer((Max - Min) << !!A_IsUnicode, 0)
Text := Buffer((Max - Min) << !!1, 0) ;Changed
TEXTRANGE := Buffer(16, 0) ; TEXTRANGE Struktur
NumPut(Min, TEXTRANGE, 0, "UInt")
NumPut(Max, TEXTRANGE, 4, "UInt")
NumPut(&Text, TEXTRANGE, 8, "UPtr")
SendMessage(0x044B, 0, &TEXTRANGE, , "ahk_id " . This.HWND)
VarSetStrCapacity(&Text, -1) ; Länge des Zeichenspeichers korrigieren
Return Text
}
; -------------------------------------------------------------------------------------------------------------------
HideSelection(Mode) { ; Hides or shows the selection.
; Mode : True to hide or False to show the selection.
; EM_HIDESELECTION = 0x043F (WM_USER + 63)
SendMessage(0x043F, Mode, 0, , "ahk_id " . This.HWND)
Return True
}
; -------------------------------------------------------------------------------------------------------------------
LimitText(Limit) { ; Sets an upper limit to the amount of text the user can type or paste into a rich edit control.
; Limit : Specifies the maximum amount of text that can be entered.
; If this parameter is zero, the default maximum is used, which is 64K characters.
; EM_EXLIMITTEXT = 0x435 (WM_USER + 53)
SendMessage(0x0435, 0, Limit, , "ahk_id " . This.HWND)
Return True
}
; -------------------------------------------------------------------------------------------------------------------
ReplaceSel(Text := "") { ; Replaces the selected text with the specified text.
; EM_REPLACESEL = 0xC2
ErrorLevel := SendMessage(0xC2, 1, &Text, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
SetText(&Text := "", Mode := "") { ; Replaces the selection or the whole content of the control.
; Mode : Option flags. It can be any reasonable combination of the keys defined in 'ST'.
; For details see http://msdn.microsoft.com/en-us/library/bb774284(v=vs.85).aspx.
; EM_SETTEXTEX = 0x0461, CP_UNICODE = 1200
; ST_DEFAULT = 0, ST_KEEPUNDO = 1, ST_SELECTION = 2, ST_NEWCHARS = 4 ???
Static ST := {DEFAULT: 0, KEEPUNDO: 1, SELECTION: 2}
Flags := 0
Mode := StrSplit(Mode, " ")
For Each, Value In Mode
If ST.HasKey(Value)
Flags |= ST[Value]
CP := 1200
BufAddr := &Text
; RTF formatted text has to be passed as ANSI!!!
If (SubStr(Text, 1, 5) = "{\rtf") || (SubStr(Text, 1, 5) = "{urtf") {
Len := StrPut(Text, "CP0")
;Old VarSetCapacity(Buf, Len, 0)
Buf := Buffer(Len, 0) ;Changed
StrPut(Text, &Buf, , "CP0")
BufAddr := &Buf
CP := 0
}
;Old VarSetCapacity(STX, 8, 0) ; SETTEXTEX structure
STX := Buffer(8, 0) ; SETTEXTEX structure ;Changed
NumPut(Flags, STX, 0, "UInt") ; flags
NumPut(CP , STX, 4, "UInt") ; codepage
ErrorLevel := SendMessage(0x0461, &STX, BufAddr, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
SetSel(Start, End) { ; Selects a range of characters.
; Start : zero-based start index
; End : zero-beased end index (-1 = end of text))
; EM_EXSETSEL = 0x0437
;Old VarSetCapacity(CR, 8, 0)
CR := Buffer(8, 0) ;Changed
NumPut(Start, CR, 0, "Int")
NumPut(End, CR, 4, "Int")
return SendMessage(0x0437, 0, &CR, , "ahk_id " . This.HWND)
}
; -------------------------------------------------------------------------------------------------------------------
; Appearance, styles, and options
; -------------------------------------------------------------------------------------------------------------------
AutoURL(On) { ; Turn AutoURLDetection on/off
; EM_AUTOURLDETECT = 0x45B
ErrorLevel := SendMessage(0x45B, !!On, 0, , "ahk_id " . This.HWND)
WinRedraw("ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
GetOptions() { ; Retrieves rich edit control options.
; Returns an array of currently the set options as the keys defined in 'ECO'.
; For details see http://msdn.microsoft.com/en-us/library/bb774178(v=vs.85).aspx.
; EM_GETOPTIONS = 0x044E
Static ECO := {AUTOWORDSELECTION: 0x01, AUTOVSCROLL: 0x40, AUTOHSCROLL: 0x80, NOHIDESEL: 0x100
, READONLY: 0x800, WANTRETURN: 0x1000, SAVESEL: 0x8000, SELECTIONBAR: 0x01000000
, VERTICAL: 0x400000}
O := SendMessage(0x044E, 0, 0, , "ahk_id " . This.HWND)
Options := []
For Key, Value In ECO
If (O & Value)
Options.Push(Key)
Return Options
}
; -------------------------------------------------------------------------------------------------------------------
GetStyles() { ; Retrieves the current edit style flags.
; Returns an object containing keys as defined in 'SES'.
; For details see http://msdn.microsoft.com/en-us/library/bb788031(v=vs.85).aspx.
; EM_GETEDITSTYLE = 0x04CD (WM_USER + 205)
Static SES := {1: "EMULATESYSEDIT", 1: "BEEPONMAXTEXT", 4: "EXTENDBACKCOLOR", 32: "NOXLTSYMBOLRANGE", 64: "USEAIMM"
, 128: "NOIME", 256: "ALLOWBEEPS", 512: "UPPERCASE", 1024: "LOWERCASE", 2048: "NOINPUTSEQUENCECHK"
, 4096: "BIDI", 8192: "SCROLLONKILLFOCUS", 16384: "XLTCRCRLFTOCR", 32768: "DRAFTMODE"
, 0x0010000: "USECTF", 0x0020000: "HIDEGRIDLINES", 0x0040000: "USEATFONT", 0x0080000: "CUSTOMLOOK"
, 0x0100000: "LBSCROLLNOTIFY", 0x0200000: "CTFALLOWEMBED", 0x0400000: "CTFALLOWSMARTTAG"
, 0x0800000: "CTFALLOWPROOFING"}
Result := SendMessage(0x04CD, 0, 0, , "ahk_id " . This.HWND)
Styles := []
For Key, Value In SES
If (Result & Key)
Styles.Push(Value)
Return Styles
}
; -------------------------------------------------------------------------------------------------------------------
GetZoom() { ; Gets the current zoom ratio.
; Returns the zoom ratio in percent.
; EM_GETZOOM = 0x04E0
;Old VarSetCapacity(N, 4, 0), VarSetCapacity(D, 4, 0)
N := Buffer(4, 0), D := Buffer(4, 0) ;Changed
SendMessage(0x04E0, &N, &D, , "ahk_id " . This.HWND)
N := NumGet(N, 0, "Int"), D := NumGet(D, 0, "Int")
Return (N = 0) && (D = 0) ? 100 : Round(N / D * 100)
}
; -------------------------------------------------------------------------------------------------------------------
SetBackgroundColor(Color) { ; Sets the background color.
; Color : RGB integer value or HTML color name or
; "Auto" to reset to system default color.
; Returns the prior background color.
; EM_SETBKGNDCOLOR = 0x0443
If (Color = "Auto")
System := True, Color := 0
Else
System := False, Color := This.GetBGR(Color)
r := SendMessage(0x0443, System, Color, , "ahk_id " . This.HWND)
Return This.GetRGB(r)
}
; -------------------------------------------------------------------------------------------------------------------
SetOptions(Options := "", Mode := "SET") { ; Sets the options for a rich edit control.
; Options : Space delimited string of options as the keys defined in 'ECO'.
; Mode : Settings mode: SET, OR, AND, XOR
; For details see http://msdn.microsoft.com/en-us/library/bb774254(v=vs.85).aspx.
; EM_SETOPTIONS = 0x044D
Static ECO := {AUTOWORDSELECTION: 0x01, AUTOVSCROLL: 0x40, AUTOHSCROLL: 0x80, NOHIDESEL: 0x100, READONLY: 0x800
, WANTRETURN: 0x1000, SAVESEL: 0x8000, SELECTIONBAR: 0x01000000, VERTICAL: 0x400000}
, ECOOP := {SET: 0x01, OR: 0x02, AND: 0x03, XOR: 0x04}
If !ECOOP.HasKey(Mode)
Return False
O := 0
Options := StrSplit(Options, " ")
For Each, Option In Options {
Option := Trim(Option, " `t`n`r")
If ECO.HasKey(Option)
O |= ECO[Option]
Else
Return False
}
ErrorLevel := SendMessage(0x044D, ECOOP[Mode], O, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
SetStyles(SetStyles:=0, ClearStyles:=0) { ; Sets the current edit style flags for a rich edit control.
; SetStyles <= styles to set ; ClearStyles <= styles to clear. Use space delimited strings for each
; For details see http://msdn.microsoft.com/en-us/library/bb774236(v=vs.85).aspx.
; EM_SETEDITSTYLE = 0x04CC (WM_USER + 204)
Static SES := {EMULATESYSEDIT: 1, BEEPONMAXTEXT: 2, EXTENDBACKCOLOR: 4, NOXLTSYMBOLRANGE: 32, USEAIMM: 64
, NOIME: 128, ALLOWBEEPS: 256, UPPERCASE: 512, LOWERCASE: 1024, NOINPUTSEQUENCECHK: 2048
, BIDI: 4096, SCROLLONKILLFOCUS: 8192, XLTCRCRLFTOCR: 16384, DRAFTMODE: 32768
, USECTF: 0x0010000, HIDEGRIDLINES: 0x0020000, USEATFONT: 0x0040000, CUSTOMLOOK: 0x0080000
, LBSCROLLNOTIFY: 0x0100000, CTFALLOWEMBED: 0x0200000, CTFALLOWSMARTTAG: 0x0400000
, CTFALLOWPROOFING: 0x0800000}
Flags := Mask := 0
if SetStyles is "Integer"
Flags := SetStyles
else {
SetStyles := StrSplit(SetStyles, " ")
For _, v In SetStyles {
v := Trim(v, " `t`n`r")
If SES.HasKey(v) {
Mask |= SES[v]
Flags |= SES[v]
}
}
}
if ClearStyles is "Integer"
Mask := Flags | ClearStyles
else {
ClearStyles := StrSplit(ClearStyles, " ")
For _, v In ClearStyles {
v := Trim(v, " `t`n`r")
If SES.HasKey(v) {
Mask |= SES[v]
}
}
}
If (Mask) {
return SendMessage(0x04CC, Flags, Mask, , "ahk_id " This.HWND)
}
Return False
}
ClearStyles(clearStyles) {
return this.SetStyles(, clearStyles)
}
; -------------------------------------------------------------------------------------------------------------------
SetZoom(Ratio := "") { ; Sets the zoom ratio of a rich edit control.
; Ratio : Float value between 100/64 and 6400; a ratio of 0 turns zooming off.
; EM_SETZOOM = 0x4E1
ErrorLevel := SendMessage(0x4E1, (Ratio > 0 ? Ratio : 100), 100, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
; Copy, paste, etc.
; -------------------------------------------------------------------------------------------------------------------
CanRedo() { ; Determines whether there are any actions in the control redo queue.
; EM_CANREDO = 0x0455 (WM_USER + 85)
ErrorLevel := SendMessage(0x0455, 0, 0, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
CanUndo() { ; Determines whether there are any actions in an edit control's undo queue.
; EM_CANUNDO = 0x00C6
ErrorLevel := SendMessage(0x00C6, 0, 0, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
Clear() {
; WM_CLEAR = 0x303
ErrorLevel := SendMessage(0x303, 0, 0, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
Copy() { ; WM_COPY = 0x301
ErrorLevel := SendMessage(0x301, 0, 0, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
Cut() { ; WM_CUT = 0x300
ErrorLevel := SendMessage(0x300, 0, 0, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
Paste() { ; WM_PASTE = 0x302
ErrorLevel := SendMessage(0x302, 0, 0, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
Redo() { ; EM_REDO := 0x454
ErrorLevel := SendMessage(0x454, 0, 0, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
Undo() { ; EM_UNDO = 0xC7
ErrorLevel := SendMessage(0xC7, 0, 0, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
SelAll() { ; Select all
Return This.SetSel(0, -1)
}
; -------------------------------------------------------------------------------------------------------------------
Deselect() { ; Deselect all
Sel := This.GetSel()
Return This.SetSel(Sel.S, Sel.S)
}
; -------------------------------------------------------------------------------------------------------------------
; Font & colors
; -------------------------------------------------------------------------------------------------------------------
ChangeFontSize(Diff) { ; Change font size
; Diff : any positive or negative integer, positive values are treated as +1, negative as -1.
; Returns new size.
; EM_SETFONTSIZE = 0x04DF
; Font size changes by 1 in the range 4 - 11 pt, by 2 for 12 - 28 pt, afterward to 36 pt, 48 pt, 72 pt, 80 pt,
; and by 10 for > 80 pt. The maximum value is 160 pt, the minimum is 4 pt
Font := This.GetFont()
If (Diff > 0 && Font.Size < 160) || (Diff < 0 && Font.Size > 4)
SendMessage(0x04DF, (Diff > 0 ? 1 : -1), 0, , "ahk_id " . This.HWND)
Else
Return False
Font := This.GetFont()
Return Font.Size
}
; -------------------------------------------------------------------------------------------------------------------
GetFont(Default := False) { ; Get current font
; Set Default to True to get the default font.
; Returns an object containing current options (see SetFont())
; EM_GETCHARFORMAT = 0x043A
; BOLD_FONTTYPE = 0x0100, ITALIC_FONTTYPE = 0x0200
; CFM_BOLD = 1, CFM_ITALIC = 2, CFM_UNDERLINE = 4, CFM_STRIKEOUT = 8, CFM_PROTECTED = 16, CFM_SUBSCRIPT = 0x30000
; CFM_BACKCOLOR = 0x04000000, CFM_CHARSET := 0x08000000, CFM_FACE = 0x20000000, CFM_COLOR = 0x40000000
; CFM_SIZE = 0x80000000
; CFE_SUBSCRIPT = 0x10000, CFE_SUPERSCRIPT = 0x20000, CFE_AUTOBACKCOLOR = 0x04000000, CFE_AUTOCOLOR = 0x40000000
; SCF_SELECTION = 1
Static Mask := 0xEC03001F
Static Effects := 0xEC000000
CF2 := New This.CF2
CF2.Mask := Mask
CF2.Effects := Effects
SendMessage(0x043A, (Default ? 0 : 1), CF2.CF2, , "ahk_id " . This.HWND)
Font := {}
Font.Name := CF2.FaceName
Font.Size := CF2.Height / 20
CFS := CF2.Effects
Style := (CFS & 1 ? "B" : "") . (CFS & 2 ? "I" : "") . (CFS & 4 ? "U" : "") . (CFS & 8 ? "S" : "")
. (CFS & 0x10000 ? "L" : "") . (CFS & 0x20000 ? "H" : "") . (CFS & 16 ? "P" : "")
Font.Style := Style = "" ? "N" : Style
Font.Color := This.GetRGB(CF2.TextColor)
If (CF2.Effects & 0x04000000)
Font.BkColor := "Auto"
Else
Font.BkColor := This.GetRGB(CF2.BackColor)
Font.CharSet := CF2.CharSet
Return Font
}
; -------------------------------------------------------------------------------------------------------------------
SetDefaultFont(Font := "") { ; Set default font
; Font : Optional object - see SetFont().
If IsObject(Font) {
For Key, Value In Font
If This.DefFont.HasKey(Key)
This.DefFont[Key] := Value
}
Return This.SetFont(This.DefFont)
}
; -------------------------------------------------------------------------------------------------------------------
SetFont(Font) { ; Set current/default font
; Font : Object containing the following keys
; Name : optional font name
; Size : optional font size in points
; Style : optional string of one or more of the following styles
; B = bold, I = italic, U = underline, S = strikeout, L = subscript
; H = superscript, P = protected, N = normal
; Color : optional text color as RGB integer value or HTML color name
; "Auto" for "automatic" (system's default) color
; BkColor : optional text background color (see Color)
; "Auto" for "automatic" (system's default) background color
; CharSet : optional font character set
; 1 = DEFAULT_CHARSET, 2 = SYMBOL_CHARSET
; UlColor :
; Empty parameters preserve the corresponding properties
; EM_SETCHARFORMAT = 0x0444
; SCF_DEFAULT = 0, SCF_SELECTION = 1
CF2 := New This.CF2
Mask := Effects := 0
If (Font.Name != "") {
Mask |= 0x20000000, Effects |= 0x20000000 ; CFM_FACE, CFE_FACE
CF2.FaceName := Font.Name
}
Size := Font.Size
If (Size != "") {
If (Size < 161)
Size *= 20
Mask |= 0x80000000, Effects |= 0x80000000 ; CFM_SIZE, CFE_SIZE
CF2.Height := Size
}
If (Font.Style != "") {
Mask |= 0x3001F ; all font styles
If InStr(Font.Style, "B")
Effects |= 1 ; CFE_BOLD
If InStr(Font.Style, "I")
Effects |= 2 ; CFE_ITALIC
If InStr(Font.Style, "U")
Effects |= 4 ; CFE_UNDERLINE
If InStr(Font.Style, "S")
Effects |= 8 ; CFE_STRIKEOUT
If InStr(Font.Style, "P")
Effects |= 16 ; CFE_PROTECTED
If InStr(Font.Style, "L")
Effects |= 0x10000 ; CFE_SUBSCRIPT
If InStr(Font.Style, "H")
Effects |= 0x20000 ; CFE_SUPERSCRIPT
}
If (Font.Color != "") {
Mask |= 0x40000000 ; CFM_COLOR
If (Font.Color = "Auto")
Effects |= 0x40000000 ; CFE_AUTOCOLOR
Else
CF2.TextColor := This.GetBGR(Font.Color)
}
If (Font.BkColor != "") {
Mask |= 0x04000000 ; CFM_BACKCOLOR
If (Font.BkColor = "Auto")
Effects |= 0x04000000 ; CFE_AUTOBACKCOLOR
Else
CF2.BackColor := This.GetBGR(Font.BkColor)
}
If (Font.CharSet != "") {
Mask |= 0x08000000, Effects |= 0x08000000 ; CFM_CHARSET, CFE_CHARSET
CF2.CharSet := Font.CharSet = 2 ? 2 : 1 ; SYMBOL|DEFAULT
}
If (Mask != 0) {
Mode := Font.Default ? 0 : 1
CF2.Mask := Mask
CF2.Effects := Effects
return SendMessage(0x0444, Mode, CF2.CF2, , "ahk_id " . This.HWND)
}
Return False
}
; -------------------------------------------------------------------------------------------------------------------
ToggleFontStyle(Style) { ; Toggle single font style
; Style : one of the following styles
; B = bold, I = italic, U = underline, S = strikeout, L = subscript, H = superschript, P = protected,
; N = normal (reset all other styles)
; EM_GETCHARFORMAT = 0x043A, EM_SETCHARFORMAT = 0x0444
; CFM_BOLD = 1, CFM_ITALIC = 2, CFM_UNDERLINE = 4, CFM_STRIKEOUT = 8, CFM_PROTECTED = 16, CFM_SUBSCRIPT = 0x30000
; CFE_SUBSCRIPT = 0x10000, CFE_SUPERSCRIPT = 0x20000, SCF_SELECTION = 1
CF2 :=This.GetCharFormat()
CF2.Mask := 0x3001F ; FontStyles
If (Style = "N")
CF2.Effects := 0
Else
CF2.Effects ^= Style = "B" ? 1 : Style = "I" ? 2 : Style = "U" ? 4 : Style = "S" ? 8
: Style = "H" ? 0x20000 : Style = "L" ? 0x10000 : 0
ErrorLevel := SendMessage(0x0444, 1, CF2.CF2, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
; Paragraph formatting
; -------------------------------------------------------------------------------------------------------------------
AlignText(Align := 1) { ; Set paragraph's alignment
; Note: Values greater 3 doesn't seem to work though they should as documented
; Align: may contain one of the following numbers:
; PFA_LEFT 1
; PFA_RIGHT 2
; PFA_CENTER 3
; PFA_JUSTIFY 4 // New paragraph-alignment option 2.0 (*)
; PFA_FULL_INTERWORD 4 // These are supported in 3.0 with advanced
; PFA_FULL_INTERLETTER 5 // typography enabled
; PFA_FULL_SCALED 6
; PFA_FULL_GLYPHS 7
; PFA_SNAP_GRID 8
; EM_SETPARAFORMAT = 0x0447, PFM_ALIGNMENT = 0x08
If (Align >= 1) && (ALign <= 8) {
PF2 := New This.PF2 ; PARAFORMAT2 struct
PF2.Mask := 0x08 ; dwMask
PF2.Alignment := Align ; wAlignment
SendMessage(0x0447, 0, PF2.PF2, , "ahk_id " . This.HWND)
Return True
}
Return False
}
; -------------------------------------------------------------------------------------------------------------------
SetBorder(Widths, Styles) { ; Set paragraph's borders
; Borders are not displayed in RichEdit, so the call of this function has no visible result.
; Even WordPad distributed with Win7 does not show them, but e.g. Word 2007 does.
; Widths : Array of the 4 border widths in the range of 1 - 15 in order left, top, right, bottom; zero = no border
; Styles : Array of the 4 border styles in the range of 0 - 7 in order left, top, right, bottom (see remarks)
; Note:
; The description on MSDN at http://msdn.microsoft.com/en-us/library/bb787942(v=vs.85).aspx is wrong!
; To set borders you have to put the border width into the related nibble (4 Bits) of wBorderWidth
; (in order: left (0 - 3), top (4 - 7), right (8 - 11), and bottom (12 - 15). The values are interpreted as
; half points (i.e. 10 twips). Border styles are set in the related nibbles of wBorders.
; Valid styles seem to be:
; 0 : \brdrdash (dashes)
; 1 : \brdrdashsm (small dashes)
; 2 : \brdrdb (double line)
; 3 : \brdrdot (dotted line)
; 4 : \brdrhair (single/hair line)
; 5 : \brdrs ? looks like 3
; 6 : \brdrth ? looks like 3
; 7 : \brdrtriple (triple line)
; EM_SETPARAFORMAT = 0x0447, PFM_BORDER = 0x800
If !IsObject(Widths)
Return False
W := S := 0
For I, V In Widths {
If (V)
W |= V << ((A_Index - 1) * 4)
If Styles[I]
S |= Styles[I] << ((A_Index - 1) * 4)
}
PF2 := New This.PF2
PF2.Mask := 0x800
PF2.BorderWidth := W
PF2.Borders := S
ErrorLevel := SendMessage(0x0447, 0, PF2.PF2, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
SetLineSpacing(Lines) { ; Sets paragraph's line spacing.
; Lines : number of lines as integer or float.
; SpacingRule = 5:
; The value of dyLineSpacing / 20 is the spacing, in lines, from one line to the next. Thus, setting
; dyLineSpacing to 20 produces single-spaced text, 40 is double spaced, 60 is triple spaced, and so on.
; EM_SETPARAFORMAT = 0x0447, PFM_LINESPACING = 0x100
PF2 := New This.PF2
PF2.Mask := 0x100
PF2.LineSpacing := Abs(Lines) * 20
PF2.LineSpacingRule := 5
ErrorLevel := SendMessage(0x0447, 0, PF2.PF2, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
SetParaIndent(Indent := "Reset") { ; Sets space left/right of the paragraph.
; Indent : Object containing up to three keys:
; - Start : Optional - Absolute indentation of the paragraph's first line.
; - Right : Optional - Indentation of the right side of the paragraph, relative to the right margin.
; - Offset : Optional - Indentation of the second and subsequent lines, relative to the indentation
; of the first line.
; Values are interpreted as centimeters/inches depending on the user's locale measurement settings.
; Call without passing a parameter to reset indentation.
; EM_SETPARAFORMAT = 0x0447
; PFM_STARTINDENT = 0x0001
; PFM_RIGHTINDENT = 0x0002
; PFM_OFFSET = 0x0004
Static PFM := {STARTINDENT: 0x01, RIGHTINDENT: 0x02, OFFSET: 0x04}
Measurement := This.GetMeasurement()
PF2 := New This.PF2
If (Indent = "Reset")
PF2.Mask := 0x07 ; reset indentation
Else If !IsObject(Indent)
Return False
Else {
PF2.Mask := 0
If (Indent.HasKey("Start")) {
PF2.Mask |= PFM.STARTINDENT
PF2.StartIndent := Round((Indent.Start / Measurement) * 1440)
}
If (Indent.HasKey("Offset")) {
PF2.Mask |= PFM.OFFSET
PF2.Offset := Round((Indent.Offset / Measurement) * 1440)
}
If (Indent.HasKey("Right")) {
PF2.Mask |= PFM.RIGHTINDENT
PF2.RightIndent := Round((Indent.Right / Measurement) * 1440)
}
}
If (PF2.Mask) {
ErrorLevel := SendMessage(0x0447, 0, PF2.PF2, , "ahk_id " . This.HWND)
Return ErrorLevel
}
Return False
}
; -------------------------------------------------------------------------------------------------------------------
SetParaNumbering(Numbering := "Reset") {
; Numbering : Object containing up to four keys:
; - Type : Options used for bulleted or numbered paragraphs.
; - Style : Optional - Numbering style used with numbered paragraphs.
; - Tab : Optional - Minimum space between a paragraph number and the paragraph text.
; - Start : Optional - Sequence number used for numbered paragraphs (e.g. 3 for C or III)
; Tab is interpreted as centimeters/inches depending on the user's locale measurement settings.
; Call without passing a parameter to reset numbering.
; EM_SETPARAFORMAT = 0x0447
; PARAFORMAT numbering options
; PFN_BULLET 1 ; tomListBullet
; PFN_ARABIC 2 ; tomListNumberAsArabic: 0, 1, 2, ...
; PFN_LCLETTER 3 ; tomListNumberAsLCLetter: a, b, c, ...
; PFN_UCLETTER 4 ; tomListNumberAsUCLetter: A, B, C, ...
; PFN_LCROMAN 5 ; tomListNumberAsLCRoman: i, ii, iii, ...
; PFN_UCROMAN 6 ; tomListNumberAsUCRoman: I, II, III, ...
; PARAFORMAT2 wNumberingStyle options
; PFNS_PAREN 0x0000 ; default, e.g., 1)
; PFNS_PARENS 0x0100 ; tomListParentheses/256, e.g., (1)
; PFNS_PERIOD 0x0200 ; tomListPeriod/256, e.g., 1.
; PFNS_PLAIN 0x0300 ; tomListPlain/256, e.g., 1
; PFNS_NONUMBER 0x0400 ; used for continuation w/o number
; PFNS_NEWNUMBER 0x8000 ; start new number with wNumberingStart
; PFM_NUMBERING 0x0020
; PFM_NUMBERINGSTYLE 0x2000
; PFM_NUMBERINGTAB 0x4000
; PFM_NUMBERINGSTART 0x8000
Static PFM := {Type: 0x0020, Style: 0x2000, Tab: 0x4000, Start: 0x8000}
Static PFN := {Bullet: 1, Arabic: 2, LCLetter: 3, UCLetter: 4, LCRoman: 5, UCRoman: 6}
Static PFNS := {Paren: 0x0000, Parens: 0x0100, Period: 0x0200, Plain: 0x0300, None: 0x0400, New: 0x8000}
PF2 := New This.PF2
If (Numbering = "Reset")
PF2.Mask := 0xE020
Else If !IsObject(Numbering)
Return False
Else {
If (Numbering.HasKey("Type")) {
PF2.Mask |= PFM.Type
PF2.Numbering := PFN[Numbering.Type]
}
If (Numbering.HasKey("Style")) {
PF2.Mask |= PFM.Style
PF2.NumberingStyle := PFNS[Numbering.Style]
}
If (Numbering.HasKey("Tab")) {
PF2.Mask |= PFM.Tab
PF2.NumberingTab := Round((Numbering.Tab / This.GetMeasurement()) * 1440)
}
If (Numbering.HasKey("Start")) {
PF2.Mask |= PFM.Start
PF2.NumberingStart := Numbering.Start
}
}
If (PF2.Mask) {
ErrorLevel := SendMessage(0x0447, 0, PF2.PF2, , "ahk_id " . This.HWND)
Return ErrorLevel
}
Return False
}
; -------------------------------------------------------------------------------------------------------------------
SetParaSpacing(Spacing := "Reset") { ; Set space before / after the paragraph
; Spacing : Object containing one or two keys:
; - Before : additional space before the paragraph in points
; - After : additional space after the paragraph in points
; Call without passing a parameter to reset spacing to zero.
; EM_SETPARAFORMAT = 0x0447
; PFM_SPACEBEFORE = 0x0040
; PFM_SPACEAFTER = 0x0080
Static PFM := {Before: 0x40, After: 0x80}
PF2 := New This.PF2
If (Spacing = "Reset")
PF2.Mask := 0xC0 ; reset spacing
Else If !IsObject(Spacing)
Return False
Else {
If (Spacing.Before >= 0) {
PF2.Mask |= PFM.Before
PF2.SpaceBefore := Round(Spacing.Before * 20)
}
If (Spacing.After >= 0) {
PF2.Mask |= PFM.After
PF2.SpaceAfter := Round(Spacing.After * 20)
}
}
If (PF2.Mask) {
ErrorLevel := SendMessage(0x0447, 0, PF2.PF2, , "ahk_id " . This.HWND)
Return ErrorLevel
}
Return False
}
; -------------------------------------------------------------------------------------------------------------------
SetDefaultTabs(Distance) { ; Set default tabstops
; Distance will be interpreted as inches or centimeters depending on the current user's locale.
; EM_SETTABSTOPS = 0xCB
Static DUI := 64 ; dialog units per inch
, MinTab := 0.20 ; minimal tab distance
, MaxTab := 3.00 ; maximal tab distance
IM := This.GetMeasurement()
Distance := StrReplace(Distance, "," , ".")
Distance := Round(Distance / IM, 2)
If (Distance < MinTab)
Distance := MinTab
If (Distance > MaxTab)
Distance := MaxTab
;Old VarSetCapacity(TabStops, 4, 0)
TabStops := Buffer(4, 0) ;Changed
NumPut(Round(DUI * Distance), TabStops, "Int")
ErrorLevel := SendMessage(0xCB, 1, &TabStops, , "ahk_id " . This.HWND)
Result := ErrorLevel
DllCall("User32.dll\UpdateWindow", "Ptr", This.HWND)
Return Result
}
; -------------------------------------------------------------------------------------------------------------------
SetTabStops(TabStops := "Reset") { ; Set paragraph's tabstobs
; TabStops is an object containing the integer position as hundredth of inches/centimeters as keys
; and the alignment ("L", "C", "R", or "D") as values.
; The position will be interpreted as hundredth of inches or centimeters depending on the current user's locale.
; Call without passing a parameter to reset to default tabs.
; EM_SETPARAFORMAT = 0x0447, PFM_TABSTOPS = 0x10
Static MinT := 30 ; minimal tabstop in hundredth of inches
Static MaxT := 830 ; maximal tabstop in hundredth of inches
Static Align := {L: 0x00000000 ; left aligned (default)
, C: 0x01000000 ; centered
, R: 0x02000000 ; right aligned
, D: 0x03000000} ; decimal tabstop
Static MAX_TAB_STOPS := 32
IC := This.GetMeasurement()
PF2 := New This.PF2
PF2.Mask := 0x10
If (TabStops = "Reset") {
ErrorLevel := SendMessage(0x0447, 0, PF2.PF2, , "ahk_id " . This.HWND)
Return !!(ErrorLevel)
}
If !IsObject(TabStops)
Return False
TabCount := 0
Tabs := []
For Position, Alignment In TabStops {
Position /= IC
If (Position < MinT) Or (Position > MaxT)
Or !Align.HasKey(Alignment) Or (A_Index > MAX_TAB_STOPS)
Return False
Tabs[A_Index] := (Align[Alignment] | Round((Position / 100) * 1440))
TabCount := A_Index
}
If (TabCount) {
PF2.TabCount := TabCount
PF2.Tabs := Tabs
ErrorLevel := SendMessage(0x0447, 0, PF2.PF2, , "ahk_id " . This.HWND)
Return ErrorLevel
}
Return False
}
; -------------------------------------------------------------------------------------------------------------------
; Line handling
; -------------------------------------------------------------------------------------------------------------------
GetLineCount() { ; Get the total number of lines
; EM_GETLINECOUNT = 0xBA
ErrorLevel := SendMessage(0xBA, 0, 0, , "ahk_id " . This.HWND)
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
GetCaretLine() { ; Get the line containing the caret
; EM_LINEINDEX = 0xBB, EM_EXLINEFROMCHAR = 0x0436
r := SendMessage(0xBB, -1, 0, , "ahk_id " . This.HWND)
r := SendMessage(0x0436, 0, r, , "ahk_id " . This.HWND)
Return r + 1
}
; -------------------------------------------------------------------------------------------------------------------
; Statistics
; -------------------------------------------------------------------------------------------------------------------
GetStatistics() { ; Get some statistic values
; Get the line containing the caret, it's position in this line, the total amount of lines, the absolute caret
; position and the total amount of characters.
; EM_GETSEL = 0xB0, EM_LINEFROMCHAR = 0xC9, EM_LINEINDEX = 0xBB, EM_GETLINECOUNT = 0xBA
Stats := {}
;Old VarSetCapacity(GTL, 8, 0) ; GETTEXTLENGTHEX structure
GTL := Buffer(8, 0) ; GETTEXTLENGTHEX structure ;Changed
SB := 0
SendMessage(0xB0, &SB, 0, , "ahk_id " . This.HWND)
SB := NumGet(SB, 0, "UInt") + 1
r := SendMessage(0xBB, -1, 0, , "ahk_id " . This.HWND)
Stats.LinePos := SB - r
r := SendMessage(0xC9, -1, 0, , "ahk_id " . This.HWND)
Stats.Line := r + 1
r := SendMessage(0xBA, 0, 0, , "ahk_id " . This.HWND)
Stats.LineCount := r
Stats.CharCount := This.GetTextLen()
Return Stats
}
; -------------------------------------------------------------------------------------------------------------------
; Layout
; -------------------------------------------------------------------------------------------------------------------
WordWrap(On) { ; Turn wordwrapping on/off
; EM_SCROLLCARET = 0xB7, EM_SETTARGETDEVICE = 0x0448
Sel := This.GetSel()
SendMessage(0x0448, 0, (On ? 0 : -1), , "ahk_id " . This.HWND)
This.SetSel(Sel.S, Sel.E)
SendMessage(0xB7, 0, 0, "ahk_id " . This.HWND)
Return On
}
; -------------------------------------------------------------------------------------------------------------------
;~ WYSIWYG(On) { ; Show control as printed (WYSIWYG)
;~ ; Text measuring is based on the default printer's capacities, thus changing the printer may produce different
;~ ; results. See remarks/comments in Print() also.
;~ ; EM_SCROLLCARET = 0xB7, EM_SETTARGETDEVICE = 0x0448
;~ ; PD_RETURNDC = 0x0100, PD_RETURNDEFAULT = 0x0400
;~ Static PDC := 0
;~ Static PD_Size := (A_PtrSize = 4 ? 66 : 120)
;~ Static OffFlags := A_PtrSize * 5
;~ Sel := This.GetSel()
;~ If !(On) {
;~ DllCall("User32.dll\LockWindowUpdate", "Ptr", This.HWND)
;~ DllCall("Gdi32.dll\DeleteDC", "Ptr", PDC)
;~ SendMessage(0x0448, 0, -1, , "ahk_id " . This.HWND)
;~ This.SetSel(Sel.S, Sel.E)
;~ SendMessage(0xB7, 0, 0, "ahk_id " . This.HWND)
;~ DllCall("User32.dll\LockWindowUpdate", "Ptr", 0)
;~ Return ErrorLevel
;~ }
;~ Numput(VarSetCapacity(PD, PD_Size, 0), PD)
;~ NumPut(0x0100 | 0x0400, PD, A_PtrSize * 5, "UInt") ; PD_RETURNDC | PD_RETURNDEFAULT
;~ If !DllCall("Comdlg32.dll\PrintDlg", "Ptr", &PD, "Int")
;~ Return
;~ DllCall("Kernel32.dll\GlobalFree", "Ptr", NumGet(PD, A_PtrSize * 2, "UPtr"))
;~ DllCall("Kernel32.dll\GlobalFree", "Ptr", NumGet(PD, A_PtrSize * 3, "UPtr"))
;~ PDC := NumGet(PD, A_PtrSize * 4, "UPtr")
;~ DllCall("User32.dll\LockWindowUpdate", "Ptr", This.HWND)
;~ Caps := This.GetPrinterCaps(PDC)
;~ ; Set up page size and margins in pixel
;~ UML := This.Margins.LT ; user margin left
;~ UMR := This.Margins.RT ; user margin right
;~ PML := Caps.POFX ; physical margin left
;~ PMR := Caps.PHYW - Caps.HRES - Caps.POFX ; physical margin right
;~ LPW := Caps.HRES ; logical page width
;~ ; Adjust margins
;~ UML := UML > PML ? (UML - PML) : 0
;~ UMR := UMR > PMR ? (UMR - PMR) : 0
;~ LineLen := LPW - UML - UMR
;~ SendMessage(0x0448, PDC, LineLen, , "ahk_id " . This.HWND)
;~ This.SetSel(Sel.S, Sel.E)
;~ SendMessage(0xB7, 0, 0, "ahk_id " . This.HWND)
;~ DllCall("User32.dll\LockWindowUpdate", "Ptr", 0)
;~ Return ErrorLevel
;~ }
; -------------------------------------------------------------------------------------------------------------------
; File handling
; -------------------------------------------------------------------------------------------------------------------
;~ LoadFile(File, Mode := "Open") { ; Load file
;~ ; File : file name
;~ ; Mode : Open / Add / Insert
;~ ; Open : Replace control's content
;~ ; Append : Append to conrol's content
;~ ; Insert : Insert at / replace current selection
;~ If !FileExist(File)
;~ Return False
;~ SplitPath(File, , , Ext)
;~ If (Ext = "rtf") {
;~ If (Mode = "Open") {
;~ Selection := False
;~ } Else If (Mode = "Insert") {
;~ Selection := True
;~ } Else If (Mode = "Append") {
;~ This.SetSel(-1, -2)
;~ Selection := True
;~ }
;~ This.LoadRTF(File, Selection)
;~ } Else {
;~ Text := FileRead(File)
;~ If (Mode = "Open") {
;~ This.SetText(Text)
;~ } Else If (Mode = "Insert") {
;~ This.ReplaceSel(Text)
;~ } Else If (Mode = "Append") {
;~ This.SetSel(-1, -2)
;~ This.ReplaceSel(Text)
;~ }
;~ }
;~ Return True
;~ }
; -------------------------------------------------------------------------------------------------------------------
;~ SaveFile(File) { ; Save file
;~ ; File : file name
;~ ; Returns True on success, otherwise False.
;~ this.Gui.opt("+OwnDialogs")
;~ SplitPath(File, , , Ext)
;~ Text := Ext = "rtf" ? This.GetRTF() : This.GetText()
;~ If IsObject(FileObj := FileOpen(File, "w")) {
;~ FileObj.Write(Text)
;~ FileObj.Close()
;~ Return True
;~ }
;~ Return False
;~ }
; -------------------------------------------------------------------------------------------------------------------
; Printing
; THX jballi -> http://www.autohotkey.com/board/topic/45513-function-he-print-wysiwyg-print-for-the-hiedit-control/
; -------------------------------------------------------------------------------------------------------------------
;~ Print() {
;~ ; ----------------------------------------------------------------------------------------------------------------
;~ ; Static variables
;~ Static PD_ALLPAGES := 0x00, PD_SELECTION := 0x01, PD_PAGENUMS := 0x02, PD_NOSELECTION := 0x04
;~ , PD_RETURNDC := 0x0100, PD_USEDEVMODECOPIES := 0x040000, PD_HIDEPRINTTOFILE := 0x100000
;~ , PD_NONETWORKBUTTON := 0x200000, PD_NOCURRENTPAGE := 0x800000
;~ , MM_TEXT := 0x1
;~ , EM_FORMATRANGE := 0x0439, EM_SETTARGETDEVICE := 0x0448
;~ , DocName := "AHKRichEdit"
;~ , PD_Size := (A_PtrSize = 8 ? (13 * A_PtrSize) + 16 : 66)
;~ ErrorMsg := ""
;~ ; ----------------------------------------------------------------------------------------------------------------
;~ ; Prepare to call PrintDlg
;~ ; Define/Populate the PRINTDLG structure
;~ VarSetCapacity(PD, PD_Size, 0)
;~ Numput(PD_Size, PD, 0, "UInt") ; lStructSize
;~ Numput(This.Gui.hwnd, PD, A_PtrSize, "UPtr") ; hwndOwner
;~ ; Collect Start/End select positions
;~ Sel := This.GetSel()
;~ ; Determine/Set Flags
;~ Flags := PD_ALLPAGES | PD_RETURNDC | PD_USEDEVMODECOPIES | PD_HIDEPRINTTOFILE | PD_NONETWORKBUTTON
;~ | PD_NOCURRENTPAGE
;~ If (Sel.S = Sel.E)
;~ Flags |= PD_NOSELECTION
;~ Else
;~ Flags |= PD_SELECTION
;~ Offset := A_PtrSize * 5
;~ NumPut(Flags, PD, Offset, "UInt") ; Flags
;~ ; Page and copies
;~ NumPut( 1, PD, Offset += 4, "UShort") ; nFromPage
;~ NumPut( 1, PD, Offset += 2, "UShort") ; nToPage
;~ NumPut( 1, PD, Offset += 2, "UShort") ; nMinPage
;~ NumPut(-1, PD, Offset += 2, "UShort") ; nMaxPage
;~ NumPut( 1, PD, Offset += 2, "UShort") ; nCopies
;~ ; Note: Use -1 to specify the maximum page number (65535).
;~ ; Programming note: The values that are loaded to these fields are critical. The Print dialog will not
;~ ; display (returns an error) if unexpected values are loaded to one or more of these fields.
;~ ; ----------------------------------------------------------------------------------------------------------------
;~ ; Print dialog box
;~ ; Open the Print dialog. Bounce If the user cancels.
;~ If !DllCall("Comdlg32.dll\PrintDlg", "Ptr", &PD, "UInt") {
;~ ErrorLevel := "Function: " . A_ThisFunc . " - DLLCall of 'PrintDlg' failed."
;~ Return False
;~ }
;~ ; Get the printer device context. Bounce If not defined.
;~ If !(PDC := NumGet(PD, A_PtrSize * 4, "UPtr")) { ; hDC
;~ ErrorLevel := "Function: " . A_ThisFunc . " - Couldn't get a printer's device context."
;~ Return False
;~ }
;~ ; Free global structures created by PrintDlg
;~ DllCall("Kernel32.dll\GlobalFree", "Ptr", NumGet(PD, A_PtrSize * 2, "UPtr"))
;~ DllCall("Kernel32.dll\GlobalFree", "Ptr", NumGet(PD, A_PtrSize * 3, "UPtr"))
;~ ; ----------------------------------------------------------------------------------------------------------------
;~ ; Prepare to print
;~ ; Collect Flags
;~ Offset := A_PtrSize * 5
;~ Flags := NumGet(PD, OffSet, "UInt") ; Flags
;~ ; Determine From/To Page
;~ If (Flags & PD_PAGENUMS) {
;~ PageF := NumGet(PD, Offset += 4, "UShort") ; nFromPage (first page)
;~ PageL := NumGet(PD, Offset += 2, "UShort") ; nToPage (last page)
;~ } Else {
;~ PageF := 1
;~ PageL := 65535
;~ }
;~ ; Collect printer capacities
;~ Caps := This.GetPrinterCaps(PDC)
;~ ; Set up page size and margins in Twips (1/20 point or 1/1440 of an inch)
;~ UML := This.Margins.LT ; user margin left
;~ UMT := This.Margins.TT ; user margin top
;~ UMR := This.Margins.RT ; user margin right
;~ UMB := This.Margins.BT ; user margin bottom
;~ PML := Caps.POFX ; physical margin left
;~ PMT := Caps.POFY ; physical margin top
;~ PMR := Caps.PHYW - Caps.HRES - Caps.POFX ; physical margin right
;~ PMB := Caps.PHYH - Caps.VRES - Caps.POFY ; physical margin bottom
;~ LPW := Caps.HRES ; logical page width
;~ LPH := Caps.VRES ; logical page height
;~ ; Adjust margins
;~ UML := UML > PML ? (UML - PML) : 0
;~ UMT := UMT > PMT ? (UMT - PMT) : 0
;~ UMR := UMR > PMR ? (UMR - PMR) : 0
;~ UMB := UMB > PMB ? (UMB - PMB) : 0
;~ ; Define/Populate the FORMATRANGE structure
;~ VarSetCapacity(FR, (A_PtrSize * 2) + (4 * 10), 0)
;~ NumPut(PDC, FR, 0, "UPtr") ; hdc
;~ NumPut(PDC, FR, A_PtrSize, "UPtr") ; hdcTarget
;~ ; Define FORMATRANGE.rc
;~ ; rc is the area to render to (rcPage - margins), measured in twips (1/20 point or 1/1440 of an inch).
;~ ; If the user-defined margins are smaller than the printer's margins (the unprintable areas at the edges of each
;~ ; page), the user margins are set to the printer's margins. In addition, the user-defined margins must be adjusted
;~ ; to account for the printer's margins.
;~ ; For example: If the user requests a 3/4 inch (19.05 mm) left margin but the printer's left margin is 1/4 inch
;~ ; (6.35 mm), rc.Left is set to 720 twips (1/2 inch or 12.7 mm).
;~ Offset := A_PtrSize * 2
;~ NumPut(UML, FR, Offset += 0, "Int") ; rc.Left
;~ NumPut(UMT, FR, Offset += 4, "Int") ; rc.Top
;~ NumPut(LPW - UMR, FR, Offset += 4, "Int") ; rc.Right
;~ NumPut(LPH - UMB, FR, Offset += 4, "Int") ; rc.Bottom
;~ ; Define FORMATRANGE.rcPage
;~ ; rcPage is the entire area of a page on the rendering device, measured in twips (1/20 point or 1/1440 of an inch)
;~ ; Note: rc defines the maximum printable area which does not include the printer's margins (the unprintable areas
;~ ; at the edges of the page). The unprintable areas are represented by PHYSICALOFFSETX and PHYSICALOFFSETY.
;~ NumPut(0, FR, Offset += 4, "Int") ; rcPage.Left
;~ NumPut(0, FR, Offset += 4, "Int") ; rcPage.Top
;~ NumPut(LPW, FR, Offset += 4, "Int") ; rcPage.Right
;~ NumPut(LPH, FR, Offset += 4, "Int") ; rcPage.Bottom
;~ ; Determine print range.
;~ ; If "Selection" option is chosen, use selected text, otherwise use the entire document.
;~ If (Flags & PD_SELECTION) {
;~ PrintS := Sel.S
;~ PrintE := Sel.E
;~ } Else {
;~ PrintS := 0
;~ PrintE := -1 ; (-1 = Select All)
;~ }
;~ Numput(PrintS, FR, Offset += 4, "Int") ; cr.cpMin
;~ NumPut(PrintE, FR, Offset += 4, "Int") ; cr.cpMax
;~ ; Define/Populate the DOCINFO structure
;~ VarSetCapacity(DI, A_PtrSize * 5, 0)
;~ NumPut(A_PtrSize * 5, DI, 0, "UInt")
;~ NumPut(&DocName, DI, A_PtrSize, "UPtr") ; lpszDocName
;~ NumPut(0 , DI, A_PtrSize * 2, "UPtr") ; lpszOutput
;~ ; Programming note: All other DOCINFO fields intentionally left as null.
;~ ; Determine MaxPrintIndex
;~ If (Flags & PD_SELECTION) {
;~ PrintM := Sel.E
;~ } Else {
;~ PrintM := This.GetTextLen()
;~ }
;~ ; Be sure that the printer device context is in text mode
;~ DllCall("Gdi32.dll\SetMapMode", "Ptr", PDC, "Int", MM_TEXT)
;~ ; ----------------------------------------------------------------------------------------------------------------
;~ ; Print it!
;~ ; Start a print job. Bounce If there is a problem.
;~ PrintJob := DllCall("Gdi32.dll\StartDoc", "Ptr", PDC, "Ptr", &DI, "Int")
;~ If (PrintJob <= 0) {
;~ ErrorLevel := "Function: " . A_ThisFunc . " - DLLCall of 'StartDoc' failed."
;~ Return False
;~ }
;~ ; Print page loop
;~ PageC := 0 ; current page
;~ PrintC := 0 ; current print index
;~ While (PrintC < PrintM) {
;~ PageC++
;~ ; Are we done yet?
;~ If (PageC > PageL)
;~ Break
;~ If (PageC >= PageF) && (PageC <= PageL) {
;~ ; StartPage function. Break If there is a problem.
;~ If (DllCall("Gdi32.dll\StartPage", "Ptr", PDC, "Int") <= 0) {
;~ ErrorMsg := "Function: " . A_ThisFunc . " - DLLCall of 'StartPage' failed."
;~ Break
;~ }
;~ }
;~ ; Format or measure page
;~ If (PageC >= PageF) && (PageC <= PageL)
;~ Render := True
;~ Else
;~ Render := False
;~ SendMessage(EM_FORMATRANGE, Render, &FR, , "ahk_id " . This.HWND)
;~ PrintC := ErrorLevel
;~ If (PageC >= PageF) && (PageC <= PageL) {
;~ ; EndPage function. Break If there is a problem.
;~ If (DllCall("Gdi32.dll\EndPage", "Ptr", PDC, "Int") <= 0) {
;~ ErrorMsg := "Function: " . A_ThisFunc . " - DLLCall of 'EndPage' failed."
;~ Break
;~ }
;~ }
;~ ; Update FR for the next page
;~ Offset := (A_PtrSize * 2) + (4 * 8)
;~ Numput(PrintC, FR, Offset += 0, "Int") ; cr.cpMin
;~ NumPut(PrintE, FR, Offset += 4, "Int") ; cr.cpMax
;~ }
;~ ; ----------------------------------------------------------------------------------------------------------------
;~ ; End the print job
;~ DllCall("Gdi32.dll\EndDoc", "Ptr", PDC)
;~ ; Delete the printer device context
;~ DllCall("Gdi32.dll\DeleteDC", "Ptr", PDC)
;~ ; Reset control (free cached information)
;~ SendMessage %EM_FORMATRANGE%, 0, 0, , "ahk_id " . This.HWND
;~ ; Return to sender
;~ If (ErrorMsg) {
;~ ErrorLevel := ErrorMsg
;~ Return False
;~ }
;~ Return True
;~ }
; -------------------------------------------------------------------------------------------------------------------
;~ GetMargins() { ; Get the default print margins
;~ Static PSD_RETURNDEFAULT := 0x00000400, PSD_INTHOUSANDTHSOFINCHES := 0x00000004
;~ , I := 1000 ; thousandth of inches
;~ , M := 2540 ; hundredth of millimeters
;~ , PSD_Size := (4 * 10) + (A_PtrSize * 11)
;~ , PD_Size := (A_PtrSize = 8 ? (13 * A_PtrSize) + 16 : 66)
;~ , OffFlags := 4 * A_PtrSize
;~ , OffMargins := OffFlags + (4 * 7)
;~ If !This.HasKey("Margins") {
;~ VarSetCapacity(PSD, PSD_Size, 0) ; PAGESETUPDLG structure
;~ NumPut(PSD_Size, PSD, 0, "UInt")
;~ NumPut(PSD_RETURNDEFAULT, PSD, OffFlags, "UInt")
;~ If !DllCall("Comdlg32.dll\PageSetupDlg", "Ptr", &PSD, "UInt")
;~ Return false
;~ DllCall("Kernel32.dll\GlobalFree", UInt, NumGet(PSD, 2 * A_PtrSize, "UPtr"))
;~ DllCall("Kernel32.dll\GlobalFree", UInt, NumGet(PSD, 3 * A_PtrSize, "UPtr"))
;~ Flags := NumGet(PSD, OffFlags, "UInt")
;~ Metrics := (Flags & PSD_INTHOUSANDTHSOFINCHES) ? I : M
;~ Offset := OffMargins
;~ This.Margins := {}
;~ This.Margins.L := NumGet(PSD, Offset += 0, "Int") ; Left
;~ This.Margins.T := NumGet(PSD, Offset += 4, "Int") ; Top
;~ This.Margins.R := NumGet(PSD, Offset += 4, "Int") ; Right
;~ This.Margins.B := NumGet(PSD, Offset += 4, "Int") ; Bottom
;~ This.Margins.LT := Round((This.Margins.L / Metrics) * 1440) ; Left in twips
;~ This.Margins.TT := Round((This.Margins.T / Metrics) * 1440) ; Top in twips
;~ This.Margins.RT := Round((This.Margins.R / Metrics) * 1440) ; Right in twips
;~ This.Margins.BT := Round((This.Margins.B / Metrics) * 1440) ; Bottom in twips
;~ }
;~ Return True
;~ }
; -------------------------------------------------------------------------------------------------------------------
;~ GetPrinterCaps(DC) { ; Get printer's capacities
;~ Static HORZRES := 0x08, VERTRES := 0x0A
;~ , LOGPIXELSX := 0x58, LOGPIXELSY := 0x5A
;~ , PHYSICALWIDTH := 0x6E, PHYSICALHEIGHT := 0x6F
;~ , PHYSICALOFFSETX := 0x70, PHYSICALOFFSETY := 0x71
;~ , Caps := {}
;~ ; Number of pixels per logical inch along the page width and height
;~ LPXX := DllCall("Gdi32.dll\GetDeviceCaps", "Ptr", DC, "Int", LOGPIXELSX, "Int")
;~ LPXY := DllCall("Gdi32.dll\GetDeviceCaps", "Ptr", DC, "Int", LOGPIXELSY, "Int")
;~ ; The width and height of the physical page, in twips.
;~ Caps.PHYW := Round((DllCall("Gdi32.dll\GetDeviceCaps", "Ptr", DC, "Int", PHYSICALWIDTH, "Int") / LPXX) * 1440)
;~ Caps.PHYH := Round((DllCall("Gdi32.dll\GetDeviceCaps", "Ptr", DC, "Int", PHYSICALHEIGHT, "Int") / LPXY) * 1440)
;~ ; The distance from the left/right edge (PHYSICALOFFSETX) and the top/bottom edge (PHYSICALOFFSETY) of the
;~ ; physical page to the edge of the printable area, in twips.
;~ Caps.POFX := Round((DllCall("Gdi32.dll\GetDeviceCaps", "Ptr", DC, "Int", PHYSICALOFFSETX, "Int") / LPXX) * 1440)
;~ Caps.POFY := Round((DllCall("Gdi32.dll\GetDeviceCaps", "Ptr", DC, "Int", PHYSICALOFFSETY, "Int") / LPXY) * 1440)
;~ ; Width and height of the printable area of the page, in twips.
;~ Caps.HRES := Round((DllCall("Gdi32.dll\GetDeviceCaps", "Ptr", DC, "Int", HORZRES, "Int") / LPXX) * 1440)
;~ Caps.VRES := Round((DllCall("Gdi32.dll\GetDeviceCaps", "Ptr", DC, "Int", VERTRES, "Int") / LPXY) * 1440)
;~ Return Caps
;~ }
}
;*****************For Ole Callback
;~ RE_GetDocObj(HRE) {
;~ ; Get the document object of the specified RichEdit control
;~ Static IID_ITextDocument := "{8CC497C0-A1DF-11CE-8098-00AA0047BE5D}"
;~ DocObj := 0
;~ If DllCall("SendMessage", "Ptr", HRE, "UInt", 0x043C, "Ptr", 0, "PtrP", IRichEditOle, "UInt") { ; EM_GETOLEINTERFACE
;~ DocObj := ComObject(9, ComObjQuery(IRichEditOle, IID_ITextDocument), 1) ; ITextDocument
;~ ObjRelease(IRichEditOle)
;~ }
;~ Return DocObj
;~ }