halildurmus / win32

Access common Win32 APIs directly from Dart using FFI — no C required!
https://win32.pub
BSD 3-Clause "New" or "Revised" License
758 stars 123 forks source link

Create wrappers for `VARIANT` and `PROPVARIANT` structures #820

Open halildurmus opened 8 months ago

halildurmus commented 8 months ago

VARIANT and PROPVARIANT structures are commonly used in COM APIs. Essentially, they are containers for a large union that carries many types of data.

Here's the current way of creating a VARIANT struct that holds a BSTR type:

final variant = calloc<VARIANT>();
variant.ref
  ..vt = VARENUM.VT_BSTR // define the type of VARIANT
  ..bstrVal = BSTR.fromString('I am a happy BSTR').ptr; // set the value

// Do something with the VARIANT...

// Clean up
VariantClear(variant);
calloc.free(variant);

As you can see, it's a bit verbose. In v6, I plan to create wrappers for these structures using extension types.

Here's how the wrapper for VARIANT could look like:

/// Represents a pointer to [VARIANT] struct.
extension type const Variant(Pointer<VARIANT> _) implements Pointer<VARIANT> {
  /// Constructs an empty VARIANT.
  Variant.empty() : this(calloc<VARIANT>());

  /// Whether this VARIANT is empty.
  bool get isEmpty => _.ref.vt == VARENUM.VT_EMPTY;

  /// Constructs a VARIANT holding a [BSTR] value.
  static VariantBSTR bstr(String value) => VariantBSTR(value);

  // ...

  /// Releases the memory allocated for this VARIANT.
  void free() {
    VariantClear(this);
    calloc.free(this);
  }
}

/// Represents a VARIANT holding a [BSTR] value.
extension type const VariantBSTR._(Variant _) implements Variant {
  /// Constructs a VARIANT holding a [BSTR] value.
  factory VariantBSTR(String value) {
    final variant = Variant.empty();
    variant._.ref
      ..vt = VARENUM.VT_BSTR
      ..bstrVal = BSTR.fromString(value).ptr;
    return VariantBSTR._(variant);
  }

  /// The [BSTR] value stored in this VARIANT.
  String get value => ref.bstrVal.toDartString();
  set value(String value) => ref.bstrVal = BSTR.fromString(value).ptr;
}

// ...

With this wrapper, the original example simply becomes:

final variant = Variant.bstr('I am a happy BSTR');

// Do something with the VARIANT...

// Clean up
variant.free();
android-dev2015 commented 6 months ago

I just encountered this similar problem,haha