Link to home
Start Free TrialLog in
Avatar of vipin072998
vipin072998

asked on

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?
Avatar of ajitm
ajitm

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.
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.
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
yes Norbert is correct You may need to pass the size of buffer with it.
Use VT_UI1 | VT_ARRAY
>>Use VT_UI1 | VT_ARRAY
Create a safearray
variant.vt=VT_UI1 | VT_ARRAY
variant.parray=TheCreatedSafeArray
ASKER CERTIFIED SOLUTION
Avatar of gvg
gvg

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.
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