Skip to main content

Strings

Most COM interfaces use regular C strings, which are allocated and managed using the techniques described in Allocating strings.

However, some COM APIs use the BSTR type, particularly those that support late binding (often known as IDispatch) interfaces.

BSTR types differ from Pointer<Utf16> in that they include a 4-byte prefix stored immediately prior to the string itself, representing its length in bytes. The pointer points to the first character of the data string, not to the length prefix.

WARNING

BSTRs should never be created using Dart's memory allocation functions.

For example, the following code is incorrect because it does not allocate and store the length prefix.

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

Creating BSTR Objects

win32 package offers a wrapper for the COM memory allocation functions, ensuring that BSTR types can be created correctly. Instead of using Dart's memory allocation directly, you should use the wrapper provided:

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

When examined by a debugger, the 4-bytes prior to this location will contain a 32-bit integer with the value 34, representing the length of the string encoded in UTF-16 (two bytes per character):

  final bstr = BSTR.fromString('I am a happy BSTR');
final len = bstr.ptr.cast<Uint32>()[-1];
print('Length of bstr: $len');
bstr.free();

As demonstrated above, you can access the pointer for a BSTR using its .ptr property.

Freeing BSTR Objects

As with other manually allocated memory, Dart does not garbage collect BSTR objects; therefore, you are responsible for freeing the memory allocated for a BSTR when it is no longer needed.

WARNING

Do not use the global free() function to release BSTR memory, as it will not free the length prefix. Instead, use either the .free() method on the BSTR object itself, or the Windows API SysFreeString:

free(bstr);              // BAD!!! This will leak memory

bstr.free(); // OK
SysFreeString(bstr.ptr); // Also OK