Binary data out of the BSTR


I am building an ATL Based DLL. This DLL exposes a interface say MyInterface having two methods
SetIconStream (BSTR a_bstrIconFileName)
GetIconStream (BSTR* a_pIconStream)
 SetIconStream Method takes the parameter as the filename of the icon file. In this method it opens the File and read the binary data of the icon file using the normal file functions and store this binary icon stream into a stream of a Compound Doc File.
The GetIconStream method opens the stream and gets the binary icon stream into a buffer. After Converting the buffer into the BSTR through the SysAllocByteLen () function and pass it back to the Caller of the method.

Now if I open a new file in binary mode after getting the binary icon stream from the stream of the compound file and put this into the newly opened file, then the icon file thus created is same as the original icon file.
But If I convert the buffer into the BSTR and then try to put the contents of the BSTR into another file then the icon file generated is not same as the original icon file. Plus the binary contents of the file are different than the Original file.

So my question is how to get the binary data out of the BSTR so that the file created (contents from BSTR) will be same as original one?
vipin072998Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ajitmCommented:
Hi vipin,
1. Try not to use any string related functions like strlen,strcpy etc.Because it serches for \0.Even the BSTR related functions like SysStringLen() uses the same method.As the data is binary you can't say where it can encouter the \0.
If you are using any such functions may be for allocating the BSTR try it hard coding the size.

2. The other way is that you should use VRAIANT * as a return value for the function GetIconStream (VARIANT*a_pIconStream) and pass the binary buffer as
V_VT(pVal) = VT_UI1|VT_BYREF;
V_UI1REF(pVal) = (unsigned char *)buff;

Here buff is the static buffer containing the binary data.

In receiving function
CComVariant a_pIconStream;
GetIconStream ((struct tagVARIANT *)&a_pIconStream)
switch(pdfBuffer.vt)
{
case  VT_BYREF|VT_UI1:
{
pdfBuf = (char *)V_UI1REF(&Buffer);
break;
}
default : break;
}
Here pdfBuf is again a char buffer to collect the binary data.

Hope this helps.
0
ajitmCommented:
Hi vipin,
1. Try not to use any string related functions like strlen,strcpy etc.Because it serches for \0.Even the BSTR related functions like SysStringLen() uses the same method.As the data is binary you can't say where it can encouter the \0.
If you are using any such functions may be for allocating the BSTR try it hard coding the size.

2. The other way is that you should use VRAIANT * as a return value for the function GetIconStream (VARIANT*a_pIconStream) and pass the binary buffer as
V_VT(pVal) = VT_UI1|VT_BYREF;
V_UI1REF(pVal) = (unsigned char *)buff;

Here buff is the static buffer containing the binary data.

In receiving function
CComVariant a_pIconStream;
GetIconStream ((struct tagVARIANT *)&a_pIconStream)
switch(pdfBuffer.vt)
{
case  VT_BYREF|VT_UI1:
{
pdfBuf = (char *)V_UI1REF(&Buffer);
break;
}
default : break;
}
Here pdfBuf is again a char buffer to collect the binary data.

Hope this helps.
0
NorbertCommented:
But if you using VT_UI1|VT_BYREF you will have no information about the size
My be it is better to use a safearray
0
Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

ajitmCommented:
yes Norbert is correct You may need to pass the size of buffer with it.
0
sboucher789Commented:
Use VT_UI1 | VT_ARRAY
0
NorbertCommented:
>>Use VT_UI1 | VT_ARRAY
Create a safearray
variant.vt=VT_UI1 | VT_ARRAY
variant.parray=TheCreatedSafeArray
0
gvgCommented:
When you send a BSTR the length is included.  It is a 32-bit value that is preceeding the string it self.  I am not sure if BSTR will point to this 32-bit value or the first byte in the string.   If it points to the first byte in the string you can do like this.

DWORD* pointer;
DWORD length;

pointer = (DWORD*)bStr;

// IF THE 32-BIT value is at front.
length = *pointer;

// IF THE 32-BIT value before front.
length--;
length = *pointer;

Now you know the size of the buffer so you can type cast it and you know its length.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
gvgCommented:
And now I know that this 32-Bit value is in front of the buffer.

so
DWORD* pointer;
DWORD length;
BYTE* buffer;

buffer = (BYTE*)bstr;
pointer = (DWORD*)bstr;
pointer--;
length = *pointer;

Gunnar Valur.
0
mikeblasCommented:
ajitm> Even the BSTR related functions like SysStringLen() uses the same method.

This is incorrect. SysStringLen() returns the number of characters allocated to the string, and does not count the nubmer of characters in the string.  The documentation even specifically says so!

Verify it empircally yourself with the following program.

--- begin file strlen.cpp ---

// compile with
//    cl strlen.cpp

#include <windows.h>
#include <stdio.h>

#pragma comment(lib, "oleaut32.lib")

void main()
{
   //                              1234567890123456 78901234567
   BSTR bstr = SysAllocStringLen(L"Hockey is best!\0Golf Sucks!", 27);

   if (bstr != NULL)
   {
      UINT n = SysStringLen(bstr);
      printf("Length by SysStringLen() is %u\n", n);

      n = lstrlenW(bstr);
      printf("Length by lstrlenW() is %u\n", n);

      SysFreeString(bstr);
   }
}

--- end file stlren.cpp ---

 gvg> you can do like this

You really mustn't do that. You should call the SysStringLen() or SysStringByteLen() APIs. BSTRs are data structures that are handled by APIs, not hacky pointer deferences.

 vipin> how to get the binary data out ...

You get the binary data out dereferencing the BSTR. It's difficult to give you any more information than that. Your question essentially says "I coded something and it didn't work". It's impossible for us to tell you why it didn't work without seeing the code.

..B ekiM
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.