From: dom_perron on
Hi,

I developed a component in .net which I call from an MFC program.
A .net function called in my c++ program return a safearray ** (wich
is a byte [] in .net). This function convert a string of binary data
base64 encoded in a array of byte[].

Here is my .NET implementation:

byte[] GetDecodedImage(String i_innerText)
{
byte[] base64 = Convert.FromBase64String(i_innerText);

return base64;
}

Here is the COM c++ implementation of this function:

virtual HRESULT __stdcall GetDecodedImage (/*[out,retval]*/ SAFEARRAY
* * pRetVal ) = 0;

I want to create a cbitmap or a HBITMAP with the pointer of this
struct but I dont know how to use it... Did someone could give me any
idea?

Thanks

Dominique

From: MrAsm on
On 14 Mar 2007 05:52:21 -0700, dom_perron(a)hotmail.com wrote:

It's not clear to me if your array stores just bitmap pixel data in
RGB (but, in this case, how do you know bitmap width and height? Is
this information already known, or constant?), or if these are the
bytes of a .bmp file (just copied into memory).

Could you please clarify this?

Moreover, I'm not sure about this point, but I think that you can call
C# and other .NET managed stuff from C++ and MFC, enabling some Visual
Studio .NET/2005 switch (/CLR?).
In this way, you would avoid the pain of SAFEARRAY management...

MrAsm


>Hi,
>
>I developed a component in .net which I call from an MFC program.
>A .net function called in my c++ program return a safearray ** (wich
>is a byte [] in .net). This function convert a string of binary data
>base64 encoded in a array of byte[].
>
>Here is my .NET implementation:
>
>byte[] GetDecodedImage(String i_innerText)
>{
>byte[] base64 = Convert.FromBase64String(i_innerText);
>
> return base64;
>}
>
>Here is the COM c++ implementation of this function:
>
>virtual HRESULT __stdcall GetDecodedImage (/*[out,retval]*/ SAFEARRAY
>* * pRetVal ) = 0;
>
>I want to create a cbitmap or a HBITMAP with the pointer of this
>struct but I dont know how to use it... Did someone could give me any
>idea?
>
>Thanks
>
>Dominique
From: dom_perron on
On Mar 14, 11:18 am, MrAsm <m...(a)usa.com> wrote:
> On 14 Mar 2007 05:52:21 -0700, dom_per...(a)hotmail.com wrote:
>
> It's not clear to me if your array stores just bitmap pixel data in
> RGB (but, in this case, how do you know bitmap width and height? Is
> this information already known, or constant?), or if these are the
> bytes of a .bmp file (just copied into memory).
>
> Could you please clarify this?
>
> Moreover, I'm not sure about this point, but I think that you can call
> C# and other .NET managed stuff from C++ and MFC, enabling some Visual
> Studio .NET/2005 switch (/CLR?).
> In this way, you would avoid the pain of SAFEARRAY management...
>
> MrAsm
>
>
>
> >Hi,
>
> >I developed a component in .net which I call from an MFC program.
> >A .net function called in my c++ program return a safearray ** (wich
> >is a byte [] in .net). This function convert a string of binary data
> >base64 encoded in a array of byte[].
>
> >Here is my .NET implementation:
>
> >byte[] GetDecodedImage(String i_innerText)
> >{
> >byte[] base64 = Convert.FromBase64String(i_innerText);
>
> > return base64;
> >}
>
> >Here is the COM c++ implementation of this function:
>
> >virtual HRESULT __stdcall GetDecodedImage (/*[out,retval]*/ SAFEARRAY
> >* * pRetVal ) = 0;
>
> >I want to create a cbitmap or a HBITMAP with the pointer of this
> >struct but I dont know how to use it... Did someone could give me any
> >idea?
>
> >Thanks
>
> >Dominique- Hide quoted text -
>
> - Show quoted text -

Do you know where I can find documentation on how I can call .NET
component in an MFC ActiveX using /CLR? I am working with VS2003.

Thanks
Dominique

From: MrAsm on
On 14 Mar 2007 08:43:17 -0700, dom_perron(a)hotmail.com wrote:


>Do you know where I can find documentation on how I can call .NET
>component in an MFC ActiveX using /CLR? I am working with VS2003.
>
>Thanks
>Dominique

Hi,

sorry, but I don't know how to mix C++ and .NET stuff.

(Frankly speaking, if I want to use .NET, I would use C# - a well
designed language - and not what I consider an ugly "genetic-modified"
:) C++ with managed .NET extensions: the so called "managed C++".

And if I need communication between .NET managed world and native
Win32 world, I would use simple C-interface DLLs or COM interop.
But it's just IMHO.)

However, if you have a pointer to the SAFEARRAY, and you want to use
its data, this is how you might consider to do:

<CODE>

// SAFEARRAY * psa;

HRESULT hr;
BYTE * pBytes = NULL;

// Get a pointer to the elements of the array
hr = SafeArrayAccessData( psa, (void HUGEP**)&pBytes );
if (FAILED(hr))
// Error ...


// *** Use the data pointed by pBytes ***

....
....

// Release array
SafeArrayUnaccessData( psa );
pBytes = NULL;

</CODE>


If your byte array is just a memory copy of a bitmap file, you may
consider using the following function to create the bitmap from this
data.

It's just:

HBITMAP hbmpMyImage = LoadBitmapFromMemory( pBytes );

(The routine uses ::CreateDIBSection.)

Here's the code:


<CODE>

//------------------------------------------------------------------
// Load a DIB file from memory buffer.
// Return bitmap handle on success, NULL on error
//
// by MrAsm
//------------------------------------------------------------------
HBITMAP LoadBitmapFromMemory( void * pBmpFileData )
{
// Check parameter
ASSERT( pBmpFileData != NULL );
if ( pBmpFileData == NULL )
return NULL;

// Pointer to file bytes
BYTE * pFileBytes = (BYTE *)pBmpFileData;

// DIB bits (will be set by CreateDIBSection)
BYTE * pBits = NULL;

// Access the BITMAPINFOHEADER section
BITMAPINFOHEADER * pbmih = (BITMAPINFOHEADER *)(pFileBytes +
sizeof(BITMAPFILEHEADER));

// Create the DIB
HBITMAP hBitmap = ::CreateDIBSection(
NULL, // No HDC used
(BITMAPINFO *)pbmih, // Pointer to DIB information
0, // Default
(void **)&pBits, // The function will return pointer to
// bitmap bits
NULL, // No file mapping
0 ); // No file mapping
if ( hBitmap == NULL )
return NULL;


// Get pointer to bitmap bits in original file
// (we obtain the offset from BITMAPFILEHEADER.bfOffBits field)
BITMAPFILEHEADER * pbmfh = (BITMAPFILEHEADER *)pFileBytes;
BYTE * pSourceBitmapBits = pFileBytes + pbmfh->bfOffBits;

// Copy bits
memcpy(pBits, pSourceBitmapBits, pbmih->biSizeImage);

// Return bitmap handle
return hBitmap;
}

</CODE>

Hope it helps,
MrAsm
From: MrAsm on
On 14 Mar 2007 08:43:17 -0700, dom_perron(a)hotmail.com wrote:

>> >I developed a component in .net which I call from an MFC program.
>> >A .net function called in my c++ program return a safearray ** (wich
>> >is a byte [] in .net). This function convert a string of binary data
>> >base64 encoded in a array of byte[].
>>
>> >Here is my .NET implementation:
>>
>> >byte[] GetDecodedImage(String i_innerText)
>> >{
>> >byte[] base64 = Convert.FromBase64String(i_innerText);
>>
>> > return base64;
>> >}

If you are using .NET just for the built-in base-64 decoding class,
you might consider the following C++ code. I adapted the core decoding
engine from a set of C functions at:

http://www.fourmilab.ch/webtools/base64/

(they have a command line base64 decoder/encoder written in C.)

If you have a base-64 encoded string, and you want to decode it, you
can write e.g.:

// Your base64 encoded input string:
// std::string base64data;

// Buffer to store result
Base64Decoder::Buffer result;

// Do the decoding
BYTE * pBytes = Base64Decoder::Decode( base64data, result );


The Base64Decoder::Decode method takes in input the base64 encoded
string, and a reference to a byte buffer. The method will decode the
input data into the buffer, and will return a pointer to first buffer
byte.
Note that the buffer is a std::vector<BYTE> allocated onto the stack,
so there's no need to delete[] the buffer.

The code follows:


<CODE File="Base64Decoder.h">

//////////////////////////////////////////////////////////////////////////
// FILE: Base64Decoder.h

#pragma once

//
// *** Base-64 Decoder ***
//
// By MrAsm
//
class Base64Decoder
{
public:

// Byte buffer
typedef std::vector< BYTE > Buffer;

//
// NOTE:
// Base-64 encoded strings are pure ASCII strings,
// so they don't need Unicode, and can be stored
// into std::string.
//

// Decode a base64-encoded string, and return the decoded string
static std::string DecodeString( IN const std::string &
encodedString );

// Decode a base64-encoded string, and save result into a buffer.
// Return pointer to first buffer byte.
static BYTE * Decode( IN const std::string & encodedString,
OUT Buffer & out );

// Decode base64-encoded data read from file, and save result
// into a buffer.
// Return pointer to first buffer byte on success.
// Return NULL on error.
static BYTE * DecodeFile( IN LPCTSTR szFileName,
OUT Buffer & out );



//
// IMPLEMENTATION
//

private:

static const std::string base64Chars;

static bool IsBase64( IN unsigned char c ) {
return (isalnum(c) || (c == '+') || (c == '/'));
}

static bool CompactLines( IN LPCTSTR szFileName,
OUT std::string & data );
};

//////////////////////////////////////////////////////////////////////////

</CODE>



<CODE File="Base64Decoder.cpp">

//////////////////////////////////////////////////////////////////////////
// FILE: Base64Decoder.cpp

#include "StdAfx.h"
#include "Base64Decoder.h"


const std::string Base64Decoder::base64Chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";



std::string Base64Decoder::DecodeString( IN const std::string &
encodedString )
{
//
// This decoding engine is adapted from:
//
// http://www.fourmilab.ch/webtools/base64/
//

int in_len = (int) encodedString.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;

while (in_len-- && ( encodedString[in_] != '=') &&
IsBase64(encodedString[in_]))
{
char_array_4[i++] = encodedString[in_]; in_++;
if (i ==4)
{
for (i = 0; i <4; i++)
char_array_4[i] = (unsigned char)
base64Chars.find(char_array_4[i]);

char_array_3[0] = (char_array_4[0] << 2) +
((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) +
((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) +
char_array_4[3];

for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}

if (i)
{
for (j = i; j <4; j++)
char_array_4[j] = 0;

for (j = 0; j <4; j++)
char_array_4[j] = (unsigned char)
base64Chars.find(char_array_4[j]);

char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] &
0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) +
((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) +
char_array_4[3];

for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}

return ret;
}


// Build a single line from Base64 file content
bool Base64Decoder::CompactLines( IN LPCTSTR szFileName, OUT
std::string & data )
{
data.clear();

FILE * file = _tfopen( szFileName, _T("rt") );
if ( file == NULL )
return false;

static const int maxLineChars = 100;
char line[ maxLineChars + 1 ];

std::ostringstream os;
while ( true )
{
ZeroMemory( line, sizeof(line) );
if ( ! fgets( line, maxLineChars, file ) )
{
break;
}

// Remove ending '\r\n'
size_t len = strlen(line);
if ( line[len-2] == '\r' )
line[len-2] = '\0';

// Add line
os << std::string( line );
}

fclose( file );
file = NULL;

data = os.str();
return true;
}


BYTE * Base64Decoder::Decode( IN const std::string & encodedString,
OUT Buffer & out )
{
// Clear output buffer
out.clear();

// std::string is a vector of bytes, so we can store
// decoded stuff into it
std::string decoded = DecodeString( encodedString );

// Copy the string content into destination buffer
out.resize( decoded.length() );
BYTE * pOutput = &(*out.begin());
memcpy( pOutput, decoded.c_str(), decoded.length() );

// Return pointer to destination buffer
return pOutput;
}


BYTE * Base64Decoder::DecodeFile( IN LPCTSTR szFileName, OUT
std::vector<BYTE> & out )
{
// Clear output buffer
out.clear();

// Check file name
ASSERT( szFileName != NULL );
if ( szFileName == NULL )
return NULL;

// Compact input file lines into a single base64 string
std::string base64data;
if ( ! CompactLines( szFileName, base64data ) )
return NULL;


// Decode into buffer
return Decode( base64data, out );
}


//////////////////////////////////////////////////////////////////////////

</CODE>


MrAsm