//
you're reading...
BSTR, COM, Programming Issues/Tips

How to Store Binary Data in a BSTR.

1. Introduction

1.1 A BSTR is flexible in the sense that not only can you store a character string in it, you can also store binary data.

1.2 This programming tip presents sample code which demonstrates how this can be done.

2. The SysAllocStringByteLen() API.

2.1 Normally, when you want to allocate a BSTR, you would use the SysAllocString() API.

2.2 In managed code, you would use Marshal.StringToBSTR().

2.3 But in order to allocate a BSTR in which you want to store binary data, you would use the SysAllocStringByteLen() API.

2.4 When you call this API, pass NULL as the first parameter but pass an integer value for the second parameter which will indicate the actual byte length of the BSTR buffer. Doing so will allow SysAllocStringByteLen() to allocate a memory buffer for the BSTR but leave it uninitialized.

2.5 In addition, the 4-byte length indicator which is located just before the BSTR data will be set to the correct value as indicated by the second parameter.

3. The Sample Code.

3.1 In this section, I shall present a simple sample code written in C# which will demonstrate how to use SysAllocStringByteLen() to allocate a BSTR that can be used to contain binary data.

3.2 The code is listed below :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace CSConsoleApp
{
    class Program
    {
        [DllImport(@"Oleaut32.dll")]
        public static extern IntPtr SysAllocStringByteLen([MarshalAs(UnmanagedType.LPStr)] string psz, UInt32 len);

        [DllImport(@"Oleaut32.dll")]
        public static extern UInt32 SysFreeString(IntPtr bstr);

        public static void DoTest()
        {
            // Allocate a byte array.
            byte [] byteArray = new byte[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            // Allocate an uninitialized BSTR. The length of the BSTR will be 
            // recorded in the 4 byte memory area just ahead of the pointer to
            // the actual BSTR.
            IntPtr pBSTR = SysAllocStringByteLen(null, (UInt32)(byteArray.Length));
            // Copy the binary data from byteArray into the BSTR.
            // The length of the BSTR will not change. Hence be careful
            // of the number of bytes to transfer to the BSTR memory.
            Marshal.Copy(byteArray, 0, pBSTR, byteArray.Length);
            // Free the BSTR. The 4-byte length indicator will also be de-allocated.
            SysFreeString(pBSTR);
            pBSTR = IntPtr.Zero;
        }

        static void Main(string[] args)
        {
            DoTest();
        }
    }
}

The following is a summary of the code above :

  • In the DoTest() function, we first allocate a byte array (byteArray) of length 10 bytes.
  • The byte array is initialized to values from 0 through 9.
  • The SysAllocStringByteLen() is then called with null being passed as first parameter and byteArray.Length being passed as second parameter.
  • This will allocate a memory buffer for a BSTR of 10 bytes.
  • When you look at memory though the memory viewer, you will see that the 4 byte length indicator is set to value 10 but the buffer of the BSTR is left unitialized with random bytes :

  • In the above diagram, the BSTR pointer as returned from SysAllocStringByteLen() is 0x001c0aa4. The preceding 4 byte length indicator contains 0x0000000a which is 10. The contents of the BSTR (the second red-box) is random.
  • Next, Marshal.Copy() is used to transfer the data of byteArray into the BSTR.
  • When you now look at memory though the memory viewer, you will see that the BSTR buffer area is indeed filled with data from byteArray. Note that the first byte is a 0 value which shows that the BSTR can contain embedded NULL bytes.

  • Next comes the litmus test of our allocation process : using SysFreeString() to free the contents of the BSTR.
  • After SysFreeString() is called, look at the memory of the BSTR. You will see that the memory buffer for the BSTR is released and the 4-byte length indicator is also recovered :

3.3 Note that I have run the code above after setting the OANOCACHE environment string to “1” which will indicate to the COM sub-system to not perform BSTR caching. This is why the BSTR is actually freed (viz cached for re-use).

4. In Conclusion.

4.1Just a few comments before signing off :

4.2 As stated in the comments of the sample code, as you copy data into the buffer area of the BSTR, the length of the BSTR will remain the same. Hence be careful not to copy more bytes into the buffer than what has been allocated.

4.3 Also, although it is possible to use the BSTR for storing binary data, it is better to use a SAFEARRAY of bytes wherever possible.

Advertisements

About Lim Bio Liong

I've been in software development for nearly 20 years specializing in C , COM and C#. It's truly an exicting time we live in, with so much resources at our disposal to gain and share knowledge. I hope my blog will serve a small part in this global knowledge sharing network. For many years now I've been deeply involved with C development work. However since circa 2010, my current work has required me to use more and more on C# with a particular focus on COM interop. I've also written several articles for CodeProject. However, in recent years I've concentrated my time more on helping others in the MSDN forums. Please feel free to leave a comment whenever you have any constructive criticism over any of my blog posts.

Discussion

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: