zoukankan      html  css  js  c++  java
  • 第一个windows桌面应用程序

    第一个windows桌面应用程序

    为了更好的还原crackme的exe文件,现在开始学习利用VS2019写windows桌面的应用

    首先我们先了解一下VS生成win32应用程序的一个重要函数——WinMain函数,类似于控制台程序必须有一个main函数一样,WinMain函数就是桌面应用程序的main函数。

    而winmain函数和main函数一样,有着参数:

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); 
    

    我们一个一个的来看看这些参数:

    hinstance:为程序生成实例句柄。

    hprevinstance:用来跟踪前一个应用程序的实例,现在不再使用。

    lpcmdline:包含了命令行参数,该参数为unicode字符串形式。

    ncmdshow:一个标志,表明窗口是否要最大化,最小化,或者是正常显示。

    WINAPI是一个调用惯例,它定义了函数如何从调用者处接收参数。

    在winmain函数中,我们需要创建一个窗口类结构WNDCLASSEX

    下面就是WNDCLASSEX创建的窗口类结构。

    
            **//创建 WNDCLASSEX 类型的窗口类结构。 此结构包含关于窗口的信息**
    ​	**//例如应用程序图标、窗口背景色、标题栏中显示的名称、窗口过程函数的名称等。**
    ​	WNDCLASSEX 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_APPLICATION)); 
    ​	wcex.hCursor        = LoadCursor(NULL, IDC_ARROW); 
    ​	wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1); 
    ​	wcex.lpszMenuName   = NULL;
    ​	wcex.lpszClassName  = szWindowClass;
    ​	wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    

    创建了窗口类后,我们必须要进行注册:

    这里我们使用到RegisterClassEx函数:

    我们先来看RegisterClassEX()函数的定义:

    函数功能:该函数为随后在调用Createwindow函数和CreatewindowEx函数中使用的窗口注册一个窗口类。

    ATON RegisterClassEX(CONST WNDCLASSEX* Ipwcx);

    这里的WNDCLASSEX* Ipwcx就是我们刚刚创建的WNDCLASSEX结构。在传递给这个函数之前,必须在结构内填充适当的类的属性返回值:如果函数成功,返回值是唯一识别被注册类的一个原于;如果函数失败,返回值为0。

    注册好窗口类后,我们就可以使用CreateWindow函数 创建窗口,使用ShowWindow窗口显示函数。

    首先我们看看CreateWindow:

    CreateWindow(
      lpClassName: PChar;     {窗口类的名字}
      lpWindowName: PChar;    {窗口标题}
      dwStyle: DWORD;         {窗口样式, 参加下表}
      X,Y: Integer;           {位置; 默认的X,Y可以指定为: Integer(CW_USEDEFAULT)}
      nWidth,nHeight: Integer;{大小; 默认的宽度、高度可以指定为: Integer(CW_USEDEFAULT)}}
      hWndParent: HWND;       {父窗口句柄}
      hMenu: HMENU;           {主菜单句柄}
      hInstance: HINST;       {模块实例句柄, 也就是当前 exe 的句柄}
      lpParam: Pointer        {附加参数, 创建多文档界面时才用到, 一般设为 nil}
    ): HWND;                  {返回所创建的窗口的句柄}
    
    //dwStyle 窗口样式参数可选值:
    WS_OVERLAPPED       = 0;                {重叠式窗口, 应带标题栏和边框}
    WS_POPUP            = DWORD($80000000); {弹出式窗口, 不能与 WS_CHILD 一起使用}
    WS_CHILD            = $40000000;        {子窗口, 不能与 WS_POPUP 一起使用}
    WS_MINIMIZE         = $20000000;        {最小化窗口}
    WS_VISIBLE          = $10000000;        {初始时可见}
    WS_DISABLED         = $8000000;         {禁止输入}
    WS_CLIPSIBLINGS     = $4000000;         {裁剪子窗口, 也就是子窗口重绘不影响重叠的其他子窗口, 应与 WS_CHILD 一起使用}
    WS_CLIPCHILDREN     = $2000000;         {在父窗口中绘图时绕开子窗口区域, 创建父窗口是使用}
    WS_MAXIMIZE         = $1000000;         {最大化窗口}
    WS_CAPTION          = $C00000;          {有标题栏}
    WS_BORDER           = $800000;          {有细线边框}
    WS_DLGFRAME         = $400000;          {对话框窗口}
    WS_VSCROLL          = $200000;          {有垂直滚动条}
    WS_HSCROLL          = $100000;          {有水平滚动条}
    WS_SYSMENU          = $80000;           {带系统标题栏, 须同时指定 WS_CAPTION}
    WS_THICKFRAME       = $40000;           {带宽边框, 宽边框用于改变窗口大小}
    WS_GROUP            = $20000;           {能用方向键转移焦点}
    WS_TABSTOP          = $10000;           {能用 TAB 转移焦点}
    WS_MINIMIZEBOX      = $20000;           {有最小化按钮}
    WS_MAXIMIZEBOX      = $10000;           {有最大化按钮}
    WS_TILED            = WS_OVERLAPPED;
    WS_ICONIC           = WS_MINIMIZE;
    WS_SIZEBOX          = WS_THICKFRAME;
    WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED or WS_CAPTION or WS_SYSMENU or WS_THICKFRAME or WS_MINIMIZEBOX or WS_MAXIMIZEBOX);
    WS_TILEDWINDOW      = WS_OVERLAPPEDWINDOW;
    WS_POPUPWINDOW      = (WS_POPUP or WS_BORDER or WS_SYSMENU);
    WS_CHILDWINDOW      = (WS_CHILD);
    
    //另外还有一些扩展样式:
    WS_EX_DLGMODALFRAME    = 1;      {指定双边界窗口; 藉此指定 WS_CAPTION 创建标题栏}
    WS_EX_NOPARENTNOTIFY   = 4;      {在窗口创建或取消时不向父窗口发送 WM_PARENTNOTIFY 消息}
    WS_EX_TOPMOST          = 8;      {在所有非最顶层窗口的上面}
    WS_EX_ACCEPTFILES      = $10;    {可接受拖放文件}
    WS_EX_TRANSPARENT      = $20;    {透明样式, 在同属窗口已重画时该窗口才可重画}
    WS_EX_MDICHILD         = $40;    {创建一个 MDI 子窗口}
    WS_EX_TOOLWINDOW       = $80;    {工具窗口}
    WS_EX_WINDOWEDGE       = $100;   {带立体的边框}
    WS_EX_CLIENTEDGE       = $200;   {带阴影的边界}
    WS_EX_CONTEXTHELP      = $400;   {标题包含一个问号标志, 不能与 WS_MAXIMIZEBOX 和 WS_MINIMIZEBOX 同时使用}
    WS_EX_RIGHT            = $1000;  {窗口具有右对齐属性}
    WS_EX_LEFT             = 0;      {窗口具有左对齐属性, WS_EX_LEFT 是缺省设置}
    WS_EX_RTLREADING       = $2000;  {窗口文本从右到左}
    WS_EX_LTRREADING       = 0;      {窗口文本从左到右, WS_EX_LTRREADING 是缺省设置}
    WS_EX_LEFTSCROLLBAR    = $4000;  {垂直滚动条在左边界, 只用于特殊语言环境}
    WS_EX_RIGHTSCROLLBAR   = 0;      {垂直滚动条在右边界, WS_EX_RIGHTSCROLLBAR 是缺省设置}
    WS_EX_CONTROLPARENT    = $10000; {允许用户使用 Tab 键在窗口的子窗口间搜索}
    WS_EX_STATICEDGE       = $20000; {窗口不可用时创建一个三维边界}
    WS_EX_APPWINDOW        = $40000; {当窗口可见时, 将一个顶层窗口放置到任务条上}
    WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE or WS_EX_CLIENTEDGE); {立体边框并带阴影}
    WS_EX_PALETTEWINDOW    = (WS_EX_WINDOWEDGE or WS_EX_TOOLWINDOW or WS_EX_TOPMOST); {立体边框、工具条窗口样式、在顶层}
    WS_EX_LAYERED          = $00080000; {分层或透明窗口, 该样式可使用混合特效}
    WS_EX_NOINHERITLAYOUT  = $00100000; {子窗口不继承父窗口的布局}
    WS_EX_LAYOUTRTL        = $00400000; {从右到左的布局}
    WS_EX_COMPOSITED       = $02000000; {用双缓冲从下到上绘制窗口的所有子孙}
    WS_EX_NOACTIVATE       = $08000000; {处于顶层但不激活}
    

    分析:

    首先要用 CreateWindow 创建窗口, 才能用 ShowWindow 显示窗口; 因为 ShowWindow 需要 CreateWindow 返回的句柄.

    在 CreateWindow 的参数中, 位置与大小与窗口标题无须多说;
    父窗口与菜单, 暂时都不需要, 先可置为 0;
    程序实例的句柄, Delphi 已经为我们准备好了: HInstance;
    窗口样式在前面的例子中我们使用了: WS_OVERLAPPEDWINDOW, 它代表几种特点的组合, 表示了常规窗口.

    CreateWindow 还有一个重要参数(第一个参数 lpClassName): 窗口类的名字.
    Windows 要求我们要登记并注册一个窗口类以后, 才可以用 CreateWindow 建立窗口!

    showWindow函数是一个较为简单的函数,并不复杂:

    ShowWindow(
      hWnd: HWND;       {要显示的窗口的句柄}
      nCmdShow: Integer {选项, 参加下表}
    ): BOOL;
    
    //uCmdShow 参数可选值:
    SW_HIDE            = 0;  {隐藏, 并且任务栏也没有最小化图标}
    SW_SHOWNORMAL      = 1;  {用最近的大小和位置显示, 激活}
    SW_NORMAL          = 1;  {同 SW_SHOWNORMAL}
    SW_SHOWMINIMIZED   = 2;  {最小化, 激活}
    SW_SHOWMAXIMIZED   = 3;  {最大化, 激活}
    SW_MAXIMIZE        = 3;  {同 SW_SHOWMAXIMIZED}
    SW_SHOWNOACTIVATE  = 4;  {用最近的大小和位置显示, 不激活}
    SW_SHOW            = 5;  {同 SW_SHOWNORMAL}
    SW_MINIMIZE        = 6;  {最小化, 不激活}
    SW_SHOWMINNOACTIVE = 7;  {同 SW_MINIMIZE}
    SW_SHOWNA          = 8;  {同 SW_SHOWNOACTIVATE}
    SW_RESTORE         = 9;  {同 SW_SHOWNORMAL}
    SW_SHOWDEFAULT     = 10; {同 SW_SHOWNORMAL}
    SW_MAX             = 10; {同 SW_SHOWNORMAL}
    

    然后我们要写一个用于侦听操作系统所发送消息的消息循环。

    而这里我们用到了Wndproc函数:

    函数原型:

         LRESULTCALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    
         窗口过程函数决定了当一个窗口从外界接收到不同的信息时,所采取的不同反应,即主要用于处理发送给窗口的信息。hwnd是要处理窗口的句柄;message是消息ID,代表了不同的消息类型;wParam和lParam代表了消息的附加信息,附加信息会随着消息类型的不同而不同。
    

    最后附上一个大佬的帖子,这个帖子里有这位大佬写的源文件:
    https://blog.csdn.net/h549570564/article/details/44043065/

  • 相关阅读:
    java Future模式的使用
    Objects源码解析
    VUE优秀的组件库总结
    数据库的一致性读,赃读,多线程与赃读,ACID,UNDO
    线程基础,多线程架构,高并发,线程安全基础知识
    程序员必备的开发利器
    spring security 实现登录验证码及记住我
    springboot 集成 spring security 自定义登录
    ELK整合SpringBoot日志收集
    ElasticSearch整合SpringBoot的API操作
  • 原文地址:https://www.cnblogs.com/lex-shoukaku/p/13284334.html
Copyright © 2011-2022 走看看