奇怪的问题,求大大解答

nakedavril 2011-03-21 10:28:55
我简单封装了一个简单的win32程序

class AppInit
{
public:
AppInit(HINSTANCE instance);
~AppInit();

void initMainWnd();//注册窗口类,创建窗口
LRESULT CALLBACK msgProc(UINT msg, WPARAM wParam, LPARAM lParam);
int go();//消息循环

private:
HWND m_hWnd;
HINSTANCE m_hInstance;
};

//-----------------------------------------------
int WINAPI WinMain(...)
{
gApp =&AppInit(hInstance);//gApp是个全局的AppInit *,并初始化为0
gApp->go();
}

LRESULT CALLBACK MainWndProc(...)//这是注册窗口类时的窗口过程函数
{
if (gApp != 0)
{
return gApp->msgProc(msg, wParam, lParam);
}
else
{
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}

go()函数就是消息循环,本来initMainWnd()是放到默认构造函数中的,但考虑到CreateWindow时,gApp还是0,
就不能处理WM_CREATE消息了,所以就把initMainWnd()移到go函数中了,却发现CreateWindow失败,返回值是0,
GetLastError也是0。。。求大神解答!

...全文
214 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
yarpee 2011-03-22
  • 打赏
  • 举报
回复
CreateWindow中参数应该WS_OVERLAPPEDWINDOW | ~WS_MAXIMIZEBOX | ~WS_THICKFRAME
nakedavril 2011-03-22
  • 打赏
  • 举报
回复
楼上的大大,你把AppInit构造函数中的initMainWnd剪切到go函数中,放到第一行,再编译试试
就靠你了。。
nakedavril 2011-03-22
  • 打赏
  • 举报
回复
是啊,可以编译,但是运行出错
我跟踪了一下,CreateWindow消息返回前m_hWnd还是0,WM_CREATE前的WM_GETMINMAXINFO,WM_NCCREATE
通过我的DefWindowProc(m_hWnd, msg, wParam, lParam);处理了,但是m_hWnd还是0,出错了。
同样在WM_CREATE中调用SetTimer(m_hWnd,...);也是出错,我就郁闷了,既然此时m_hWnd还是0,说明
CreateWindow还没返回,m_hWnd还没有值,那为什么按照C的写法(msgProc有HWND参数),SetTimer没问题,
他的HWND的实参是什么呢。。。
pengzhixi 2011-03-22
  • 打赏
  • 举报
回复
编译没任何问题

pengzhixi 2011-03-22
  • 打赏
  • 举报
回复
请用app直接调用go.原因的话,如果你通过指针来调用那么你会发现最后调用的是
DefWindowProc(m_hwnd, msg, wParam, lParam);
而m_hwnd在返回之前是NULL。所以肯定不行。
nakedavril 2011-03-22
  • 打赏
  • 举报
回复
满意结贴。。
nakedavril 2011-03-22
  • 打赏
  • 举报
回复
谢谢这位大大,从昨天晚上到今天下午的耐心解答,
目前的解决方案 类中函数 msgProc增加一个参数 HWND hwnd
LRESULT CALLBACK msgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

然后在MainWndProc就是注册窗口类时的窗口过程函数中
if (gApp != 0)
{

return gApp->msgProc(hwnd, msg, wParam, lParam);
}
else
{
return DefWindowProc(hwnd, msg, wParam, lParam);
}
这样,不管在什么时候,msgProc的hwnd参数都是对的
pengzhixi 2011-03-22
  • 打赏
  • 举报
回复
我说了,虽然没返回,但是windows已经创建好了。
nakedavril 2011-03-22
  • 打赏
  • 举报
回复
额,那怎么办,难道只能按
LRESULT CALLBACK
MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);来处理消息。。
ps:我设了个全局变量,在MainWndProc 将他赋值为hwnd,然后在类的方法里用这个全局变量
作为DefWndProc的参数,然后没问题,可这个MainWndProc的 hwnd参数是哪来的呢?既然
CreateWindow还没返回。。。
pengzhixi 2011-03-22
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 nakedavril 的回复:]
嗯,对 WM_CREATE之前还有WM_NCCREATE消息,但这时候窗口还没创建完,m_hWnd还没值,那么处理WM_NCCREATE消息的HWND的实参应该是声明呢?
[/Quote]

额 实际上在CreateWindow返回之前HWND已经创建好了,只是你不能人为的将还没有得到的返回值传给你的WinPro.
nakedavril 2011-03-22
  • 打赏
  • 举报
回复
笔误。。
嗯,对 WM_CREATE之前还有WM_NCCREATE消息,但这时候窗口还没创建完,m_hWnd还没值,那么处理WM_NCCREATE消息的HWND的实参应该是什么呢?
nakedavril 2011-03-22
  • 打赏
  • 举报
回复
嗯,对 WM_CREATE之前还有WM_NCCREATE消息,但这时候窗口还没创建完,m_hWnd还没值,那么处理WM_NCCREATE消息的HWND的实参应该是声明呢?
hhddzz 2011-03-22
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 nakedavril 的回复:]

是啊,可以编译,但是运行出错
我跟踪了一下,CreateWindow消息返回前m_hWnd还是0,WM_CREATE前的WM_GETMINMAXINFO,WM_NCCREATE
通过我的DefWindowProc(m_hWnd, msg, wParam, lParam);处理了,但是m_hWnd还是0,出错了。
同样在WM_CREATE中调用SetTimer(m_hWnd,...);也是出……
[/Quote]
消息分队列消息和非队列消息
非队列消息直接发送给窗口消息处理程序,相当于以一定的参数调用窗口过程

就像你测试的,CreateWindow发送了几个非队列消息。虽然CreateWindow还没返回,但窗体句柄实际上已经建立了。窗口过程在接收这些非队列消息时同样会收到完整的参数信息——包括窗体句柄hwnd。所以按照C的写法直接用MainWndProc收到的hwnd来调用DefWindowProc没问题。

而你这里用值为0的m_hWnd来调用DefWindowProc当然就不行
nakedavril 2011-03-22
  • 打赏
  • 举报
回复
楼上,&~,没错,去掉属性就是这样写的
nakedavril 2011-03-21
  • 打赏
  • 举报
回复
源文件上传了,哪位大大有时间的话帮我看看

http://u.115.com/file/t7b7c7626d
nakedavril 2011-03-21
  • 打赏
  • 举报
回复
注册了啊。。。、

void AppInit::initMainWnd()
{

WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_ERROR);
wc.hInstance = m_hInstance;
wc.lpfnWndProc = MainWndProc;
wc.lpszClassName = "CLASS";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;

if ( !RegisterClass(&wc) )
{
MessageBox(0, "RegisterClass FAILED!", 0, 0);
PostQuitMessage(0);
}
m_hWnd = CreateWindow("CLASS", "Tetris", WS_OVERLAPPEDWINDOW
&~WS_MAXIMIZEBOX&~WS_THICKFRAME, 200, 100, 900, 500, NULL,
NULL, m_hInstance, NULL);

if ( !m_hWnd )
{
MessageBox(0, "CreateWindow FAILED!", 0, 0);
PostQuitMessage(0);
}
}

这个函数本来放到AppInit构造函数里没问题,但是移到go函数里就没法创建窗口了。。
pengzhixi 2011-03-21
  • 打赏
  • 举报
回复
AppInit(HINSTANCE instance);
这个函数里面先调用窗口类注册函数,然后才是创建窗口。
pengzhixi 2011-03-21
  • 打赏
  • 举报
回复
额 ,老大,要先注册窗口类然后才能创建窗口
nakedavril 2011-03-21
  • 打赏
  • 举报
回复

int AppInit::go()
{

ShowWindow(m_hWnd, SW_SHOW);
UpdateWindow(m_hWnd);//若放到initMainWnd则失去第一次处理WM_PAINT消息的机会
MSG msg;
msg.message = WM_NULL;
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{

}
}
return (int)msg.wParam;
}
nakedavril 2011-03-21
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 pengzhixi 的回复:]

引用 2 楼 nakedavril 的回复:
C/C++ code

AppInit app(hInstance);
gApp =&app;


还是不行,CreateWindow失败。。。

额 ,你这个局部变量出了这个函数就销毁了。
[/Quote]

额,给个完整的WinMain吧:

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR lpCmdLine,int nShowCmd )
{
AppInit app(hInstance);
gApp =&app;
return gApp->go();
}

要是出了WinMain程序就结束了。。
加载更多回复(3)
cms-Cloud后台管理系统 cms-Cloud 基于Spring Boot、Spring Cloud & Alibaba、OAuth2的前后端分离的后台管理系统,内置模块如:部门管理、角色用户、菜单及按钮授权、数据权限、系统参数、日志管理、代码生成等。在线定时任务配置;支持集群,支持多数据源。核心技术前端技术栈 ES6、vue、vuex、vue-router、vue-cli、axios、element-ui后端技术栈 Spring Boot、Spring Cloud & Alibaba、OAuth2系统需JDK >= 1.8MySQL >= 5.5Maven >= 3.0主要特性1. 完全响应式布局(支持电脑、平板、手机等所有主流设备)2. 强大的一键生成功能(包括控制器、模型、视图、菜单等)3. 支持多数据源,简单配置即可实现切换。4. 支持按钮及数据权限,可自定义部门数据权限。5. 对常用js插件进行二次封装,使js代码变得简洁,更加易维护6. 完善的XSS防范及脚本过滤,彻底杜绝XSS攻击7. Maven多项目依赖,模块及插件分项目,尽量松耦合,方便模块升级、增减模块。8. 国际化支持,服务端及客户端支持9. 完善的日志记录体系简单注解即可实现技术选型1、系统环境Java EE 8Servlet 3.0Apache Maven 32、主框架Spring Boot 2.2Spring Cloud Hoxton.SR3Spring Framework 5.1Spring Security 5.13、持久层Apache MyBatis 3.4Alibaba Druid 1.14、视图层Vue 2.6Axios 0.18Element UI 2.11内置功能(1) 用户管理:用户是系统操作者,该功能主要完成系统用户配置。(2) 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。(3) 岗位管理:配置系统用户所属担任职务。(4) 菜单管理:配置系统菜单,操作权限,按钮权限标识等。(5) 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。(6) 字典管理:对系统中经常使用的一些较为固定的数据进行维护。(7) 参数管理:对系统动态配置常用参数。(8) 通知公告:系统通知公告信息发布维护。(9) 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。(10) 登录日志:系统登录日志记录查询包含登录异常。(11) 在线用户:当前系统中活跃用户状态监控。(12) 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。(13) 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。(14) 系统接口:根据业务代码自动生成相关的api接口文档。(15) 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。(16) 在线构建器:拖动表单元素生成相应的HTML代码。(17) 连接池监视:监视当期系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 环境部署准备工作JDK >= 1.8 (推荐1.8版本)Mysql >= 5.5.0 (推荐5.7版本)Redis >= 3.0Maven >= 3.0Node >= 10nacos >= 1.1.0sentinel >= 1.6.0运行系统因为本项目是前后端分离的,所以需要前后端都启动好,才能进行访问。后端运行1、导入cms到Eclipse,菜单 File -> Import,然后选择 Maven -> Existing Maven Projects,点击 Next> 按钮,选择工作目录,然后点击 Finish 按钮,即可成功导入Eclipse会自动加载Maven依赖包,初次加载会比较慢(根据自身网络情况而定)2、创建数据库cms-cloud并导入数据脚本cms.sql(必须),quartz.sql(可选)3、创建数据库cms-config并导入数据脚本cms_config.sql(必须)4、配置nacos持久化,修改conf/application.properties文件,增加支持mysql数据源配置。# db mysqlspring.datasource.platform=mysqldb.num=1db.url.0=jdbc:mysql://localhost:3306/cms-config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTCdb.user=rootdb.password=password5、打开运行基础模块(启动没有先后顺序)CmsGatewayApplication (网关模块 必须)CmsAuthApplication (认证模块 必须)CmsSystemApplication (系统模块 必须)CmsMonitorApplication (监控中心 可选)CmsGenApplication (代码生成 可选)CmsJobApplication (定时任务 可选)CmsFileApplication (文件服务 可选)前端运行# 进入项目目录cd cms-ui# 安装依赖npm install# 强烈建议不要用直接使用 cnpm 安装,会有各种诡异的 bug,可以通过重新指定 registry 来解决 npm 安装速度慢的问题。npm install --registry=https://registry.npm.taobao.org 本地开发 启动项目npm run dev打开浏览器,输入:http://localhost:80 (默认账户 admin/admin123)若能正确展示登录页面,并能成功登录,菜单及页面展示正常,则表明环境搭建成功提示前端安装完node后,最好设置下淘宝的镜像源,不建议使用cnpm(可能会出现奇怪问题)部署系统因为本项目是前后端分离的,所以需要前后端都部署好,才能进行访问后端部署bin/package.bat 在项目的目录下执行然后会在项目下生成 target文件夹包含 war 或jar1、jar部署方式使用命令行执行:java –jar xxxx.jar 或者执行脚本:bin/run.bat2、war部署方式pom.xml packaging修改为war 放入tomcat服务器webapps提示SpringBoot去除内嵌tomcat前端部署当项目开发完毕,只需要运行一行命令就可以打包你的应用# 打包正式环境npm run build:prod# 打包预发布环境npm run build:stage构建打包成功之后,会在根目录生成 dist 文件夹,里面就是构建打包好的文件,通常是 ***.js 、***.css、index.html 等静态文件。通常情况下 dist 文件夹的静态文件发布到你的 nginx 或者静态服务器即可,其中的 index.html 是后台服务的入口页面。环境变量所有测试环境或者正式环境变量的配置都在 .env.development (opens new window)等 .env.xxxx文件中。它们都会通过 webpack.DefinePlugin 插件注入到全局。常见问题如果使用Mac 需要修改application.yml文件路径profile如果使用Linux 提示表不存在,设置大小写敏感配置在/etc/my.cnf 添加lower_case_table_names=1,重启MYSQL服务如果提示当前权限不足,无法写入文件请检查profile是否可读可写,或者无法访问此目录

64,646

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧