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/

  • 相关阅读:
    LeetCode 242. Valid Anagram (验证变位词)
    LeetCode 205. Isomorphic Strings (同构字符串)
    LeetCode 204. Count Primes (质数的个数)
    LeetCode 202. Happy Number (快乐数字)
    LeetCode 170. Two Sum III
    LeetCode 136. Single Number (落单的数)
    LeetCode 697. Degree of an Array (数组的度)
    LeetCode 695. Max Area of Island (岛的最大区域)
    Spark中的键值对操作
    各种排序算法总结
  • 原文地址:https://www.cnblogs.com/chendeqiang/p/14396347.html
Copyright © 2011-2022 走看看