用VC处理ACCESS中的位图数据

----比较复杂的数据库中一般会有位图数据(比如相片)。虽然这类“OLE对象”的插入、删除以及替换操作在ACCESS里容易实现,在VC中却显得复杂而且颇费周折。以下把作者用VC处理ACCESS数据库中的位图数据的体会简单叙述一下,以请教于大家。
----在CdaoRecordset派生类的对象中,VC自动为ACCESS的“OLE对象”域生成一个CLongBinary对象。该类虽然较简单,在程序里却需要使用全局函数GlobalAlloc()和GlobalFree()处理与它的内存句柄m_hData有关操作,访问数据前后要调用GlobalLock()和GlobalUnlock(),而且还要给它的m_dwDataLength赋值,使用起来相对复杂,所以一般推荐使用CByteArray类。这只需要在CdaoRecordset派生类对象的数据说明里修改一下,并把DoFieldExchange()里的DFX_LongBinary()改成DFX_Binary()即可。
----作者定义了一个以CObject为基类的CDib类(CDaoRecordView的派生类里定义了CDib对象成员m_DIB),其中包括一下成员和方法:

CByteArray m_bufDIB; 

BOOL Create(CByteArray& ba); 

BOOL Create(CFile& bmpFile); 

BOOL Paint(HDC hDC);


----m_bufDIB是存储位图数据的缓冲区。为简便起见,它不包含包装信息和BITMAPFILEHEADER结构。这样对数据库更新后,原有的“OLE对象”类型将变成“长二进制数据”,不能在ACCESS里查看了。
----第一个Create()重载方法的参数ba是记录集的位图数据(比如m_image),使用CByteArray::Copy()把数据复制给m_bufDIB;第二个Create()方法的参数bmpFile是已打开的位图文件,使用CFile::ReadHuge()把文件里的数据读入m_bufDIB(放弃前面的BITMAPFILEHEADER结构):

DWORDdwBufSize; 

dwBufSize=bmpFile.GetLength();//获得文件长度 

bmpFile.Seek((long)sizeof(BITMAPFILEHEADER), 

CFile::begin);//放弃文件头 

dwBufSize-=sizeof(BITMAPFILEHEADER); 

m_bufDIB.SetSize(dwBufSize);//设置缓冲区大小 

file.ReadHuge((LPSTR)(m_bufDIB.GetData()),dwBufSize); 

……


----Paint()方法调用了SetDIBitsToDevice()函数(根据情况也可以使用StretchDIBits()),参数hDC是CDaoRecordview的资源中的一个静态控制的设备句柄,作为SetDIBitsToDevice()的第一个参数。如果不是16或24位的位图,还需要建立和设置调色板。Paint()方法除了在CDaoRecordView派生类的OnMove()里调用外,也被OnPaint()调用(最好不在OnDraw()里调用):

void CDerivedView::OnPaint() 

{ 

CPaintDC dc(this); 

CClientDC dc1(&m_ctlImage); 

if(m_DIB.Create(m_pSet->m_image)) 

m_DIB.Paint(dc1.m_hDC); 

}


----作者首先采用的方法是,每当打开一个位图文件,调用m_DIB.Create()和m_DIB.Paint(),然后复制给m_pSet->m_image,再设置“脏”标识:

if(m_DIB.Create(bmpFile)) 

{ 

CClientDC dc(&m_ctlImage); 

m_DIB.Paint(dc.m_hDC); 

(m_pSet->m_image).Copy(m_DIB.m_bufDIB); 

SetFieldDirty(&(m_pSet->m_image)); 

}


----记录滚动时,OnMove()调用Update()对数据进行更新。
----但是这样做的结果是,只有在域的内容不为空(NULL)的时候才能更新数据。也就是说,添加“长二进制数据”不能实现。
----最后发现使用SeieldValue()可以实现添加和替换。但由于作者未知的原因,还需要把另外某个域设置为“脏”才行:

if(m_DIB.Create(bmpFile)) 

{ 

CClientDC dc(&m_ctlImage); 

m_DIB.Paint(dc.m_hDC); 

(m_pSet->m_image).Copy(m_DIB.m_bufDIB); 

// 只 为OnPaint() 调 用 时 使 用 

m_pSet->SetFieldValue(_T("[image]"), 

COleVariant(m_DIB.m_bufDIB)); 

m_pSet->SetFieldDirty(&(m_pSet->m_name)); 

// 任 意 另 外 一 个 域 

}


----如果打算删除数据库里的位图数据,可以把一个“空”的CByteArray对象替换原来的就行了。