March 29, 2024, 12:55:04 AM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


String bytes

Started by fasecero, October 12, 2017, 12:43:12 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

fasecero

I'm pretty sure I saw something similar before but I could not find it and I did it again. This code show the bytes of a "null-terminated" string (string/wstring), and the bytes of an UNICODE_STRING, which is a "counted string", and there's no guarantee that it will be null-terminated.

The last 4 bytes of an UNICODE_STRING always points to the address of a wstring. You can visualize each string type below.



'------------------------------------------
' WINAPI
'------------------------------------------

$INCLUDE "windowssdk.inc"

DECLARE RtlInitUnicodeString(pointer DestinationString, wstring SourceString)

type UNICODE_STRING
USHORT Length
USHORT MaximumLength
PWSTR  Buffer
endtype

'------------------------------------------
' BASE WSTRING
'------------------------------------------

WSTRING base = L"HELLO WORLD"

'------------------------------------------
' ENTRY POINT
'------------------------------------------

PRINT
PRINT base
print

string ansi = W2S(base)
print PrintString(ansi)

print
print PrintWString(base)
PRINT

UNICODE_STRING unic_str
InitUnicodeString(unic_str, base)
PRINT PrintUnicodeString(unic_str)
PRINT

DO:UNTIL INKEY$ <> ""

'------------------------------------------
' AUXILIAR FUNC
'------------------------------------------

SUB InitUnicodeString(pointer DestinationString, wstring SourceString)
UINT hInst=LoadLibrary("ntdll.dll")

IF hInst THEN
UINT proc = GetProcAddress(hInst,"RtlInitUnicodeString")

IF proc THEN
!<RtlInitUnicodeString>proc(DestinationString, SourceString)
ENDIF

FreeLibrary(hInst)
ENDIF

ENDSUB

SUB PrintString(string ansi), string
string bytes = "STRING: "
pointer p = &ansi + 0
char a = 0

DO
a = *<char>p
int t = ASC(chr$(a))

IF t THEN
bytes += STR$(t) + " -"
ELSE
bytes += STR$(t)
ENDIF

p+=1
UNTIL a = 0

RETURN bytes
ENDSUB

SUB PrintWString(wstring ansi), string
string bytes = "WSTRING: "
pointer p = &ansi + 0
char a = 0
char b = 0

DO
a = *<char>p
int t = ASC(chr$(a))

b = *<char>(p+1)
int t2 = ASC(chr$(b))

IF t THEN
bytes += STR$(t) + " -" + STR$(t2) + " -"
ELSE
bytes += STR$(t) + " -" + STR$(t2)
ENDIF

p+=2
UNTIL a = 0 AND b = 0

RETURN bytes
ENDSUB

SUB PrintUnicodeString(UNICODE_STRING unic_str), string
string bytes = "COUNTED STRING: "
pointer p = &unic_str + 0
char a = 0

INT lenght = LEN(unic_str)

INT j

FOR j = 1 TO lenght
a = *<char>p
int t = ASC(chr$(a))

IF j < lenght THEN
bytes += STR$(t) + " -"
ELSE
bytes += STR$(t)
ENDIF

p+=1
NEXT j

RETURN bytes
ENDSUB


fasecero

Small Addition. Now it shows also the content of the wide-character string inside UNICODE_STRING.


'------------------------------------------
' WINAPI
'------------------------------------------

$INCLUDE "windowssdk.inc"

DECLARE RtlInitUnicodeString(pointer DestinationString, wstring SourceString)

type UNICODE_STRING
USHORT Length
USHORT MaximumLength
PWSTR  Buffer
endtype

'------------------------------------------
' BASE WSTRING
'------------------------------------------

WSTRING base = L"HELLO WORLD"

'------------------------------------------
' ENTRY POINT
'------------------------------------------

PRINT
PRINT base
print

string ansi = W2S(base)
print PrintString(ansi)

print
print PrintWString(base)
PRINT

UNICODE_STRING unic_str
InitUnicodeString(unic_str, base)
string unic = PrintUnicodeString(unic_str)
PRINT unic
PRINT

string mem_address = ExtractMemAddress(unic)

IF LEN(mem_address) THEN
PRINT "    Memory address [ " + mem_address + " ] points to: "
PRINT "    " + PrintUnicodeStringMemAddress(unic_str)
ENDIF

DO:UNTIL INKEY$ <> ""

'------------------------------------------
' AUXILIAR FUNC
'------------------------------------------

SUB PrintUnicodeStringMemAddress(UNICODE_STRING unic_str), string
string bytes = ""
pointer p = unic_str.Buffer
char a = 0

INT lenght = unic_str.MaximumLength

INT j

FOR j = 1 TO lenght
a = *<char>p
int t = ASC(chr$(a))

IF j < lenght THEN
bytes += STR$(t) + " -"
ELSE
bytes += STR$(t)
ENDIF

p+=1
NEXT j

RETURN bytes
ENDSUB

SUB ExtractMemAddress(string unic), STRING
string result = ""

INT pos = 0

IF LEN(unic) THEN
INT j

FOR j = 1 TO 4
pos = INSTR(unic, "-", pos + 1)

IF j = 4 AND pos > 0 THEN
result = MID$(unic, pos + 2)
ENDIF
NEXT j
ENDIF

RETURN result
ENDSUB

SUB InitUnicodeString(pointer DestinationString, wstring SourceString)
UINT hInst=LoadLibrary("ntdll.dll")

IF hInst THEN
UINT proc = GetProcAddress(hInst,"RtlInitUnicodeString")

IF proc THEN
!<RtlInitUnicodeString>proc(DestinationString, SourceString)
ENDIF

FreeLibrary(hInst)
ENDIF

ENDSUB

SUB PrintString(string ansi), string
string bytes = "STRING: "
pointer p = &ansi + 0
char a = 0

DO
a = *<char>p
int t = ASC(chr$(a))

IF t THEN
bytes += STR$(t) + " -"
ELSE
bytes += STR$(t)
ENDIF

p+=1
UNTIL a = 0

RETURN bytes
ENDSUB

SUB PrintWString(wstring ansi), string
string bytes = "WSTRING: "
pointer p = &ansi + 0
char a = 0
char b = 0

DO
a = *<char>p
int t = ASC(chr$(a))

b = *<char>(p+1)
int t2 = ASC(chr$(b))

IF t THEN
bytes += STR$(t) + " -" + STR$(t2) + " -"
ELSE
bytes += STR$(t) + " -" + STR$(t2)
ENDIF

p+=2
UNTIL a = 0 AND b = 0

RETURN bytes
ENDSUB

SUB PrintUnicodeString(UNICODE_STRING unic_str), string
string bytes = "COUNTED STRING: "
pointer p = &unic_str + 0
char a = 0

INT lenght = LEN(unic_str)

INT j

FOR j = 1 TO lenght
a = *<char>p
int t = ASC(chr$(a))

IF j < lenght THEN
bytes += STR$(t) + " -"
ELSE
bytes += STR$(t)
ENDIF

p+=1
NEXT j

RETURN bytes
ENDSUB


fasecero

I really wanted to program today ::) gui version...



'------------------------------------------
' BUFFER SIZE
'------------------------------------------

CONST BUFF_SIZE = 10000 ' if something goes wrong because you r using a looong text, increase this value

'------------------------------------------
' WINAPI
'------------------------------------------

$INCLUDE "windowssdk.inc"

DECLARE RtlInitUnicodeString(pointer DestinationString, wstring SourceString)
DECLARE RtlFreeUnicodeString(pointer DestinationString)

type UNICODE_STRING
USHORT Length
USHORT MaximumLength
PWSTR  Buffer
endtype

'------------------------------------------
' VARIABLES
'------------------------------------------

ISTRING buffer[2*BUFF_SIZE]
iwstring buff[BUFF_SIZE]
UNICODE_STRING unic_str

'------------------------------------------
' INTERFACE
'------------------------------------------

CONST STATIC_1 = 1
CONST EDIT_2 = 2
CONST STATIC_3 = 3
CONST EDIT_5 = 5
CONST STATIC_6 = 6
CONST EDIT_7 = 7
CONST STATIC_8 = 8
CONST EDIT_9 = 9
DIALOG d1
CREATEDIALOG d1,0,0,716,385,0x80C80080,0,"String bytes",&d1_handler
CONTROL d1,@STATIC,"Type your text here",21,15,120,18,0x5000010B,STATIC_1
CONTROL d1,@EDIT,"",143,12,549,59,0x50800004,EDIT_2
CONTROL d1,@STATIC,"String",28,84,70,20,0x5000010B,STATIC_3
CONTROL d1,@EDIT,"",142,82,549,116,0x50A00804,EDIT_5
CONTROL d1,@STATIC,"Wstring",25,212,70,20,0x5000010B,STATIC_6
CONTROL d1,@EDIT,"",139,210,552,118,0x50A00804,EDIT_7
CONTROL d1,@STATIC,"UNICODE_STRING",23,341,114,20,0x5000010B,STATIC_8
CONTROL d1,@EDIT,"",140,340,551,20,0x50800800,EDIT_9

'------------------------------------------
' ENTRY POINT
'------------------------------------------

DOMODAL d1

'------------------------------------------
' PROCEDURE
'------------------------------------------

SUB d1_handler
SELECT @MESSAGE
CASE @IDINITDIALOG
CENTERWINDOW d1
/* Initialize any controls here */
InitUnicodeString(unic_str, L"")
CASE @IDCLOSEWINDOW
FreeUnicodeString(unic_str)
CLOSEDIALOG d1,@IDOK
CASE @IDCONTROL
SELECT @CONTROLID
CASE EDIT_2
/* respond to edit notifications here */
SELECT @NOTIFYCODE
CASE @ENCHANGE
buffer = GETCONTROLTEXT(d1, EDIT_2)
DoWork(buffer)
ENDSELECT
ENDSELECT
ENDSELECT
RETURN
ENDSUB

'------------------------------------------
' INPUT TEXT CHANGE
'------------------------------------------

SUB DoWork(string base)
SETCONTROLTEXT(d1, EDIT_5, PrintString(base))

buff = S2W(base)
SETCONTROLTEXT(d1, EDIT_7, PrintWString(buff))

FreeUnicodeString(unic_str)
InitUnicodeString(unic_str, buff)
SETCONTROLTEXT(d1, EDIT_9, PrintUnicodeString(unic_str))
ENDSUB

'------------------------------------------
' AUX
'------------------------------------------

SUB PrintUnicodeStringMemAddress(UNICODE_STRING unic_str), string
istring bytes[2*BUFF_SIZE] = ""
pointer p = unic_str.Buffer
char a = 0

INT lenght = unic_str.MaximumLength

INT j

FOR j = 1 TO lenght
a = *<char>p
int t = ASC(chr$(a))

IF j < lenght THEN
bytes += STR$(t) + " -"
ELSE
bytes += STR$(t)
ENDIF

p+=1
NEXT j

RETURN bytes
ENDSUB

SUB ExtractMemAddress(string unic), STRING
istring result[2*BUFF_SIZE] = ""

INT pos = 0

IF LEN(unic) THEN
INT j

FOR j = 1 TO 4
pos = INSTR(unic, "-", pos + 1)

IF j = 4 AND pos > 0 THEN
result = MID$(unic, pos + 2)
ENDIF
NEXT j
ENDIF

RETURN result
ENDSUB

SUB InitUnicodeString(pointer DestinationString, wstring SourceString)
UINT hInst=LoadLibrary("ntdll.dll")

IF hInst THEN
UINT proc = GetProcAddress(hInst,"RtlInitUnicodeString")

IF proc THEN
!<RtlInitUnicodeString>proc(DestinationString, SourceString)
ENDIF

FreeLibrary(hInst)
ENDIF
ENDSUB

SUB FreeUnicodeString(pointer DestinationString)
UINT hInst=LoadLibrary("ntdll.dll")

IF hInst THEN
UINT proc = GetProcAddress(hInst,"RtlFreeUnicodeString")

IF proc THEN
!<RtlFreeUnicodeString>proc(DestinationString)
ENDIF

FreeLibrary(hInst)
ENDIF
ENDSUB

SUB PrintString(string ansi), string
istring bytes[2*BUFF_SIZE] = ""
pointer p = &ansi + 0
char a = 0

DO
a = *<char>p
int t = ASC(chr$(a))

IF t THEN
bytes += STR$(t) + " -"
ELSE
bytes += STR$(t)
ENDIF

p+=1
UNTIL a = 0

RETURN bytes
ENDSUB

SUB PrintWString(wstring ansi), string
istring bytes[2*BUFF_SIZE] = ""
pointer p = &ansi + 0
char a = 0
char b = 0

DO
a = *<char>p
int t = ASC(chr$(a))

b = *<char>(p+1)
int t2 = ASC(chr$(b))

IF t THEN
bytes += STR$(t) + " -" + STR$(t2) + " -"
ELSE
bytes += STR$(t) + " -" + STR$(t2)
ENDIF

p+=2
UNTIL a = 0 AND b = 0

RETURN bytes
ENDSUB

SUB PrintUnicodeString(UNICODE_STRING unic_str), string
istring bytes[2*BUFF_SIZE] = ""
pointer p = &unic_str + 0
char a = 0

INT lenght = LEN(unic_str)

INT j

FOR j = 1 TO lenght
a = *<char>p
int t = ASC(chr$(a))

IF j < lenght THEN
bytes += STR$(t) + " -"
ELSE
bytes += STR$(t)
ENDIF

p+=1
NEXT j

RETURN bytes
ENDSUB




Andy

fasecero,

I like this one, it does give me a better understanding of strings especially wstrings. Looking at this shows me wstrings are very much like registry multi string in that each character is followed by a NULL, and the whole string is terminated by two extra nulls.

In registry multi strings, each line is followed by a NULL, and the whole multi string is terminated by two extra nulls.

Like this, maybe this post should be moved to tutorials?
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

fasecero

Thanks, Andy! Actually for me it was a surprise the two extra nulls, I do not know why, but I always assumed that the end of wstrings were limited by a single null and the next byte was simply a random value.

I've cleaned it up a bit, moved a local buffer shared by several functions to global scope to save resources, and also delete a couple of unused functions from the dos version.


'------------------------------------------
' BUFFER SIZE
'------------------------------------------

CONST BUFF_SIZE = 10000 ' if something goes wrong because you r using a looong text, increase this value

'------------------------------------------
' WINAPI
'------------------------------------------

$INCLUDE "windowssdk.inc"

DECLARE RtlInitUnicodeString(pointer DestinationString, wstring SourceString)
DECLARE RtlFreeUnicodeString(pointer DestinationString)

type UNICODE_STRING
USHORT Length
USHORT MaximumLength
PWSTR  Buffer
endtype

'------------------------------------------
' VARIABLES
'------------------------------------------

ISTRING buffer[2*BUFF_SIZE]
iwstring buff[BUFF_SIZE]
UNICODE_STRING unic_str
istring bytes[2*BUFF_SIZE] = ""

'------------------------------------------
' INTERFACE
'------------------------------------------

CONST STATIC_1 = 1
CONST EDIT_2 = 2
CONST STATIC_3 = 3
CONST EDIT_5 = 5
CONST STATIC_6 = 6
CONST EDIT_7 = 7
CONST STATIC_8 = 8
CONST EDIT_9 = 9
DIALOG d1
CREATEDIALOG d1,0,0,716,385,0x80C80080,0,"String bytes",&d1_handler
CONTROL d1,@STATIC,"Type your text here",21,15,120,18,0x5000010B,STATIC_1
CONTROL d1,@EDIT,"",143,12,549,59,0x50800004,EDIT_2
CONTROL d1,@STATIC,"String",28,84,70,20,0x5000010B,STATIC_3
CONTROL d1,@EDIT,"",142,82,549,116,0x50A00804,EDIT_5
CONTROL d1,@STATIC,"Wstring",25,212,70,20,0x5000010B,STATIC_6
CONTROL d1,@EDIT,"",139,210,552,118,0x50A00804,EDIT_7
CONTROL d1,@STATIC,"UNICODE_STRING",23,341,114,20,0x5000010B,STATIC_8
CONTROL d1,@EDIT,"",140,340,551,20,0x50800800,EDIT_9

'------------------------------------------
' ENTRY POINT
'------------------------------------------

DOMODAL d1

'------------------------------------------
' PROCEDURE
'------------------------------------------

SUB d1_handler
SELECT @MESSAGE
CASE @IDINITDIALOG
CENTERWINDOW d1
/* Initialize any controls here */
InitUnicodeString(unic_str, L"")
CASE @IDCLOSEWINDOW
FreeUnicodeString(unic_str)
CLOSEDIALOG d1,@IDOK
CASE @IDCONTROL
SELECT @CONTROLID
CASE EDIT_2
/* respond to edit notifications here */
SELECT @NOTIFYCODE
CASE @ENCHANGE
buffer = GETCONTROLTEXT(d1, EDIT_2)
DoWork(buffer)
ENDSELECT
ENDSELECT
ENDSELECT
RETURN
ENDSUB

'------------------------------------------
' INPUT TEXT CHANGE
'------------------------------------------

SUB DoWork(string base)
SETCONTROLTEXT(d1, EDIT_5, PrintString(base))

buff = S2W(base)
SETCONTROLTEXT(d1, EDIT_7, PrintWString(buff))

FreeUnicodeString(unic_str)
InitUnicodeString(unic_str, buff)
SETCONTROLTEXT(d1, EDIT_9, PrintUnicodeString(unic_str))
ENDSUB

'------------------------------------------
' AUX
'------------------------------------------

SUB InitUnicodeString(pointer DestinationString, wstring SourceString)
UINT hInst=LoadLibrary("ntdll.dll")

IF hInst THEN
UINT proc = GetProcAddress(hInst,"RtlInitUnicodeString")

IF proc THEN
!<RtlInitUnicodeString>proc(DestinationString, SourceString)
ENDIF

FreeLibrary(hInst)
ENDIF
ENDSUB

SUB FreeUnicodeString(pointer DestinationString)
UINT hInst=LoadLibrary("ntdll.dll")

IF hInst THEN
UINT proc = GetProcAddress(hInst,"RtlFreeUnicodeString")

IF proc THEN
!<RtlFreeUnicodeString>proc(DestinationString)
ENDIF

FreeLibrary(hInst)
ENDIF
ENDSUB

SUB PrintString(string ansi), string
bytes = ""
pointer p = &ansi + 0
char a = 0

DO
a = *<char>p
int t = ASC(chr$(a))

IF t THEN
bytes += STR$(t) + " -"
ELSE
bytes += STR$(t)
ENDIF

p+=1
UNTIL a = 0

RETURN bytes
ENDSUB

SUB PrintWString(wstring unic), string
bytes = ""
pointer p = &unic + 0
char a = 0
char b = 0

DO
a = *<char>p
int t = ASC(chr$(a))

b = *<char>(p+1)
int t2 = ASC(chr$(b))

IF t THEN
bytes += STR$(t) + " -" + STR$(t2) + " -"
ELSE
bytes += STR$(t) + " -" + STR$(t2)
ENDIF

p+=2
UNTIL a = 0 AND b = 0

RETURN bytes
ENDSUB

SUB PrintUnicodeString(UNICODE_STRING unic_str), string
bytes = ""
pointer p = &unic_str + 0
char a = 0

INT lenght = LEN(unic_str)

INT j

FOR j = 1 TO lenght
a = *<char>p
int t = ASC(chr$(a))

IF j < lenght THEN
bytes += STR$(t) + " -"
ELSE
bytes += STR$(t)
ENDIF

p+=1
NEXT j

RETURN bytes
ENDSUB


fasecero

Final version, at least I think so. Spaces (32 or 32-0) are replaced by spaces in the output also, so it is easier to distinguish the bytes in a multi-word text. Input edit now supports unicode characters, try for example: ❤ ☀ ☆ â˜, ☻ ♞ ☯ ☭ ☢


'------------------------------------------
' BUFFER SIZE
'------------------------------------------

CONST BUFF_SIZE = 10000 ' if something goes wrong because you r using a looong text, increase this value

'------------------------------------------
' WINAPI
'------------------------------------------

$INCLUDE "windowssdk.inc"

DECLARE RtlInitUnicodeString(pointer DestinationString, wstring SourceString)
DECLARE RtlFreeUnicodeString(pointer DestinationString)

type UNICODE_STRING
USHORT Length
USHORT MaximumLength
PWSTR  Buffer
endtype

'------------------------------------------
' VARIABLES
'------------------------------------------

ISTRING buffer[2*BUFF_SIZE]
iwstring buff[BUFF_SIZE]
UNICODE_STRING unic_str
istring bytes[2*BUFF_SIZE]
INT guiFont = 0

'------------------------------------------
' INTERFACE
'------------------------------------------

CONST STATIC_1 = 1
CONST EDIT_2 = 2
CONST STATIC_3 = 3
CONST EDIT_5 = 5
CONST STATIC_6 = 6
CONST EDIT_7 = 7
CONST STATIC_8 = 8
CONST EDIT_9 = 9
DIALOG d1
CREATEDIALOG d1,0,0,716,385,0x80C80080,0,"String bytes",&d1_handler
CONTROL d1,@STATIC,"Type your text here",21,15,120,18,0x5000010B,STATIC_1
'CONTROL d1,@EDIT,"",143,12,549,59,0x50800004,EDIT_2
CONTROL d1,@STATIC,"String",28,84,70,20,0x5000010B,STATIC_3
CONTROL d1,@EDIT,"",142,82,549,116,0x50A00804,EDIT_5
CONTROL d1,@STATIC,"Wstring",25,212,70,20,0x5000010B,STATIC_6
CONTROL d1,@EDIT,"",139,210,552,118,0x50A00804,EDIT_7
CONTROL d1,@STATIC,"UNICODE_STRING",23,341,114,20,0x5000010B,STATIC_8
CONTROL d1,@EDIT,"",140,340,551,20,0x50800800,EDIT_9

'------------------------------------------
' ENTRY POINT
'------------------------------------------

DOMODAL d1

'------------------------------------------
' PROCEDURE
'------------------------------------------

SUB d1_handler
SELECT @MESSAGE
CASE @IDINITDIALOG
CENTERWINDOW d1
/* Initialize any controls here */
InitUnicodeString(unic_str, L"")
guiFont = CreateGuiFont()
UnicodeEditCreate(d1, EDIT_2, 143 , 12, 549, 59, guiFont)
CASE @IDCLOSEWINDOW
FreeUnicodeString(unic_str)
DeleteGuiFont(guiFont)
CLOSEDIALOG d1,@IDOK
CASE @IDCONTROL
SELECT @CONTROLID
CASE EDIT_2
/* respond to edit notifications here */
SELECT @NOTIFYCODE
CASE @ENCHANGE
UnicodeEditGetText(d1, EDIT_2, buff, BUFF_SIZE)
DoWork(buff)
ENDSELECT
ENDSELECT
ENDSELECT
RETURN
ENDSUB

'------------------------------------------
' INPUT TEXT CHANGE
'------------------------------------------

SUB DoWork(wstring base)
buffer = W2S(base)
SETCONTROLTEXT(d1, EDIT_5, PrintString(buffer))

SETCONTROLTEXT(d1, EDIT_7, PrintWString(base))

FreeUnicodeString(unic_str)
InitUnicodeString(unic_str, buff)
SETCONTROLTEXT(d1, EDIT_9, PrintUnicodeString(unic_str))
ENDSUB

'------------------------------------------
' UNICODE EDIT CONTROL
'------------------------------------------

SUB UnicodeEditCreate(window w, INT ctrlID, INT x, INT y, INT width, INT height, INT font)
INT dwStyles = WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE
INT hwndEDIT = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT",NULL, dwStyles, x, y, width, height, w.hwnd, ctrlID, GetModuleHandle(0), NULL)
SendMessageW(hwndEDIT, WM_SETFONT, font, MAKELPARAM(TRUE,0) )
ENDSUB

SUB UnicodeEditGetText(window w, INT ctrlID, pointer buffer, INT maxCount)
INT hwndEDIT = GetDlgItem(w.hwnd, ctrlID)
GetWindowTextW(hwndEDIT, buffer, maxCount)
ENDSUB

'------------------------------------------
' GUI FONT
'------------------------------------------

SUB CreateGuiFont(), INT
NONCLIENTMETRICSW metrics
metrics.cbSize = LEN(metrics)
SystemParametersInfow(SPI_GETNONCLIENTMETRICS, LEN(metrics), &metrics, 0)

RETURN CreateFontIndirectW(&metrics.lfSmCaptionFont)
ENDSUB

SUB DeleteGuiFont(INT font)
IF font THEN DeleteObject(font)
ENDSUB

'------------------------------------------
' AUX
'------------------------------------------

SUB InitUnicodeString(pointer DestinationString, wstring SourceString)
UINT hInst=LoadLibrary("ntdll.dll")

IF hInst THEN
UINT proc = GetProcAddress(hInst,"RtlInitUnicodeString")

IF proc THEN
!<RtlInitUnicodeString>proc(DestinationString, SourceString)
ENDIF

FreeLibrary(hInst)
ENDIF
ENDSUB

SUB FreeUnicodeString(pointer DestinationString)
UINT hInst=LoadLibrary("ntdll.dll")

IF hInst THEN
UINT proc = GetProcAddress(hInst,"RtlFreeUnicodeString")

IF proc THEN
!<RtlFreeUnicodeString>proc(DestinationString)
ENDIF

FreeLibrary(hInst)
ENDIF
ENDSUB

SUB PrintString(string ansi), string
bytes = ""
pointer p = &ansi + 0
char a = 0

DO
a = *<char>p
int t = ASC(chr$(a))

IF t = 32 THEN
bytes += "      "
ELSE
IF t THEN
bytes += STR$(t) + " "
ELSE
bytes += STR$(t)
ENDIF
ENDIF

p+=1
UNTIL a = 0

RETURN bytes
ENDSUB

SUB PrintWString(wstring unic), string
bytes = ""
pointer p = &unic + 0
char a = 0
char b = 0

DO
a = *<char>p
int t = ASC(chr$(a))

b = *<char>(p+1)
int t2 = ASC(chr$(b))

IF t = 32 AND t2 = 0 THEN
bytes += "         "
ELSE
IF t > 0 or t2 > 0 THEN
bytes += STR$(t) + " " + STR$(t2) + " "
ELSE
bytes += STR$(t) + " " + STR$(t2)
ENDIF
ENDIF

p+=2
UNTIL a = 0 AND b = 0

RETURN bytes
ENDSUB

SUB PrintUnicodeString(UNICODE_STRING unic_str), string
bytes = ""
pointer p = &unic_str + 0
char a = 0

INT lenght = LEN(unic_str)

INT j

FOR j = 1 TO lenght
a = *<char>p
int t = ASC(chr$(a))

IF j < lenght THEN
bytes += STR$(t) + " -"
ELSE
bytes += STR$(t)
ENDIF

p+=1
NEXT j

RETURN bytes
ENDSUB


fasecero

A small update. Now it shows the hexagesimal string.


'------------------------------------------
' BUFFER SIZE
'------------------------------------------

CONST BUFF_SIZE = 10000 ' if something goes wrong because you r using a looong text, increase this value

'------------------------------------------
' WINAPI
'------------------------------------------

$INCLUDE "windowssdk.inc"

'------------------------------------------
' VARIABLES
'------------------------------------------

ISTRING buffer[2*BUFF_SIZE]
iwstring buff[BUFF_SIZE]
istring bytes[2*BUFF_SIZE]
istring hexString[4*BUFF_SIZE+6]
INT guiFont = 0

'------------------------------------------
' INTERFACE
'------------------------------------------

CONST STATIC_1 = 1
CONST EDIT_2 = 2
CONST STATIC_3 = 3
CONST EDIT_5 = 5
CONST STATIC_6 = 6
CONST EDIT_7 = 7
CONST STATIC_8 = 8
CONST EDIT_9 = 9
DIALOG d1
CREATEDIALOG d1,0,0,716,490,0x80C80080,0,"String bytes",&d1_handler
CONTROL d1,@STATIC,"Type your text here",21,15,120,18,0x5000010B,STATIC_1
'CONTROL d1,@EDIT,"",143,12,549,59,0x50800004,EDIT_2
CONTROL d1,@STATIC,"String",28,84,70,20,0x5000010B,STATIC_3
CONTROL d1,@EDIT,"",142,82,549,116,0x50A00804,EDIT_5
CONTROL d1,@STATIC,"Wstring",25,212,70,20,0x5000010B,STATIC_6
CONTROL d1,@EDIT,"",139,210,552,118,0x50A00804,EDIT_7
CONTROL d1,@STATIC,"Hex String",23,341,134,20,0x5000010B,STATIC_8
CONTROL d1,@EDIT,"",140,340,551,118,0x50A00804,EDIT_9

'------------------------------------------
' ENTRY POINT
'------------------------------------------

DOMODAL d1

'------------------------------------------
' PROCEDURE
'------------------------------------------

SUB d1_handler
SELECT @MESSAGE
CASE @IDINITDIALOG
CENTERWINDOW d1
/* Initialize any controls here */
guiFont = CreateGuiFont()
UnicodeEditCreate(d1, EDIT_2, 143 , 12, 549, 59, guiFont)
CASE @IDCLOSEWINDOW
DeleteGuiFont(guiFont)
CLOSEDIALOG d1,@IDOK
CASE @IDCONTROL
SELECT @CONTROLID
CASE EDIT_2
/* respond to edit notifications here */
SELECT @NOTIFYCODE
CASE @ENCHANGE
UnicodeEditGetText(d1, EDIT_2, buff, BUFF_SIZE)
DoWork(buff)
ENDSELECT
ENDSELECT
ENDSELECT
RETURN
ENDSUB

'------------------------------------------
' INPUT TEXT CHANGE
'------------------------------------------

SUB DoWork(wstring base)
buffer = W2S(base)
SETCONTROLTEXT(d1, EDIT_5, PrintString(buffer))

SETCONTROLTEXT(d1, EDIT_7, PrintWString(base))

SETCONTROLTEXT(d1, EDIT_9, PrintHexString(base))
ENDSUB

'------------------------------------------
' UNICODE EDIT CONTROL
'------------------------------------------

SUB UnicodeEditCreate(window w, INT ctrlID, INT x, INT y, INT width, INT height, INT font)
INT dwStyles = WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_WANTRETURN
INT hwndEDIT = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT",NULL, dwStyles, x, y, width, height, w.hwnd, ctrlID, GetModuleHandle(0), NULL)
SendMessageW(hwndEDIT, WM_SETFONT, font, MAKELPARAM(TRUE,0) )
ENDSUB

SUB UnicodeEditGetText(window w, INT ctrlID, pointer buffer, INT maxCount)
INT hwndEDIT = GetDlgItem(w.hwnd, ctrlID)
GetWindowTextW(hwndEDIT, buffer, maxCount)
ENDSUB

'------------------------------------------
' GUI FONT
'------------------------------------------

SUB CreateGuiFont(), INT
NONCLIENTMETRICSW metrics
metrics.cbSize = LEN(metrics)
SystemParametersInfow(SPI_GETNONCLIENTMETRICS, LEN(metrics), &metrics, 0)

RETURN CreateFontIndirectW(&metrics.lfSmCaptionFont)
ENDSUB

SUB DeleteGuiFont(INT font)
IF font THEN DeleteObject(font)
ENDSUB

'------------------------------------------
' AUX
'------------------------------------------

SUB PrintString(string ansi), string
bytes = ""
pointer p = &ansi + 0
char a = 0

DO
a = *<char>p
int t = ASC(chr$(a))

IF t THEN
bytes += STR$(t) + " "
ELSE
bytes += STR$(t)
ENDIF

p+=1
UNTIL a = 0

RETURN bytes
ENDSUB

SUB PrintWString(wstring unic), string
bytes = ""
pointer p = &unic + 0
char a = 0
char b = 0

DO
a = *<char>p
int t = ASC(chr$(a))

b = *<char>(p+1)
int t2 = ASC(chr$(b))

IF t > 0 or t2 > 0 THEN
bytes += STR$(t) + ", " + STR$(t2) + ", "
ELSE
bytes += STR$(t) + ", " + STR$(t2)
ENDIF

p+=2
UNTIL a = 0 AND b = 0

RETURN bytes
ENDSUB

SUB PrintHexString(wstring unic), string
hexString = "0x"
pointer p = &unic + 0
char a = 0
char b = 0

DO
a = *<char>p
int t = ASC(chr$(a))
hexString+= GetHEX(t)

b = *<char>(p+1)
int t2 = ASC(chr$(b))
hexString+= GetHEX(t2)

p+=2
UNTIL a = 0 AND b = 0

SETCONTROLTEXT d1, STATIC_8, "Hex String (" + LTRIM$(STR$(len(hexString))) + ")           "

RETURN hexString
ENDSUB

SUB GetHEX(int t), string
istring hex[10] = HEX$(t)
if LEN(hex) = 1 THEN hex = "0" + hex
RETURN hex
ENDSUB


Hex strings can be handy to load literal unicodes. Let's suppose we want to load some unicode data in one or more controls

Quotehello how are you
Σωκρᾰ́Ï,,ηÏ,
❤ ☀ ☆ â˜, ☻ ♞ ☯ ☭ ☢

Instead of setting up each wstring within a DATABLOCK and read it, it is much easier to use hex strings directly.

IWSTRING text[10000] = L""
text += HexStringToWstring("0x680065006C006C006F00200068006F0077002000610072006500200079006F0075000000")
text += L"\n"
text += HexStringToWstring("0xA303C903BA03C103B01F0103C403B703C2032C000000")
text += L"\n"
text += HexStringToWstring("0x642720000026200006262000022620003B2620005E2620002F2620002D26200022260000")
text += L"\n"
UnicodeEditSetText(w1, EDIT_1, text)


Complete sample


$INCLUDE "windowssdk.inc"

$DEFINE MAX_UNICHARS 1000  ' MAXIMUN NUMBER OF UNICODE CHARACTER ALLOWED/WANTED
IWSTRING buffer[MAX_UNICHARS]

CONST EDIT_1 = 1
WINDOW w1
OPENWINDOW w1,0,0,600,400,@MINBOX|@MAXBOX|@SIZE,NULL,"Simple Window",&w1_handler
UnicodeEditCreate(w1, EDIT_1, 30, 30, 520, 280, 1)

OnInit()

' main loop
WAITUNTIL w1 = 0
END

' window procedure
SUB w1_handler(), INT
SELECT @MESSAGE
CASE @IDCREATE
CENTERWINDOW w1

CASE @IDCLOSEWINDOW
CLOSEWINDOW w1
ENDSELECT

RETURN 0
ENDSUB

SUB OnInit()
SETFONT w1,"Segoe UI",11,400,0,EDIT_1

IWSTRING text[10000] = L""
text += HexStringToWstring("0x680065006C006C006F00200068006F0077002000610072006500200079006F0075000000")
text += L"\n"
text += HexStringToWstring("0xA303C903BA03C103B01F0103C403B703C2032C000000")
text += L"\n"
text += HexStringToWstring("0x642720000026200006262000022620003B2620005E2620002F2620002D26200022260000")
text += L"\n"
UnicodeEditSetText(w1, EDIT_1, text)
ENDSUB

'------------------------------------------
' CONVERT HEX STRING TO UNICODE STRING
'------------------------------------------

SUB HexStringToWstring(string hexString), WSTRING
iwstring buff[MAX_UNICHARS] = L""
INT pos = 2
string hex1, hex2

' some basic format check
IF LEN(hexString) <= 6 THEN RETURN L""
IF LEFT$(hexString, 2) <> "0x" THEN RETURN L""

DO
hex1 = MID$(hexString, pos + 1, 2)
hex2 = MID$(hexString, pos + 3, 2)

char t = strtol(hex1, NULL, 16)
char t2 = strtol(hex2, NULL, 16)

buff += GetUnicodeChar(t, t2)

pos+=4
UNTIL hex1 = "00" AND hex2 = "00"

RETURN buff
ENDSUB

SUB GetUnicodeChar(char byte1, char byte2, OPT char byte3 = 0, OPT char byte4 = 0, OPT char byte5 = 0, OPT char byte6 = 0), wstring
iwstring c[8] : pointer p = &c + 0
*<char>p = byte1 : p+=1
*<char>p = byte2 : p+=1
*<char>p = byte3 : p+=1
*<char>p = byte4 : p+=1
*<char>p = byte5 : p+=1
*<char>p = byte6 : p+=1
*<char>p = 0 : p+=1
*<char>p = 0
RETURN c
ENDSUB

'------------------------------------------
' UNICODE EDIT CONTROL
'------------------------------------------

SUB UnicodeEditCreate(window w, INT ctrlID, INT x, INT y, INT width, INT height, INT multiline)
INT dwStyles = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP
IF multiline THEN dwStyles = dwStyles | WS_VSCROLL | ES_MULTILINE | ES_WANTRETURN
INT hwndEDIT = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT",NULL, dwStyles, x, y, width, height, w.hwnd, ctrlID, GetModuleHandle(0), NULL)
ENDSUB

SUB UnicodeEditSetText(window w, INT ctrlID, pointer buffer)
INT hwndEDIT = GetDlgItem(w.hwnd, ctrlID)
SetWindowTextW(hwndEDIT, buffer)
ENDSUB


Andy

Fasecero,

That's another great idea.

Our only problem is knowing what the wstring or hex value is.

In my latest program I'm using your Unicode edit to wstring program so I can use it in a DATA command, and I have to copy the Unicode word in, then copy the string to a DATA command - and it work well - as does this example.

In Ebasic (probably before you joined), I remember you could set a static or edit control to say Greek characters i.e. just type them and Ebasic would display them.

It seems that since moving to IWB (and it's not a criticism!) that ability has been lost for what ever reason.

But it's still nice to know we can work around it.

Andy.
:)

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.