65.9K
CodeProject 正在变化。 阅读更多。
Home

在 WTL OLE DB 数据库应用程序中使用 Blob

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (4投票s)

2002年9月7日

6分钟阅读

viewsIcon

129275

downloadIcon

6061

描述了DDX的扩展,可以使用OLE DB提供程序读写blob。包括针对SQL Server "Pubs"和MS Access "Northwind"的WTL OLE DB数据库示例项目。

WTL OLE DB DDX Sample 2

图1. SQL Server Pubs.pub_info 示例项目

WTL OLE DB DDX Sample 3

图2. MS Access Northwind.Categories 示例


引言

本文描述了blobddx.h,它是atlddx.h的一个扩展,用于OLE DB消费者应用程序,以与数据库交换图像和文本blob数据。该扩展包含通过流读写MS SQL Server文本和MS Access备注字段的代码。它还允许读写非OLE图像blob。最后,它提供了对OLE对象位图图像的只读支持,例如Northwind数据库中的图像。

有两个示例项目可供下载。第一个是一个标准的基于WTL对话框的应用程序,它使用编辑控件和静态图片控件进行数据显示。它通过OLE DB for SQL Server提供程序从MS SQL Server "Pubs"数据库获取数据。您必须有权访问SQL Server才能使用该示例。

第二个示例通过OLE DB for Jet 4.0提供程序从MS Access "Northwind"数据库获取数据。由于图像是OLE对象,因此它们是只读的。您必须拥有Microsoft Office 97或2000示例目录中的Northwind.mdb文件。

使用Blob DDX

blobddx.h包含扩展atlddx.h的源代码,通过为文本和图像blob提供DDX(动态数据交换)。它包含以下宏/方法:

  1. DDX_IMAGE - 支持从SQL Server图像列交换位图、gif和jpg图像,以在静态图片控件中显示。它还提供对MS Access OLE对象位图图像的只读支持。
  2. DDX_EDIT - 在编辑控件和SQL Server文本列或MS Access备注列之间交换最大64K的文本blob。
  3. DDX_RICHEDIT - 支持最大2GB的文本blob与RichEdit控件。

当Unicode标志设置为TRUE时,DDX_EDITDDX_RICHEDIT都提供有限的Unicode支持。使用DDX_RICHEDIT时需要RichEdit 2.0控件。

您可以手动编辑.rc文件,为VC6对话框应用程序启用RichEdit 2.0。将资源编辑器添加的任何RichEdit控件的"RICHEDIT"更改为"RichEdit20a"。此外,您必须将stdafx.h中的RICHEDIT_VER定义更改为0x0200。

Blob DDX还包含CISSHelper类的WTL移植以及blob长度宏的副本,两者都来自AOTBLOB MSDN示例。此外,它还提供了一个辅助方法来剥离Access位图图像的OLE头,以及可以加载(bmp,gif,jpg)和保存(仅bmp)磁盘文件图像的辅助方法。

示例DDX映射

以下是SQL Server示例项目Oledb2View.h中的DDX_MAP。它展示了DDX_IMAGE宏所需的语法。

BEGIN_DDX_MAP(COledb2View)
   DDX_TEXT(IDC_PUBID, m_pub.m_pubid)
   DDX_TEXT(IDC_PRINFO, m_pub.m_prinfo)
   DDX_IMAGE(IDC_LOGO, m_pub.m_logo, m_pub.m_logoLength, m_pub.m_logoStatus)
END_DDX_MAP()

pr_info列定义为SQL Server文本列。它实际上是一个blob,但ATL OLE DB向导将其定义为TCHAR [1024]。由于实际数据比这长,示例项目的变量已更改为TCHAR [65536]。理论上,对于SQL Server 7或更高版本,您可以定义两个blob流,一个用于文本blob,一个用于图像blob。

Unicode支持

要在RichEdit 2.0控件中支持带有pr_info列的Unicode,您需要进行以下更改(当然,列数据类型必须更改为ISequentialStream*,并且必须定义长度和状态变量)

// old DDX entry
   DDX_TEXT(IDC_PRINFO, m_pub.m_prinfo)

// replace with
   DDX_RICHEDIT(IDC_PRINFO, m_pub.m_prinfo, m_pub.m_prinfoLength,
		m_pub.m_prinfoStatus, TRUE)

OLE DB访问器

访问器是消费者创建(在示例项目的pubinfo.h中定义)的一种数据结构,它描述了数据存储中的行或参数数据如何在消费者的数据缓冲区中布局。提供程序使用此访问器来确定如何将数据传输到和传输出自消费者。

OLE DB消费者向导创建了一个COLUMN_MAPACCESSOR_MAP的单个访问器版本),其中包含所选表中的所有列。在某些情况下,COLUMN_MAP就足够了,例如对于只读或非blob数据,尤其是在Jet 4.0中。

然而,消费者可能需要多个访问器。例如,以下ACCESSOR_MAP,来自SQL Server示例项目的pubinfo.h,包含访问器0,它访问两个文本列的数据,以及访问器1,它访问图像blob数据。此访问器映射用于读写SQL Server中的Pubs.pub_info表。

BEGIN_ACCESSOR_MAP(CPubInfoAccessor, 2)
   BEGIN_ACCESSOR( 0, true )
      COLUMN_ENTRY(1, m_pubid)
      COLUMN_ENTRY(3, m_prinfo)
   END_ACCESSOR()
   BEGIN_ACCESSOR( 1, false )
      BLOB_ENTRY_LENGTH_STATUS(2, IID_ISequentialStream, STGM_READ, m_logo,
			       m_logoLength, m_logoStatus)
   END_ACCESSOR()
END_ACCESSOR_MAP()

请注意Logo列使用BLOB_ENTRY_LENGTH_STATUS宏。此宏使用ISequentialStream访问列2进行读取,并提供数据、数据长度和列状态。atldbcli.h中定义了几个列宏,但此宏是从MSDN示例AOTBLOB复制到blobddx.h的。

以下是如何定义上述映射以支持两个blob列。SQL Server 7及更高版本支持多个流(如果DBPROP_MULTIPLESTORAGEOBJECTS为真)。

BEGIN_ACCESSOR_MAP(CPubInfoAccessor, 3)
   BEGIN_ACCESSOR( 0, true )
      COLUMN_ENTRY(1, m_pubid)
   END_ACCESSOR()
   BEGIN_ACCESSOR( 1, false )
      BLOB_ENTRY_LENGTH_STATUS(2, IID_ISequentialStream, STGM_READ, m_logo,
			       m_logoLength, m_logoStatus)
   END_ACCESSOR()
   BEGIN_ACCESSOR( 2, false )
      BLOB_ENTRY_LENGTH_STATUS(3, IID_ISequentialStream, STGM_READ, m_prinfo,
			       m_prinfoLength, m_prinfoStatus)
   END_ACCESSOR()
END_ACCESSOR_MAP()

处理图像

Blob DDX使用IPicture对象来保存图像。IPicture可以处理多种图像格式,包括位图、gif和jpeg。Blob DDX使用各种流和缓冲区在数据库和IPicture之间移动图像数据,并使用静态图片控件在对话框上显示图像。

以下代码片段显示了支持DDX_IMAGE的方法中的读取代码。唯一棘手的部分是OLE DB提供程序是ISequentialStream,而IPicture需要IStream。因此,使用了中间缓冲区。

BOOL DDX_Image(UINT nID, ISequentialStream* &pStream, BOOL bSave,
	       ULONG& ulLength, ULONG& ulStatus)
{
   T* pT = static_cast< T* >(this);

   if (!bSave)
   {
      IPicture* pIPicture;
      IStream* pIStream = NULL;
      void* buffer = ::CoTaskMemAlloc(ulLength);

      // read the provider supplied ISequential stream
      if (pStream->Read(buffer, ulLength, NULL) == S_OK)
      {
	 // create an IStream on the buffer. TRUE means that
	 // the stream will be automatically released
	 ::CreateStreamOnHGlobal(buffer, TRUE, &pIStream);

	 // load the IPicture from the IStream
	 if (::OleLoadPicture(pIStream, 0, FALSE, IID_IPicture,
			      (LPVOID*)&pIPicture) == S_OK)
	 {
	    // display the image in the static control
	    OLE_HANDLE handle;
	    pIPicture->get_Handle(&handle);
	    CStatic(pT->GetDlgItem(nID)).SetBitmap((HBITMAP)handle);
	 }
      // release the database stream
      pStream->Release();
      }
      ::CoTaskMemFree(buffer);
   }
}

Blob DDX还提供了加载和保存磁盘文件图像的辅助工具。读取由LoadImageFromFile()方法处理,写入由SaveImageToFile()处理。这两种方法都启动标准文件对话框以提示用户输入文件名。图像从文件加载后,它被放置在IPicture对象中,随后可以保存到数据库中(请记住,不支持保存OLE对象)。

已知问题

  1. MS Access OLE对象位图图像是只读的。blobddx.h的未来版本可能允许写入。
  2. SaveImageToFile()仅以位图格式保存。(Unisys LZW专利问题,不是技术问题)
  3. OleSavePictureFile(),在SaveImageToFile()中使用,可能会在处理大图像(> 5MB)时崩溃。
  4. OleLoadPicturePath(),在LoadImageFromFile()中使用,可能会分配资源但不释放。
  5. DDX_EDIT Unicode支持是从将Unicode数据源(例如MS Access备注字段)转换为ANSI以在ANSI编辑控件中显示的角度。它可能不适用于Unicode编辑控件。

致谢

部分信息来源于Microsoft知识库文章Q190958 "AOTBLOB使用OLE DB消费者模板读写BLOB"。两个宏被复制,ISSHelper类从MSDN示例AOTBLOB移植过来。

使用条款

本文提供的示例项目是免费的。SoftGee保留blobddx.h中代码的版权,但AOTBLOB示例中属于Microsoft版权的部分除外。

请注意,此代码能够永久删除活动数据库中的记录。请自行承担风险,并始终备份您的数据!

本软件按“现状”分发,不提供任何形式的担保。

© . All rights reserved.