إذا ترك خطأ في الأحداث المحددة "غير كافية تخزين"، ولكن يبدو أنه لا يزال يعمل على أي حال

StackOverflow https://stackoverflow.com/questions/2418776

سؤال

كلما يحاول تطبيقي إنشاء قسم DIB، إما عن طريق استدعاء CreateBsection () أو عن طريق استدعاء LoadImage () مع LR_CREATEDIBSECTION علم، يبدو أن العودة بنجاح. ال HBITMAP تعود صالحة، ويمكنني التعامل معها وعرضها على ما يرام.

ومع ذلك، ستعود المكالمات إلى GetLasterRor () 8: Not enough storage is available to process this command. يحدث هذا من الدعوة الأولى للغاية إلى الأخير. يبدو حجم الصورة النقطية المطلوبة غير منطقي؛ 800x600 أو 16x16، نفس النتيجة. مباشرة قبل دعوة الوظيفة، إرجاع getlasterror () أي خطأ؛ بالإضافة إلى ذلك، استدعاء SETLASTERROR (0) قبل مكالمة الوظيفة لها نفس النتيجة.

لقد وجدت أشخاصا آخرين يسألون أسئلة مماثلة، لكنها تبين أنها تستخدم CreateCompatibleBitMap () وتخلص المشكلة عند التبديل إلى CreateDibSection ()، أو أنهم يستخدمون بالفعل CreateDibSection () والنتيجة التي ترجع إليها غير صالحة لا يعمل على الإطلاق.

نظرا لأن الأمور تبدو تعمل، فقد اعتقدت أنني يمكن أن أتجاهلها (واستدعت SetLasterRor (0) بعد المكالمات إلى أي وظيفة)، ولكن قد تكون هناك مشكلة خفية أنا أطلني عن طريق القيام بذلك.

وبالطبع، إليك بعض التعليمات البرمجية الأساسية التي أستخدمها. أولا، الدعوة إلى تحميل ()، وهي جزء من فئة نقطية أساسية تستخدمها لكثير من الأشياء، والتي قمت بتبسيطها قليلا لإظهار الجوانب الأكثر أهمية:

bool Bitmap::Load( const char* szBitmapName, /*...*/ )
{
   m_hBitmap = (HBITMAP)LoadImage( GetModuleHandle( NULL ), szBitmapName,
            IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE );
   //...
}
// ...
Bitmap::~Bitmap()
{
   if( m_hBitmap ) DeleteObject( m_hBitmap );
}
bool Bitmap::Draw( HDC hDC, int iDstX, int iDstY, int iDstWidth,
                   int iDstHeight, int iSrcX, int iSrcY, int iSrcWidth,
                   int iSrcHeight, bool bUseMask ) const
{
   HDC hdcMem = CreateCompatibleDC( hDC );
   if( hdcMem == NULL ) return false;
   HBITMAP hOld = (HBITMAP)SelectObject( hdcMem, m_hBitmap );
   BLENDFUNCTION blendFunc;
   blendFunc.BlendOp = AC_SRC_OVER;
   blendFunc.BlendFlags = 0;
   blendFunc.AlphaFormat = AC_SRC_ALPHA;
   blendFunc.SourceConstantAlpha = 255;
   AlphaBlend( hDC, iDstX, iDstY, iDstWidth, iDstHeight, hdcMem, iSrcX,
               iSrcY, iSrcWidth, iSrcHeight, blendFunc );
   SelectObject( hdcMem, hOld );
   DeleteDC( hdcMem );
}

تتم عادة إجراء المكالمات إلى CreateDibSection عند تحديث نافذة الطبقات:

HDC hDCScreen( GetDC(0) );
POINT tSourcePos = { 0, 0 };
HDC hDCSource( CreateCompatibleDC( hDCScreen ) );
// iWidth and iHeight are used both for the bitmap size and window size
// to keep this example simpler
BITMAPINFO bi32 = {0};
bi32.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi32.bmiHeader.biWidth = iWidth;
bi32.bmiHeader.biHeight = iHeight;
bi32.bmiHeader.biPlanes = 1;
bi32.bmiHeader.biBitCount = 32;
bi32.bmiHeader.biCompression = BI_RGB;
void* pBits = NULL;
HBITMAP hBitmap = CreateDIBSection(NULL, &bi32, DIB_RGB_COLORS,
                  (void**)&pBits, NULL, NULL);

HBITMAP hOldBitmap = (HBITMAP)SelectObject( hDCSource, hBitmap );
POINT tWindowPos = { 0, 0 };
SIZE tWindowSize = { iWidth, iHeight };
BLENDFUNCTION blendFunction = {0};
blendFunction.BlendOp = AC_SRC_OVER;
blendFunction.SourceConstantAlpha = 255;
blendFunction.AlphaFormat = AC_SRC_ALPHA;
DWORD iFlags( ULW_ALPHA );

// m_tBitmap is an instance of Bitmap class previously mentioned
m_tBitmap.Draw( hDCSource, 0, 0, iWidth, iHeight, 0, 0, iWidth, iHeight );
UpdateLayeredWindow( GetHandle(), hDCScreen, &tWindowPos, &tWindowSize,
                     hDCSource, &tSourcePos, 0, &blendFunction, iFlags );
SelectObject( hDCSource, hOldBitmap );
DeleteObject( hBitmap );
DeleteDC( hDCSource );
ReleaseDC( 0, hDCScreen );

أي مؤشرات حول أي شيء أنا خارج القاعدة تماما حول سيكون موضع تقدير.

هل كانت مفيدة؟

المحلول

أعتقد أنك لا تتابع ما تقوله الوثائق (من deuctibsction.):

إذا نجحت الوظيفة، فإن قيمة الإرجاع هي مقبض إلى DIB الذي تم إنشاؤه حديثا، و *ppvBits يشير إلى القيم بت الصورة النقطية.

إذا فشلت الوظيفة، فإن قيمة الإرجاع هي NULL, ، و *ppvBits هو NULL.

هذه الوظيفة يمكن أن تعيد القيمة التالية. [...

إذا كانت قيمة الإرجاع ليست كذلك NULL, ، نجحت الوظيفة. دعا GetLastError لن يرجع بالضرورة أي معلومات مفيدة بشكل موثوق عن النجاح (من getlasterror.):

إذا لم يتم توثيق الوظيفة لتعيين رمز الخطأ الأخير، فإن القيمة التي تم إرجاعها بواسطة هذه الوظيفة هي ببساطة أحدث رمز أخير آخر تم تعيينه؛ تعيين بعض الوظائف رمز الخطأ الأخير إلى 0 على النجاح والبعض الآخر لا.

نصائح أخرى

وماذا في ذلك؟ DeuctibSection هي وظيفة معقدة تستفيد من العديد من واجهات برمجة التطبيقات الأخرى القيام بعملها. بعض من هؤلاء واجهات برمجة التطبيقات يمكن أن تحدد الخطأ الأخير للتفكير هُم الحالة الداخلية. لن يتم مسح CreateBsectionction الخطأ، فقط حتى يمكن إرجاع 0 عندما لا تفشل.

يقول العقد، عندما يفشل، يتم تعيين GetLasterRor إلى قيمة ذات معنى: لا يقول أن قيمة الخطأ الأخيرة لها أي معنى للمتصل عند إرجاع CreateBsection.

من الممكن تماما أنه، إذا كان هناك نقص في الذاكرة، يتم إلقاء الاستثناء و / أو تبسيط التعليمات البرمجية، فإن قيمة الخطأ الأخيرة تحظى ببساطة بدقة بالقرب من أعلى المخصصات بحيث تحددها بشكل صحيح دون أي جهد إضافي يجب أن تكون المخصصات فشل أو رمي استثناء.

أتذكر أنه في بعض الحالات، من أجل الحصول على قيمة موثوقة من GetLastError عليك الاتصال SetLastError(0) قبل استدعاء أي وظيفة API، ثم تحصل في وقت لاحق على الخطأ الصحيح with GetLastError(). وبعد لأنه في حالة نجاحه لم يتم تحديثه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top