首页 > 其他分享 >《Win32篇》纯C和Win32实现窗口

《Win32篇》纯C和Win32实现窗口

时间:2023-07-27 13:46:28浏览次数:48  
标签:窗口 实现 return Win32 msg int hInstance wc rect

纯C和Win32实现窗口

参考链接:https://www.cnblogs.com/zjutzz/p/10806955.html

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;

标签:窗口,实现,return,Win32,msg,int,hInstance,wc,rect
From: https://www.cnblogs.com/fusio/p/17584693.html

相关文章

  • 成功实现FaceTime拨打,FaceTime数据筛选,检测手机号是否开通FaceTime的原理
    FaceTime是苹果公司iOS和macOS(以前称MacOSX或OSX)内置的一款视频通话软件,通过Wi-Fi或者蜂窝数据接入互联网,在两个装有FaceTime的设备之间实现视频通话。其要求通话双方均具有装有FaceTime的苹果设备,苹果ID以及可接入互联网的3G/4G/5G或者Wi-Fi网络。 一、Windows电脑上部署苹......
  • java 实现接口 使整型和字符串比较大小
    Java实现接口:使整型和字符串比较大小在Java中,我们经常需要比较两个对象的大小。通常情况下,我们可以直接使用比较运算符(如>、<、==)来比较整型数据或字符串。然而,有时我们可能需要在比较过程中使用自定义的逻辑。为了实现这一点,我们可以使用接口来定义比较逻辑,并在需要的地方实现该......
  • 《Win32篇》新建项目vs2008
    VS2008新建项目参考链接:https://blog.csdn.net/candyliuxj/article/details/7350053(1)新建Win32项目点击上图的确定后,出现Win32应用程序向导,点击下一步,出现下图界面,选择附加选项中的空项目,点击完成,新建项目完成。(2)添加预编译头从解决方案资源管理器中可看到,新建的Win32项目......
  • 《Win32篇》新建项目vs2015
    vs2015新建项目参考链接:https://blog.csdn.net/wowocpp/article/details/79260945创建一个最简单的win32应用程序使用的是vs2013中文版首先创建一个win32应用程序工程也可以使用快捷键Ctrl+Shift+N创建的工程名字是HelloApp下一步建立一个空项目创建后的工程如......
  • 《Win32篇》空项目、Win32项目、MFC项目、Win32控制台的区别
    空项目、Win32项目、MFC项目、Win32控制台的区别参考链接:https://www.cnblogs.com/MCSFX/p/13267287.html参考链接:https://www.zhihu.com/question/20524989/answer/17575697空项目控制台控制台没有窗口,控制台与有窗口的(例如:win32、mfc)交互方式不同,前者是CML(命令模式),后者是G......
  • nginx支持.htaccess文件实现伪静态
    server{listen80;server_nametsov.netwww.tsov.net;root/www/web/www.tsov.net;include/www/web/www.tsov.net/.htaccess;//增加这句,注意路径。  很多网站需要采用伪静态来访问动态网页。所以像phpcms这样的系统,都提供了一个.htaccess文件,供写伪......
  • FCKEditor实现word图片自动转存
    ​如何做到ueditor批量上传word图片?1、前端引用代码<!DOCTYPE html PUBLIC "-//W3C//DTDXHTML1.0Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head>......
  • 2、了解Webots的窗口-2
    一、WebotsGUI由四部分组成:1、3D窗口:显示并允许与3D模拟交互的窗口;2、Scenetree:它是当前世界的层次表示;3、Texteditor:允许编辑源码;4、Console:显示编译和控制输出;二、分别介绍一下八个菜单栏1、File:允许执行通常的文件操作,如加载,保存等等2、View:允许控制仿真窗口中的可视......
  • js实现websocket
    import{UserManager}from"@/utils/userManager.js";classwebSocketClass{constructor(url="ws://127.0.0.1:8088/",time=3){this.url=urlthis.filterMessagesList=[""];//服务端返回的内容message事件不监听的内容,不会再message返回......
  • 利用NAS实现全自动观影追剧的几种方案对比
    https://fairysen.com/788.html想象一下打开一个网页,点开搜索框输入想看的电影或者电视剧,只需要点一个按钮,过几分钟对应的高清资源就已经呈现在你的影视库中,刮削完毕,字幕配好,你可以随时在家里的大屏幕或手机的小屏幕上欣赏。上周花了两天时间研究了下这套自动化流程,之前一直是手......