// Manages a BSTR string pointer.
// The class interface is based on scoped_ptr.
class ScopedBstr {
public:
ScopedBstr() : bstr_(NULL) {
}
// Constructor to create a new BSTR.
// NOTE: Do not pass a BSTR to this constructor expecting ownership to
// be transferred - even though it compiles! ;-)
explicit ScopedBstr(const wchar_t* non_bstr);
~ScopedBstr();
// Give ScopedBstr ownership over an already allocated BSTR or NULL.
// If you need to allocate a new BSTR instance, use |allocate| instead.
void Reset(BSTR bstr = NULL);
// Releases ownership of the BSTR to the caller.
BSTR Release();
// Creates a new BSTR from a wide string.
// If you already have a BSTR and want to transfer ownership to the
// ScopedBstr instance, call |reset| instead.
// Returns a pointer to the new BSTR, or NULL if allocation failed.
BSTR Allocate(const wchar_t* wide_str);
// Allocates a new BSTR with the specified number of bytes.
// Returns a pointer to the new BSTR, or NULL if allocation failed.
BSTR AllocateBytes(int bytes);
// Sets the allocated length field of the already-allocated BSTR to be
// |bytes|. This is useful when the BSTR was preallocated with e.g.
// SysAllocStringLen or SysAllocStringByteLen (call |AllocateBytes|) and
// then not all the bytes are being used.
// Note that if you want to set the length to a specific number of characters,
// you need to multiply by sizeof(wchar_t). Oddly, there's no public API to
// set the length, so we do this ourselves by hand.
//
// NOTE: The actual allocated size of the BSTR MUST be >= bytes.
// That responsibility is with the caller.
void SetByteLen(uint32 bytes);
// Swap values of two ScopedBstr's.
void Swap(ScopedBstr& bstr2);
// Retrieves the pointer address.
// Used to receive BSTRs as out arguments (and take ownership).
// The function DCHECKs on the current value being NULL.
// Usage: GetBstr(bstr.Receive());
BSTR* Receive();
// Returns number of chars in the BSTR.
uint32 Length() const;
// Returns the number of bytes allocated for the BSTR.
uint32 ByteLength() const;
operator BSTR() const {
return bstr_;
}
protected:
BSTR bstr_;
private:
// Forbid comparison of ScopedBstr types. You should never have the same
// BSTR owned by two different scoped_ptrs.
bool operator==(const ScopedBstr& bstr2) const;
bool operator!=(const ScopedBstr& bstr2) const;
DISALLOW_COPY_AND_ASSIGN(ScopedBstr);
};
ScopedBstr::ScopedBstr(const wchar_t* non_bstr)
: bstr_(SysAllocString(non_bstr)) {
}
ScopedBstr::~ScopedBstr() {
COMPILE_ASSERT(sizeof(ScopedBstr) == sizeof(BSTR), ScopedBstrSize);
SysFreeString(bstr_);
}
void ScopedBstr::Reset(BSTR bstr) {
if (bstr != bstr_) {
// if |bstr_| is NULL, SysFreeString does nothing.
SysFreeString(bstr_);
bstr_ = bstr;
}
}
BSTR ScopedBstr::Release() {
BSTR bstr = bstr_;
bstr_ = NULL;
return bstr;
}
void ScopedBstr::Swap(ScopedBstr& bstr2) {
BSTR tmp = bstr_;
bstr_ = bstr2.bstr_;
bstr2.bstr_ = tmp;
}
BSTR* ScopedBstr::Receive() {
DCHECK(bstr_ == NULL) << "BSTR leak.";
return &bstr_;
}
BSTR ScopedBstr::Allocate(const wchar_t* wide_str) {
Reset(SysAllocString(wide_str));
return bstr_;
}
BSTR ScopedBstr::AllocateBytes(int bytes) {
Reset(SysAllocStringByteLen(NULL, bytes));
return bstr_;
}
void ScopedBstr::SetByteLen(uint32 bytes) {
DCHECK(bstr_ != NULL) << "attempting to modify a NULL bstr";
uint32* data = reinterpret_cast<uint32*>(bstr_);
data[-1] = bytes;
}
uint32 ScopedBstr::Length() const {
return SysStringLen(bstr_);
}
uint32 ScopedBstr::ByteLength() const {
return SysStringByteLen(bstr_);
}