LoadImage加载到系统OEM图片的BUG解决方案

第三节: 串口通信(用CubeMX学习STM32) 用CubeMX学习STM32, 串口通信学习, 通过轮询方式和中断方式两种方式进行通信演示。 STM32F407zgt6 阅读详情

简单说解决方法就是LoadImage第一个参数不要传递NULL,而使用GetModuleHandle(NULL)代替。

 

以下是邮件原文:

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 the 
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 calls the function _LoadBmp@20, with 
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 could 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,24h 
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 to 
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 of 
module is NULL
77D55EAA mov dword ptr [ebp-4],edi 
77D55EAD mov dword ptr [ebp-8],edi 
77D55EB0 je _LoadBmp@20+21h (77D57C6Eh) ; If esi was NULL jumps 
to code at 77D57C6E
77D55EB6 push dword ptr [ebp+18h] 
77D55EB9 push dword ptr [ebp+14h] 
77D55EBC push dword ptr [ebp+10h] 
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 above 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 into 
LoadImage is NULL. If we jump to the code at address 77D57C6E becuase of this 
line:

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


This takes us to this assembly:

77D57C6E mov esi,dword ptr [_hmodUser (77DA0264h)] 
77D57C74 movzx eax,cx 
77D57C77 xor ebx,ebx 
77D57C79 sub eax,7FDCh 
77D57C7E mov dword ptr [ebp+0Ch],edi 
77D57C81 mov dword ptr [ebp+8],edi 
77D57C84 je 77D745B6 
77D57C8A sub eax,16h 
77D57C8D je _LoadBmp@20+141h (77D74471h) 
77D57C93 sub eax,0Dh 
77D57C96 je _LoadBmp@20+128h (77D74458h) 
77D57C9C xor eax,eax 
77D57C9E cmp cx,7FE2h 
77D57CA3 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 the 
filename addesss
77D57CC0 je _LoadBmp@20+81h (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+70h (77D57CBDh) 
77D57CCE cmp eax,20h ; 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+70h (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,20h ; 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 the line the loop keeps jumping to:
77D57CBD cmp word ptr [edx],cx 

ecx is where the address of the bmps filename is stored shown earlier. 
However, this line uses the register cx which is the lower 16 bits of the 
address. And it is checking to see if it matches a value at the address of 
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 to:
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 the 
documentation states:
hinst - [in] Handle to an instance of the module that contains the image to 
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 of 
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 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 bmps into DirectX, 
and replicate the extra couple of features 'D3DXLoadTextureFromFile' provides 
that I use. 

Adam Dokter

从零开始的计网学习——物理层 计算机网络对于IT人不论是就业还是升学都是核心的一门课程,一起从零开始,学习计算机网络! 阅读详情

相关推荐

立创星火计划:基于STM32H743VIH6的Maverick_H743_MK1.0高性能开源飞控硬件全解析

本文详细解析了基于STM32H743VIH6核心的Maverick_H743_MK1.0高性能开源飞控硬件设计。重点阐述了采用双IMU冗余设计、高精度气压计、多路独立电源管理以及丰富接口(如CAN总线)的考量,旨在为穿越机、科研无人机等平台提供强大、可靠的飞行控制解决方案。

weixin_28787801的博客 200

解决LoadImage加载图片报告内存不足的错误

在使用Win32 API LoadImage加载大量图片,或者加载很大的图片的时候,你可能会碰到图片加载失败,而且调用GetLastError显示错误是“内存不足,无法完成此操作!”,打开任务管理器,却发现系统里面还有大量的内存空闲。比如使用下面的代码你就会碰到这个错误—当然你要准备大量的BMP图片:#include "StdAfx.h"#include "SampleBa

Donjuan的专栏 6570

论文分享 - OctoMap八叉树建图原理

论文:OctoMap:An Efficient Probabilistic 3D Mapping Framework Based on Octrees。

一只废佐_的博客 2539

docker的save和load

实战 [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE clearlinux latest 32685d114002 7 days ago

实践求真知 1522

AlphaFold2算法详解

正文:https://www.nature.com/articles/s41586-021-03819-2 补充文件:https://static-content.springer.com/esm/art%3A10.1038%2Fs41586-021-03819-2/MediaObjects/41586_2021_3819_MOESM1_ESM.pdfhttps://static-content.springer.com/esm/art%3A10.1038%2Fs41586-021-03819-2/Med

Daisy4的博客 1万+

【电驱动】永磁同步电机工作原理及分类

永磁同步电机工作原理及分类

星Yeah 的博客 7331

docker运行

docker

weixin_41169280的博客 729

vs2017配置liblas库+测试代码

之前已经配置好pcl(vs2017配置pcl),可以单独配置liblas,也可以在原有pcl属性表的基础上继续配置

孙悟空 4023

LoadImage()的使用

系统中的定义是:WINUSERAPIHANDLEWINAPILoadImageA(    HINSTANCE,    LPCSTR,    UINT,    int,    int,    UINT);WINUSERAPIHANDLEWINAPILoadImageW(    HINSTANCE,    LPCWSTR,    UINT,    int,    int,    UINT);#if

eric1031的专栏 5万+

人工智能之数学基础:弄懂数学本质,让我们不再害怕数学

数学的用途远远超过了人们的想象,甚至无处不在,任何领域都需要用到数学知识,人工智能也不例外。我将尽可能地将数学知识和机器学习算法相结合,让大家知道这些数学知识咋人工智能领域中的应用,使得数学的学习不会过于枯燥,同时也帮助大家扫清在学习算法过程中的数学障碍。除此之外,我还希望帮助大家建立一种不一样的数学思维,不再将数学看成是符号的演算、公式的推导,而是将数学看成是一种描述这个世界的工具,这样你就会发现这个世界处处有数学。当我们面对问题的时候,你是否会对问题进行抽象,然后通过数学来解决问题?

huanfeng_AI的博客 633

多测师肖sir_高级金牌讲师_数据库之存储练习题(8.13.1)

实验 一、 实验要求: 理解存储过程的概念 掌握存储过程的语法格式、使用方法 掌握存 储过程的创建、执行 二、实验前提: – drop table if exists student; – Create table student – (Id varchar(255), #学号 – Name varchar(255), #姓名 – Roomid varchar(255), #班级 – Sex char(1), #性别 – Degree varchar(3) );#成绩; Insert into stud

多测师肖sir的博客 706

LoadImage()使用

该系统被定义: WINUSERAPIHANDLEWINAPILoadImageA(    HINSTANCE,    LPCSTR,    UINT,    int,    int,    UINT);WINUSERAPIHANDLEWINAPILoadImageW(    HINSTANCE,    LPCWSTR,    UINT,    int,    int,    UINT);#i...

weixin_34306593的博客 799

SAP AI Core 高阶能力实战参考

文章摘要:本文探讨了在企业SAP架构中整合GenAI技术的工程化实践,重点分析了SAP AI Core的高阶能力应用。作者指出,企业级AI应用需解决多轮对话管理、Git同步工作流、提示词治理等核心问题,而非简单接入大模型API。技术方案展示了如何通过SAP AI Core的orchestration service管理对话历史,利用GitOps实现AI资产版本控制,并强调prompt template在审计合规中的治理价值。全文以SAP技术栈(ABAP/RAP/Fiori)为背景,阐释了AI能力与企业核心系

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 104

MFC打开BMP图片

第一步:新建项目"MFC应用程序",项目名为ShowBMP,在应用程序类型中选择"单个文档",点击"确定" 第二步:向CShowBMPView类添加成员变量和成员函数.在右栏的"类视图"右键CShowBMPView添加函数或直接在ShowBMPView.h中直接添加public成员变量和成员函数.添加代码如下: public: //成员变量 CS

Aries鹏的专栏 3947

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

给窗口添加背景图的案例

HINSTANCE 介绍 是“句柄型”介绍数据类型。相当于装入到了内存的资源的ID。HINSTANCE对应的资源是instance.句柄实际上是一个 无符号长整数 AfxGetInstanceHandle()函数的介绍 HINSTANCE AfxGetInstanceHandle( ); 返回值 :代表应用程序的当前实例的HINSTANCE值。如果是从与MFC的USRDLL版本

Car12 1508

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

上一篇: 带有可变参数的宏
下一篇: WINCE下程序移植问题集
loongee
博客等级 码龄20年 23粉丝 27原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值