windows下控制台程序实现窗口显示
windows下实现窗口显示,如果限定是C/C++语言,并且是原生Windows支持,需要使用GDI或GDI+。一般是在Visual Studio里新建Win32应用程序,而不是Win32 console application(控制台程序),然后使用GDI的一些API,例如CreateWindow、CreateWindowEx来实现窗口的创建、显示等。
实际上MSDN官方并没有说只能是Win32应用程序,控制台程序完全可以。个人并不习惯WinMain()函数,更习惯main(int argc, char** argv)。例如OpenCV的highgui模块,它里面的cvNamedWindow(), cvShowImage(), cvWaitKey()这几个函数,在windows下的实现,如果不考虑其opengl版本的话,它是基于GDI实现的;而作为一个广泛使用的图像处理库,OpenCV源码中并没有WinMain函数。
第1种实现
下面是用纯C实现的“调用GDI的API接口,实现控制台类型程序中显示窗口”的样例程序,改编自How do you create a Win32 window from Console Application?
#include <stdio.h>
#include <windows.h>
LRESULT __stdcall WindowProcedure(HWND window, unsigned int msg, WPARAM wp, LPARAM lp)
{
switch(msg)
{
case WM_DESTROY:
printf("\ndestroying window\n");
PostQuitMessage(0) ;
return 0L ;
case WM_LBUTTONDOWN:
printf("\nmouse left button down at (%d, %d)\n", LOWORD(lp), HIWORD(lp));
// fall thru
default:
printf(".");
return DefWindowProc( window, msg, wp, lp ) ;
}
}
typedef struct MyRect{
int x, y, width, height;
} MyRect;
int main()
{
printf("hello world!\n");
const char* const myclass = "myclass" ;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
/* Win 3.x */
wc.style = CS_DBLCLKS;
wc.lpfnWndProc = WindowProcedure;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(0);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = 0;
wc.lpszClassName = myclass;
/* Win 4.0 */
wc.hIconSm = LoadIcon(0, IDI_APPLICATION);
if(RegisterClassEx(&wc))
{
MyRect rect;
rect.x = 300;
rect.y = 300;
rect.width = 640;
rect.height = 480;
HWND window = CreateWindowEx( 0, myclass, "title",
WS_OVERLAPPEDWINDOW, rect.x, rect.y,
rect.width, rect.height, 0, 0, GetModuleHandle(0), 0 ) ;
if(window)
{
ShowWindow( window, SW_SHOWDEFAULT ) ;
MSG msg ;
while( GetMessage( &msg, 0, 0, 0 ) ) DispatchMessage(&msg);
}
}
}
第2种实现
实际上,在Visual Studio中通过“菜单栏”->"文件"->“新建项目”->"Win32项目"(或"Win32控制台项目"进入后再选“Windows应用程序”),创建的“Hello World”工程提供的代码也仅仅是“显示一个窗口”,只不过入口函数是WinMain,其内容如下:
// gdi_show_png.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "gdi_show_png.h"
#define MAX_LOADSTRING 100
// 全局变量:
HINSTANCE hInst; // 当前实例
WCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
WCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
// 此代码模块中包含的函数的前向声明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此放置代码。
// 初始化全局字符串
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_GDI_SHOW_PNG, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GDI_SHOW_PNG));
MSG msg;
// 主消息循环:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// 函数: MyRegisterClass()
//
// 目的: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GDI_SHOW_PNG));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_GDI_SHOW_PNG);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// 函数: InitInstance(HINSTANCE, int)
//
// 目的: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 将实例句柄存储在全局变量中
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 在此处添加使用 hdc 的任何绘图代码...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
而如果忽略WinProc函数(各种事件处理代码),不妨把前面从gamedev上的帖子中的例子进行改造,把各种步骤都拆分到函数中,在主函数中调用,就得到如下代码:
#include <stdio.h>
#include <windows.h>
LRESULT __stdcall WindowProcedure(HWND window, unsigned int msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_DESTROY:
printf("\ndestroying window\n");
PostQuitMessage(0);
return 0L;
case WM_LBUTTONDOWN:
printf("\nmouse left button down at (%d, %d)\n", LOWORD(lp), HIWORD(lp));
// fall thru
default:
printf(".");
return DefWindowProc(window, msg, wp, lp);
}
}
const char* szWindowClass = "myclass";
typedef struct MyRect {
int x, y, width, height;
} MyRect;
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
/* Win 3.x */
wc.style = CS_DBLCLKS;
wc.lpfnWndProc = WindowProcedure;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = 0;
wc.lpszClassName = szWindowClass;
/* Win 4.0 */
wc.hIconSm = LoadIcon(0, IDI_APPLICATION);
return RegisterClassEx(&wc);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
MyRect rect;
rect.x = 300;
rect.y = 300;
rect.width = 640;
rect.height = 480;
HWND hwnd = CreateWindowEx(0, szWindowClass, "title",
WS_OVERLAPPEDWINDOW, rect.x, rect.y,
rect.width, rect.height, 0, 0, GetModuleHandle(0), 0);
if (!hwnd)
{
return FALSE;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
return TRUE;
}
int main()
{
printf("hello world!\n");
HINSTANCE hInstance = GetModuleHandle(0);
int nCmdShow = SW_SHOWDEFAULT;
MyRegisterClass(hInstance);
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
DispatchMessage(&msg);
}
}
对比一下发现,其实main()和WinMain()分别作为入口的差别,仅仅在于hInstance函数和nCmdShow参数有所不同:WinMain()函数中是这两个参数作为参数传入,而main()函数中则手动赋予这两个参数初值:
HINSTANCE hInstance = GetModuleHandle(0);
int nCmdShow = SW_SHOWDEFAULT;
windows下控制台程序实现窗口显示的更多相关文章
- windows下控制台程序更改图标和加载资源文件
1.在空项目的Resouce FIles中右击创建一个新的.rc文件. 2.选中这个.rc文件右击在界面中选择导入icon 3.选中icon,将icon的ID更改为IDC_MAINFRAME. 4.重 ...
- 最简单的方法是使用标准的 Linux GUI 程序之一: i-nex 收集硬件信息,并且类似于 Windows 下流行的 CPU-Z 的显示。 HardInfo 显示硬件具体信息,甚至包括一组八个的流行的性能基准程序,你可以用它们评估你的系统性能。 KInfoCenter 和 Lshw 也能够显示硬件的详细信息,并且可以从许多软件仓库中获取。
最简单的方法是使用标准的 Linux GUI 程序之一: i-nex 收集硬件信息,并且类似于 Windows 下流行的 CPU-Z 的显示. HardInfo 显示硬件具体信息,甚至包括一组八个的流 ...
- Windows下的程序及热键监视神器——Spy++
Windows下的程序及热键监视神器--Spy++ 背景 在使用Windows的时候,偶尔会发现某些应用程序的热键不生效了:又或是桌面弹出了弹框却并不知道这个弹框来自何处.例如,本人最近使用Vim的时 ...
- Windows下命令行Git无法显示中文问题解决方案
Windows下Git设置编码正常显示中文: 在 CMD 下设置环境变量 set LESSCHARSET=utf-8 在 PowerShell 下设置环境变量 $env:LESSCHARSET='ut ...
- C#下控制台程序窗口下启用快速编辑模式运行线程会阻止线程运行
最近做一个小的功能,使用C#控制台程序开启一个线程进行无限循环没5秒处理一次程序,发现控制台窗口在开启快速编辑模式情况下,进行选择程序打印 出来的文字后发现线程不走了,将快速编辑模式去除后,线程就不会 ...
- 隐藏windows任务栏中的窗口显示
在实际应用中遇到类似下列需要: 隐藏windows窗口,在windows任务栏中窗口不可见,但应用程序在后台运行. windows应用程序的窗口默认会在任务栏中添加一个可见的窗口项,方便用户操作和在不 ...
- Windows MFC 两个OpenGL窗口显示与线程RC问题
问题为:背景界面是一个OpenGL窗口(对话框),在其上弹出一个OpenGL窗口(模态对话框)时, 1.上方的OpenGL窗口能响应鼠标操作等并刷新: 2.当移动或放大缩小上方的OpenGL窗口时,其 ...
- Windows下打开某些软件时显示显卡驱动不是最新的问题
在Windows下打开某些对显卡要求比较高的软件时,会出现某些显卡驱动不是最新,要求更新到最新的提示,但是当你真的去更新显卡驱动的时候,却发现现在的显卡驱动已经是最新了,那么为什么还会有这样的提示呢, ...
- windows下tomcat在当前窗口运行,不在新弹出的窗口运行
window下tomcat在当前窗口启动,不在一个新的窗口启动startup.bat中最下几行goto setArgs:doneSetArgscall "%EXECUTABLE%" ...
随机推荐
- Docker-Compose简介及常用命令
1.Docker-Compose简介 Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排.Docker-Compose将所管理的容器分为三层,分别是 ...
- (原)使用ass字幕文件通过ffmpeg给视频添加字幕的一些研究
使用ass字幕文件通过ffmpeg给视频添加字幕的一些研究 Author:lihaiping1603@aliyun.com Create:2019-09-04 最近对ffmpeg给视频文件添加字幕效果 ...
- iOS - 浮点数去掉小数点之后的0,以0.5小数递增函数
NSMutableArray *arrNumber = [NSMutableArray array]; float a = -0.5; ) { a+=0.5; NSString *str = [sel ...
- LeetCode_459. Repeated Substring Pattern
459. Repeated Substring Pattern Easy Given a non-empty string check if it can be constructed by taki ...
- elk使用记录
1.使用elk查询接口的时候 几个常用参数 http_host.raw 2.具体的接口名称:request_uri 3.想要把左边要查询的显示出来
- kubernetes之Scheduler原理分析
scheduler在整个系统承担了承上启下的重要功能 承上值负责接受Controller Manager创建新的pod,安排目标Node 旗下指安置工作完成后,目标Node上的kubelet服务进程接 ...
- 一段隐藏文字的css代码,记录下
<span style="width:1px; height:1px; color:#fff; outline-width:hidden; overflow:hidden; displ ...
- C#反射机制(转自Binfire博客)
一:反射的定义 审查元数据并收集关于它的类型信息的能力.元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等. Sys ...
- eclipse项目有红色感叹号
1.依赖有问题 找到build path 点击configure build path 点击libraries 找到有红叉的包,然后选中移除 2.引用的包有问题 利用maven引用的包出现问题,有的包 ...
- 在ensp上的动态NAT的配置
原理 实验模拟 搭建实验拓扑 相关参数 配置静态NAT ,一对一映射 首先设置静态路由,使路由器能够访问 我们ping一下抓一下包 发现我们出去的包已经封装成为了另外一个ip 配置动态NAT ,一对一 ...