Skip to content

Instantly share code, notes, and snippets.

@khchen
Created November 11, 2021 00:59
Show Gist options
  • Save khchen/e2697a9b809b099880c682d92754f1ed to your computer and use it in GitHub Desktop.
Save khchen/e2697a9b809b099880c682d92754f1ed to your computer and use it in GitHub Desktop.
#[
Author: Ward
Example of GetUserName
References:
https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getusernamea
]#
import winim/lean
import winim/inc/lm # for UNLEN
# Method 1: create a nim string as a buffer
# This is the easiest way to understand, however, it has two shortcomings.
# 1. It only works for ansi string API.
# 2. It store ansi string in nim string, which should be utf8 encoding. This may be wrong.
block:
var
buffer = newString(UNLEN + 1)
cb = DWORD buffer.len
GetUserNameA(&buffer, &cb)
buffer.setLen(cb - 1) # cb including the terminating null character
echo buffer
# Method 2: create a wstring or mstring as a buffer
# wstring is unicode string (aka wide character string), mstring is ansi string
# (aka multibyte character string), both of them are defined in winstr.
# This method has no encoding problem, but works only for specific API.
block:
var
buffer = newMString(UNLEN + 1) # return a mstring
cb = DWORD buffer.len
GetUserNameA(&buffer, &cb)
buffer.setLen(cb - 1)
echo $buffer # `$` convert mstring (ansi) to nim string (utf8).
block:
var
buffer = newWString(UNLEN + 1) # return a wstring
cb = DWORD buffer.len
GetUserNameW(&buffer, &cb)
buffer.setLen(cb - 1)
echo $buffer # `$` convert wstring (unicode) to nim string (utf8).
# Method 3: create a buffer by `T` template
# Nim/winim use unicode API by default, but it can be switched to ansi API if
# compiles with -d:useWinAnsi. So there is a T template.
# T template accept:
# 1: string => generate wstring or mstring depend on conditional symbol
# 2: Natural (range[0 .. high(int)]) => generate wstring buffer or mstring buffer
# This should be the best way for winim. It always works without encoding problem.
block:
var
buffer = T(UNLEN + 1)
cb = DWORD buffer.len
GetUserName(&buffer, &cb)
buffer.setLen(cb - 1)
echo $buffer
# More exercise... Using array as a buffer
block:
# TCHAR and LPTSTR are also automatically switched
var
buffer: array[UNLEN + 1, TCHAR]
cb = DWORD buffer.len
GetUserName(&buffer[0], &cb)
echo $cast[LPTSTR](&buffer[0]) # Use `$` and cast, only for null-terminated string
echo nullTerminated(%$buffer) # %$ Always treat `openArray[SomeChar]` as string,
# This way can deal with binary strings
echo %$(buffer[0..<cb-1]) # Should be the optimized way
# Using seq as a buffer
block:
var
buffer = newSeq[TCHAR](UNLEN + 1)
cb = DWORD buffer.len
GetUserName(&buffer[0], &cb)
echo $cast[LPTSTR](&buffer[0])
echo nullTerminated(%$buffer)
echo %$(buffer[0..<cb-1])
# Using memory block as a buffer
block:
var
buffer = alloc0(sizeof(TCHAR) * (UNLEN + 1))
cb: DWORD = UNLEN + 1
defer:
dealloc(buffer)
GetUserName(cast[LPTSTR](buffer), &cb)
echo $cast[LPTSTR](buffer)
echo %$cast[ptr UncheckedArray[TCHAR]](buffer).toOpenArray(0, cb-2) # <- wtf, don't ask...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment