問題描述:
專案里一個控制元件,需要加載本地圖片,單張的時候可以的,但是多次選擇發現圖片例外,
直接上圖,圖片部分顯示不全了,

問題分析:
一開始懷疑現象是有個圖片重復選擇后顯示是好的,其他某幾個圖很容易復現,就懷疑是圖片問題,查了半天jpg圖片完整性,發現圖片也沒什么區別,后面又查解析度,在DrawImage()里修改解析度為偶數了也不行,,,最后只能看代碼了,發現是代碼里自己清理GLOBAL記憶體了,其實之前有專案我遇到清理GLOBAL記憶體導致圖片顯示不全或者例外的問題,時間太久忘記了,還是記錄一下吧,
知識附錄:
1, 是Bitmap(RT_BITMAP)型別的圖片無法加載, RT_BITMAP是預定義型別, 資源里面沒有bmp檔案的頭, SizeofResource 的回傳值要比圖片檔案少幾個位元組,因為少了這幾個位元組, 所以GDI+會回傳invalid parameter錯誤,
2, 從IStream里面創建出來的Image物件會參考到堆里面的GLOBAL記憶體, 如果GLOBAL記憶體hBuffer被釋放了, 創建的Image的內容就會被破壞,有時只能畫出一小部分圖片, 有時整個圖片有大片的亂碼,好像是編碼失敗的樣子, 視當時的記憶體狀況而定,
另外呼叫Image的Clone也沒用,深層次想Clone不是真正的深拷貝,還是依賴那個GLOBAL記憶體的,如果那個記憶體被銷毀了,Clone的圖片也會例外,
只有在銷毀或者析構的時候才能清理那個GLOBAL記憶體,否則會導致顯示例外(不是100%出現,而是間歇性出現,但是肯定會出現),
這是看到的demo,拷貝過來的,可以看看,注意看注釋,
?
CYourClass::~CYourClass()
{
for(IMG_VECTOR::iterator it = m_arImage.begin(); it != m_arImage.end(); it++)
delete *it;
for(HGLB_VECTOR::iterator it = m_arGlobal.begin(); it != m_arGlobal.end(); it++)
{
::GlobalUnlock(*it);
::GlobalFree(*it);
}
}
void CYourClass::AddImage(HMODULE hInst, UINT nResourceID, LPCTSTR lpType)
{
if(lpType == RT_BITMAP)
{
//GDI+ can not load RT_BITMAP resouce,
//because they are predefined resource,
//they don't contains the image file header.
assert(FALSE);
return;
}
HRSRC hResource = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), lpType);
if (!hResource)
return;
DWORD imageSize = ::SizeofResource(hInst, hResource);
if (!imageSize)
return;
const void* pResourceData = ::LockResource(::LoadResource(hInst, hResource));
if (!pResourceData)
return;
HGLOBAL hBuffer = ::GlobalAlloc(GMEM_FIXED, imageSize);
if (NULL == hBuffer)
return;
void* pBuffer = ::GlobalLock(hBuffer);
if (pBuffer)
{
CopyMemory(pBuffer, pResourceData, imageSize);
IStream* pStream = NULL;
if (::CreateStreamOnHGlobal(hBuffer, FALSE, &pStream) == S_OK)
{
Gdiplus::Image * pImage = Gdiplus::Image::FromStream(pStream);
pStream->Release();
if (pImage)
{
if (pImage->GetLastStatus() == Gdiplus::Ok &&
pImage->GetWidth() > 0)
{
m_arImage.push_back(pImage);
//it seems the image will take usage of the global memory.
//so the global memory should be kept until the image destroy.
//GDI++此種打開本地檔案的方式占用了這片記憶體,只有在你銷毀圖片時才能銷毀這片
//記憶體,否則會破壞你的圖片,導致顯示例外
m_arGlobal.push_back(hBuffer);
return;
}
delete pImage;
}
}
::GlobalUnlock(hBuffer);
}
::GlobalFree(hBuffer);
}
?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/12118.html
標籤:其他
