博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
windows下控制台程序实现窗口显示
阅读量:4883 次
发布时间:2019-06-11

本文共 8584 字,大约阅读时间需要 28 分钟。

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接口,实现控制台类型程序中显示窗口”的样例程序,改编自

#include 
#include
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 
#include
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;

转载于:https://www.cnblogs.com/zjutzz/p/10806955.html

你可能感兴趣的文章
Palindrome Number
查看>>
H5上传功能
查看>>
PHP命名空间(Namespace)的使用详解
查看>>
java项目@override报错问题
查看>>
DataTable 和Json 字符串互转
查看>>
Django中Template does not exit
查看>>
Redis安装 java中的连接 序列化 反序列化
查看>>
hdu 1896 优先队列的应用
查看>>
递推和迭代的比较
查看>>
OpenGL 头文件,库文件
查看>>
点与不规则图形关系判断
查看>>
linux不开启图形界面
查看>>
菜鸟学习SSH(二)——Struts国际化
查看>>
iOS 自定义控件--重写一些方法
查看>>
第二次冲刺作业
查看>>
【转】HTML, CSS和Javascript调试入门
查看>>
折线图-小案例
查看>>
STL:优先队列Priority Aueue
查看>>
蓝桥历年试题 套娃
查看>>
EF4.0和EF5.0增删改查的写法区别及执行Sql的方法
查看>>