| 4051 | |
| 4052 | |
| 4053 | LPCOLORREF getbits(HBITMAP ahImage, HDC hdc, LONG &aWidth, LONG &aHeight, bool &aIs16Bit) |
| 4054 | // Helper function used by PixelSearch below. |
| 4055 | // Returns an array of pixels to the caller, which it must free when done. Returns NULL on failure, |
| 4056 | // in which case the contents of the output parameters is indeterminate. |
| 4057 | { |
| 4058 | HDC tdc = CreateCompatibleDC(hdc); |
| 4059 | if (!tdc) |
| 4060 | return NULL; |
| 4061 | |
| 4062 | // From this point on, "goto end" will assume tdc is non-NULL, but that the below |
| 4063 | // might still be NULL. Therefore, all of the following must be initialized so that the "end" |
| 4064 | // label can detect them: |
| 4065 | HGDIOBJ tdc_orig_select = NULL; |
| 4066 | LPCOLORREF image_pixel = NULL; |
| 4067 | bool success = false; |
| 4068 | |
| 4069 | // Confirmed: |
| 4070 | // Needs extra memory to prevent buffer overflow due to: "A bottom-up DIB is specified by setting |
| 4071 | // the height to a positive number, while a top-down DIB is specified by setting the height to a |
| 4072 | // negative number. THE BITMAP COLOR TABLE WILL BE APPENDED to the BITMAPINFO structure." |
| 4073 | // Maybe this applies only to negative height, in which case the second call to GetDIBits() |
| 4074 | // below uses one. |
| 4075 | struct BITMAPINFO3 |
| 4076 | { |
| 4077 | BITMAPINFOHEADER bmiHeader; |
| 4078 | RGBQUAD bmiColors[3]; // 3 vs. 1. |
| 4079 | } bmi; |
| 4080 | |
| 4081 | bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); |
| 4082 | bmi.bmiHeader.biBitCount = 0; // i.e. "query bitmap attributes" only. |
| 4083 | if (!GetDIBits(tdc, ahImage, 0, 0, NULL, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS) || bmi.bmiHeader.biBitCount < 16) // Relies on short-circuit boolean order. |
| 4084 | goto end; |
| 4085 | |
| 4086 | // Set output parameters for caller: |
| 4087 | aIs16Bit = (bmi.bmiHeader.biBitCount == 16); |
| 4088 | aWidth = bmi.bmiHeader.biWidth; |
| 4089 | aHeight = bmi.bmiHeader.biHeight; |
| 4090 | |
| 4091 | size_t size = bmi.bmiHeader.biWidth * bmi.bmiHeader.biHeight; |
| 4092 | if ( !(image_pixel = new DWORD[size]) ) |
| 4093 | goto end; |
| 4094 | memset(image_pixel, 0xAA, size*4); |
| 4095 | |
| 4096 | bmi.bmiHeader.biBitCount = 32; |
| 4097 | bmi.bmiHeader.biHeight = -bmi.bmiHeader.biHeight; |
| 4098 | |
| 4099 | // Must be done only after GetDIBits() because: "The bitmap identified by the hbmp parameter |
| 4100 | // must not be selected into a device context when the application calls GetDIBits()." |
| 4101 | // (Although testing shows it works anyway, perhaps because GetDIBits() above is being |
| 4102 | // called in its informational mode only). |
| 4103 | // Note that this seems to return NULL sometimes even though everything still works. |
| 4104 | // Perhaps that is normal. |
| 4105 | tdc_orig_select = SelectObject(tdc, ahImage); // Returns NULL when we're called the second time? |
| 4106 | |
| 4107 | if ( !(GetDIBits(tdc, ahImage, 0, -bmi.bmiHeader.biHeight, image_pixel, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS)) ) |
| 4108 | goto end; |
| 4109 | |
| 4110 | success = true; // Flag for use below. |
no outgoing calls
no test coverage detected