# winim/winstr

Dark Mode

- Github Page
- winim
- winstr
- utils
- com
- clr

This module contains new string types and utilities to deal with strings in Windows. Windows SDK use following types to represent a char or a string:

    type
      CHAR = char
      WCHAR = uint16
      LPSTR|LPCSTR = ptr CHAR # however, it should be ansi string, not utf8 string
      LPWSTR|LPCWSTR = ptr WCHAR
      BSTR = distinct ptr WCHAR # BSTR is not binary compatible with LPWSTR
      (ptr) array[I, CHAR] # sometimes string defined as array[1, CHAR] but not only one char
      (ptr) array[I, WCHAR] # sometimes string defined as array[1, WCHAR] but not only one widechar

By default, Nim's string type is utf8 encoding. However, Windows use wide character string (aka. unicode string) or multibyte character string (aka. ansi string). So, this module introduce following string types.

    type
      string # nim built-in string type, utf8 encoding by default, can be ansi string sometimes.
      cstring # compatible to the type char* in Ansi C
      wstring = distinct string # new string type to store unicode string
      mstring = distinct string # new string type to store ansi string

Some type classes are also defined for convenience to deal with strings.

    type
      SomeChar = byte | char | WCHAR
      SomeString = string | mstring | wstring
      SomeBuffer[I] = ptr SomeChar | array[I, SomeChar] | ptr array[I, SomeChar] |
        ptr UncheckedArray[SomeChar] | openArray[SomeChar] | seq[SomeChar]
      Stringable = SomeChar | SomeString | SomeBuffer | cstring | BSTR

Here are the pseudocode for most useful functions introduced by this module.

    proc `&`(s: cstring|string|wstring|mstring): pointer
      # Get address of the first char of a string.
      # For string, it has a similar meaning to cstring(s).

    proc `$`(x: Stringable): string
    proc `+$`(x: Stringable): wstring
    proc `-$`(x: Stringable): mstring
      # Convert any stringable type to string, wstring, or mstring.
      # These operators assume string|cstring|ptr char|openArray[char] are utf8 encoding.
      # setOpenArrayStringable() can be used to switch the behavior of `$` operator.

    proc `$$`(x: Stringable): string
    proc `+$$`(x: Stringable): wstring
    proc `-$$`(x: Stringable): mstring
      # Convert any stringable type to string, wstring, or mstring.
      # These operators assume string|cstring|ptr char|openArray[char] are ansi encoding.
      # For mstring|wstring|LPWSTR etc, these operators are the same as `$`, `+$`, `-$`.

    template `<<`(s: SomeString, b: SomeBuffer)
    template `<<`(b: SomeBuffer, s: SomeString)
    template `<<<`(b: SomeBuffer, s: SomeString)
    template `>>`(a: typed, b: typed) = b << a
    template `>>>`(a: typed, b: typed) = b <<< a
      # String << Buffer or Buffer >> String: Fill string by buffer.
      # Buffer << String or String >> Buffer: Fill buffer by string.
      # Buffer <<< String or String >>> Buffer: Fill buffer by string, include a null.

      # These operators don't convert the encoding (copy byte by byte).
      # Please make sure both side have the same character size.
      # If destination don't have the length information (e.g. pointer or UncheckedArray),
      # please make sure the buffer size is large enough.

    proc nullTerminate(s: var SomeString)
      # Assume a string is null terminated and set the correct length.

    proc nullTerminated[T: SomeString](s: T): T
      # Assume a string is null terminated and return the length-corrected string.

    template L(s: string): wstring
      # Generate wstring at compile-time if possible.
      # Only const string or string literal can be converted to unicode string at compile-time,
      # otherwise it is just `+$`.

    template T(s: string): mstring|wstring
      # Generate wstring or mstring depend on conditional symbol: useWinAnsi.
      # For example: (this code works under both unicode and ansi mode)

        MessageBox(0, T"hello, world", T"Nim is Powerful 中文測試", 0)

    template T(n: Natural): mstring|wstring
      # Generate wstring or mstring buffer depend on conditional symbol: useWinAnsi.
      # Use `&` to get the buffer address and then pass to Windows API.

    converter winstrConverter(s: SomeString): SomeBuffer
      # With these converters, passing string to Windows API is more easy.
      #   Following converters don't need encoding conversion:
      #     string => LPSTR|ptr char
      #     mstring => LPSTR|ptr char
      #     wstring => LPWSTR|BSTR
      #     cstring => ptr char
      #     BSTR => LPWSTR
      #
      #   Some converters DO need encoding conversion (utf8 to unicode).
      #   New memory block will be allocated. However, they are useful and convenience.
      #     cstring|string => LPWSTR|BSTR

There are also new string functions to deal with wstring and mstring just like built-in string type.

    proc newWString(len: Natural): wstring
      # Generate wstring buffer
    proc newMString(len: Natural): mstring
      # Generate mstring buffer

    proc setLen(s: var mstring|wstring, newLen: Natural)
    proc substr(s: wstring|mstring, first = 0): wstring|mstring
    proc substr(s: wstring|mstring, first, last: int): wstring|mstring
    proc len(s: wstring|mstring): int
    proc high(s: wstring|mstring): int
    proc low(s: wstring|mstring): int
    proc repr(s: wstring|mstring): string
    proc toHex(s: wstring|mstring): string

    proc `[]`(s: wstring|mstring, i: int): WCHAR|mstring
    proc `[]=`(s: wstring|mstring, i: int, u: WCHAR|CHAR)
    proc `[]=`(s: wstring|mstring, i: int, u: wstring|mstring)
    proc `[]`(s: wstring|mstring, x: HSlice)
    proc `[]=`(s: var wstring|var mstring, x: HSlice[int], b: wstring|mstring)
    proc `==`(x, y: wstring|mstring): bool
    proc `<=`(x, y: wstring|mstring): bool
    proc `<`(x, y: wstring|mstring): bool
    proc cmp(x, y: wstring|mstring): int
    proc `&`(s: wstring|mstring, t: wstring|mstring): wstring|mstring

    iterator items(s: wstring|mstring): WCHAR|mstring
    iterator mitems(s: var wstring): WCHAR
    iterator pairs(s: wstring|mstring): tuple[key: int|mIndex, val: WCHAR|mstring]
    iterator mpairs(s: var wstring): WCHAR

Winim don't use built-in `WideCString`, but still support it.

    converter winstrConverter(s: WideCString): LPWSTR
      # WideCString can be sent to Windows API directly (unicode only).

    proc `+$`(s: WideCString): wstring
      # Converts WideCString to wstring.

    proc newWideCString(s: wstring): WideCString
      # Converts wstring to WideCString.

# Types

    mIndex = distinct int

  Use `mIndex` in substr, [] or []= for `mstring` means index by MBCS characters, not by bytes.

    mstring = distinct string

  New string type to store multibyte character string (aka. ansi string).

    SomeBuffer[I] = ptr SomeChar | array[I, SomeChar] | ptr array[I, SomeChar] |
        ptr UncheckedArray[SomeChar] |
        openArray[SomeChar] |
        seq[SomeChar]

  Type class matching all string buffer types.

    SomeChar = byte | char | WCHAR

  Type class matching all char types.

    SomeString = string | mstring | wstring

  Type class matching all string types.

    Stringable = SomeChar | SomeString | SomeBuffer | cstring | BSTR

  Type class matching all stringable types.

    TString = wstring

  `wstring` or `mstring` depend on conditional symbol: `useWinAnsi`.

    wstring = distinct string

  New string type to store wide character string (aka. unicode string).

# Procs

    proc `$$`(s: Stringable): string {.inline.}

  Convert any stringable type to `string`. This operator assume `string|cstring|ptr char|openArray[char]` is ansi encoding.

    proc `$`(s: Stringable): string {.inline.}

  Convert any stringable type to `string`. This operator assume `string|cstring|ptr char|openArray[char]` is utf8 encoding.

    proc `%$`(s: Stringable): string {.inline.}

  Convert any stringable type to `string`. Always treat `openArray[SomeChar]` as string. This operator assume `string|cstring|ptr char|openArray[char]` is utf8 encoding.

    proc `&`(s, u: wstring): wstring {.inline, ...raises: [], tags: [].}

  Concatenates `s` with `u`.

    proc `&`(s: cstring): ptr char {.inline, ...raises: [], tags: [].}

  Get address of the first char of a `cstring`.

    proc `&`(s: mstring): ptr char {.inline, ...raises: [], tags: [].}

  Get address of the first char of a `mstring`.

    proc `&`(s: string): ptr char {.inline, ...raises: [], tags: [].}

  Get address of the first char of a `string`.

    proc `&`(s: wstring): ptr WCHAR {.inline, ...raises: [], tags: [].}

  Get address of the first WCHAR of a `wstring`.

    proc `&`(s: wstring; c: WCHAR | char): wstring {.inline.}

  Concatenates `s` with `c`.

    proc `&`(x, y: mstring): mstring {.borrow, ...raises: [], tags: [].}

  Concatenates `x` with `y`.

    proc `&`(x: char; y: mstring): mstring {.borrow, ...raises: [], tags: [].}

  Concatenates `x` with `y`.

    proc `&`(x: mstring; y: char): mstring {.borrow, ...raises: [], tags: [].}

  Concatenates `x` with `y`.

    proc `+$$`(s: Stringable): wstring {.inline.}

  Convert any stringable type to `wstring`. This operator assume `string|cstring|ptr char|openArray[char]` is ansi encoding.

    proc `+$`(s: Stringable): wstring {.inline.}

  Convert any stringable type to `wstring`. This operator assume `string|cstring|ptr char|openArray[char]` is utf8 encoding.

    proc `+$`(s: WideCString): wstring {.inline, ...raises: [], tags: [].}

  Converts `WideCString` to `wstring`.

    proc `-$$`(s: Stringable): mstring {.inline.}

  Convert any stringable type to `mstring`. This operator assume `string|cstring|ptr char|openArray[char]` is ansi encoding.

    proc `-$`(s: Stringable): mstring {.inline.}

  Convert any stringable type to `mstring`. This operator assume `string|cstring|ptr char|openArray[char]` is utf8 encoding.

    proc `<=`(x, y: mstring): bool {.borrow, ...raises: [], tags: [].}

  Lexicographic `<=` operator for `mstring`.

    proc `<=`(x, y: wstring): bool {.borrow, ...raises: [], tags: [].}

  Lexicographic `<=` operator for `wstring`.

    proc `<`(x, y: mstring): bool {.borrow, ...raises: [], tags: [].}

  Lexicographic `<` operator for `mstring`.

    proc `<`(x, y: wstring): bool {.borrow, ...raises: [], tags: [].}

  Lexicographic `<` operator for `wstring`.

    proc `==`(x, y: mstring): bool {.borrow, ...raises: [], tags: [].}

  Checks for equality between two `mstring`.

    proc `==`(x, y: wstring): bool {.borrow, ...raises: [], tags: [].}

  Checks for equality between two `wstring`.

    proc `[]=`(s: var mstring; i: int; x: char | byte) {.inline.}

  Index assignment operator for `mstring`, counting by bytes.

    proc `[]=`(s: var mstring; i: mIndex; u: mstring) {....raises: [], tags: [].}

  Index assignment operator for `mstring`, counting by MBCS characters, and only first MBCS characters of `u` will be used.

    proc `[]=`(s: var wstring; i: int; c: WCHAR | char) {.inline.}

  Index assignment operator for `wstring`.

    proc `[]=`[T, U](s: var mstring; x: HSlice[T, U]; u: mstring)

  Slice assignment for `mstrings`.

    proc `[]=`[T, U](s: var wstring; x: HSlice[T, U]; b: wstring)

  Slice assignment for `wstring`.

    proc `[]`(s: mstring; i: int): char {.inline, ...raises: [], tags: [].}

  Index operator for `mstring`, counting by bytes.

    proc `[]`(s: mstring; i: mIndex): mstring {....raises: [], tags: [].}

  Index operator for `mstring`, counting by MBCS characters.

    proc `[]`(s: wstring; i: int): WCHAR {.inline, ...raises: [], tags: [].}

  Index operator for `wstring`.

    proc `[]`[T, U](s: mstring; x: HSlice[T, U]): mstring

  Slice operation for `mstring`.

    proc `[]`[T, U](s: wstring; x: HSlice[T, U]): wstring

  Slice operation for `wstring`.

    proc add(s: var wstring; c: char | WCHAR)

  Appends `c` to `s` in place.

    proc add(s: var wstring; u: wstring) {....raises: [], tags: [].}

  Appends `u` to `s` in place.

    proc add(x: var mstring; y: byte) {.inline, ...raises: [], tags: [].}

  Appends `y` to `x` in place.

    proc add(x: var mstring; y: char) {.borrow, ...raises: [], tags: [].}

  Appends `y` to `x` in place.

    proc add(x: var mstring; y: mstring) {.borrow, ...raises: [], tags: [].}

  Appends `y` to `x` in place.

    proc add(x: var mstring; y: string) {.borrow, ...raises: [], tags: [].}

  Appends `y` to `x` in place.

    proc cmp(x, y: mstring): int {.borrow, ...raises: [], tags: [].}

  Compare proc for `mstring` (in binary format only).

    proc cmp(x, y: wstring): int {.borrow, ...raises: [], tags: [].}

  Compare proc for `wstring` (in binary format only).

    proc high(s: mstring): int {.borrow, ...raises: [], tags: [].}

  Returns the highest possible index of `mstring`.

    proc high(s: wstring): int {.inline, ...raises: [], tags: [].}

  Returns the highest possible index of `wstring`.

    proc len(s: mstring): int {.inline, ...raises: [], tags: [].}

  Returns the length of `mstring`, counting by bytes.

    proc len(s: wstring): int {.inline, ...raises: [], tags: [].}

  Returns the length of `wstring`, counting by wide characters.

    proc low(s: mstring): int {.borrow, ...raises: [], tags: [].}

  Returns the lowest possible index of `mstring`.

    proc low(s: wstring): int {.inline, ...raises: [], tags: [].}

  Returns the lowest possible index of `wstring`.

    proc mlen(s: mstring): int {....raises: [], tags: [].}

  Returns the length of `mstring`, counting by MBCS characters.

    proc newMString(L: Natural): mstring {....raises: [], tags: [].}

  Returns a new `mstring` of length L, counting by bytes.

    proc newMString(s: string | cstring | wstring): mstring {.inline,
        ...deprecated: "use `-$` instead".}

  Deprecated: use `-$` instead
  Return a new `mstring`.

    proc newMStringOfCap(L: Natural): mstring {....raises: [], tags: [].}

  Returns a new `mstring` of length 0 but with capacity L, counting by bytes.

    proc newWideCString(s: wstring): WideCString {.inline, ...raises: [], tags: [].}

  Converts `wstring` to `WideCString`.

    proc newWString(L: Natural): wstring {....raises: [], tags: [].}

  Returns a new `wstring` of length L, counting by wide characters.

    proc newWString(s: cstring | string | mstring): wstring {.inline,
        ...deprecated: "use `+$` instead".}

  Deprecated: use `+$` instead
  Return a new `wstring`.

    proc newWStringOfCap(L: Natural): wstring {....raises: [], tags: [].}

  Returns a new `wstring` of length 0 but with capacity L, counting by wide characters.

    proc nullTerminate(s: var SomeString) {.inline.}

  Assume a string is null terminated and set the correct length.

    proc nullTerminated[T: SomeString](s: T): T {.inline.}

  Assume a string is null terminated and return the length-corrected string.

    proc repr(s: mstring): string {....raises: [], tags: [].}

  Returns string representation of `mstring`.

    proc repr(s: wstring): string {....raises: [], tags: [].}

  Returns string representation of `wstring`.

    proc setLen(s: var mstring; L: Natural) {.inline, ...raises: [], tags: [].}

  Sets the length of `mstring` s to L, counting by wide bytes.

    proc setLen(s: var wstring; L: Natural) {.inline, ...raises: [], tags: [].}

  Sets the length of `wstring` s to L, counting by wide characters.

    proc setOpenArrayStringable(flag: bool): bool {.inline, discardable, ...raises: [],
        tags: [].}

  Nim's system.`$` will return array representation for `openArray[SomeChar]`. After turn this option on, winstr will overwrite the defualt behavior for `$` and treats `openArray[SomeChar]` as string.

    proc substr(s: mstring; first = 0): mstring {.borrow, ...raises: [], tags: [].}

  Copies a slice of `s` into a new `mstring` and returns it, counting by bytes.

    proc substr(s: mstring; first, last: int): mstring {.borrow, ...raises: [],
        tags: [].}

  Copies a slice of `s` into a new `mstring` and returns it, counting by bytes.

    proc substr(s: mstring; first, last: mIndex): mstring {....raises: [], tags: [].}

  Copies a slice of `s` into a new `mstring` and returns it, counting by MBCS characters.

    proc substr(s: mstring; first: mIndex = 0.mIndex): mstring {....raises: [],
        tags: [].}

  Copies a slice of `s` into a new `mstring` and returns it, counting by MBCS characters.

    proc substr(s: wstring; first = 0): wstring {.inline, ...raises: [], tags: [].}

  Copies a slice of `s` into a new `wstring` and returns it.

    proc substr(s: wstring; first, last: int): wstring {....raises: [], tags: [].}

  Copies a slice of `s` into a new `wstring` and returns it.

    proc toHex(s: cstring): string {.inline, ...raises: [], tags: [].}

  Converts a `cstring` to its hexadecimal representation. No prefix like `0x` is generated.

    proc toHex(s: mstring): string {.inline, ...raises: [], tags: [].}

  Converts `mstring` to its hexadecimal representation. No prefix like `0x` is generated.

    proc toHex(s: wstring): string {.inline, ...raises: [], tags: [].}

  Converts `wstring` to its hexadecimal representation. No prefix like `0x` is generated.

# Iterators

    iterator items(s: mstring): mstring {....raises: [], tags: [].}

  Iterates over each MBCS character of `mstring`.

    iterator items(s: wstring): WCHAR {....raises: [], tags: [].}

  Iterates over each `WCHAR` of `wstring`.

    iterator mitems(s: var wstring): var WCHAR {....raises: [], tags: [].}

  Iterates over each `WCHAR` of `wstring` so that you can modify the yielded value.

    iterator mpairs(s: var wstring): tuple[key: int, val: var WCHAR] {....raises: [],
        tags: [].}

  Iterates over each `WCHAR` of `wstring`. Yields `(int, var WCHAR)` pairs.

    iterator pairs(s: mstring): tuple[key: mIndex, val: mstring] {....raises: [],
        tags: [].}

  Iterates over each MBCS character of `mstring`. Yields `(mIndex, mstring)` pairs.

    iterator pairs(s: wstring): tuple[key: int, val: WCHAR] {....raises: [], tags: [].}

  Iterates over each `WCHAR` of `wstring`. Yields `(int, WCHAR)` pairs.

# Converters

    converter winstrConverterBSTRToLPWSTR(x: BSTR): LPWSTR {....raises: [], tags: [].}

  Converts `BSTR` to `LPWSTR` automatically.

    converter winstrConverterCStringToBSTR(x: cstring): BSTR {....raises: [], tags: [].}

  Converts `cstring` to `BSTR` automatically.

    converter winstrConverterCStringToLPWSTR(x: cstring): LPWSTR {....raises: [],
        tags: [].}

  Converts `cstring` to `LPWSTR` automatically.

    converter winstrConverterCStringToPtrChar(x: cstring): ptr char {....raises: [],
        tags: [].}

  Converts `cstring` to `ptr char` automatically.

    converter winstrConverterMStringToLPSTR(x: mstring): LPSTR {....raises: [],
        tags: [].}

  Converts `mstring` to `LPSTR` automatically.

    converter winstrConverterMStringToPtrChar(x: mstring): ptr char {....raises: [],
        tags: [].}

  Converts `mstring` to `ptr char` automatically.

    converter winstrConverterStringToBSTR(x: string): BSTR {....raises: [], tags: [].}

  Converts `string` to `BSTR` automatically.

    converter winstrConverterStringToLPWSTR(x: string): LPWSTR {....raises: [],
        tags: [].}

  Converts `string` to `LPWSTR` automatically.

    converter winstrConverterStringToPtrChar(x: string): ptr char {....raises: [],
        tags: [].}

  Converts `string` to `ptr char` automatically.

    converter winstrConverterWideCStringToLPWSTR(x: WideCString): LPWSTR {.
        ...raises: [], tags: [].}

  Converts `WideCString` to `LPWSTR` automatically.

    converter winstrConverterWStringToBSTR(x: wstring): BSTR {....raises: [], tags: [].}

  Converts `wstring` to `BSTR` automatically.

    converter winstrConverterWStringToLPWSTR(x: wstring): LPWSTR {....raises: [],
        tags: [].}

  Converts `wstring` to `LPWSTR` automatically.

# Templates

    template `<<<`[A: SomeBuffer | SomeString](a: A; b: SomeString)

  Fill buffer by string, include a null. Please make sure both side have the same character size. If destination don't have the length information (e.g. `pointer` or `UncheckedArray`), please make sure the buffer size is large enough.

    template `<<`[A: SomeBuffer | SomeString; B: SomeBuffer | SomeString](a: A; b: B)

  Fill operator for `SomeBuffer` and `SomeString`. Please make sure both side have the same character size. If destination don't have the length information (e.g. `pointer` or `UncheckedArray`), please make sure the buffer size is large enough.

    template `>>>`(a: typed; b: typed)

  This is the same as `b <<< a`.

    template `>>`(a: typed; b: typed)

  This is the same as `b << a`.

    template L(x: static[string]): wstring

  Generate const wstring from `static[string]` at compile-time.

    template L(x: string): wstring

  Same as `+$` for dynamic string (string at run-time).

    template T(x: Natural): untyped

  Generate wstring or mstring buffer depend on conditional symbol: `useWinAnsi`. Use `&` to get the buffer address and then pass to Windows API.

    template T(x: string): untyped

  Generate wstring or mstring depend on conditional symbol: `useWinAnsi`.