Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create wrappers for string types #946

Open
halildurmus opened this issue Jan 7, 2025 · 0 comments
Open

Create wrappers for string types #946

halildurmus opened this issue Jan 7, 2025 · 0 comments
Assignees
Labels
feature A new feature or request P2 Medium-priority issue package: win32 Issue with package:win32
Milestone

Comments

@halildurmus
Copy link
Owner

Windows APIs and COM use several string types, each with unique traits for encoding, mutability, and memory management:

  1. Win32 String Types

    • PSTR / PCSTR: Null-terminated ANSI strings for single-byte encoding.
      • PSTR is mutable, while PCSTR is immutable.
      • Used in legacy APIs or for cross-platform compatibility.
    • PWSTR / PCWSTR: Null-terminated wide (UTF-16) strings.
      • PWSTR is mutable, while PCWSTR is immutable.
      • Widely used in modern Unicode-compatible APIs.
  2. COM String Types

    • BSTR: A length-prefixed UTF-16 string, commonly used in COM automation.
      • Requires SysAllocString for allocation and SysFreeString for deallocation.
    • HSTRING: An immutable UTF-16 string introduced with WinRT.
      • Created with WindowsCreateString and freed with WindowsDeleteString.

These types have unique encodings and memory layouts (e.g., null-terminated vs. length-prefixed). Handling conversions and managing memory can be tedious and error-prone.

Similar to #820, we could create wrappers for these. These wrappers would:

  1. Use NativeFinalizer to handle automatic memory cleanup when the object is no longer referenced.
  2. Provide explicit detach and free methods for advanced users who need/prefer manual control over the object's lifecycle.
  3. Include shorthand functions for easy conversion between Dart strings and native string types.

Here's how the wrapper class for PCWSTR could look like:

/// A pointer to a constant null-terminated string of 16-bit Unicode characters.
typedef PCWSTR = Pointer<Utf16>;

/// A shorthand function to create a new [Pcwstr] from a Dart string.
///
/// This is a convenience function for quickly wrapping a Dart string in a
/// [Pcwstr]. It behaves the same as calling the [Pcwstr] constructor directly.
Pcwstr w(String string) => Pcwstr(string);

/// A wrapper for the [PCWSTR], used in Windows APIs.
///
/// This class simplifies working with [PCWSTR]s by providing automatic memory
/// management and convenient Dart-friendly operations.
///
/// This class uses a [NativeFinalizer] to automatically free the memory
/// allocated for the structure when the object is GCed. This ensures that the
/// unmanaged memory allocated for the structure is automatically freed when the
/// object is GCed.
///
/// If you need full control over the object's lifecycle, you can opt out of
/// automatic finalization by using the [detach] method. This is especially
/// useful in scenarios where ownership of the object is transferred to another
/// part of your application or when explicit lifecycle management is required.
final class Pcwstr implements Finalizable {
  /// Creates a new [Pcwstr] with the provided [string].
  ///
  /// Attaches a [NativeFinalizer] to the instance to automatically free the
  /// memory when no longer used.
  ///
  /// **Note:** If [string] contains embedded NUL characters, the result of
  /// [toDartString] may be truncated unless a specific length is provided.
  factory Pcwstr(String string) => Pcwstr.fromPointer(string.toPWSTR());

  Pcwstr.fromPointer(this.ptr) {
    _finalizer.attach(
      this,
      ptr.cast(),
      detach: this,
      externalSize: sizeOf<WCHAR>(),
    );
  }

  static final _finalizer = NativeFinalizer(...);

  final PCWSTR ptr;

  int get byteLength => length * sizeOf<WCHAR>();

  Pcwstr clone() {...}

  void detach() => _finalizer.detach(this);

  void free() {
    _finalizer.detach(this);
    calloc.free(ptr);
  }

  bool get isEmpty => length == 0;

  int get length {...}

  Pcwstr operator +(Pcwstr other) {...}

  String toDartString({int? length}) {...}
}
@halildurmus halildurmus added feature A new feature or request package: win32 Issue with package:win32 P2 Medium-priority issue labels Jan 7, 2025
@halildurmus halildurmus added this to the win32 v6 milestone Jan 7, 2025
@halildurmus halildurmus self-assigned this Jan 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature A new feature or request P2 Medium-priority issue package: win32 Issue with package:win32
Projects
None yet
Development

No branches or pull requests

1 participant