Page 1 of 1

Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI

Posted: 30 May 2017, 16:29
by jeeswg
[EDIT:] Click here to jump to updated version below:
Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 20#p173620

==================================================

Do notify of any errors, and do discuss if these functions might be useful to you, or what related/similar functions might be useful to you for using Unicode in AHK Basic / AHK ANSI. Cheers.

[Note: there are a few functions I will return to soon, listed at the bottom, but I thought it better to post what I have now.]

Code: Select all

;'AutoHotkey Basic Unicode'
;Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI
;Unicode functions for AHK v1.0 / v1.1 ANSI by jeeswg

;==================================================

JEE_AhkBasicWinGetTitleUtf8(hWnd)
{
	vDHW := A_DetectHiddenWindows
	DetectHiddenWindows, On
	vChars := DllCall("GetWindowTextLengthW", Int,hWnd)+1
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("GetWindowTextW", Int,hWnd, Int,&vTextUtf16, Int,vChars)
	vSize := DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16, Int,vChars, Int,0, Int,0, Int,0, Int,0)
	VarSetCapacity(vWinTitle, vSize, 0)
	DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16, Int,vChars, Str,vWinTitle, Int,vSize, Int,0, Int,0)
	DetectHiddenWindows, % vDHW
	return vWinTitle
}

;==================================================

JEE_AhkBasicClipboardGetTextUtf8()
{
	Transform, vText, Unicode
	return vText
}

;==================================================

;alternative method (that does not retrieve file paths, see JEE_AhkBasicClipboardGetPathsUtf8 instead)
JEE_AhkBasicClipboardGetTextUtf8Alt()
{
	;CF_LOCALE := 0x10 ;CF_UNICODETEXT := 0xD
	;CF_OEMTEXT := 0x7 ;CF_TEXT := 0x1
	if !DllCall("IsClipboardFormatAvailable", UInt,0xD)
		if DllCall("IsClipboardFormatAvailable", UInt,0x1)
			return Clipboard
		else
			return ""
	if !DllCall("OpenClipboard", Int,0)
		return ""
	if !hBuf := DllCall("GetClipboardData", UInt,0xD)
	{
		DllCall("CloseClipboard")
		return ""
	}

	pBuf := DllCall("GlobalLock", Int,hBuf, Int)
	vSize := DllCall("GlobalSize", Int,hBuf)
	VarSetCapacity(vOutputUtf16, vSize, 0)
	DllCall("kernel32\RtlMoveMemory", Int,&vOutputUtf16, Int,pBuf, UInt,vSize)

	vChars := vSize/2
	vSize := DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vOutputUtf16, Int,vChars, Int,0, Int,0, Int,0, Int,0)
	VarSetCapacity(vOutput, vSize, 0)
	DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vOutputUtf16, Int,vChars, Str,vOutput, Int,vSize, Int,0, Int,0)

	DllCall("GlobalUnlock", Int,hBuf)
	DllCall("CloseClipboard")
	return vOutput
}

;==================================================

JEE_AhkBasicClipboardGetPathsUtf8(vSep="`n")
{
	;CF_HDROP := 0xF
	if !DllCall("IsClipboardFormatAvailable", UInt,0xF)
		return ""
	if !DllCall("OpenClipboard", Int,0)
		return ""
	if !hDrop := DllCall("GetClipboardData", UInt,0xF)
	{
		DllCall("CloseClipboard")
		return ""
	}

	;==============================
	;based on JEE_DropGetPaths:
	vOutput := ""
	vCount := DllCall("shell32\DragQueryFileW", Int,hDrop, UInt,-1, Int,0, UInt,0, UInt)
	Loop, % vCount
	{
		vChars := DllCall("shell32\DragQueryFileW", Int,hDrop, UInt,A_Index-1, Int,0, UInt,0, UInt) + 1
		VarSetCapacity(vPathUtf16, vChars*2, 0)
		DllCall("shell32\DragQueryFileW", Int,hDrop, UInt,A_Index-1, Int,&vPathUtf16, UInt,vChars, UInt)

		vSize := DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vPathUtf16, Int,vChars, Int,0, Int,0, Int,0, Int,0)
		VarSetCapacity(vPath, vSize, 0)
		DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vPathUtf16, Int,vChars, Str,vPath, Int,vSize, Int,0, Int,0)
		vOutput .= vPath vSep
	}
	DllCall("shell32\DragFinish", Int,hDrop)
	;==============================

	DllCall("CloseClipboard")
	return SubStr(vOutput, 1, -StrLen(vSep))
}

;==================================================

JEE_AhkBasicClipboardSetTextUtf8(vText)
{
	Transform, Clipboard, Unicode, % vText
}

;==================================================

;alternative method
JEE_AhkBasicClipboardSetTextUtf8Alt(vText)
{
	;GMEM_ZEROINIT := 0x40, GMEM_MOVEABLE := 0x2
	hBuf := DllCall("GlobalAlloc", UInt,0x42, UInt,(StrLen(vText)+2)*2, Int)
	pBuf := DllCall("GlobalLock", Int,hBuf, Int)

	vChars := DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,&vTextUtf16, Int,vChars*2)
	DllCall("kernel32\RtlMoveMemory", Int,pBuf, Int,&vTextUtf16, UInt,vChars*2)

	;CF_LOCALE := 0x10 ;CF_UNICODETEXT := 0xD
	;CF_OEMTEXT := 0x7 ;CF_TEXT := 0x1
	hWnd := A_ScriptHwnd ? A_ScriptHwnd : WinExist("ahk_pid " DllCall("GetCurrentProcessId", UInt))
	DllCall("GlobalUnlock", Int,hBuf)
	DllCall("OpenClipboard", Int,hWnd)
	DllCall("EmptyClipboard")
	DllCall("SetClipboardData", UInt,0xD, Int,hBuf)
	DllCall("CloseClipboard")
	return
}

;==================================================

JEE_AhkBasicCtlGetTextUtf8(hCtl)
{
	SendMessage, 0xE, 0, 0,, % "ahk_id " hCtl ;WM_GETTEXTLENGTH := 0xE
	vChars := ErrorLevel+1
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("SendMessageW", Int,hCtl, UInt,0xD, UInt,vChars, Int,&vTextUtf16) ;WM_GETTEXT := 0xD
	vSize := DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16, Int,vChars, Int,0, Int,0, Int,0, Int,0)
	VarSetCapacity(vText, vSize, 0)
	DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16, Int,vChars, Str,vText, Int,vSize, Int,0, Int,0)
	return vText
}

;==================================================

JEE_AhkBasicCtlGetSelTextUtf8(hCtl)
{
	VarSetCapacity(vPos1, 4, 0), VarSetCapacity(vPos2, 4, 0)
	SendMessage, 0xB0, % &vPos1, % &vPos2,, % "ahk_id " hCtl ;EM_GETSEL := 0xB0
	vPos1 := NumGet(&vPos1, 0, "UInt"), vPos2 := NumGet(&vPos2, 0, "UInt")
	if (vPos1 = vPos2)
		return
	vOffset := vPos1*2
	vCharsSel := vPos2-vPos1

	SendMessage, 0xE, 0, 0,, % "ahk_id " hCtl ;WM_GETTEXTLENGTH := 0xE
	vChars := ErrorLevel+1
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("SendMessageW", Int,hCtl, UInt,0xD, UInt,vChars, Int,&vTextUtf16) ;WM_GETTEXT := 0xD
	vSize := DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16+vOffset, Int,vCharsSel, Int,0, Int,0, Int,0, Int,0)
	VarSetCapacity(vText, vSize, 0)
	DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16+vOffset, Int,vCharsSel, Str,vText, Int,vSize, Int,0, Int,0)
	return vText
}

;==================================================

JEE_AhkBasicMsgBoxUtf8(vText, vWinTitle, vType=0)
{
	vChars := DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,&vTextUtf16, Int,vChars*2)

	vChars := DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vWinTitle, Int,-1, Int,0, Int,0)
	VarSetCapacity(vWinTitleUtf16, vChars*2, 0)
	DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vWinTitle, Int,-1, Int,&vWinTitleUtf16, Int,vChars*2)
	return DllCall("MessageBoxW", Int,0, Int,&vTextUtf16, Int,&vWinTitleUtf16, UInt,vType)
}

;==================================================

;get nth Unicode character
JEE_AhkBasicChrUtf8(vNum)
{
	VarSetCapacity(vTextUtf16, 4, 0)
	NumPut(vNum, &vTextUtf16+0, 0, "UShort")
	vSize := DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16, Int,2, Int,0, Int,0, Int,0, Int,0)
	VarSetCapacity(vOutput, vSize, 0)
	DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16, Int,2, Str,vOutput, Int,vSize, Int,0, Int,0)
	return vOutput
}

;==================================================

;get nth ANSI character
JEE_AhkBasicChrAUtf8(vNum)
{
	VarSetCapacity(vText, 2, 0)
	NumPut(vNum, &vText+0, 0, "UChar")
	VarSetCapacity(vTextUtf16, 4, 0)
	DllCall("MultiByteToWideChar", UInt,0, UInt,0, UInt,&vText, Int,-1, Int,&vTextUtf16, Int,4)

	vSize := DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16, Int,2, Int,0, Int,0, Int,0, Int,0)
	VarSetCapacity(vOutput, vSize, 0)
	DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16, Int,2, Str,vOutput, Int,vSize, Int,0, Int,0)
	return vOutput
}

;==================================================

JEE_AhkBasicSendCharsUtf8(vText, hWnd="")
{
	if (hWnd = "")
	{
		WinGet, hWnd, ID, A
		ControlGetFocus, vCtlClassNN, % "ahk_id " hWnd
		if !(vCtlClassNN = "")
			ControlGet, hWnd, Hwnd,, % vCtlClassNN, % "ahk_id " hWnd
	}
	vChars := DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,&vTextUtf16, Int,vChars*2)
	Loop, % vChars-1
	{
		vNum := NumGet(&vTextUtf16+0, A_Index*2-2, "UShort")
		DllCall("PostMessageW", Int,hWnd, UInt,0x102, UInt,vNum, Int,1) ;WM_CHAR := 0x102
	}
}

;==================================================

JEE_AhkBasicCtlSetTextUtf8(vText, hWnd="")
{
	vChars := DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,&vTextUtf16, Int,vChars*2)
	DllCall("SendMessageW", Int,hWnd, UInt,0xC, UInt,0, Int,&vTextUtf16) ;WM_SETTEXT := 0xC
}

;==================================================

JEE_AhkBasicEditPasteUtf8(vText, hWnd="", vCanUndo=1)
{
	vChars := DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,&vTextUtf16, Int,vChars*2)
	DllCall("SendMessageW", Int,hWnd, UInt,0xC2, UInt,vCanUndo, Int,&vTextUtf16) ;EM_REPLACESEL := 0xC2
}

;==================================================

JEE_AhkBasicAnsiToUtf8(vText)
{
	vChars := DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("MultiByteToWideChar", UInt,0, UInt,0, Str,vText, Int,-1, Int,&vTextUtf16, Int,vChars*2)

	vSize := DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16, Int,vChars, Int,0, Int,0, Int,0, Int,0)
	VarSetCapacity(vOutput, vSize, 0)
	DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16, Int,vChars, Str,vOutput, Int,vSize, Int,0, Int,0)
	return vOutput
}

;==================================================

;note: best-fit characters (replace Unicode chars with lookalike chars if available, otherwise '?')
JEE_AhkBasicUtf8ToAnsi(vText, vBFC=0)
{
	;WC_NO_BEST_FIT_CHARS := 0x400
	vFlags := vBFC ? 0 : 0x400

	vChars := DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Int,&vTextUtf16, Int,vChars*2)

	vSize := DllCall("WideCharToMultiByte", UInt,65001, UInt,0, Int,&vTextUtf16, Int,vChars, Int,0, Int,0, Int,0, Int,0)
	VarSetCapacity(vOutput, vSize, 0)
	DllCall("WideCharToMultiByte", UInt,0, UInt,vFlags, Int,&vTextUtf16, Int,vChars, Str,vOutput, Int,vSize, Int,0, Int,0)
	return vOutput
}

;==================================================

;JEE_AhkBasicAscUtf8(vText)

;==================================================

;JEE_AhkBasicAscAUtf8(vText)

;==================================================

;JEE_AhkBasicOrdUtf8(vText, vAscMode=0)

;==================================================

;JEE_AhkBasicOrdAUtf8(vText, vAscMode=0)

;==================================================

;JEE_AhkBasicStrLenUtf8(vText)

;==================================================

;note: uses same parameters as AHK v2's SubStr
;JEE_AhkBasicSubStrUtf8(vText, vPos, vLen)

;==================================================

;note: unlike NumGet, vAddrDest/vAddrSource must be numbers
;JEE_AhkBasicMemMove(vAddrDest, vAddrSource, vSize)

;==================================================

;note: unlike NumGet, vAddr must be a number
;JEE_AhkBasicHexGet(vAddr, vSize)

;==================================================

;note: unlike NumPut, vAddr must be an address
;JEE_AhkBasicHexPut(vHex, vAddr)

;==================================================

;JEE_AhkBasicFileGetEnc(vPath, vOpt="", ByRef vIsEmpty="")

;==================================================

;JEE_AhkBasicFileEmpty(vPath)

;==================================================

;from file: ANSI/UTF-8/UTF-16/UTF-16 BE
;to var: ANSI/UTF-8/hex
;JEE_AhkBasicFileRead(vPath, vEnc, vOffset=0, vSize=-1)

;==================================================

;from var: ANSI/UTF-8/hex
;to file: ANSI/UTF-8/UTF-16/UTF-16 BE
;JEE_AhkBasicFileAppend(vText, vPath, vEnc, vOffset=0, vSize=-1)

;==================================================

;JEE_AhkBasicFileReadBin(vPath, vOffset=0, vSize=-1)

;==================================================

;JEE_AhkBasicFileAppendBin(vText, vPath, vOffset=0, vSize=-1)

;==================================================
Example code:

Code: Select all

q::
WinGet, hWnd, ID, A
ControlGet, hCtl, Hwnd,, Edit1, % "ahk_id " hWnd
vChars := JEE_AhkBasicChrUtf8(33) JEE_AhkBasicChrUtf8(333) JEE_AhkBasicChrUtf8(3333) JEE_AhkBasicChrUtf8(33333)

vWinTitle := JEE_AhkBasicWinGetTitleUtf8(hWnd)
JEE_AhkBasicMsgBoxUtf8(vChars, A_ScriptName)

MsgBox, % "selected text:`r`n" SubStr(JEE_AhkBasicCtlGetSelTextUtf8(hCtl), 1, 100)
MsgBox, % "control text:`r`n" SubStr(JEE_AhkBasicCtlGetTextUtf8(hCtl), 1, 100)

vWinTitle := JEE_AhkBasicWinGetTitleUtf8(hWnd)
JEE_AhkBasicMsgBoxUtf8(vWinTitle, A_ScriptName)

MsgBox, % JEE_AhkBasicUtf8ToAnsi(vChars) "`r`n" JEE_AhkBasicUtf8ToAnsi(vChars, 1)

;characters 128-159 (ANSI cf. Unicode)
vOutput := ""
Loop, 32
{
	vNum := 127+A_Index
	vOutput .= vNum "`t" JEE_AhkBasicChrAUtf8(vNum) "`t" JEE_AhkBasicChrUtf8(vNum) "`r`n"
}
MsgBox, % vOutput
JEE_AhkBasicMsgBoxUtf8(vOutput, A_ScriptName)

vOutput := "", vTemp := vChars
Loop, 10
{
	vOutput .= vTemp "`r`n"
	vTemp := JEE_AhkBasicAnsiToUtf8(vTemp)
}
MsgBox, % vOutput
return

;==================================================

w::
WinGet, hWnd, ID, A
ControlGet, hCtl, Hwnd,, Edit1, % "ahk_id " hWnd
vChars := JEE_AhkBasicChrUtf8(33) JEE_AhkBasicChrUtf8(333) JEE_AhkBasicChrUtf8(3333) JEE_AhkBasicChrUtf8(33333)

JEE_AhkBasicSendCharsUtf8(vChars)
JEE_AhkBasicEditPasteUtf8(vChars, hCtl)
;JEE_AhkBasicCtlSetTextUtf8(vChars, hCtl)
return

Re: Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI

Posted: 31 May 2017, 02:17
by Drugwash
Slightly off-topic (in reply to this comment) I'll say that no Windows version - except maybe for 10 - has any complete Unicode font installed by default and moreover such fonts may not be available for free.
Some versions of Windows may be able to use a composite font, which is nothing but an XML file containing directions for which character blocks should be retrieved from which font file. I'm not sure how this works and whether any application can take advantage of such font.

BabelMap is capable of building a composite font automatically and it can be tweaked manually, however the system must have installed a wide range and assortment of specialized fonts that could fill all the gaps. I tried to gather fonts for this purpose but still couldn't build up the entire Unicode range in a composite font (under XP - dunno if 9x can recognize and use composite fonts,I'd guess not).

Emojis, in my humble opinion, are nothing but trouble. Some of them may have utility in case one agrees with the overly simplistic - and ugly - GUI in Windows 10 which matches them perfectly, but unfortunately they are being abused of as emoticons in blogging (and possibly other areas) and due to the small size they are literally illegible, leading to misunderstanding and/or frustration. In my browser I had to build myself a couple js scripts driven by Greasemonkey in order to replace some of the emoji characters with the old Yahoo! Messenger animated emoticons that can actually be properly understood, because the blogs I read are full of this crap.

Anyway, problem is many modern smartphones have an extended range of emojis implemented by default and some of them can't be found in the default desktop fonts that come with the OS (other than maybe Win10 as mentioned before) and may not have yet been implemented in the Google fonts that way too many websites make use of nowadays. That is the reason why browsers may display empty squares (IE) or other placeholders for nonexistant characters. Me having Google fonts blocked in my browser (by means of the RequestPolicy add-on) I frequently see such unknown characters. Same with the e-mail application (POP Peeper) which uses IE's rendering engine for HTML view (currently IE8 on my XP system, IE6-SP1 on 98SE).

Now in regard to the topic at hand I'd like to ask what exactly is the purpose of these functions? I figured they'd be used when running any version of AHK ANSI on an Unicode system, but why would one do that while the Unicode AHK is compatible with that OS? As for using them on a 9x system, well that may prove a little bit more complicated. Maybe I'm not getting it right so a few details would be useful.
Oh and no offense but function names seem quite long and cumbersome. Maybe drop the "AhkBasic" part completely or replace it with something shorter like "AxU_" (standing for ANSI x Unicode) or something.
Haven't tested any of them yet so can't comment on their accuracy or anything. Well, that's about it for now. :)

Re: Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI

Posted: 01 Jun 2017, 08:04
by jeeswg
@Drugwash: Thanks for your comments re. Unicode and re. the functions. They were intended for use with older systems, and possibly for scripts written for AHK ANSI on newer systems, where adding the occasional Unicode function would be easier than converting the script.

Partly also, the functions were to test my understanding, to see if I could get certain functions to work in AHK Basic. Furthermore, some of these functions, or versions designed for Unicode versions of AHK, could be useful as general functions, providing features that AHK doesn't have.

I did consider renaming the functions, but I have two considerations: replacing 'JEE_AhkBasic' and replacing the trailing 'Utf8'. I.e. to separate the functions into a UTF-8 functions and a non-UTF-8 functions.

My main concern is if any of these functions could be useful to anyone, or if anyone wants to request some similar functions that might be useful. Personally they would have been very useful for me back when only AHK Basic existed, but at that time I didn't have the knowledge to write the functions, and unfortunately there were not, or I did not find, such functions written by other people.

Re: Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI

Posted: 01 Jun 2017, 09:00
by Drugwash
Ah, don't mention it - sometimes I'm a good guy. :P :D

The Unicode <-> ANSI conversion can be provided by the StrGet()/StrPut() pair which are readily available in AHK 1.1+ and were made available at some point by Lexikos for AHK Basic, which should be installed in the global Lib folder. Using those functions would simplify your functions a little bit, I believe, but it would directly depend on the two scripts (StrGet.ahk and StrPut.ahk) being available on the systems running AHK Basic.
Additionally, if I recall correctly Win9x have only stubs, partial or no implementation of WideCharToMultiByte() and MultiByteToWideChar() in kernel32.dll, their usage requiring the presence of MSLU (unicows.dll) on the system and a straight call for those APIs in that library, unless KernelEx and/or Kext (see the MSFN.org board) are installed and properly set up to redirect the respective APIs. Quite a lot of assumptions, I'd say.

Since AHK Basic only creates ANSI controls for its GUIs I believe sending/retrieving Unicode strings to/from those controls would be useless. However manipulating strings for internal use (such as converting, sending to APIs, retrieving results and reconverting as necessary) or to/from other Unicode-aware applications would indeed be useful and I know I've hit this wall sometimes in the past. Of course there's also the ability to work with RichEdit controls and also HTML/COM even in AHK Basic (where the necessary libraries and scripts are installed).

The naming convention of the functions is at your leisure, the only thing to keep in mind is the ease of use and the descriptiveness (is that a real word? :D ). UTF-8 is one encoding, but how about UTF-16 or UTF-32? No idea if AHK supports them already, I've done very little work with actual Unicode lately and forgot everything I've learned earlier (got a very bad memory :( ).

Anyway, if you plan on building a set of Unicode <-> ANSI functions that could be used in a wide range of OS versions and AHK versions you'll have to build yourself a few virtual machines (in case you don't have all OS versions on real hardware) and start testing thoroughly. ;)

Re: Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI

Posted: 01 Jun 2017, 09:34
by jeeswg
Thank you, I wasn't sure if the dll functions were available on older OSes, so that's interesting to know. I was focusing on UTF-8 because AHK Basic/ANSI can handle ANSI natively, and UTF-8 is stored as ANSI bytes without any null characters. Out of interest, I have been working on some functions to create GUIs via DllCall, so perhaps those could be used/modified to create Unicode controls via AHK Basic/ANSI.

Anyhow, my plans are to add the remaining functions, and possibly add one or two other functions if there are any requests. My testing will amount to testing the functions on Windows 7 with AHK Basic.

I kind of thought that no-one or very few people would want these functions, it depends on how big the AHK Basic user base is, however, I thought I might release them anyway just in case. Also it is possible to do the maths, to do ANSI/UTF-8/UTF-16 conversion manually using NumGet/NumPut (I will put this in my maths/strings tutorials I'm writing). Also, I do use some of these functions or Unicode versions of these functions regularly.

Re: Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI

Posted: 01 Jun 2017, 11:29
by Drugwash
Win7 is already too much - you'd need 98SE and 2000/XP. Try Virtual PC 2004 or VirtualBox.
To be on the safe side you should probably test for the presence of the two counterpart converter functions (WideCharToMultiByte() and MultiByteToWideChar() ) in kernel32 (should return ERROR_CALL_NOT_IMPLEMENTED - error 120 - or something on vanilla 9x) and then for the presence of unicows.dll. Unless you don't care about those OS versions, that is.

Creating Unicode windows via CreateWindowExW() would be possible under 9x too (again it might need unicows.dll) but then again all other controls would have to be added by the same means and all window messages would have to be translated to Unicode if they're not already. Complicated, I'd say.

Anyway, I wouldn't want to deter you but I'm probably the only one that (openly) declares to be using AHK Basic (and Win9x) in these times of bloated OS and applications. Quite a narrow user base. :P :lol:

Re: Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI

Posted: 01 Jun 2017, 12:15
by BoBo
Drugwash wrote:Win7 is already too much - [...]

Anyway, I wouldn't want to deter you but I'm probably the only one that (openly) declares to be using AHK Basic (and Win9x) in these times of bloated OS and applications. Quite a narrow user base. :P :lol:
I have to admit, you're not alone (when it comes to the first). Well, you're obviously a pro, what I'm definitely not - and because I haven't really adopted the current syntax (and therefore won't be able to 'reanimate' a bunch of old fashioned scripts) I had to beg for [this] - without success *crybaby-smiley*

Btw, covfefe !! :thumbup:

Re: Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI

Posted: 01 Jun 2017, 12:40
by Drugwash
@ BoBo: Haha, I've never been a real pro, not even when AHK Basic was mainstream. :) Don't worry, you'll get there in time, unless your memory is as bad as mine (which I hope is not). ;)

As for your request in that topic, would you believe me that's exactly what I'm working on right now? Wanted it to be a surprise but… Anyway, it'll take a little while until I get it to work properly, coz when it comes to registry one must be very careful. So stand by, it'll come out one of these days and it might be more than you asked for. :D

Re: Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI

Posted: 01 Oct 2017, 20:41
by jeeswg
I have updated/completed the functions, they have only been tested in AutoHotkey Basic (v1.0), although some may be usable as they are, or with some alterations in AutoHotkey v1.1 ANSI/Unicode versions.

The original aim was to create the functions that I felt were missing but needed in AutoHotkey Basic (one or two could still benefit AHK v1.1/v2). I wanted all of these functions in some form for AutoHotkey v1.1/v2 anyway, and it was an interesting challenge to try to bring them to AutoHotkey Basic.

Note: I have also recreated StrReplace and Trim/LTrim/RTrim for AutoHotkey Basic.

Note: The Winapi function wsprinf is useful for when AHK's Format function is not available.

AutoHotkey Basic was pretty good to work with, it did already have so many of the features that make AutoHotkey great. The one annoyance that sticks out is that I couldn't do things like (A_IsUnicode?"W":"A"), I had to space it out to avoid causing a script error.

==================================================

Code: Select all

;'AutoHotkey Basic Unicode' by jeeswg
;Unicode functions for AutoHotkey v1.0 'Basic' / AutoHotkey v1.1. x32 ANSI

;JEE_AhkBWinGetTitleUtf8(hWnd)
;JEE_AhkBClipboardGetTextUtf8()
;JEE_AhkBClipboardGetTextUtf8Alt()
;JEE_AhkBClipboardGetPathsUtf8(vSep="`n")
;JEE_AhkBClipboardSetTextUtf8(vText)
;JEE_AhkBClipboardSetTextUtf8Alt(vText)
;JEE_AhkBCtlGetTextUtf8(hCtl=0)
;JEE_AhkBCtlGetSelTextUtf8(hCtl=0)
;JEE_AhkBMsgBoxUtf8(vText, vWinTitle="", vType=0)
;JEE_AhkBChrUtf8(vNum)
;JEE_AhkBChrAUtf8(vNum)
;JEE_AhkBSendCharsUtf8(hWnd, vText)
;JEE_AhkBCtlSetTextUtf8(hCtl, vText)
;JEE_AhkBEditPasteUtf8(hCtl, vText, vCanUndo=1)
;JEE_AhkBAnsiToUtf8(vText)
;JEE_AhkBUtf8ToAnsi(vText, vBFC=0)
;JEE_AhkBAscUtf8(vText)
;JEE_AhkBAscAUtf8(vText)
;JEE_AhkBOrdUtf8(vText, vAscMode=0)
;JEE_AhkBOrdAUtf8(vText)
;JEE_AhkBStrLenUtf8(vText)
;JEE_AhkBSubStrUtf8(vText, vPos, vLen="")
;JEE_AhkBMemMove(vAddrDest, vAddrSource, vSize)
;JEE_AhkBHexGet(vAddr, vSize)
;JEE_AhkBHexPut(vHex, vAddr)
;JEE_AhkBHex2Dec(vHex)
;JEE_AhkBDec2Hex(vNum, vLen=0, vCase="U")
;JEE_AhkBDec2HexAlt(vNum, vLen=0, vCase="U")
;JEE_AhkBFileGetEnc(vPath, vOpt="", ByRef vIsEmpty="")
;JEE_AhkBFileEmpty(vPath)
;JEE_AhkBFileReadUtf8(vPath, vEnc="", vOffset=0, vSize=-1)
;JEE_AhkBFileAppendHex(vHex, vPath)
;JEE_AhkBFileReadHex(vPath, vOffset=0, vSize=-1)
;JEE_AhkBFileAppendUtf8(vText, vPath, vEnc="", vAddBOM=1)
;JEE_AhkBFileReadBin(ByRef vData, vPath, vOffset=0, vSize=-1, ByRef vBytesRead=0)
;JEE_AhkBFileReadBinAlt(ByRef vData, vPath, vOffset=0, vSize=-1, ByRef vBytesRead=0)
;JEE_AhkBFileAppendBin(vAddr, vPath, vSize=0)
;JEE_AhkBUtf16ToUtf8(vAddr16, vSize16, vAddr8=0, vSize8=-1)
;JEE_AhkBUtf8ToUtf16(vAddr8, vSize8=-1, vAddr16=0, vSize16=-1)
;JEE_AhkBUtf16ToAnsi(vAddr16, vSize16, vAddrA=0, vSizeA=-1, vBFC=1)
;JEE_AhkBAnsiToUtf16(vAddrA, vSizeA, vAddr16=0, vSize16=-1)
;StrReplace(vText, vNeedle, vReplaceText="", ByRef vCount="", vLimit=-1)
;Trim(vText, vOmitChars=" `t")
;LTrim(vText, vOmitChars=" `t")
;RTrim(vText, vOmitChars=" `t")

;==================================================

JEE_AhkBWinGetTitleUtf8(hWnd)
{
	static Ptr := "Int", UPtr := "UInt"
	vDHW := A_DetectHiddenWindows
	DetectHiddenWindows, On
	vChars := DllCall("user32\GetWindowTextLengthW", Ptr,hWnd)+1
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("user32\GetWindowTextW", Ptr,hWnd, Ptr,&vTextUtf16, Int,vChars)
	vSize := DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16, Int,vChars, Ptr,0, Int,0, Ptr,0, Ptr,0)
	VarSetCapacity(vWinTitle, vSize, 0)
	DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16, Int,vChars, Str,vWinTitle, Int,vSize, Ptr,0, Ptr,0)
	DetectHiddenWindows, % vDHW
	return vWinTitle
}

;==================================================

JEE_AhkBClipboardGetTextUtf8()
{
	static Ptr := "Int", UPtr := "UInt"
	Transform, vText, Unicode
	return vText
}

;==================================================

;alternative method (that does not retrieve file paths, see JEE_AhkBClipboardGetPathsUtf8 instead)
JEE_AhkBClipboardGetTextUtf8Alt()
{
	static Ptr := "Int", UPtr := "UInt"
	;CF_LOCALE := 0x10 ;CF_UNICODETEXT := 0xD
	;CF_OEMTEXT := 0x7 ;CF_TEXT := 0x1
	if !DllCall("user32\IsClipboardFormatAvailable", UInt,0xD)
		if DllCall("user32\IsClipboardFormatAvailable", UInt,0x1)
			return Clipboard
		else
			return ""
	if !DllCall("user32\OpenClipboard", Ptr,0)
		return ""
	if !hBuf := DllCall("user32\GetClipboardData", UInt,0xD, Ptr)
	{
		DllCall("user32\CloseClipboard")
		return ""
	}

	pBuf := DllCall("kernel32\GlobalLock", Ptr,hBuf, Ptr)
	vSize := DllCall("kernel32\GlobalSize", Ptr,hBuf, UPtr)
	VarSetCapacity(vOutputUtf16, vSize, 0)
	DllCall("kernel32\RtlMoveMemory", Ptr,&vOutputUtf16, Ptr,pBuf, UPtr,vSize)

	vChars := vSize/2
	vSize := DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vOutputUtf16, Int,vChars, Ptr,0, Int,0, Ptr,0, Ptr,0)
	VarSetCapacity(vOutput, vSize, 0)
	DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vOutputUtf16, Int,vChars, Str,vOutput, Int,vSize, Ptr,0, Ptr,0)

	DllCall("kernel32\GlobalUnlock", Ptr,hBuf)
	DllCall("user32\CloseClipboard")
	return vOutput
}

;==================================================

JEE_AhkBClipboardGetPathsUtf8(vSep="`n")
{
	static Ptr := "Int", UPtr := "UInt"
	;CF_HDROP := 0xF
	if !DllCall("user32\IsClipboardFormatAvailable", UInt,0xF)
		return ""
	if !DllCall("user32\OpenClipboard", Ptr,0)
		return ""
	if !hDrop := DllCall("user32\GetClipboardData", UInt,0xF, Ptr)
	{
		DllCall("user32\CloseClipboard")
		return ""
	}

	;==============================
	;based on JEE_DropGetPaths:
	vOutput := ""
	vCount := DllCall("shell32\DragQueryFileW", Ptr,hDrop, UInt,-1, Ptr,0, UInt,0, UInt)
	Loop, % vCount
	{
		vChars := DllCall("shell32\DragQueryFileW", Ptr,hDrop, UInt,A_Index-1, Ptr,0, UInt,0, UInt) + 1
		VarSetCapacity(vPathUtf16, vChars*2, 0)
		DllCall("shell32\DragQueryFileW", Ptr,hDrop, UInt,A_Index-1, Ptr,&vPathUtf16, UInt,vChars, UInt)

		vSize := DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vPathUtf16, Int,vChars, Ptr,0, Int,0, Ptr,0, Ptr,0)
		VarSetCapacity(vPath, vSize, 0)
		DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vPathUtf16, Int,vChars, Str,vPath, Int,vSize, Ptr,0, Ptr,0)
		vOutput .= vPath vSep
	}
	DllCall("shell32\DragFinish", Ptr,hDrop)
	;==============================

	DllCall("user32\CloseClipboard")
	return SubStr(vOutput, 1, -StrLen(vSep))
}

;==================================================

JEE_AhkBClipboardSetTextUtf8(vText)
{
	static Ptr := "Int", UPtr := "UInt"
	Transform, Clipboard, Unicode, % vText
}

;==================================================

;alternative method
JEE_AhkBClipboardSetTextUtf8Alt(vText)
{
	static Ptr := "Int", UPtr := "UInt"
	;GMEM_ZEROINIT := 0x40, GMEM_MOVEABLE := 0x2
	hBuf := DllCall("kernel32\GlobalAlloc", UInt,0x42, UPtr,(StrLen(vText)+2)*2, Ptr)
	pBuf := DllCall("kernel32\GlobalLock", Ptr,hBuf, Ptr)

	vChars := DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,&vTextUtf16, Int,vChars*2)
	DllCall("kernel32\RtlMoveMemory", Ptr,pBuf, Ptr,&vTextUtf16, UPtr,vChars*2)

	;CF_LOCALE := 0x10 ;CF_UNICODETEXT := 0xD
	;CF_OEMTEXT := 0x7 ;CF_TEXT := 0x1
	hWnd := A_ScriptHwnd ? A_ScriptHwnd : WinExist("ahk_pid " DllCall("kernel32\GetCurrentProcessId", UInt))
	DllCall("kernel32\GlobalUnlock", Ptr,hBuf)
	DllCall("user32\OpenClipboard", Ptr,hWnd)
	DllCall("user32\EmptyClipboard")
	DllCall("user32\SetClipboardData", UInt,0xD, Ptr,hBuf, Ptr)
	DllCall("user32\CloseClipboard")
	return
}

;==================================================

JEE_AhkBCtlGetTextUtf8(hCtl=0)
{
	static Ptr := "Int", UPtr := "UInt"
	if !hCtl
	{
		WinGet, hWnd, ID, A
		ControlGetFocus, vCtlClassNN, % "ahk_id " hWnd
		ControlGet, hCtl, Hwnd,, % vCtlClassNN, % "ahk_id " hWnd
	}
	SendMessage, 0xE, 0, 0,, % "ahk_id " hCtl ;WM_GETTEXTLENGTH := 0xE
	vChars := ErrorLevel+1
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("user32\SendMessageW", Ptr,hCtl, UInt,0xD, UPtr,vChars, Ptr,&vTextUtf16, Ptr) ;WM_GETTEXT := 0xD
	vSize := DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16, Int,vChars, Ptr,0, Int,0, Ptr,0, Ptr,0)
	VarSetCapacity(vText, vSize, 0)
	DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16, Int,vChars, Str,vText, Int,vSize, Ptr,0, Ptr,0)
	return vText
}

;==================================================

JEE_AhkBCtlGetSelTextUtf8(hCtl=0)
{
	static Ptr := "Int", UPtr := "UInt"
	if !hCtl
	{
		WinGet, hWnd, ID, A
		ControlGetFocus, vCtlClassNN, % "ahk_id " hWnd
		ControlGet, hCtl, Hwnd,, % vCtlClassNN, % "ahk_id " hWnd
	}
	VarSetCapacity(vPos1, 4, 0), VarSetCapacity(vPos2, 4, 0)
	SendMessage, 0xB0, % &vPos1, % &vPos2,, % "ahk_id " hCtl ;EM_GETSEL := 0xB0
	vPos1 := NumGet(&vPos1, 0, "UInt"), vPos2 := NumGet(&vPos2, 0, "UInt")
	if (vPos1 = vPos2)
		return
	vOffset := vPos1*2
	vCharsSel := vPos2-vPos1

	SendMessage, 0xE, 0, 0,, % "ahk_id " hCtl ;WM_GETTEXTLENGTH := 0xE
	vChars := ErrorLevel+1
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("user32\SendMessageW", Ptr,hCtl, UInt,0xD, UPtr,vChars, Ptr,&vTextUtf16, Ptr) ;WM_GETTEXT := 0xD
	vSize := DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16+vOffset, Int,vCharsSel, Ptr,0, Int,0, Ptr,0, Ptr,0)
	VarSetCapacity(vText, vSize, 0)
	DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16+vOffset, Int,vCharsSel, Str,vText, Int,vSize, Ptr,0, Ptr,0)
	return vText
}

;==================================================

JEE_AhkBMsgBoxUtf8(vText, vWinTitle="", vType=0)
{
	static Ptr := "Int", UPtr := "UInt"
	vChars := DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,&vTextUtf16, Int,vChars*2)

	if (vWinTitle = "")
		vWinTitle := A_ScriptName
	vChars := DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vWinTitle, Int,-1, Ptr,0, Int,0)
	VarSetCapacity(vWinTitleUtf16, vChars*2, 0)
	DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vWinTitle, Int,-1, Ptr,&vWinTitleUtf16, Int,vChars*2)
	return DllCall("user32\MessageBoxW", Ptr,0, Ptr,&vTextUtf16, Ptr,&vWinTitleUtf16, UInt,vType)
}

;==================================================

;get nth Unicode character
JEE_AhkBChrUtf8(vNum)
{
	static Ptr := "Int", UPtr := "UInt"
	VarSetCapacity(vTextUtf16, 6, 0)
	if (vNum <= 0) || (vNum + 0 = "")
		return
	else if (vNum <= 65535)
		vChars := 2, NumPut(vNum, &vTextUtf16, 0, "UShort")
	else
	{
		vChars := 3, vNum -= 65536
		NumPut(55296+Floor(vNum/1024), &vTextUtf16, 0, "UShort")
		NumPut(56320+Mod(vNum,1024), &vTextUtf16, 2, "UShort")
	}

	vSize := DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16, Int,vChars, Ptr,0, Int,0, Ptr,0, Ptr,0)
	VarSetCapacity(vOutput, vSize, 0)
	DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16, Int,vChars, Str,vOutput, Int,vSize, Ptr,0, Ptr,0)
	return vOutput
}

;==================================================

;get nth ANSI character
JEE_AhkBChrAUtf8(vNum)
{
	static Ptr := "Int", UPtr := "UInt"
	VarSetCapacity(vText, 2, 0)
	NumPut(vNum, &vText+0, 0, "UChar")
	VarSetCapacity(vTextUtf16, 4, 0)
	DllCall("kernel32\MultiByteToWideChar", UInt,0, UInt,0, Ptr,&vText, Int,-1, Ptr,&vTextUtf16, Int,4)

	vSize := DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16, Int,2, Ptr,0, Int,0, Ptr,0, Ptr,0)
	VarSetCapacity(vOutput, vSize, 0)
	DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16, Int,2, Str,vOutput, Int,vSize, Ptr,0, Ptr,0)
	return vOutput
}

;==================================================

JEE_AhkBSendCharsUtf8(hWnd, vText)
{
	static Ptr := "Int", UPtr := "UInt"
	if !hWnd
	{
		WinGet, hWnd, ID, A
		ControlGetFocus, vCtlClassNN, % "ahk_id " hWnd
		if !(vCtlClassNN = "")
			ControlGet, hWnd, Hwnd,, % vCtlClassNN, % "ahk_id " hWnd
	}
	vChars := DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,&vTextUtf16, Int,vChars*2)
	Loop, % vChars-1
	{
		vNum := NumGet(&vTextUtf16+0, A_Index*2-2, "UShort")
		DllCall("user32\PostMessageW", Ptr,hWnd, UInt,0x102, UPtr,vNum, Ptr,1) ;WM_CHAR := 0x102
	}
}

;==================================================

JEE_AhkBCtlSetTextUtf8(hCtl, vText)
{
	static Ptr := "Int", UPtr := "UInt"
	if !hCtl
	{
		WinGet, hWnd, ID, A
		ControlGetFocus, vCtlClassNN, % "ahk_id " hWnd
		ControlGet, hCtl, Hwnd,, % vCtlClassNN, % "ahk_id " hWnd
	}
	vChars := DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,&vTextUtf16, Int,vChars*2)
	DllCall("user32\SendMessageW", Ptr,hCtl, UInt,0xC, UPtr,0, Ptr,&vTextUtf16, Ptr) ;WM_SETTEXT := 0xC
}

;==================================================

JEE_AhkBEditPasteUtf8(hCtl, vText, vCanUndo=1)
{
	static Ptr := "Int", UPtr := "UInt"
	if !hCtl
	{
		WinGet, hWnd, ID, A
		ControlGetFocus, vCtlClassNN, % "ahk_id " hWnd
		ControlGet, hCtl, Hwnd,, % vCtlClassNN, % "ahk_id " hWnd
	}
	vChars := DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,&vTextUtf16, Int,vChars*2)
	DllCall("user32\SendMessageW", Ptr,hCtl, UInt,0xC2, UPtr,vCanUndo, Ptr,&vTextUtf16, Ptr) ;EM_REPLACESEL := 0xC2
}

;==================================================

JEE_AhkBAnsiToUtf8(vText)
{
	static Ptr := "Int", UPtr := "UInt"
	vChars := DllCall("kernel32\MultiByteToWideChar", UInt,0, UInt,0, Str,vText, Int,-1, Ptr,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("kernel32\MultiByteToWideChar", UInt,0, UInt,0, Str,vText, Int,-1, Ptr,&vTextUtf16, Int,vChars*2)

	vSize := DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16, Int,vChars, Ptr,0, Int,0, Ptr,0, Ptr,0)
	VarSetCapacity(vOutput, vSize, 0)
	DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16, Int,vChars, Str,vOutput, Int,vSize, Ptr,0, Ptr,0)
	return vOutput
}

;==================================================

;note: best-fit characters (replace Unicode chars with lookalike chars if available, otherwise '?')
JEE_AhkBUtf8ToAnsi(vText, vBFC=0)
{
	static Ptr := "Int", UPtr := "UInt"
	;WC_NO_BEST_FIT_CHARS := 0x400
	vFlags := vBFC ? 0 : 0x400

	vChars := DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,0, Int,0)
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,&vTextUtf16, Int,vChars*2)

	vSize := DllCall("kernel32\WideCharToMultiByte", UInt,0, UInt,vFlags, Ptr,&vTextUtf16, Int,vChars, Ptr,0, Int,0, Ptr,0, Ptr,0)
	VarSetCapacity(vOutput, vSize, 0)
	DllCall("kernel32\WideCharToMultiByte", UInt,0, UInt,vFlags, Ptr,&vTextUtf16, Int,vChars, Str,vOutput, Int,vSize, Ptr,0, Ptr,0)
	return vOutput
}

;==================================================

JEE_AhkBAscUtf8(vText)
{
	static Ptr := "Int", UPtr := "UInt"
	VarSetCapacity(vTextUtf16, 2, 0)
	DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,&vTextUtf16, Int,2)
	return NumGet(&vTextUtf16, 0, "UShort")
}

;==================================================

JEE_AhkBAscAUtf8(vText)
{
	static Ptr := "Int", UPtr := "UInt"
	vAnsi := JEE_AhkBUtf8ToAnsi(vText)
	return NumGet(&vAnsi, 0, "UChar")
}

;==================================================

;AscMode, get the number of the first 2 bytes
JEE_AhkBOrdUtf8(vText, vAscMode=0)
{
	static Ptr := "Int", UPtr := "UInt"
	VarSetCapacity(vTextUtf16, 4, 0)
	DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,-1, Ptr,&vTextUtf16, Int,4)
	vNum := NumGet(&vTextUtf16, 0, "UShort")
	if vAscMode || (vNum < 55296) || (vNum > 56319)
		return vNum
	else
	{
		vNum1 := NumGet(&vTextUtf16, 0, "UShort")
		vNum2 := NumGet(&vTextUtf16, 2, "UShort")
		return (vNum1-55296)*1024+(vNum2-56320)+65536
	}
}

;==================================================

JEE_AhkBOrdAUtf8(vText)
{
	static Ptr := "Int", UPtr := "UInt"
	vAnsi := JEE_AhkBUtf8ToAnsi(vText)
	return NumGet(&vAnsi, 0, "UChar")
}

;==================================================

JEE_AhkBStrLenUtf8(vText)
{
	static Ptr := "Int", UPtr := "UInt"
	vSize := StrLen(vText)
	return DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,vSize, Ptr,0, Int,0)
}

;==================================================

;note: uses same parameters as AHK v2's SubStr
JEE_AhkBSubStrUtf8(vText, vPos, vLen="")
{
	static Ptr := "Int", UPtr := "UInt"
	if (vLen = 0)
		return
	vSize := StrLen(vText)
	vChars := DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,vSize, Ptr,0, Int,0)
	if (vLen = "")
		vLen := vChars
	VarSetCapacity(vTextUtf16, vChars*2, 0)
	DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Str,vText, Int,vSize, Ptr,&vTextUtf16, Int,vChars*2)
	if (vPos < 0)
		vPos := vChars + 1 + vPos
	if (vPos < 0) || (vPos > vChars)
		return
	if (vLen < 0)
		vLen := vChars - vPos + 1 + vLen
	if (vLen < 0)
		return
	if (vPos + vLen > vChars + 1)
		vLen -= vPos + vLen - vChars - 1
	if (vLen < 0)
		return
	vSize := vLen*2
	VarSetCapacity(vOutput, vSize, 0)
	DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,&vTextUtf16+vPos*2-2, Int,vLen, Str,vOutput, Int,vSize, Ptr,0, Ptr,0)
	return vOutput
}

;==================================================

;note: unlike NumGet, vAddrDest/vAddrSource must be numbers
;note: RtlMoveMemory parameter order is: 'dest, source' [NOT 'source, destination']
JEE_AhkBMemMove(vAddrDest, vAddrSource, vSize)
{
	static Ptr := "Int", UPtr := "UInt"
	DllCall("kernel32\RtlMoveMemory", Ptr,vAddrDest, Ptr,vAddrSource, UPtr,vSize)
}

;==================================================

;note: unlike NumGet, vAddr must be a number
JEE_AhkBHexGet(vAddr, vSize)
{
	static Ptr := "Int", UPtr := "UInt", UIntP := "UInt*"
	;CRYPT_STRING_HEX := 0x4 ;to return space/CRLF-separated text
	;CRYPT_STRING_HEXRAW := 0xC ;to return raw hex (not supported by Windows XP)
	DllCall("crypt32\CryptBinaryToString" (A_IsUnicode ? "W" : "A"), Ptr,vAddr, UInt,vSize, UInt,0x4, Ptr,0, UIntP,vChars)
	VarSetCapacity(vHex, vChars*(A_IsUnicode ? 2 : 1), 0)
	DllCall("crypt32\CryptBinaryToString" (A_IsUnicode ? "W" : "A"), Ptr,vAddr, UInt,vSize, UInt,0x4, Str,vHex, UIntP,vChars)
	vHex := StrReplace(vHex, "`r`n")
	vHex := StrReplace(vHex, " ")
	return vHex
}

;==================================================

;note: unlike NumPut, vAddr must be an address
JEE_AhkBHexPut(vHex, vAddr)
{
	static Ptr := "Int", UPtr := "UInt"
	vChars := StrLen(vHex)
	;CRYPT_STRING_HEX := 0x4
	;CRYPT_STRING_HEXRAW := 0xC ;(not supported by Windows XP)
	DllCall("crypt32\CryptStringToBinary" (A_IsUnicode ? "W" : "A"), Ptr,&vHex, UInt,vChars, UInt,0x4, Ptr,0, UIntP,vSize, Ptr,0, Ptr,0)
	DllCall("crypt32\CryptStringToBinary" (A_IsUnicode ? "W" : "A"), Ptr,&vHex, UInt,vChars, UInt,0x4, Ptr,vAddr, UIntP,vSize, Ptr,0, Ptr,0)
}

;==================================================

JEE_AhkBHex2Dec(vHex)
{
	static Ptr := "Int", UPtr := "UInt"
	if !(SubStr(vHex, 1, 2) = "0x")
		vHex := "0x" vHex
	return vHex + 0
}

;==================================================

;printf - C++ Reference
;http://www.cplusplus.com/reference/cstdio/printf/
;Format Specification Syntax: printf and wprintf Functions
;https://msdn.microsoft.com/en-us/library/56e442dc.aspx

JEE_AhkBDec2Hex(vNum, vLen=0, vCase="U")
{
	static Ptr := "Int", UPtr := "UInt"
	vLen := (vLen > 0) ? "0" vLen : ""
	vFormat := "%" vLen "I64" (vCase = "U" ? "X" : "x") ;e.g. %I64X, %02I64X
	VarSetCapacity(vNum2, A_IsUnicode ? 40 : 20, 0)
	DllCall("user32\wsprintf" (A_IsUnicode ? "W" : "A"), Str,vNum2, Str,vFormat, Int64,vNum, "CDecl Int")
	return vNum2
}

;==================================================

JEE_AhkBDec2HexAlt(vNum, vLen=0, vCase="U")
{
	static Ptr := "Int", UPtr := "UInt"
	if (vLen = "")
		vLen := 0

	SetFormat, Integer, H
	vNum += 0
	SetFormat, Integer, D
	StringReplace, vNum, vNum, 0x,, 0
	if (vCase = "U")
		StringUpper, vNum, vNum
	else
		StringLower, vNum, vNum

	if (StrLen(vNum) < vLen)
	{
		Loop, % vLen - StrLen(vNum)
			vNum := "0" vNum
	}
	return vNum
}

;==================================================

JEE_AhkBFileGetEnc(vPath, vOpt="", ByRef vIsEmpty="")
{
	static Ptr := "Int", UPtr := "UInt"
	vIsEmpty := 0
	vAttrib := FileExist(vPath)
	if (vAttrib = "") || InStr(vAttrib, "D")
		return

	FileGetSize, vSize, % vPath
	if (vSize <= 1)
	{
		if (vSize = 0)
			vIsEmpty := 1
		return "ANSI"
	}

	;GENERIC_READ := 0x80000000 ;OPEN_EXISTING := 3
	;FILE_SHARE_WRITE := 0x2 ;FILE_SHARE_READ := 0x1
	if !hFile := DllCall("kernel32\CreateFile", Str,vPath, UInt,0x80000000, UInt,0x3, Ptr,0, UInt,3, UInt,0, Ptr,0, Ptr)
		return
	VarSetCapacity(vData, 4, 0)
	DllCall("kernel32\ReadFile", Ptr,hFile, Ptr,&vData, UInt,4, UIntP,vBytesActuallyRead, Ptr,0)
	DllCall("kernel32\CloseHandle", Ptr,hFile)
	if (NumGet(vData, 0, "UShort") "," NumGet(vData, 2, "UChar") = "48111,191") ;239,187,191
	{
		if (vSize = 3)
			vIsEmpty := 1
		return "UTF-8"
	}
	if (NumGet(vData, 0, "UShort") = 65279) ;255,254
	{
		if (vSize = 2)
			vIsEmpty := 1
		return "UTF-16"
	}
	if (NumGet(vData, 0, "UShort") = 65534) ;254,255
	{
		if (vSize = 2)
			vIsEmpty := 1
		return "UTF-16 BE"
	}
}

;==================================================

JEE_AhkBFileEmpty(vPath)
{
	static Ptr := "Int", UPtr := "UInt"
	vIsEmpty := 0
	vAttrib := FileExist(vPath)
	if (vAttrib = "") || InStr(vAttrib, "D")
		return 0
	FileGetSize, vSize, % vPath
	if (vSize = 0)
		return 1

	;GENERIC_WRITE := 0x40000000 ;OPEN_EXISTING := 3
	;FILE_SHARE_WRITE := 0x2 ;FILE_SHARE_READ := 0x1
	;TRUNCATE_EXISTING := 5 ;(if exists truncate to 0 bytes else do nothing)

	hFile := DllCall("kernel32\CreateFile", Str,vPath, UInt,0x40000000, UInt,0x3, Ptr,0, UInt,5, UInt,0, Ptr,0, Ptr)
	if (hFile <= 0)
	{
		MsgBox, % A_ThisFunc ": error: clearing file:`r`n" vPath
		return 0
	}
	DllCall("kernel32\CloseHandle", Ptr,hFile)
	return 1
}

;==================================================

;reads as UTF-8 unless otherwise specified
;from file: ANSI/UTF-8/UTF-16/UTF-16 BE/bin
;to var: ANSI/UTF-8/hex
JEE_AhkBFileReadUtf8(vPath, vEnc="", vOffset=0, vSize=-1)
{
	static Ptr := "Int", UPtr := "UInt"
	vBOM := Chr(239) Chr(187) Chr(191)
	if !FileExist(vPath)
		return
	if (vEnc = "")
		vEnc := JEE_AhkBFileGetEnc(vPath, "", vIsEmpty)
	if (vEnc = "UTF-8")
		FileRead, vUtf8, % vPath
	else if (vEnc = "ANSI")
	{
		FileRead, vText, % vPath
		vSize := JEE_AhkBAnsiToUtf16(&vText, StrLen(vText))
		VarSetCapacity(vUtf16, vSize, 0)
		JEE_AhkBAnsiToUtf16(&vText, StrLen(vText), &vUtf16, vSize)

		vSize8 := JEE_AhkBUtf16ToUtf8(&vUtf16, vSize)
		VarSetCapacity(vUtf8, vSize8, 0)
		JEE_AhkBUtf16ToUtf8(&vUtf16, vSize, &vUtf8, vSize8)
		return vText
	}
	else if (vEnc = "UTF-16")
	{
		JEE_AhkBFileReadBin(vUtf16, vPath, 0, -1, vSize)
		vSize8 := JEE_AhkBUtf16ToUtf8(&vUtf16, vSize)
		VarSetCapacity(vUtf8, vSize8, 0)
		JEE_AhkBUtf16ToUtf8(&vUtf16, vSize, &vUtf8, vSize8)
	}
	else if (vEnc = "UTF-16 BE")
	{
		JEE_AhkBFileReadBin(vBE, vPath, 0, -1, vSize)
		VarSetCapacity(vUtf16, vSize, 0)
		;LCMAP_BYTEREV := 0x800
		DllCall("kernel32\LCMapStringW", UInt,0, UInt,0x800, Str,vBE, Int,vSize/2, Str,vUtf16, Int,vSize/2)

		vSize8 := JEE_AhkBUtf16ToUtf8(&vUtf16, vSize)
		VarSetCapacity(vUtf8, vSize8, 0)
		JEE_AhkBUtf16ToUtf8(&vUtf16, vSize, &vUtf8, vSize8)
	}
	VarSetCapacity(vUtf8, -1)
	if (SubStr(vUtf8, 1, 3) = vBOM)
		vUtf8 := SubStr(vUtf8, 4)
	return vUtf8
}

;==================================================

JEE_AhkBFileAppendHex(vHex, vPath)
{
	static Ptr := "Int", UPtr := "UInt"
	VarSetCapacity(vData, vSize := StrLen(vHex)/(A_IsUnicode ? 1 : 2), 0)
	JEE_AhkBHexPut(vHex, &vData)
	JEE_AhkBFileAppendBin(&vData, vPath, vSize)
}

;==================================================

JEE_AhkBFileReadHex(vPath, vOffset=0, vSize=-1)
{
	static Ptr := "Int", UPtr := "UInt"
	if !JEE_AhkBFileReadBin(vData, vPath, vOffset, vSize, vBytesRead)
		return
	return JEE_AhkBHexGet(&vData, vBytesRead)
}

;==================================================

;if file doesn't exist, creates a UTF-8 file
;to file: ANSI/UTF-8/UTF-16/UTF-16 BE
JEE_AhkBFileAppendUtf8(vText, vPath, vEnc="", vAddBOM=1)
{
	static Ptr := "Int", UPtr := "UInt"
	vBOM := Chr(239) Chr(187) Chr(191)
	if (vEnc = "")
		vEnc := JEE_AhkBFileGetEnc(vPath, "", vIsEmpty)
	if (vEnc = "")
		vEnc := "UTF-8"
	if (vIsEmpty || !FileExist(vPath)) && vAddBOM
		vText := vBOM vText
	if (vEnc = "ANSI") || (vEnc = "UTF-8")
		FileAppend, % vText, % "*" vPath
	else if (vEnc = "UTF-16")
	{
		vSize := JEE_AhkBUtf8ToUtf16(&vText, StrLen(vText))
		VarSetCapacity(vUtf16, vSize, 0)
		JEE_AhkBUtf8ToUtf16(&vText, StrLen(vText), &vUtf16, vSize)
		JEE_AhkBFileAppendBin(&vUtf16, vPath, vSize)
	}
	else if (vEnc = "UTF-16 BE")
	{
		vSize := JEE_AhkBUtf8ToUtf16(&vText, StrLen(vText))
		VarSetCapacity(vUtf16, vSize, 0)
		JEE_AhkBUtf8ToUtf16(&vText, StrLen(vText), &vUtf16, vSize)
		VarSetCapacity(vBE, vSize, 0)
		;LCMAP_BYTEREV := 0x800
		DllCall("kernel32\LCMapStringW", UInt,0, UInt,0x800, Str,vUtf16, Int,vSize/2, Str,vBE, Int,vSize/2)
		JEE_AhkBFileAppendBin(&vBE, vPath, vSize)
	}
}

;==================================================

JEE_AhkBFileReadBin(ByRef vData, vPath, vOffset=0, vSize=-1, ByRef vBytesRead=0)
{
	static Ptr := "Int", UPtr := "UInt"
	vBytesRead := 0
	if !FileExist(vPath)
		return 0
	FileGetSize, vSize2, % vPath
	if (vOffset > vSize2)
		return 0
	if (vSize = -1)
		vSize := vSize2
	if (vOffset + vSize > vSize2)
		vSize -= (vOffset + vSize - vSize2)

	;GENERIC_READ := 0x80000000 ;OPEN_EXISTING := 3
	;FILE_SHARE_WRITE := 0x2 ;FILE_SHARE_READ := 0x1
	hFile := DllCall("kernel32\CreateFile", Str,vPath, UInt,0x80000000, UInt,3, Ptr,0, UInt,3, UInt,0, Ptr,0, Ptr)
	if !hFile
		return 0
	VarSetCapacity(vData, vSize, 0)
	if vOffset
	{
		DllCall("kernel32\SetFilePointerEx", Ptr,hFile, Int64,vOffset, Int64P,vPointer, UInt,0) ;FILE_BEGIN := 0
		if !vPointer
		{
			DllCall("kernel32\CloseHandle", Ptr,hFile)
			return 0
		}
	}
	DllCall("kernel32\ReadFile", Ptr,hFile, Ptr,&vData, UInt,vSize, UIntP,vBytesRead, Ptr,0)
	DllCall("kernel32\CloseHandle", Ptr,hFile)
	return 1
}

;==================================================

JEE_AhkBFileReadBinAlt(ByRef vData, vPath, vOffset=0, vSize=-1, ByRef vBytesRead=0)
{
	static Ptr := "Int", UPtr := "UInt"
	vBytesRead := 0
	if !FileExist(vPath)
		return 0
	FileGetSize, vSize2, % vPath
	if (vOffset > vSize2)
		return 0
	vRet := 0
	if (vOffset = 0) && (vSize = -1)
	{
		FileRead, vData, % "*c " vPath
		if !ErrorLevel
			vBytesRead := vSize2, vRet := 1
	}
	else
	{
		if (vSize = -1)
			vSize := vSize2
		if (vOffset + vSize > vSize2)
			vSize -= (vOffset + vSize - vSize2)
		FileRead, vData2, % "*c " vPath
		if !ErrorLevel
			vBytesRead := vSize, vRet := 1
		VarSetCapacity(vData, vSize, 1)
		DllCall("kernel32\RtlMoveMemory", Ptr,&vData, Ptr,&vData2+vOffset, UPtr,vSize)
	}
	return vRet
}

;==================================================

;note: unlike NumPut, vAddr must be an address
JEE_AhkBFileAppendBin(vAddr, vPath, vSize=0)
{
	static Ptr := "Int", UPtr := "UInt"
	if (vSize <= 0)
		return
	SplitPath, vPath, vName, vDir, vExt, vNameNoExt, vDrive
	if !FileExist(vDir)
		FileCreateDir, % vDir

	;GENERIC_WRITE := 0x40000000 ;OPEN_ALWAYS := 4
	hFile := DllCall("kernel32\CreateFile", Str,vPath, UInt,0x40000000, UInt,0, Ptr,0, UInt,4, UInt,0, Ptr,0, Ptr)
	if (hFile <= 0)
	{
		MsgBox, % A_ThisFunc ": error:`r`n" vPath
		return 0
	}

	DllCall("kernel32\SetFilePointerEx", Ptr,hFile, Int64,0, Int64P,vPointer, UInt,2) ;FILE_END := 2
	if !vPointer
	{
		DllCall("kernel32\CloseHandle", Ptr,hFile)
		return 0
	}

	vRet := DllCall("kernel32\WriteFile", Ptr,hFile, Ptr,vAddr, UInt,vSize, UIntP,0, Ptr,0)
	DllCall("kernel32\CloseHandle", Ptr,hFile)
	return !!vRet
}

;==================================================

JEE_AhkBUtf16ToUtf8(vAddr16, vSize16, vAddr8=0, vSize8=-1)
{
	static Ptr := "Int", UPtr := "UInt"
	if (vAddr8 = 0)
		return DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,vAddr16, Int,vSize16/2, Ptr,0, Int,0, Ptr,0, Ptr,0)
	else
		DllCall("kernel32\WideCharToMultiByte", UInt,65001, UInt,0, Ptr,vAddr16, Int,vSize16/2, Ptr,vAddr8, Int,vSize8, Ptr,0, Ptr,0)
}

;==================================================

JEE_AhkBUtf8ToUtf16(vAddr8, vSize8=-1, vAddr16=0, vSize16=-1)
{
	static Ptr := "Int", UPtr := "UInt"
	if (vAddr16 = 0)
		return DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Ptr,vAddr8, Int,vSize8, Ptr,0, Int,0)*2 ;size of UTF-16 string in bytes
	else
		DllCall("kernel32\MultiByteToWideChar", UInt,65001, UInt,0, Ptr,vAddr8, Int,vSize8, Ptr,vAddr16, Int,vSize16)
}

;==================================================

JEE_AhkBUtf16ToAnsi(vAddr16, vSize16, vAddrA=0, vSizeA=-1, vBFC=1)
{
	static Ptr := "Int", UPtr := "UInt"
	;WC_NO_BEST_FIT_CHARS := 0x400
	vFlags := vBFC ? 0 : 0x400

	if (vAddrA = 0)
		return DllCall("kernel32\WideCharToMultiByte", UInt,0, UInt,vFlags, Ptr,vAddr16, Int,vSize16/2, Ptr,0, Int,0, Ptr,0, Ptr,0)
	else
		DllCall("kernel32\WideCharToMultiByte", UInt,0, UInt,vFlags, Ptr,vAddr16, Int,vSize16/2, Ptr,vAddrA, Int,vSizeA, Ptr,0, Ptr,0)
}

;==================================================

JEE_AhkBAnsiToUtf16(vAddrA, vSizeA, vAddr16=0, vSize16=-1)
{
	static Ptr := "Int", UPtr := "UInt"
	if (vAddr16 = 0)
		return DllCall("kernel32\MultiByteToWideChar", UInt,0, UInt,0, Ptr,vAddrA, Int,vSizeA, Ptr,0, Int,0)*2 ;size of UTF-16 string in bytes
	else
		DllCall("kernel32\MultiByteToWideChar", UInt,0, UInt,0, Ptr,vAddrA, Int,vSizeA, Ptr,vAddr16, Int,vSize16)
}

;==================================================

StrReplace(vText, vNeedle, vReplaceText="", ByRef vCount="", vLimit=-1)
{
	if (vLimit > 0)
	{
		StringGetPos, vPos, vText, % vNeedle, % "L" (vLimit+1)
		if vPos
			vSfx := SubStr(vText, vPos), vText := SubStr(vText, 1, vPos-1)
	}
	StringReplace, vOutput, vText, % vNeedle, % vReplaceText, UseErrorLevel
	vCount := ErrorLevel
	return vOutput vSfx
}

;==================================================

Trim(vText, vOmitChars=" `t")
{
	vOmitChars := RegExReplace(vOmitChars, "[\Q^-]\\E]", "\$0") ;make 4 chars literal: ^-]\
	return RegExReplace(vText, "^[" vOmitChars "]*|[" vOmitChars "]*$")
}

;==================================================

LTrim(vText, vOmitChars=" `t")
{
	vOmitChars := RegExReplace(vOmitChars, "[\Q^-]\\E]", "\$0") ;make 4 chars literal: ^-]\
	return RegExReplace(vText, "^[" vOmitChars "]*")
}

;==================================================

RTrim(vText, vOmitChars=" `t")
{
	vOmitChars := RegExReplace(vOmitChars, "[\Q^-]\\E]", "\$0") ;make 4 chars literal: ^-]\
	return RegExReplace(vText, "[" vOmitChars "]*$")
}

;==================================================
[EDIT:] Made changes to:
JEE_AhkBCtlGetTextUtf8(hCtl=0)
JEE_AhkBCtlGetSelTextUtf8(hCtl=0)
JEE_AhkBSendCharsUtf8(hWnd, vText)
JEE_AhkBCtlSetTextUtf8(hCtl, vText)
JEE_AhkBEditPasteUtf8(hCtl, vText, vCanUndo=1)
[hWnds should be always be the first parameter, and allowed specifying a blank hWnd to mean the active window or control.]

Re: Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI

Posted: 01 Oct 2017, 20:50
by jeeswg
Thank you Drugwash for your mention of AHK Basic versions of StrGet/StrPut, I didn't use these in the end because I'd already worked on various functions to achieve the same ends, however I was considering converting them, so that's saved me a lot of bother.

StrPut / StrGet - Scripts and Functions - AutoHotkey Community
https://autohotkey.com/board/topic/55299-strput-strget/

If anyone knows where the latest versions are, that would be good to know, or if any other new AutoHotkey_L (v1.1/v2) functions were rewritten for AutoHotkey Basic. Note: I recreated StrReplace and Trim/LTrim/RTrim, they are amongst the functions above.

Re: Unicode functions for AutoHotkey Basic / AutoHotkey x32 ANSI

Posted: 02 Oct 2017, 10:40
by Drugwash
In my updates.ahk script I build the global variable AW that resolves to A or W according to current AHK type (ANSI or Unicode). That would be a much cleaner way of appending API suffix where necessary, provided AW is declared as global in user functions. This however would be most useful în AHK Basic where only a few system libraries are automatically checked for suffix, whereas AHK_L seems to check all libraries (unless I misread the Help).

I myself find StrGet/StrPut quite complex for some operations so I use the two conversion APIs directly.

Trouble is, all the adapted functions will always perform poorer than the originals because interpreted code in adapted functions is slower than built-in code.