• 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("
    destroying window
    ");
                PostQuitMessage(0) ;
                return 0L ;
    
            case WM_LBUTTONDOWN:
    			printf("
    mouse left button down at (%d, %d)
    ", 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!
    ");
    
        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("
    destroying window
    ");
    		PostQuitMessage(0);
    		return 0L;
    
    	case WM_LBUTTONDOWN:
    		printf("
    mouse left button down at (%d, %d)
    ", 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!
    ");
    
    	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;

  • 相关阅读:
    执行序列oracle存储过程和序列化写的demo
    快捷键列表myeclipse 设置代码提示快捷键
    鼠标管理解决win8 插上usb/鼠标蓝屏或无效方法
    JQuery实现拼图数字游戏
    Django的admin定制
    Django报:AttributeError: tuple object has no attribute get
    Django的models方法返回值异常,待解决
    主页跳转子页面的时候,模板语句中的数据未返回到页面(子页面空白)
    Django报:builtin_function_or_method' object is not iterable
    Windows Azure SDK 1.5、Windows Azure Tools for Microsoft Visual Studio 2010和新的服务管理功能发布了
  • 原文地址:https://www.cnblogs.com/zjutzz/p/10806955.html
Copyright © 2020-2023  润新知