zoukankan      html  css  js  c++  java
  • Windows API笔记

    简介

    Windows API

    本教程是纯Windows API教程,不包含MFC,使用的是C99标准。

    Windows API是创建Windows应用程序的接口,要使用Windows API就要先下载Windows SDk(Software Development Kit,软件开发环境),SDK包括头文件,函数库,样例,文档和工具等。

    Windows API是由C和C++写的,被分为以下几个部分:

    • 基础服务
    • 安全
    • 绘图
    • 用户接口
    • 多媒体
    • Windows shell
    • 网络

    基础服务提供了文件系统,设备,进程,线程,注册表,以及错误处理等功能。
    安全提供了函数,接口,对象和其他的认证,版权等安全相关的元素。
    绘图提供了图形输出到屏幕,打印机及其他输出设备的功能。
    用户接口提供了创建窗口和部件的功能。
    多媒体提供了视频,音频等输出设备。
    Windows Shell提供了由操作系统提供的shell功能。
    网络提供了网络服务。

    Windows API的官方实现是在动态库里(DLLS),例如kenel32.dll,user32.dll,gdi32.dll,shell32.dll是在Windows system目录下。
    也有第三方的Windows API:最常见的就是Wine工程和ReactOS工程。
    Windows API是一个动态实体,函数的数量每年都在增长。

    Pelles C

    教程里使用的是Palles C,我用的是VS2017.

    MSDN

    两个好的参考资料:Desktop App Development DocumentationWindows API list

    主函数

    main

    主函数是C语言编程的一个进入点,然而他不是第一个运行的程序。
    在C运行库中,程序开始的第一个函数叫做mainCRTStartup(),他负责初始化内存管理,文件I/O,以及参数调用等,之后mainCRTStartuo()将会调用main(),以下是main函数的函数原型:

    int main (void);
    int main(int argc,char **argv);
    int main(int argc,char *argv[]);
    

    样例:

    #include<stdio.h>
    
    int main(void)
    {
          puts("This is a classic C Program.");
          return 0;
    }
    

    wmain

    前面的main函数原型只能接收 ASCII 字符,如果我们想让程序从命令行接收宽字符,就需要使用wmain:

    int wmain(void);
    int wmain(int argc,wchar_t **argv);
    int wmain(int argc, wchar_t *argv[]);
    

    样例;
    这个程序在命令行使用宽字符,并输出命令行的第一个参数,众所周知,第0个参数是程序的运行目录。

    #include <windows.h>
    #include <wchar.h>
    #include<clocale>
    
    int wmain(int argc, wchar_t **argv) { //wchar_t类型即宽字符类型
    
        setlocale(LC_ALL,"zh_CN.UTF-8"); //设置语言环境
        PDWORD cChars = NULL;
        HANDLE std = GetStdHandle(STD_OUTPUT_HANDLE);   //获取标准输出的句柄
        
        if (std == INVALID_HANDLE_VALUE) { //如果我们收到的返回代码是错误值INVALID_HANDLE_VALUE,
            wprintf(L"Cannot retrieve standard output handle
     (%d)",  
                GetLastError()); //就输出一条错误信息,并输出错误代码
        }
     
        if (argv[1]) {
        
            WriteConsoleW(std, argv[1], wcslen(argv[1]), cChars, NULL); //向控制台输出宽字符串
        }
        
        CloseHandle(std); //关闭标准输出的句柄
     
        return 0;
    }
    

    如果想要输入命令行参数,可以在VS2017中右侧,解决方案资源量管理器->右键->属性-> 调试->命令参数,输入汉字即可。

    _tmain 函数原型

    _tmain()函数是微软的扩展函数,通过定义一个UNICODE宏来判断创建main()函数还是wmain()函数。
    在过去,要创建这两个函数都需要创建,现在只需要一个宏就解决了,但是目前程序最通用的方式还是UNICODE程序。
    以下是_tmain()的函数原型,其中,TCHAR宏用于转换char或者wchar_t,通过UNICODE宏控制:

    int _tmain(void);
    int _tmain(int argc,TCHAR **argv);
    int _tmain(int argc,TCHAR *argv[]);
    

    以下是一个程序样例:

    #define _UNICODE  //该宏用于C运行库转换
    #define UNICODE  ////该宏用于Windows头文件转换
    
    #include <windows.h> //这个头文件定义了TCHAR宏,TCHAR宏受UNICODE宏影响
    #include <tchar.h> //为_tmain和_tcslen宏引入头文件,他们的转换受_UNICODE影响
    
    int _tmain(int argc, TCHAR *argv[]) {
    
        PDWORD cChars = NULL;
        HANDLE std = GetStdHandle(STD_OUTPUT_HANDLE);
    
        if (std == INVALID_HANDLE_VALUE) {
            _tprintf(L"Cannot retrieve standard output handle
     (%d)", 
                GetLastError());
        }  
            
        if (argv[1]) {
        
            WriteConsole(std, argv[1], _tcslen(argv[1]), cChars, NULL);
        }
        
        CloseHandle(std);
    
        return 0;
    }
    

    WinMain

    以上是控制台主函数,现在我们介绍图形用户界面的主函数:

    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
        PWSTR pCmdLine, int nCmdShow);
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
        LPSTR lpCmdLine, int nCmdShow);
    int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
        LPTSTR lpCmdLine, int nCmdShow);
    

    其中,pCmdLine是命令行参数。

    如果进入点是WinMain()函数时,那么程序开始于WinMainCRTStartup();
    如果进入点是wWinMain()函数,那么程序开始于wWinMainCRTStartup().

    下面是一个样例,在屏幕上显示一个弹窗:

    #include <windows.h>
    
    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                  PWSTR szCmdLine, int CmdShow) {
                  
       MessageBoxW(NULL, szCmdLine, L"Title", MB_OK);
    
       return 0;
    }
    

    系统函数

    系统函数用于接收系统信息并和系统通信。

    屏幕尺寸

    GetSystemMetrics() 用于查看系统指标和系统设定。
    下面是一个例子,用于输出屏幕尺寸:

    #include <windows.h>
    #include <wchar.h>
    
    #pragma comment(lib, "user32.lib") //编译需要user32.lib库
    
    int wmain(void) {
    
        int x = GetSystemMetrics(SM_CXSCREEN);
        int y = GetSystemMetrics(SM_CYSCREEN);
    
        wprintf(L"The screen size is: %dx%d
    ", x, y);
        
        return 0;
    }
    

    锁屏

    #include <windows.h>
    #include <wchar.h>
    
    #pragma comment(lib, "user32.lib")
    
    int wmain(void) { 
    
        int r = LockWorkStation();
    
        if( r == 0 ) {
        
            wprintf(L"LockWorkStation() failed %d
    ", GetLastError());
            return 1;
        }
    
        return 0;
    }
    

    电脑名

    GetComputerNameEx()用于检测NETBIOS和DNS名。

    #include <windows.h>
    #include <wchar.h>
    
    int wmain(void) {
    
        wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1]; //MAX_COMPUTERNAME_LENGTH定义了电脑名的最大长度
        DWORD size = sizeof(computerName) / sizeof(computerName[0]);
    
        int r = GetComputerNameW(computerName, &size);
    
        if (r == 0) {
            wprintf(L"Failed to get computer name %ld", GetLastError());
            return 1;
        }
    
        wprintf(L"Computer name: %ls
    ", computerName);
    
        return 0;
    }
    

    用户名

    #include <windows.h>
    #include <Lmcons.h> //ULEN定义
    #include <wchar.h>
    
    int wmain(void) {
    
        wchar_t username[UNLEN+1];
        DWORD len = sizeof(username) / sizeof(wchar_t);
    
        int r = GetUserNameW(username, &len);
    
        if (r == 0) {
            wprintf(L"Failed to get username %ld", GetLastError());
            return 1;
        }
      
        wprintf(L"User name: %ls
    ", username);
    
        return 0;
    }
    

    当前目录

    SetCurrentDirectoryW() 用于设置当前目录;GetCurrentDirectoryW()用于获取当前目录。
    在下面的样例中,我们输出了当前目录,并通过命令行参数改变了当前目录。

    #include <windows.h>
    #include <wchar.h>
    
    #define BUFSIZE MAX_PATH
    
    int wmain(int argc, wchar_t **argv) {
    
        wchar_t buf[BUFSIZE];
        
        if(argc != 2) {
    
            wprintf(L"Usage: %ls <dir>
    ", argv[0]);
            return 1;
        }
    
        DWORD r = SetCurrentDirectoryW(argv[1]);
    
        if (r == 0) {
    
            wprintf(L"SetCurrentDirectoryW() failed (%ld)
    ", GetLastError());
            return 1;
        }
    
        r = GetCurrentDirectoryW(BUFSIZE, buf);
    
        if (r == 0) {
    
            wprintf(L"GetCurrentDirectoryW() failed (%ld)
    ", GetLastError());
            return 1;
        }
    
        if (r > BUFSIZE) {
    
            wprintf(L"Buffer too small; needs %d characters
    ", r);
            return 1;
        }
    
        wprintf(L"Current directory is: %ls
    ", buf);
    
        return 0;
    }
    

    Windows版本

    通过版本辅助函数可以检测当前的系统版本。

    #include <windows.h>
    #include <wchar.h>
    #include <VersionHelpers.h>
    
    int wmain(void) {
    
        //if (IsWindows10OrGreater()) {
            
        //    wprintf(L"This is Windows 10+");
        // }
        if (IsWindows8Point1OrGreater()) {
            wprintf(L"This is Windows 8.1+
    ");
        } else if (IsWindows8OrGreater()) {
            wprintf(L"This is Windows 8
    ");
        } else if (IsWindows7OrGreater ()) {
            wprintf(L"This is Windows 7
    ");
        } else if (IsWindowsVistaOrGreater ()) {
            wprintf(L"This is Windows Vista
    ");
        } else if (IsWindowsXPOrGreater()) {
            wprintf(L"This is Windows XP
    ");
        }
    
        return 0;
    }
    

    内存

    GlobalMemoryStatusEx() 函数用于检测当前系统的物理内存和虚拟内存。

    #include <windows.h>
    #include <wchar.h>
    
    int wmain(void) {
    
        MEMORYSTATUSEX mem = {0};
    
        mem.dwLength = sizeof(mem);
    
        int r = GlobalMemoryStatusEx(&mem);
    
        if (r == 0) {
            wprintf(L"Failed to memory status %ld", GetLastError());
            return 1;
        }
    
        wprintf(L"Memory in use: %ld percent
    ", mem.dwMemoryLoad);
        wprintf(L"Total physical memory: %lld
    ", mem.ullTotalPhys);
        wprintf(L"Free physical memory: %lld
    ", mem.ullAvailPhys);
        wprintf(L"Total virtual memory: %lld
    ", mem.ullTotalVirtual);
        wprintf(L"Free virtual memory: %lld
    ", mem.ullAvailVirtual);
        
        return 0;
    }
    

    Known Folders

    从Windows Vista开始,使用了新的系统来标识重要的目录,它叫做Known Folders。Known Folders使用一组GUID(Globally unique identifier) 来索引重要的文件夹。

    SHGetKnownFolderPath()函数通过GUID返回全路径。

    #include <windows.h>
    #include <initguid.h> //由于一些内部API的问题,不包含这个编译时会报错
    #include <KnownFolders.h>
    #include <ShlObj.h>
    #include <wchar.h>
    
    int wmain(void) {
    
        PWSTR path = NULL;
        
        HRESULT hr = SHGetKnownFolderPath(&FOLDERID_Documents, 0, NULL, &path);
    
        if (SUCCEEDED(hr)) {
            wprintf(L"%ls
    ", path);
        }
    
        CoTaskMemFree(path); //释放内存
    
        return 0;
    }
    

    驱动名

    使用GetLogicalDriveStringsW()函数来获取磁盘驱动名,他返回一个驱动路径的buffer:

    #include <windows.h>
    #include <wchar.h>
    
    int wmain(void) {
    
        wchar_t LogicalDrives[MAX_PATH] = {0};
        DWORD r = GetLogicalDriveStringsW(MAX_PATH, LogicalDrives);
        
        if (r == 0) {
            wprintf(L"Failed to get drive names %ld", GetLastError());
            return 1;
        }
    
        if (r > 0 && r <= MAX_PATH) {
        
            wchar_t *SingleDrive = LogicalDrives;
            
            while(*SingleDrive) {
                wprintf(L"%ls
    ", SingleDrive);
    
                SingleDrive += wcslen(SingleDrive) + 1;
            }
        }
    
        return 0;
    }
    

    剩余空间

    函数GetDiskFreeSpaceExW() 用于检测磁盘的用量信息。他返回三条信息:空间总量,剩余空间总量,剩余可用空间总量,下面的样例检测c盘的空间情况:

    #include <windows.h>
    #include <wchar.h>
    
    int wmain(void) {
    
        unsigned __int64 freeCall,
                         total,
                         free;
    
        int r = GetDiskFreeSpaceExW(L"C:\", (PULARGE_INTEGER) &freeCall,
            (PULARGE_INTEGER) &total, (PULARGE_INTEGER) &free);
    
        if (r == 0) {
    
            wprintf(L"Failed to get free disk space %ld", GetLastError());
            return 1;
        }	
    
        wprintf(L"Available space to caller: %I64u MB
    ", freeCall / (1024*1024));
        wprintf(L"Total space: %I64u MB
    ", total / (1024*1024));
        wprintf(L"Free space on drive: %I64u MB
    ", free / (1024*1024));
        
        return 0;
    }
    

    CPU速度

    CPU速度通过检测注册表的值来检测,需要查询HARDWAREDESCRIPTIONSystemCentralProcessor key

    #include <windows.h>
    #include <wchar.h>
    
    int wmain(void) {
    
        DWORD BufSize = MAX_PATH;
        DWORD mhz = MAX_PATH;
        HKEY key;
    
        long r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
            L"HARDWARE\DESCRIPTION\System\CentralProcessor\0", 0, KEY_READ, &key);
    
        if (r != ERROR_SUCCESS) {
    
            wprintf(L"RegOpenKeyExW() failed %ld", GetLastError());
            return 1;
        }
    
        r = RegQueryValueExW(key, L"~MHz", NULL, NULL, (LPBYTE) &mhz, &BufSize);
    
        if (r != ERROR_SUCCESS) {
    
            wprintf(L"RegQueryValueExW() failed %ld", GetLastError());
            return 1;
        }
    
        wprintf(L"CPU speed: %lu MHz
    ", mhz);
    
        r = RegCloseKey(key);
    
        if (r != ERROR_SUCCESS) {
    
            wprintf(L"Failed to close registry handle %ld", GetLastError());
            return 1;
        }
        
        return 0;
    }
    

    字符串

    C语言中是没有字符串数据类型的。字符串本质是一个字符型数组,无论什么时候我们说到字符串,都是指字符串数组。

    我们有五个处理字符串的API,包括CRT和Windows API的:

    • ANSI C standard functions
    • Security enhanced CRT functions
    • Windows API kernel and user functions
    • Windows API Shell Lightweight Utility functions
    • Windows API StrSafe functions

    ANSI C 字符串函数

    CRT函数调用了Windwos API函数,因此会有一点小开销,这些函数虽然实现了字符串函数但是有一些限制,当不被正确使用时,会造成安全问题,当执行失败时不会返回错误值。

    #include <windows.h>
    #include <wchar.h>
    
    #define STR_EQUAL 0
    
    int wmain(void) {
    
        wchar_t str1[] = L"There are 15 pines";
    
        wprintf(L"The length of the string is %lld characters
    ", wcslen(str1)); //输出宽字符串的数量
    
        wchar_t buf[20];
        wcscpy(buf, L"Wuthering"); //将字符串拷贝到buffer
        wcscat(buf, L" heights
    "); //向buffer中添加字符串
        wprintf(buf);
    
        if (wcscmp(L"rain", L"rainy")== STR_EQUAL) { //比较字符串
    
            wprintf(L"rain and rainy are equal strings
    ");
        } else {
    
            wprintf(L"rain and rainy are not equal strings
    ");
        } 
    
        return 0;
    }
    

    安全提高的CRT函数

    安全提高的CRT函数不是标准函数而是微软的扩展函数。

    这些函数验证了参数,buffer大小,字符串空检测以及提供了强化的错误报告。

    安全提高的CRT函数都有一个_s后缀:

    #include <windows.h>
    #include <wchar.h>
    
    #define BUF_LEN 25
    
    int wmain(void) {
    
        wchar_t str1[] = L"There are 15 pines";
    
        const int MAX_CHARS = 50;
        size_t count = wcsnlen_s(str1, MAX_CHARS); 
    
        wprintf(L"The length of the string is %ld characters
    ", count);
    
        wchar_t buf[BUF_LEN] = {0};
    
        int r = wcscpy_s(buf, BUF_LEN, L"Wuthering");
    
        if (r != 0) {
    
            wprintf(L"wcscpy_s() failed %ld", r);
        }
    
        r = wcscat_s(buf, BUF_LEN, L" heights
    ");
    
        if (r != 0) {
    
            wcscat_s(L"wcscat_s() failed %ld", r);
        }
    
        wprintf_s(buf);
    
        return 0;
    }
    

    内核和用户字符串函数

    这些函数只用于Windows系统,他们比CRT更轻量。

    内核级字符串函数根植于Windows内核开发,他们以字母l为前缀。

    字符串长度

    TODO.

    日期和时间

    TODO.

    窗口

    在Windows中,一切都是窗口,主窗口、按钮,静态文本甚至是图标,都是一个窗口,静态文本只不过是一个特殊窗口。

    样例

    simplewindow.c

    #include <windows.h>
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
        PWSTR pCmdLine, int nCmdShow) {
        
        MSG  msg;    
        HWND hwnd;
        WNDCLASSW wc;
    
        wc.style         = CS_HREDRAW | CS_VREDRAW;
        wc.cbClsExtra    = 0;
        wc.cbWndExtra    = 0;
        wc.lpszClassName = L"Window";
        wc.hInstance     = hInstance;
        wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
        wc.lpszMenuName  = NULL;
        wc.lpfnWndProc   = WndProc;
        wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
        wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
      
        RegisterClassW(&wc);
        hwnd = CreateWindowW(wc.lpszClassName, L"Window",
                    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                    100, 100, 350, 250, NULL, NULL, hInstance, NULL);  
    
        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);
    
        while (GetMessage(&msg, NULL, 0, 0)) {
      
            DispatchMessage(&msg);
        }
    
        return (int) msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, 
        WPARAM wParam, LPARAM lParam) {
        
        switch(msg) {
      
          case WM_DESTROY:
          
              PostQuitMessage(0);
              break;
        }
    
        return DefWindowProcW(hwnd, msg, wParam, lParam);
    }
    

    参考链接:
    https://zetcode.com/gui/winapi/

  • 相关阅读:
    Fiddler捕获抓取 App端数据包
    配置Java SSL 访问网站证书
    win10+vs2015+opencv3.0 x86/x64配置(debug+release)
    VMware虚拟机安装CentOS 7并搭建lamp服务器环境
    ubuntu18.04下eclipse配置及快捷方式创建
    ubuntu 安装vmware workstation
    linux安装出错
    [集合]java中的 可变参数
    泛型
    [集合]List
  • 原文地址:https://www.cnblogs.com/chendeqiang/p/14396347.html
Copyright © 2011-2022 走看看