Embedding OLE Objects Into an Access Database

This article illustrates how to programmatically embed OLE objects into Microsoft Access database.

  • 1. Write the header
  • 2. Write the name GetUserType( USERCLASSTYPE_SHORT )
  • 3. Write the class ProgIDFromCLSID
  • 4. Write the storage OleConvertIStorageToOLESTREAM

One remaining item is that before Access actually writes out the storage, it adds a stream to it that contains information that is lost in the process of OleConvertIStorageToOLESTREAM/OleConvertOLESTREAMToIStorage. However, if this stream isn't there, Access just uses the defaults so it isn't fatal.

This means that to read an object back in the following steps have to be taken:

  • 1. Read the header
  • 2. Read the name (ignore)
  • 3. Read the class CLSIDFromProgID
  • 4. Read the storage OleConvertOLESTREAMToIStorage

The sample attached uses the Insert OLE Object dialog.


DWORD dwObjectSize = 0;
DWORD dwCheckSum = 0;
int iHeaderSize = 0;
CLongBinaryDoc* pDoc = NULL;
CLongBinaryItem* pClone = NULL;
LPSTREAM lpObjStream = NULL;
LPOLE1STREAM lpOle1Stream = NULL;
LPOLECLIENTSITE lpClientSite = NULL;
HGLOBAL hgMemObject = NULL;
HGLOBAL hgAccessHeader = NULL;
HGLOBAL hgNewLongBinary = NULL;
LPBYTE lpbMemObject = NULL;
LPBYTE lpbAccessHeader = NULL;
LPBYTE lpbNewLongBinary= NULL;
int nIDLast = 1;
ULARGE_INTEGER ulStreamSize;


// allocate enough memory to write access header to
if( NULL == ( hgAccessHeader = GlobalAlloc(GMEM_MOVEABLE, sizeof( OLEOBJHDR ) + 100 )))
{//Processing fault}

// write the access-header
if( 0 == ( iHeaderSize = WriteAccessHeader(hgAccessHeader, m_pSelection->m_lpObject )))
{//Processing fault}

// adjust size of memory-block according to WriteAccessHeader()
if ( NULL == ( hgAccessHeader = GlobalReAlloc(hgAccessHeader, iHeaderSize, GMEM_MOVEABLE )))
{//Processing fault}
// Alloc the memory to store the long binary
if ( NULL == ( hgMemObject = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, 0 )))
{//Processing fault}
// create an IStream on top of the ILockBytes 
// (indicate automatic deletion of HGLOBAL on Release)
// IMPORTANT: This IStream* (and therewith the memory
// will be released during DeleteOleStream()
if ( FAILED( ::CreateStreamOnHGlobal( hgMemObject, TRUE, &lpObjStream )))
{//Processing fault}
// convert the IStream to an IStorage ( ACCESS stores OLE Objects the OLE1 way)
// in order to do so, we first have to wrap the OLE2 IStream into an OLE1 OLESTREAM
// see MSDN Article: "More on Using Storage Objects in OLE"
// NOTE: the Get() and Put() functions wrapped in the OLESTREAMVTBL will
// access the newly opened stream using an IStream* variable
if ( NULL == ( lpOle1Stream = CreateOle1Stream( lpObjStream, 0 )))
{//Processing fault}
// if the OLE object was not loaded from the DB, but rather
// created using CreateNewItem(), or if the item was modified
// after loading it from the DB, the m_lpStorage of the item
// will not contain the updated item information, since it wasn't
// yet saved to that IStorage.
// in order to assure that m_lpStorage points to the updated
// information, we force the item to save it's data.
// NOTE: GetClientSiteFromHere() will internally call GetClientSite()
// and GetInterface(). The MFC's implementation of GetInterface()
// however, doesn't AddRef() "lpClientSite", so we don't have to
// release it.
lpClientSite = m_pSelection->GetClientSiteFromHere();
if ( FAILED ( lpClientSite->SaveObject()))
{//Processing fault}
// convert the client-item's IStorage* to an OLE1 OLESTREAM
// NOTE: as soon as the stream gets converted, the data will be written
// to the IStream* and thereby to the HGLOBAL (see Put() function)
if ( FAILED ( ::OleConvertIStorageToOLESTREAM(
m_pSelection->m_lpStorage, ( LPOLESTREAM ) lpOle1Stream )))
{//Processing fault}
// adjust stream's size to reflect exactly the amount of bytes written to it
ulStreamSize.LowPart = lpOle1Stream->dwSize;
ulStreamSize.HighPart = 0;
if ( FAILED ( lpOle1Stream->lpStream->SetSize( ulStreamSize )))
{//Processing fault}
// allocate a new memory handle which is large enough to hold the
// Access header, the OLE1 OLESTREAM containing the object and the checksum
if ( NULL == ( hgNewLongBinary = GlobalAlloc( 
GHND, iHeaderSize + lpOle1Stream->dwSize + sizeof( DWORD ))))
{//Processing fault}
// and copy the complete information into it
if ( NULL == ( lpbAccessHeader = ( LPBYTE ) GlobalLock(hgAccessHeader )))
{//Processing fault}
if ( NULL == ( lpbMemObject = ( LPBYTE ) GlobalLock( hgMemObject)))
{//Processing fault}
if ( NULL == ( lpbNewLongBinary = ( LPBYTE ) GlobalLock( hgNewLongBinary )))
{//Processing fault}

memcpy( lpbNewLongBinary, lpbAccessHeader, iHeaderSize );
lpbNewLongBinary += iHeaderSize;
memcpy( lpbNewLongBinary, lpbMemObject, lpOle1Stream->dwSize );
lpbNewLongBinary += lpOle1Stream->dwSize;
memcpy( lpbNewLongBinary, &dwCheckSum, sizeof( DWORD ));
lpbNewLongBinary += sizeof( DWORD );
GlobalUnlock( hgMemObject );
GlobalUnlock( hgAccessHeader );
GlobalUnlock( hgNewLongBinary );

// make sure recordset is open and in edit mode
if( !m_pSet->IsOpen() )
m_pSet->Open();
m_pSet->Edit();

// throw away old memory and point the longbinary to the new memory
GlobalFree( m_pSet->m_OLE_Object.m_hData );
m_pSet->m_OLE_Object.m_hData = hgNewLongBinary;

// set the CLongBinary length
m_pSet->m_OLE_Object.m_dwDataLength = 
iHeaderSize + lpOle1Stream->dwSize + sizeof( DWORD );

// Update the datasource
m_pSet->SetFieldDirty( &m_pSet->m_OLE_Object, TRUE );
m_pSet->SetFieldNull( &m_pSet->m_OLE_Object, FALSE );
m_pSet->Update();
If given only file path you can use following lines of code

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

COleDocument Doc;

HGLOBAL hgAccessHeader = NULL;

//To get the class header and implementation code download the source
CLongBinaryItem oci(&Doc);
CString strPath;

HGLOBAL hgAccessHeader = NULL; 
 ::GetTempPath(MAX_PATH,strPath.GetBuffer(MAX_PATH));

strPath.ReleaseBuffer();

strPath += _T("some.bmp");
//Create from file
if(!oci.CreateFromFile(strPath))
{//Processing fault}
// allocate enough memory to write access header to
hgAccessHeader = GlobalAlloc(GMEM_MOVEABLE, sizeof( OLEOBJHDR ) + 100);
int iHeaderSize = WriteAccessHeader(hgAccessHeader,oci.m_lpObject);

Downloads

Download demo project - 81 Kb
Download source - 10 Kb


Comments

  • er pÃ¥ udkig efter et nyt headset til ipod've fundet lige hvad du ledte efter.

    Posted by rhitmt039 on 07/17/2013 08:52am

    Beats By Dr. Dre Beats Wireless har annonceret et trådløst Bluetooth-headset. Dette er udformningen af den populære Solo HD og kan let kobles med en smartphone eller tablet. Den nye model er også udstyret med ControlTalk, med en mikrofon i øret og alle nødvendige kontroller. Beats By Dr. Dre introducerer Beats trådløse Bluetooth hovedtelefoner Beats By Dr. Dre Beats introducerer den trådløse Bluetooth-hovedtelefoner lytteren fuld musikalsk frihed. [url=http://beatsbydrdredan.ucoz.com/]beats by dre billigt[/url] If inline controls for calls is a priority, consider checking out the RHA SA950i, which is even more affordable, and also has a more substantial bass response in comparison. The Polk Audio UltraFit 2000 is another budget on-ear option—more affordable than the Zoro with phone controls built into the earpieces, and as a bonus, it’s intended to withstand sweaty workouts. If you have a bit more room in your budget and still want an emphasis on clarity in the mids, and bass that isn’t wildly boosted, the Bowers & Wilkins P3 is a comfortable on-ear option with solid audio performance. [url=http://beatsbydrdredanmark.moonfruit.com/]beats by dre billigt[/url] Det kan ikke være potentiel, at du er en total musik-freak, og du måske ikke tænker højtydende trådløse hovedtelefoner! Disse gadgets er de korrekte kammerater specielt inde du lytter til musik bestræbelser. Der er en række organisationer, først og fremmest de velkendte mærker, som Sony, Philips og Samsung osv., der tilfældigvis er i massiv organisering af elektroniske varer og tjenesteydelser og hovedtelefoner med Monstor Diddybeats White trådløse bestemmelser er en af dem. Du vil finde bestemte funktioner og faktorer, som har at blive alvorligt tages i betragtning, når 1 vælger denne fantastiske enhed. Målet er normalt at støde på en sund god kvalitet, der er helt sikkert virkelig vidunderlig og afslappende mod sindet også.

    Reply
  • Nike Air Max 1 FB release, cause a eager color character, the unheard of shoes

    Posted by Geozyoceada on 04/24/2013 03:20pm

    In the summer in a pane inside the cool sprite seems to be a godlike fitting, but if the sprite "feet"? Resolution also give you a trip, accompany a sustenance! This summer, Nike and Sprite [url=http://markwarren.org.uk/goodbuy.cfm]nike free[/url] and his sneakers to a commingling of classic snow spread of non-professional, white and indecent color scheme in the definitive Nike Arrogance Max 1 shoes let it be known a refreshing chill scent.[url=http://markwarren.org.uk/property-waet.cfm]nike air max 90[/url] Summer is the metre to pick a cleanly shoe, shoes should be a acceptable choice. Qualifying series Nike Air Max HomeTurf metropolis recently definitely comes up, this series in the immortal Breath Max shoes to London, Paris and Milan the three paid tribute to the iconic metropolis of Europe, combined with the characteristics of the three cities, Air Max 1 HYP,Air Max 90 HYP,Superciliousness Max 1 and shoes such as Quality Max 95, combined [url=http://turbo-vac.co.uk/components_13.cfm]nike free uk[/url] with the Hyperfuse, as kind-heartedly as a collection of materials, such as suede, Whether you crave going or retro-everything.

    Reply
  • How to Extract Data

    Posted by Legacy on 12/01/2003 12:00am

    Originally posted by: Amit

    Is there a way to extract the OLE data and save it as a file w/ the correct extension?

    Thanks,
    Amit

    Reply
  • Excellent

    Posted by Legacy on 05/08/2002 12:00am

    Originally posted by: P.S.Kumaran

    Very usefull code, Excellent work 
    

    Reply
  • You are the man

    Posted by Legacy on 07/13/2001 12:00am

    Originally posted by: Marius Mihalca

    Thanks u very much! I liked your articole verry much. Keep up the good work!

    Reply
  • Word documents in Acces database

    Posted by Legacy on 04/17/2001 12:00am

    Originally posted by: Udi

    Does anyone know how to store Word documents on Access 2000, possibly using OLE embedding, without flickering, with speed etc.

    I then want to merge documents according to queries, back into Word documents.

    Reply
  • Can't extract it from MS Access

    Posted by Legacy on 03/19/2001 12:00am

    Originally posted by: Nikola

    O.K. I ran the program and yes, it inserts an object. But once I've double clicked onto it the following message appears: "A problem occured while Microsoft Access was communicating with OLE Server" - "Close the OLE Server and restart it outside of Microsoft Access". Yet the object was stored as a Long binary data. How could I get rid of it?
    While I am inserting an object using the same dialog from MS Access, everything is fine

    Reply
  • OleConvertOleStreamToIStorage help!

    Posted by Legacy on 04/28/2000 12:00am

    Originally posted by: Fethi Migaou

    Hi;
    Does anyone know where I can find some (complete)
    examples on how to use OleConvertOleStreamToIStorage or
    OleConvertOleStreamToIStorageEx functions. I am trying
    to convert an OLE1 storage file format to OLE2 storage
    file. Your help is appreciated.
    Thanks.
    Fethi

    Reply
  • Where is "Using Storage Objects in OLE"

    Posted by Legacy on 01/18/2000 12:00am

    Originally posted by: Mihai Filimon

    Hi, and sorry if I bother you, but I am searching for the MSDN article: "Using Storage Objects in OLE". Where I can find it. Thanks in advance...
    Mihai

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The explosion in mobile devices and applications has generated a great deal of interest in APIs. Today's businesses are under increased pressure to make it easy to build apps, supply tools to help developers work more quickly, and deploy operational analytics so they can track users, developers, application performance, and more. Apigee Edge provides comprehensive API delivery tools and both operational and business-level analytics in an integrated platform. It is available as on-premise software or through …

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds