// ============================================== //class RQOcxPicture // ============================================== class RQOcxPicture : public CObject { DECLARE_SERIAL( RQOcxPicture ) //.... LPPICTURE mp_picture; CString m_name; int m_width, m_height; // taille en pixels int m_hiwidth, m_hiheight; // taille retounée directement par l'interface IPicture DWORD m_sizeBytes; // taille en octets de l'image // .... void M_deletePicture (); BOOL M_writePicArchive (CArchive& ar); BOOL M_readPicArchive (CArchive& ar); int M_getSaveSizeBytes (); void Serialize (CArchive& ar); }; // ----------------------------------------- // M_deletePicture() // ----------------------------------------- void RQOcxPicture::M_deletePicture() { if (mp_picture) { mp_picture->Release(); mp_picture = 0; } } // ----------------------------------------- // Serialize() // ----------------------------------------- void RQOcxPicture::Serialize(CArchive& ar) { // ECriture if(ar.IsStoring()) { ar << m_name; M_writePicArchive(ar); } // Lecture else { ar >> m_name; M_readPicArchive(ar); } } // ----------------------------------------- // M_writePicArchive() // ----------------------------------------- BOOL RQOcxPicture::M_writePicArchive(CArchive& ar) { ar << m_width; ar << m_height; ar << m_hiwidth; ar << m_hiheight; ar << m_sizeBytes; if (mp_picture != NULL && m_sizeBytes>0) { HRESULT hr; COleStreamFile f; if(f.CreateMemoryStream()) { IStream* pStream = f.GetStream() ; if (pStream==NULL) return FALSE; LARGE_INTEGER move = {0,0}; hr = pStream->Seek(move,STREAM_SEEK_SET,0); if (FAILED(hr)) return FALSE; hr = mp_picture->SaveAsFile(pStream, FALSE, 0); if (FAILED(hr)) return FALSE; HGLOBAL hMem = NULL; hr = GetHGlobalFromStream(pStream,&hMem); if(FAILED(hr)) return FALSE; LPVOID pBuffer = GlobalLock(hMem); ar.Write(pBuffer,m_sizeBytes); GlobalUnlock(hMem); } } return TRUE; } // ----------------------------------------- // M_getSaveSizeBytes() // ----------------------------------------- int RQOcxPicture::M_getSaveSizeBytes() { return m_name.GetLength() + 5*sizeof(int) + m_sizeBytes; } // ----------------------------------------- // M_readPicArchive() // ----------------------------------------- BOOL RQOcxPicture::M_readPicArchive(CArchive& ar) { M_deletePicture(); // Read Infos ar >> m_width; ar >> m_height; ar >> m_hiwidth; ar >> m_hiheight; ar >> m_sizeBytes; // Read raw picture bytes if (m_sizeBytes>0) { HRESULT hr; HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, m_sizeBytes); if(hMem==NULL) return FALSE; LPVOID pBuffer = GlobalLock(hMem); int sizeBytesRead = ar.Read(pBuffer, m_sizeBytes); if (sizeBytesRead != m_sizeBytes) return FALSE; CComPtr pStream; hr = CreateStreamOnHGlobal(hMem, TRUE, &pStream); if (FAILED(hr)) return FALSE; LARGE_INTEGER Move = {0,0}; hr = pStream->Seek(Move, STREAM_SEEK_CUR, 0); if (FAILED(hr)) return FALSE; hr = ::OleLoadPicture(pStream, m_sizeBytes, FALSE, IID_IPicture,(LPVOID *)&mp_picture); if (FAILED(hr)) return FALSE; GlobalUnlock(hMem); GlobalFree(hMem); } return TRUE; } // ============================================== //class RQOcxPictureList // List est simplement une structure décrivant // une liste chaînée // ============================================== class RQOcxPictureList : public List { //... int M_getSaveSizeBytes (); void M_serializeElements (CArchive& ar); // Itérateur void reset(); RQOcxPicture* next(); int M_getNumber(); // retourne le nombre d'éléments de la liste void M_clear(); // "nettoie" la liste //... }; // ----------------------------------------- // M_serializeElements() // ----------------------------------------- void RQOcxPictureList::M_serializeElements(CArchive& ar) { RQOcxPicture* pPicture = 0; int nbElements; if(ar.IsStoring()) { nbElements = M_getNumber(); ar << nbElements; for (reset() ; pPicture = next() ; ) pPicture->Serialize(ar); } else { M_clear(); ar >> nbElements; int i; for(i=0; iSerialize(ar); } } } // ----------------------------------------- // M_getSizeBytes() // ----------------------------------------- int RQOcxPictureList::M_getSaveSizeBytes() { int size=0; RQOcxPicture* pPicture = 0; for (reset() ; pPicture = next() ; ) if (pPicture) size += pPicture->M_getSaveSizeBytes(); size+= sizeof(int); // for nbElements return size; } // ============================================== // class CRQPuzzleListCtrl // ============================================== class CRQPuzzleListCtrl : public COleControl { DECLARE_DYNCREATE(CRQPuzzleListCtrl) // .... RQOcxPictureList m_picList; }; // ------------------------------------------------------------ // CRQPuzzleListCtrl::DoPropExchange - Persistence support // Au niveau du contrôle, sauvegarde comme BLOB de la liste // d'images. // ------------------------------------------------------------ void CRQPuzzleListCtrl::DoPropExchange(CPropExchange* pPX) { ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor)); COleControl::DoPropExchange(pPX); // TODO: Call PX_ functions for each persistent custom property. // Ecriture if(!pPX->IsLoading()) { int cbGuess = m_picList.M_getSaveSizeBytes() + sizeof(DWORD) + 1024; // sizeof(DWORD) va stocker la taille du BLOB, 1024 est une marge de sécurité. HGLOBAL hMem = GlobalAlloc(GPTR, cbGuess); BYTE *pbMem = (BYTE*) GlobalLock(hMem); if (pbMem != NULL) { //MessageBox("Saving RQPuzzleList Control."); CSharedFile file; file.Attach(pbMem + sizeof(DWORD), cbGuess - sizeof(DWORD)); CArchive ar(&file, CArchive::store); m_picList.M_serializeElements(ar); ar.Flush(); file.Flush(); *(DWORD*)pbMem = file.GetLength(); PX_Blob(pPX, _T("picList"), hMem); GlobalUnlock(hMem); } GlobalFree(hMem); } // Lecture else { HGLOBAL hMem; PX_Blob(pPX, _T("picList"), hMem); if (hMem != NULL) { LPVOID pData = (LPVOID)GlobalLock(hMem); ULONG* pLength = (ULONG*) pData; if (pData != NULL) { CMemFile f; f.Attach((BYTE*)(pLength+1), *pLength); CArchive ar(&f, CArchive::load); m_picList.M_serializeElements(ar); GlobalUnlock(hMem); } GlobalFree(hMem); } } }