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下控制台程序实现窗口显示的更多相关文章

  1. windows下控制台程序更改图标和加载资源文件

    1.在空项目的Resouce FIles中右击创建一个新的.rc文件. 2.选中这个.rc文件右击在界面中选择导入icon 3.选中icon,将icon的ID更改为IDC_MAINFRAME. 4.重 ...

  2. 最简单的方法是使用标准的 Linux GUI 程序之一: i-nex 收集硬件信息,并且类似于 Windows 下流行的 CPU-Z 的显示。 HardInfo 显示硬件具体信息,甚至包括一组八个的流行的性能基准程序,你可以用它们评估你的系统性能。 KInfoCenter 和 Lshw 也能够显示硬件的详细信息,并且可以从许多软件仓库中获取。

    最简单的方法是使用标准的 Linux GUI 程序之一: i-nex 收集硬件信息,并且类似于 Windows 下流行的 CPU-Z 的显示. HardInfo 显示硬件具体信息,甚至包括一组八个的流 ...

  3. Windows下的程序及热键监视神器——Spy++

    Windows下的程序及热键监视神器--Spy++ 背景 在使用Windows的时候,偶尔会发现某些应用程序的热键不生效了:又或是桌面弹出了弹框却并不知道这个弹框来自何处.例如,本人最近使用Vim的时 ...

  4. Windows下命令行Git无法显示中文问题解决方案

    Windows下Git设置编码正常显示中文: 在 CMD 下设置环境变量 set LESSCHARSET=utf-8 在 PowerShell 下设置环境变量 $env:LESSCHARSET='ut ...

  5. C#下控制台程序窗口下启用快速编辑模式运行线程会阻止线程运行

    最近做一个小的功能,使用C#控制台程序开启一个线程进行无限循环没5秒处理一次程序,发现控制台窗口在开启快速编辑模式情况下,进行选择程序打印 出来的文字后发现线程不走了,将快速编辑模式去除后,线程就不会 ...

  6. 隐藏windows任务栏中的窗口显示

    在实际应用中遇到类似下列需要: 隐藏windows窗口,在windows任务栏中窗口不可见,但应用程序在后台运行. windows应用程序的窗口默认会在任务栏中添加一个可见的窗口项,方便用户操作和在不 ...

  7. Windows MFC 两个OpenGL窗口显示与线程RC问题

    问题为:背景界面是一个OpenGL窗口(对话框),在其上弹出一个OpenGL窗口(模态对话框)时, 1.上方的OpenGL窗口能响应鼠标操作等并刷新: 2.当移动或放大缩小上方的OpenGL窗口时,其 ...

  8. Windows下打开某些软件时显示显卡驱动不是最新的问题

    在Windows下打开某些对显卡要求比较高的软件时,会出现某些显卡驱动不是最新,要求更新到最新的提示,但是当你真的去更新显卡驱动的时候,却发现现在的显卡驱动已经是最新了,那么为什么还会有这样的提示呢, ...

  9. windows下tomcat在当前窗口运行,不在新弹出的窗口运行

    window下tomcat在当前窗口启动,不在一个新的窗口启动startup.bat中最下几行goto setArgs:doneSetArgscall "%EXECUTABLE%" ...

随机推荐

  1. java多线程(六)线程控制类

    1.   多线程控制类 为了保证多线程的三个特性,Java引入了很多线程控制机制,下面介绍其中常用的几种: l  ThreadLocal l  原子类 l  Lock类 l  Volatile关键字 ...

  2. Win10如何开启蓝屏记录?Win10开启蓝屏信息记录的方法

    转载:http://www.xitongzhijia.net/xtjc/20170127/91010.html 蓝屏,是电脑最常见的故障,一般出现蓝屏时都会显示详细的蓝屏错误信息,方便用户排查故障.最 ...

  3. LeetCode 108. Convert Sorted Array to Binary Search Tree (将有序数组转换成BST)

    108. Convert Sorted Array to Binary Search Tree Given an array where elements are sorted in ascendin ...

  4. Delphi连接Oracle控件ODAC的安装及使用

    Delphi连接Oracle有很多种方式,但大多要在客户机上安装Oracle那庞大的客户端,比较不方便,使用ODAC控件连接Oracle则免去了这些麻烦.ODAC也是Oracle公司载发的控件.有fo ...

  5. [转]casperjs截图出现黑色背景

    原文地址:https://my.oschina.net/tuxpy/blog/879509?utm_medium=referral 如果默认没有指定 body的background-color就会出现 ...

  6. QT+FFMPEG+SDL2.0实现视频播放

    开发环境:MinGW+QT5.9+FFMPEG20190212+SDL2.0.9 一.开发环境搭建 (1)下载工具 在https://ffmpeg.zeranoe.com/builds/下载对应版本. ...

  7. 【记录】【MySQL】填充字符串函数 LPAD(str,len,padstr)

    LPAD(str,len,padstr) 1.如果str的长度等于len,那么就返回str 2.如果str的长度大于len,那么就返回str的前len个长度 3.如果str的长度小于len,那么就返回 ...

  8. 一致性hash算法应用场景、详解与实现(JAVA)

    一.概述 在分布式环境下,开发者通常会遇到一些分布存储的场景,例如数据库的分库分表(比如用户id尾号为1的放入数据库1,id尾号为2的放入数据库2):又如分布式缓存数据的获取(比如根据ip地址进行缓存 ...

  9. 【剑指offer】平衡二叉树

    题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 分析:采用后序遍历的方式判断左右子树的高度差是否大于1 class Solution { public: bool flag; int f(T ...

  10. 最新超简单解读torchvision

    torchvision https://pytorch.org/docs/stable/torchvision/index.html#module-torchvision The torchvisio ...