程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++應用ADO完成存取圖片的辦法

C++應用ADO完成存取圖片的辦法

編輯:關於C++

C++應用ADO完成存取圖片的辦法。本站提示廣大學習愛好者:(C++應用ADO完成存取圖片的辦法)文章只能為提供參考,不一定能成為您想要的結果。以下是C++應用ADO完成存取圖片的辦法正文


普通在網上查到的材料中向Server2000存儲圖片代碼比擬多,從數據庫中讀取圖片並顯示也很多,然則把圖片從數據庫中二進制數據轉換為原圖片保留在當地,就很少有C++代碼了。本文就此成績一步一步地講一講授決的辦法:

1、應用數據庫前的預備

我們應用ADO,是用_ConnectionPtr,_RecordsetPtr來把持數據庫的。還有一個_CommandPtr,本法式沒有應用它。

為了應用ADO,須要導入ADO靜態鏈接庫。在工程的stdafx.h文件中,添加以下代碼:

//導入ADO
#import "C:\Program Files\Common Files\System\ado\msado15.dll"\
rename_namespace("ADOCG")rename("EOF","EndOfFile")
using namespace ADOCG;

這些代碼聲明,在這個工程中應用ADO但不應用ADO的名字空間,而且為了不常數抵觸,將常數EOF更名為adoEOF。

再有就是要建一個簡略的數據庫,名字叫TestImage,外面有一個表Images,這個表有三個字段,分離是ID,Name,ImageData。

2、銜接數據庫

銜接數據庫的代碼可以放入一個函數中,在想挪用的處所挪用。普通不推舉在CAPP類的Initalize()裡銜接數據庫,在加入法式時封閉數據庫銜接。應當是在應用時銜接,應用完立時封閉。項目中m_pConn是_ConnectionPtr類型的變量。

BOOL OpenConnection()
{
if(m_pConn == NULL)
{
m_pConn.CreateInstance("ADODB.Connection"); //創立_ConnectionPtr的一個實例
}

try
{
if(adStateClosed == m_pConn->State) //假如已封閉
{
m_pConn->Open("driver={SQL Server};Server=HP-CADD722B76A0;DATABASE=TestImage;UID=sa;PWD=sa","","",adModeUnknown); //因數據庫而異
return true;
}
}
catch(_com_error e)
{
AfxMessageBox(_T("銜接數據庫掉敗!"));
return false;
}
}

3、翻開數據集,把持數據庫

在應用_RecordSetPtr對象m_pRecord時,必需先創立這類對象的一個實例:

m_pRecord.CreateInstance( __uuidof(RecordSet) );

CString strSQL;
//獲得表中最年夜的id,下一次拔出時就用id+1
strSQL.Format(_T("Select count(*) as num, Max(ID) as maxid from Images"));
try
{
m_pRecord->Open(strSQL.AllocSysString(), m_pConn.GetInterfacePtr(),
adOpenDynamic, adLockUnspecified, adCmdText);
}
catch (_com_error e)
{
AfxMessageBox(_T("讀取最年夜的id異常"));
eturn;
}

//從RecordSet中獲得數據數量和以後數據庫中最年夜的ID。
int num = m_pRecord->GetCollect("num");
int maxid;
if (num != 0)
{
maxid = m_pRecord->GetCollect("maxid");
}
else
{
maxid = 0;
}

strSQL.Format(_T("Select * from Images where ID = %d"), maxid);
//上面向數據庫中拔出圖片等。
//起首從數據庫中讀id最年夜的那條數據,重要目標是為了將RecordSet初始化
m_pRecord.CreateInstance(__uuidof(Recordset));

下面這句必定要留意,由於上一次把一些數據放入m_pRecord中,這一次再放的時刻,要從新創立一次,不然數據格局要末不婚配,要末保存有上一次的數據,定位艱苦。

m_pRecord->Open(strSQL.AllocSysString(), m_pConn.GetInterfacePtr(), 
adOpenDynamic, adLockOptimistic, adCmdText); //這是AddNew辦法請求的

CString imagepath = _T("F:/200713454/20090326.bmp");
CString imagename = imagepath.Right(12);
try
{
m_pRecord->AddNew(); //為記載集添加新的一行,更新時就會把這條新記載放到數據庫中
}
catch (_com_error e) 
{
AfxMessageBox(_T("不克不及拔出一條新的記載"));
return;
}

try
{

//應用putcollect拔出非圖象數據,應用SetImage2DB拔出圖象數據
m_pRecord->PutCollect("ID", _variant_t(maxid+1));
m_pRecord->PutCollect("Name", _variant_t(imagename));
SetImage2DB(imagepath);
}
catch (_com_error e)
{
AfxMessageBox(_T("拔出圖片有異常"));
return;
}
m_pRecord->Update();

//應用終了,封閉m_pRecord,並設置為NULL,最初封閉數據庫銜接
m_pRecord->Close();
m_pRecord = NULL;
CloseConnection();

4、讀取圖片並存儲到當地盤算機

要將數據庫中的二進制數據變成圖片,最簡略的辦法就是用GDI+。GDI+有一個類是Image,可以用stream來創立對象,還可以用Save辦法保留到當地,所以這個類很相符須要。

要應用GDI+,須要做些設置。起首在VS2005的項目屬性中,加上gdiplus.lib。

然後在stdafx.h中添加代碼

#include <GdiPlus.h>
using namespace Gdiplus;

在CApp類添加兩個變量:

GdiplusStartupInput m_gdiplusstartUpInput;
ULONG_PTR m_GdiplusToken;

在CApp的InitInstance函數中添加

GdiplusStartup(&m_GdiplusToken, &m_gdiplusstartUpInput, NULL);

在ExitInstance函數中添加

GdiplusShutdown(m_GdiplusToken);

以下是讀取圖片數據並保留到當地的代碼完成:

OpenConnection();

m_pRecord.CreateInstance(__uuidof(Recordset));
CString strSQL;
strSQL.Format(_T("Select * from Images where ID = 1"));
try
{
m_pRecord->Open(strSQL.AllocSysString(), m_pConn.GetInterfacePtr(),
adOpenDynamic, adLockOptimistic, adCmdText);
}
catch (_com_error e)
{
AfxMessageBox(_T("讀取圖片信息異常"));
return;
}

LPVOID Data;
char* pbuf = NULL;

long lDatasize = m_pRecord->GetFields()->GetItem("ImageData")->ActualSize; //數據庫中圖象數據長度
CString imagename = m_pRecord->GetCollect("Name").bstrVal;
if (lDatasize > 0)
{
_variant_t varBLOB;
varBLOB = m_pRecord->GetFields()->GetItem("ImageData")->GetChunk(lDatasize);
Data = new char[lDatasize+1];
if (varBLOB.vt == (VT_ARRAY|VT_UI1))
{
SafeArrayAccessData(varBLOB.parray, (void **)&pbuf);
memcpy(Data, pbuf, lDatasize);
SafeArrayUnaccessData(varBLOB.parray);
}
}
IStream* pStm;
LONGLONG cb = lDatasize;
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, cb);
LPVOID pvData;
if (hGlobal != NULL)
{
pvData = GlobalLock(hGlobal);
memcpy(pvData, Data, cb);
GlobalUnlock(hGlobal);
CreateStreamOnHGlobal(hGlobal, TRUE, &pStm);
}
else
{
AfxMessageBox(_T("Error"));
return;
}

CLSID encoderClsid;
GetEncoderClsid(L"image/bmp",&encoderClsid); //肯定編碼格局是bmp格局
Image image(pStm, TRUE);
CString imagepath;
imagepath.Format(_T("F:/200713454/%s"), imagename);
image.Save(imagepath, &encoderClsid, NULL); //把image中的數據依照bmp編碼格局存到當地

m_pRecord->Close();
m_pRecord = NULL;
CloseConnection();

下面存儲和讀取數據的代碼頂用到了兩個函數,GetEncoderClsid和SetImage2DB。它們的完成以下:
這個函數和下面的存/取函數都是一個類的成員函數,而m_pConn和m_pRecord是這個類的成員變量,所以

void CDlgTest::SetImage2DB(CString path)
{
VARIANT varChunk;
SAFEARRAY* psa;
SAFEARRAYBOUND rgsabound[1];
CFile f(path.operator LPCTSTR(),CFile::modeRead);
BYTE bval[ChunkSize+1];
long uIsRead=0;
while (1)
{
uIsRead=f.Read(bval,ChunkSize);
if (uIsRead==0) break;
rgsabound[0].cElements=uIsRead;
rgsabound[0].lLbound=0;
psa=SafeArrayCreate(VT_UI1,1,rgsabound);
for (long index=0;index<uIsRead;index++)
{
if (FAILED(SafeArrayPutElement(psa,&index,&bval[index])))
AfxMessageBox(_T("毛病。"));

}
varChunk.vt =VT_ARRAY|VT_UI1;
varChunk.parray=psa;
try
{
m_pRecord->Fields->GetItem("ImageData")->AppendChunk(varChunk);
}
catch (_com_error e)
{
AfxMessageBox(_T("毛病。"));
}
::VariantClear(&varChunk);
::SafeArrayDestroyData(psa);
if (uIsRead<ChunkSize)break;

}
f.Close();
}

INT CDlgTest::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes

ImageCodecInfo* pImageCodecInfo = NULL;

GetImageEncodersSize(&num, &size);
if(size == 0)
return -1; // Failure

pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
return -1; // Failure

GetImageEncoders(num, size, pImageCodecInfo);

for(UINT j = 0; j < num; ++j)
{
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j; // Success
} 
}

free(pImageCodecInfo);
return -1; // Failure
}

至此就完成了存儲圖片和從數據庫中把圖片下載到當地的功效。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved