| 3298 | |
| 3299 | |
| 3300 | LPCOLORREF getbits(HBITMAP ahImage, HDC hdc, LONG &aWidth, LONG &aHeight, bool &aIs16Bit, int aMinColorDepth = 8) |
| 3301 | // Helper function used by PixelSearch below. |
| 3302 | // Returns an array of pixels to the caller, which it must free when done. Returns NULL on failure, |
| 3303 | // in which case the contents of the output parameters is indeterminate. |
| 3304 | { |
| 3305 | HDC tdc = CreateCompatibleDC(hdc); |
| 3306 | if (!tdc) |
| 3307 | return NULL; |
| 3308 | |
| 3309 | // From this point on, "goto end" will assume tdc is non-NULL, but that the below |
| 3310 | // might still be NULL. Therefore, all of the following must be initialized so that the "end" |
| 3311 | // label can detect them: |
| 3312 | HGDIOBJ tdc_orig_select = NULL; |
| 3313 | LPCOLORREF image_pixel = NULL; |
| 3314 | bool success = false; |
| 3315 | |
| 3316 | // Confirmed: |
| 3317 | // Needs extra memory to prevent buffer overflow due to: "A bottom-up DIB is specified by setting |
| 3318 | // the height to a positive number, while a top-down DIB is specified by setting the height to a |
| 3319 | // negative number. THE BITMAP COLOR TABLE WILL BE APPENDED to the BITMAPINFO structure." |
| 3320 | // Maybe this applies only to negative height, in which case the second call to GetDIBits() |
| 3321 | // below uses one. |
| 3322 | struct BITMAPINFO3 |
| 3323 | { |
| 3324 | BITMAPINFOHEADER bmiHeader; |
| 3325 | RGBQUAD bmiColors[260]; // v1.0.40.10: 260 vs. 3 to allow room for color table when color depth is 8-bit or less. |
| 3326 | } bmi; |
| 3327 | |
| 3328 | bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); |
| 3329 | bmi.bmiHeader.biBitCount = 0; // i.e. "query bitmap attributes" only. |
| 3330 | if (!GetDIBits(tdc, ahImage, 0, 0, NULL, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS) |
| 3331 | || bmi.bmiHeader.biBitCount < aMinColorDepth) // Relies on short-circuit boolean order. |
| 3332 | goto end; |
| 3333 | |
| 3334 | // Set output parameters for caller: |
| 3335 | aIs16Bit = (bmi.bmiHeader.biBitCount == 16); |
| 3336 | aWidth = bmi.bmiHeader.biWidth; |
| 3337 | aHeight = bmi.bmiHeader.biHeight; |
| 3338 | |
| 3339 | int image_pixel_count = aWidth * aHeight; |
| 3340 | if ( !(image_pixel = (LPCOLORREF)malloc(image_pixel_count * sizeof(COLORREF))) ) |
| 3341 | goto end; |
| 3342 | |
| 3343 | // v1.0.40.10: To preserve compatibility with callers who check for transparency in icons, don't do any |
| 3344 | // of the extra color table handling for 1-bpp images. Update: For code simplification, support only |
| 3345 | // 8-bpp images. If ever support lower color depths, use something like "bmi.bmiHeader.biBitCount > 1 |
| 3346 | // && bmi.bmiHeader.biBitCount < 9"; |
| 3347 | bool is_8bit = (bmi.bmiHeader.biBitCount == 8); |
| 3348 | if (!is_8bit) |
| 3349 | bmi.bmiHeader.biBitCount = 32; |
| 3350 | bmi.bmiHeader.biHeight = -bmi.bmiHeader.biHeight; // Storing a negative inside the bmiHeader struct is a signal for GetDIBits(). |
| 3351 | |
| 3352 | // Must be done only after GetDIBits() because: "The bitmap identified by the hbmp parameter |
| 3353 | // must not be selected into a device context when the application calls GetDIBits()." |
| 3354 | // (Although testing shows it works anyway, perhaps because GetDIBits() above is being |
| 3355 | // called in its informational mode only). |
| 3356 | // Note that this seems to return NULL sometimes even though everything still works. |
| 3357 | // Perhaps that is normal. |
no test coverage detected