Re: Научите пользоваться GetDIBits()
От: Alex Fedotov США  
Дата: 09.10.02 18:14
Оценка: 26 (4)
Здравствуйте Topi_Nambur, Вы писали:

TN>Данная функция используется в следующем фрагменте кода:


TN>

TN>

TN>HDC dc = GetDC();
TN>HDC mem_dc = CreateCompatibleDC(dc);
TN>HBITMAP bitmap = CreateCompatibleBitmap(dc, 100, 50);
TN>ReleaseDC(dc);

TN>HBITMAP old = static_cast<HBITMAP>(SelectObject(mem_dc, bitmap));
TN>SelectObject(mem_dc, CreateFontIndirect(&lf));

TN>RECT rect = {0, 0, 100, 50};
TN>HBRUSH brush = CreateSolidBrush(RGB(255, 255, 255));

TN>BITMAPINFO bmi;
TN>char buffer[4096];

TN>for (int i = 0; i < 32; i++)
TN>{
TN>    FillRect(mem_dc, &rect, brush);

TN>    string symbol;
TN>    symbol += char('А' + i);
TN>    TextOut(mem_dc, x_offset_, y_offset_, symbol.c_str(), 1);

TN>    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
TN>    bmi.bmiHeader.biWidth = 20;
TN>    bmi.bmiHeader.biHeight = 32;
TN>    bmi.bmiHeader.biPlanes = 1;
TN>    bmi.bmiHeader.biBitCount = 4;
TN>    bmi.bmiHeader.biCompression = BI_RGB;

TN>    // Это нужно, чтобы удовлетворить следующему требованию из MSDN'а:
TN>    // The bitmap identified by the hbmp parameter must not be selected into
TN>    // a device context when the application calls this function.
TN>    SelectObject(mem_dc, old);

TN>    int rest = GetDIBits(mem_dc, bitmap, 0, 32, buffer, &bmi, DIB_PAL_COLORS);

TN>    old = static_cast<HBITMAP>(SelectObject(mem_dc, bitmap));
TN>}
TN>


TN>При запуске в debugger'е программа вылетает со следующим сообщением:


TN>Run-Time Check Failure #2 — Stack around the variable 'bmi' was corrupted.


Проблема в том, что для 4bpp GetDIBits пытается вернуть палитру, места для которой ты не зарезервировал.
Надо делать примерно так:

struct {
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD          bmiColors[16];
} bmi;

// всегда обнуляй неиспользуемые поля BITMAPINFOHEADER
memset(&bmi, 0, sizeof(bmi));

...

// сообщаем GetDIBits в каком формате мы хотим получить картинку
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = 20;
bmi.bmiHeader.biHeight = 32;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 4;
bmi.bmiHeader.biCompression = BI_RGB;

...

// вызываем GetDIBits; всегда указывай DIB_RGB_COLORS, unless
// ты действительно хочешь DIB_PAL_COLORS и знаешь, что это такое
GetDIBits(..., (BITMAPINFO *)&bmi, DIB_RGB_COLORS);
-- Alex Fedotov
Re: Научите пользоваться GetDIBits()
От: Atilla Россия  
Дата: 09.10.02 16:37
Оценка: -1
Там специальным alloc'ом надо память выделять под буфер. Так по-памяти не вспомню, поглядите в MSDN в статье GetDIBits как функция называется.
Кр-ть — с.т.
Научите пользоваться GetDIBits()
От: Topi_Nambur  
Дата: 09.10.02 16:28
Оценка:
Данная функция используется в следующем фрагменте кода:



HDC dc = GetDC();
HDC mem_dc = CreateCompatibleDC(dc);
HBITMAP bitmap = CreateCompatibleBitmap(dc, 100, 50);
ReleaseDC(dc);

HBITMAP old = static_cast<HBITMAP>(SelectObject(mem_dc, bitmap));
SelectObject(mem_dc, CreateFontIndirect(&lf));

RECT rect = {0, 0, 100, 50};
HBRUSH brush = CreateSolidBrush(RGB(255, 255, 255));

BITMAPINFO bmi;
char buffer[4096];

for (int i = 0; i < 32; i++)
{
    FillRect(mem_dc, &rect, brush);

    string symbol;
    symbol += char('А' + i);
    TextOut(mem_dc, x_offset_, y_offset_, symbol.c_str(), 1);

    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = 20;
    bmi.bmiHeader.biHeight = 32;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 4;
    bmi.bmiHeader.biCompression = BI_RGB;

    // Это нужно, чтобы удовлетворить следующему требованию из MSDN'а:
    // The bitmap identified by the hbmp parameter must not be selected into
    // a device context when the application calls this function.
    SelectObject(mem_dc, old);

    int rest = GetDIBits(mem_dc, bitmap, 0, 32, buffer, &bmi, DIB_PAL_COLORS);

    old = static_cast<HBITMAP>(SelectObject(mem_dc, bitmap));
}


При запуске в debugger'е программа вылетает со следующим сообщением:

Run-Time Check Failure #2 — Stack around the variable 'bmi' was corrupted.

Если закомментировать вызов GetDIBits() то данная ошибка не появляется.
Я предполагаю, что GetDIBits() почему пишет за пределы массива buffer, но почему не пойму.
(специально увеличивал размеры массива на несколько порядков не помогает;
динамическое выделение массива приводит к другой ошибке — heap corruption)
Re[2]: Научите пользоваться GetDIBits()
От: Atilla Россия  
Дата: 09.10.02 16:50
Оценка:
Странно: сейчас глянул msdn, там ничего такого не сказано, но точно помню, что когда юзал GetDIBits (свой код писал на основе на основе чужих исходников) — использовал GlobalAlloc или что-то в этом духе. Почему — не помню, исходников под рукой нет. Но могу гарантировать, если Вы то же самое сделаете, то debug-версия ругаться не будет
Кр-ть — с.т.
Re[2]: Научите пользоваться GetDIBits()
От: Topi_Nambur  
Дата: 10.10.02 11:48
Оценка:
Здравствуйте Alex Fedotov, Вы писали:

AF>Проблема в том, что для 4bpp GetDIBits пытается вернуть палитру, места для которой ты не зарезервировал.

AF>Надо делать примерно так:

Алекс Федотов как всегда на высоте.
Спасибо!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.