Working with BSTRs


The following is a package the demonstrates how to work with the Win32 API type BSTR. A BSTR is a pointer to a wide character string. The memory before this pointer contains the length of the string. It is used extensively in COM programming and a special set of Win32 API functions are needed to work with them.

This package allows easy conversion between null terminated BSTRs and Ada supported types. It should be noted, that it is not possible to create/use non-null terminated BSTRs with this example.


with Win32.OleAuto;
with Interfaces.C;

package BSTR is

   -- These conversion functions create a new BSTR that requires a Free
   -- to destroy
   function To_BSTR( From_Ada : Wide_String ) return Win32.OleAuto.BSTR;
   function To_BSTR( From_Ada : String ) return Win32.OleAuto.BSTR;

   function To_BSTR( From_C : Interfaces.C.WChar_Array ) return Win32.OleAuto.BSTR;
   function To_BSTR( From_C : Interfaces.C.Char_Array ) return Win32.OleAuto.BSTR;

   -- These conversion functions do not destroy the original BSTR

   function To_Ada( From_BSTR : Win32.OleAuto.BSTR ) return Wide_String;
   function To_Ada( From_BSTR : Win32.OleAuto.BSTR ) return String;

   function To_C( From_BSTR : Win32.OleAuto.BSTR ) return Interfaces.C.WChar_Array;
   function To_C( From_BSTR : Win32.OleAuto.BSTR ) return Interfaces.C.Char_Array;

   -- This conversion can free BSTRs created with this packages conversion
   -- functions and those created with the Win32 API function SysAllocString
   
   procedure Free( This : Win32.OleAuto.BSTR );
   
   BSTR_Error : exception;
   
end BSTR;

with Win32.Oleauto; use Win32.Oleauto;

with Interfaces.C; use Interfaces.C;
with Interfaces.C.Pointers;

with Ada.Exceptions;
with Ada.Characters.Handling;
with Ada.Unchecked_Conversion;

with System;

package body BSTR is

-------------------------------------------------------------------------------
-- Private
-------------------------------------------------------------------------------
   type PWChar_t is access all Interfaces.C.WChar_t;

   function To_PCWSTR is
      new Ada.Unchecked_Conversion (System.Address, Win32.PCWSTR);
   function To_PWChar_t is
      new Ada.Unchecked_Conversion (System.Address, PWChar_t);


   package WChar_Array_Pointer is new Interfaces.C.Pointers
         (index              => Interfaces.C.Size_t,
          element            => Interfaces.C.WChar_t,
          element_array      => Interfaces.C.WChar_array,
          default_terminator => Interfaces.C.Wide_Nul);

-------------------------------------------------------------------------------
-- Public
-------------------------------------------------------------------------------

   -- Create BSTR conversions
   
   function To_BSTR (From_Ada : Wide_String) return Win32.OleAuto.BSTR is
   begin
      return To_BSTR(
                Interfaces.C.To_C(From_Ada) );
   end To_BSTR;

   function To_BSTR (From_Ada : String) return Win32.OleAuto.BSTR is
   begin
      return To_BSTR (
                Interfaces.C.To_C(
                   Ada.Characters.Handling.To_Wide_String(From_Ada) ) );
   end To_BSTR;

   function To_BSTR (From_C : Interfaces.C.WChar_Array)
      return Win32.OleAuto.BSTR
   is
      New_BSTR : Win32.OleAuto.BSTR;
   begin
      New_BSTR := SysAllocString( To_PCWSTR( From_C'Address ) );

      if New_BSTR = null then
         Ada.Exceptions.Raise_Exception(BSTR_Error'Identity,
            "BSTR - Unable to create BSTR");
      end if;
      
      return New_BSTR;
   end To_BSTR;

   function To_BSTR (From_C : Interfaces.C.Char_Array)
      return Win32.OleAuto.BSTR
   is
   begin
      return To_BSTR (
                Interfaces.C.To_C(
                   Ada.Characters.Handling.To_Wide_String(
                      Interfaces.C.To_Ada(From_C) ) ) );
   end To_BSTR;

   -- Convert to Ada and C strings

   function To_Ada (From_BSTR : Win32.OleAuto.BSTR) return Wide_String is
   begin
      return Interfaces.C.To_Ada(
                To_C(From_BSTR) );
   end To_Ada;

   function To_Ada (From_BSTR : Win32.OleAuto.BSTR) return String is
   begin
      return Ada.Characters.Handling.To_String(
                To_Ada (From_BSTR) );
   end To_Ada;

   function To_C (From_BSTR : Win32.OleAuto.BSTR)
      return Interfaces.C.WChar_Array
   is
   begin
      return WChar_Array_Pointer.value (WChar_Array_Pointer.pointer (To_PWChar_t(From_BSTR.all'Address)));
   end To_C;

   function To_C (From_BSTR : Win32.OleAuto.BSTR)
      return Interfaces.C.Char_Array
   is
   begin
      return Interfaces.C.To_C(
                Ada.Characters.Handling.To_String(
                   Interfaces.C.To_Ada(
                      To_C(From_BSTR) ) ) );
   end To_C;

   -- Destroy BSTRs
   
   procedure Free (This : Win32.OleAuto.BSTR) is
   begin
      SysFreeString(This);
   end Free;

end BSTR;

Contributed by: David Botton
Contributed on: March 19, 1999
License: Public Domain
Back