Bug solution for loading LoadImage to system OEM Images

Source: Internet
Author: User

Simply put, the solution is to use GetModuleHandle (NULL) instead of passing NULL in the first parameter of LoadImage.

 

The original email is as follows:

Http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.gdi/2007-01/msg00145.html

Hi,

There is a bug that I get with LoadImage once in a while where it does not
Load the image from the file that I specify but instead loads up a system
Graphic. This only happens very rarely but is annoying when it does. To
Point where this issue has been annoying me on and off for probably the last
5 years. I use LoadImage as follows:

Hbm = (HBITMAP) LoadImage (NULL, filename, IMAGE_BITMAP, m_ddsd.dwWidth,
M_ddsd.dwHeight, LR_LOADFROMFILE | LR_CREATEDIBSECTION );

Luckily, with the current build of my software is it is finally occurring
Every time giving me a chance to debug this. below is what I have discovered
Is going wrong with LoadImage and a workaround at the end.

Stepping into the disassembly LoadImage callthe function _ loadbmp @ 20,
The first parameter as null for the handle to the instance of the module.
The second parameter is the pointer to the string for the BMP file to open,
Where my string is at address 0x00197fe8, and staying at 0x00197fe8 each time
At the moment which is why I cocould debug this.

Below is the disassembly with some of my own comments noting the important
Parts:

_ Loadbmp @ 20:
77d55e95 mov EDI, EDI
77d55e97 push EBP
77d55e98 mov EBP, ESP
77d55e9a sub ESP, 24 h
77D55E9D mov ecx, dword ptr [ebp + 0Ch]; Copies address of filename
Into ecx
77D55EA0 push ebx
77D55EA1 push esi
77D55EA2 mov esi, dword ptr [ebp + 8]; Copies paramater handle
Instance of module to esi
77D55EA5 push edi
77D55EA6 xor edi, edi; Sets edi to zero
77D55EA8 cmp esi, edi; Checks if parameter handle to instance
Module is NULL
77D55EAA mov dword ptr [ebp-4], edi
77D55EAD mov dword ptr [ebp-8], edi
77D55EB0 je _ LoadBmp @ 20 + 21 h (77D57C6Eh); If esi was NULL jumps
To code at 77D57C6E
77D55EB6 push dword ptr [ebp + 18 h]
77D55EB9 push dword ptr [ebp + 14 h]
77D55EBC push dword ptr [ebp + 10 h]
77D55EBF push 2
77D55EC1 push ecx
77D55EC2 push esi
77D55EC3 call _ ObjectFromDIBResource @ 24 (77D5298Dh); This is what
We want it to call

The two important parts abve are:
1. The code at 77D55E9D. Which copies the address of the bmp file string
Into ecx.

2. The code at 77D55EA8. This checks if the hinst parameter passed
LoadImage is NULL. If we jump to the code at address 77D57C6E becuase of this
Line:

77D55EB0 je _ LoadBmp @ 20 + 21 h (77D57C6Eh); If esi was NULL jumps
To code at 77D57C6E

This takes us to this assembly:

77D57C6E mov esi, dword ptr [_ hmodUser (77da01_h)]
77D57C74 movzx eax, cx
77D57C77 xor ebx, ebx
77D57C79 sub eax, 7 FDCh
77D57C7E mov dword ptr [ebp + 0Ch], edi
77D57C81 mov dword ptr [ebp + 8], edi
77D57C84 je 77D745B6
77D57C8A sub eax, 16 h
77D57C8D je _ LoadBmp @ 20 + 141 h (77D74471h)
77D57C93 sub eax, 0Dh
77D57C96 je _ LoadBmp @ 20 + 128 h (77D74458h)
77D57C9C xor eax, eax
77D57C9E cmp cx, 7FE2h
77d57a3 sete al
77D57CA6 mov edx, 77D41A98h; edx is set here to address 77D41A98h
77D57CAB mov dword ptr [ebp-0Ch], eax
77D57CAE xor eax, eax
77D57CB0 cmp cx, 7FF7h
77D57CB5 sete al
77D57CB8 mov dword ptr [ebp-10h], eax
77D57CBB xor eax, eax; sets eax to zero
77D57CBD cmp word ptr [edx], cx; cx is the lower 16 bits of
Filename addesss
77d57cc0 je _ loadbmp @ 20 + 81 h (77d57cceh); jumps if CX equals
Address in edX
77d57cc2 add edX, 6; edX + = 6
77d57cc5 Inc eax; eax ++
77d57cc6 CMP edX, offset _ gwszshellfont2 (77d41b58h); checks if end
Loop
77d57ccc JL _ loadbmp @ 20 + 70 h (77d57cbdh)
77d57cce CMP eax, 20 h; if we looped around 0x20
77d57cd1 je 77d55eb6; times then jumps back to 77d55eb6

The loop at the end is important part, and is what causes the issue. I will
Step through the important parts:

The register edX is set to the value 77d41a98.

77d57ca6 mov edX, 77d41a98h

Here is the loop:
77d57cc6 CMP edX, offset _ gwszshellfont2 (77d41b58h );
77d57ccc JL _ loadbmp @ 20 + 70 h (77d57cbdh );

This keeps looping around back to 77d57cbd while edX is less than the value
77d41b58. incrementing edX by 6 each time. So the following calculation:
0x77d41b58-0x77d41a98 = 0xc0/6 = 0x20

Means the max eax can equal is 0x20. This is important because the next two
Lines after the loop are:
77d57cce CMP eax, 20 h; if we looped around 0x20
77d57cd1 je 77d55eb6; times then jumps back to 77d55eb6

This is what we want as that way it jumps back to the code at 77d55eb6 which
Is the first lot of assembly code, and then continues down to the line:
77d55ec3 call _ objectfromdibresource @ 24 (77d5298dh)

Which loads the BMP from the file, and all is good.

Now the issue is at the line the loop keeps jumping:
77d57cbd CMP word PTR [edX], CX

Ecx is where the address of the BMP filename is stored shown earlier.
However, this line uses the register cx which is the lower 16 bits of
Address. And it is checking to see if it matches a value at the address
Edx which is being incremented each time through the loop. As my string is
At address 0x00197fe8 it is therefore checking if 0x7fe8 is in the list in
Memory between 0x77D41A98 and 0x77D41B58, this is the list of OEM images. In
My case it gets a match when eax equals 16, and leaves the loop. It then
Continues down through the code:
77D57D56 call _ CreateScreenBitmap @ 24 (77D52723h)

Which then creates the OEM image instead of giving loading the bitmap I
Specified.

The above loop shows why it is rare to get the wrong image. As the bottom
16 bits of the filenames address has to match an OEM's ID for it to occur.

The following code will replicate this issue:
HBITMAP hbm = 0;
Hbm = (HBITMAP) LoadImage (NULL, (TCHAR *) 0x00197fe8, IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION );

If you use this code you will find you get a handle to a bitmap even though
You have given an address which will have random data in it. This is because
It will never try use access this address, but will just use the 0x7fe8 part
Of it as it happens to match and OEM image ID.

The fix for this when loading from a file is to always pass
'Getmodulehandle (0) 'as the first parameter to LoadImage. Even though
Documentation states:
Hinst-[in] handle to an instance of the module that contains the image
Be loaded.

This is because of the following in the first lot of Assembly I posted is:
77d55ea2 mov ESI, dword ptr [EBP + 8]

This copies the handle to instance of module into ESI.

It then checks if this is zero with the following code:
77d55ea6 xor edi, EDI; Sets EDI to zero
77d55ea8 cmp esi, EDI; checks if parameter handle to instance
Module null

If it is not null then it does not do the next lot of assembly which checks
If the lower 16 bits of your address matches an OEM image.

So the verdict is if you are loading a BMP from a file you should always
Pass the first parameter to LoadImage, till this issue is fixed (if ever ).

My problem is the case where I am currently experiencing this bug I am not
Actually calling LoadImage directly, but calling the DirectX function
'D3dxloadtexturefromfile' which ends up calling LoadImage internally, passing
NULL as the first parameter.

I guess I will have to go back to LoadImage for loading BMP s into DirectX,
And replicate the extra couple of features 'd3dxloadtexturefromfile 'provides
That I use.

Adam Dokter

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.