0%

windows系统相关的总结

一、系统知识

二、windows编程

1. 网络编程

1.1. 工具函数

1) 网络字节序转换

1
2
3
4
5
6
// #include <WinSock2.h>

uint32_t ntohl (uint32_t __netlong);
uint16_t ntohs (uint16_t __netshort);
uint32_t htonl (uint32_t __hostlong);
uint16_t htons (uint16_t __hostshort);

2) 时间函数

windows平台时间函数性能比较QueryPerformanceCounter,GetTickCount,ftime,time,GetLocalTime,GetSystemTimeAsFileTime

用途精度耗时比(不精确)
GetTickCount系统启动时间1ms26
GetSystemTimeAsFileTime系统时间(UTC)100ns39
GetLocalTime系统时间(本地时区)100ns1722
QueryPerformanceFrequency
QueryPerformanceCounter
系统启动时间和cpu频率相关2258
系统启动时间,不随系统时间调整变化
  • GetTickCount: ms级系统启动时间,不随系统时间变化,速度更快
  • QueryPerformanceFrequency: 系统内部计时其的时钟频率,速度很慢
  • QueryPerformanceCounter: 计数器计数,速度很慢
系统时间,修改系统时间会变化
  • GetLocalTime: 精度100ns
  • GetSystemTimeAsFileTime

2. 编译器

2.1. visual studio

1) 预定义宏

https://docs.microsoft.com/zh-cn/cpp/preprocessor/predefined-macros?view=msvc-170

3. 宽字符

3.1. C语言方式转换

1
2
3
4
5
6
7
8
9
10
int main()
{
char path[] = {"./aaaa"};
// 先使用NULL获取需要多少个宽字符(宽字符个数包括结束符,不是多少个字节)
int wcharLen = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
// 申请对应的空间
wchar_t *wcharPath = (wchar_t *)(malloc(wcharLen * sizeof(wchar_t)));
// 转换
MultiByteToWideChar(CP_UTF8, 0, path, -1, wcharPath, wcharLen);
}

3.2. C++标准库

1
2
3
4
5
6
7
8
9
int main()
{
char path[] = {"./aaaa"};
// 申请一个wstring_convert,要求从utf8编码的字符串转成wchar_t,最大字符支持0x10ffff,小端序
// 不设置小端序则默认会根据编译器来,MSVC会默认小端序,所有终端执行效果一致
// mingw编译完的二进制会根据环境变量来,在powershell下是大端序,在git bash下是小端序
std::wstring_convert<std::codecvt_utf8<wchar_t, 0x10ffff, std::little_endian>> converter;
std::wstring wcharPath = converter.from_bytes(path, path + sizeof(path));
}

或者下面的方式

1
2
3
4
5
6
7
int main()
{
char path[] = {"./aaaa"};
// 申请一个wstring_convert,任意编码从char转成wchar_t
std::wstring_convert<deletable_facet<std::codecvt<wchar_t, char, std::mbstate_t>>> converter;
std::wstring wcharPath = converter.from_bytes(path, path + sizeof(path));
}

4. windows特殊类型

WORD

  • 16位无符号整数
  • 一般用于windows系统调用的参数

DWORD

  • 32位无符号整数
  • 一般用于windows系统调用的返回值

WCHAR

  • 宽字符类型,2字节16位
  • 一般用于windows系统调用的参数

5. 注册表修改

5.1. 修改系统环境变量

  • 使用官方的SetEnvironmentVariable函数只能修改当前进程和子进程的,无法影响到其他进程
  • 需要修改注册表进行修改到系统环境变量,还需要进行通知
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// 修改系统的temp环境变量
static bool changeSystemTempDir(const std::string& newTempPath, std::error_code& ec) {
DWORD dwRet = 0;
auto wNewTempPath = s2ws(newTempPath);
auto szNewTempPath = wNewTempPath.c_str();
DWORD dwlen = wNewTempPath.size() * sizeof(wchar_t); // 这里需要字节数,不是宽字符长度
HKEY hKey = NULL;
DWORD dwtype = REG_EXPAND_SZ;
DWORD dwMsgRet = 0;
dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
0,
KEY_WRITE | KEY_READ,
&hKey);
if (dwRet != ERROR_SUCCESS) {
ec.assign(::GetLastError(), std::system_category());
ERRW("[ChangeTempDir]RegOpenKeyEx failed %s", std::to_string(ec).c_str());
return FALSE;
}
ON_SCOPE_EXIT({
if (hKey) {
RegCloseKey(hKey);
hKey = NULL;
}
});
dwRet = RegSetValueEx(hKey, L"TEMP", 0, dwtype, (LPBYTE)szNewTempPath, dwlen);
if (dwRet != ERROR_SUCCESS) {
ec.assign(::GetLastError(), std::system_category());
ERRW("[ChangeTempDir]RegSetValueEx TEMP %s failed %s", szNewTempPath, std::to_string(ec).c_str());
return false;
}
INFOW("[ChangeTempDir]RegSetValueEx TEMP %s success", szNewTempPath);

dwRet = RegSetValueEx(hKey, L"TMP", 0, dwtype, (LPBYTE)szNewTempPath, dwlen);
if (dwRet != ERROR_SUCCESS) {
ec.assign(::GetLastError(), std::system_category());
ERRW("[ChangeTempDir]RegSetValueEx TMP %s failed %s", szNewTempPath, std::to_string(ec).c_str());
return false;
}
INFOW("[ChangeTempDir]RegSetValueEx TMP %s success", szNewTempPath);

RegFlushKey(hKey);
PostMessage(HWND_BROADCAST, WM_SETTINGCHANGE, NULL, NULL);
SendMessageTimeoutW(HWND_BROADCAST,
WM_SETTINGCHANGE,
NULL,
(LPARAM)(L"Environment"),
SMTO_NORMAL,
INFINITE,
&dwMsgRet);
SendMessageTimeoutW(HWND_BROADCAST,
WM_SETTINGCHANGE,
NULL,
(LPARAM)(L"Environment"),
SMTO_NOTIMEOUTIFNOTHUNG,
INFINITE,
&dwMsgRet);
SendMessageTimeoutW(HWND_BROADCAST,
WM_SETTINGCHANGE,
NULL,
(LPARAM)(L"Environment"),
SMTO_ABORTIFHUNG,
INFINITE,
&dwMsgRet);
INFO("[ChangeTempDir]dwMsgRet is %d", dwMsgRet);
return true;
}

三、有用的几个技巧

1. 查看程序是64bit还是32bit

  • 对exe右键属性
  • 若降低色彩和分辨率的选项可勾选就是32位,不可勾选就是64位

四、好用的软件

1. mingw

  • minimal gnu for windows
  • 在windows上使用gcc

1.1. 安装

posix和win32

  • posix可以将std::thread转发成windows的实现
  • win32不允许使用std::thread,需要使用win32实现

seh和sjlj

  • seh可以处理signal()

2. make

2.1. 安装

五、win11

1. 跳过windows11安装检查

  • 在安装界面输入Shift + F10调出cmd
  • 输入regedit打开注册表
  • HKEY_LOCAL_MACHINE\SYSTEM\Setup下面添加一个key,值为LabConfig
  • 在其下面新建下面的几个DWORD (32bit)的值
    • BypassTPMCheck: 跳过tpm检查
    • BypassSecureBootCheck: 跳过安全启动检查
    • BypassRAMCheck: 跳过内存检查
  • 返回重新选择系统进入即可

小技巧和踩坑记

1. 低版本windows调用系统api获取dns地址时报11003错误

  • 根据排查,发现是系统api对于dns回包的兼容性不好
  • dns请求在win7上请求会有A和AAAA两个记录,但是如果AAAA记录的响应返回了A的ip,就会报这个错误

2. windows的线程轮转时间是10ms

  • 使用std::futurewait_for()方法,看似等待3ms,实际可能整体执行时间是10ms以上

3. IN和OUT为windows的api默认定义用来进行标识参数的方向

  • 定义关键字不能使用INOUT,因为它们是windows的api的默认定义
1
2
3
4
5
// 编译会报错,因为IN和OUT在windows下定义成了空
enum class Direction {
IN,
OUT,
};

4. 编译错误

4.1. 无法解析外部符号 _GetAdaptersInfo@8

  • 在代码中添加下面一句即可
1
#pragma comment(lib, "iphlpapi.lib")

4.2. error C2899: typename cannot be used outside a template declaration

  • VS2015的某个版本之前会报错,在2015.3之后就不会了

5. 添加开机启动脚本

  • 编写bat文件
1
2
@echo off
start /d"D:\Program\nginx-1.19.1" nginx.exe
  • 将bat文件放到C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup即可

6. windows和linux双系统时间不一致

  • windows把系统硬件时间作为本地时间,直接显示硬件时间
  • linux把硬件时间作为UTC,会根据当前时区做运算,也就是显示硬件时间+8(北京时间UTC+8)
  • 修改可以从linux或windows两方面改,建议从windows改,因为更加符合未来趋势,硬件时间不用频繁变动
  • windows按照下面管理员运行设置将硬件时间作为UTC时间,重启就生效了
1
Reg add HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation /v RealTimeIsUniversal /t REG_DWORD /d 1

7. 修改windows的远程桌面的默认端口

  • 注册表项HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\PortNumber
  • 修改完之后重启即可

8. 管理员修改其他用户密码

  • 命令行输入lusrmgr.msc,打开用户和用户组
  • 点击用户,在右侧找到对应的用户,右键设置密码就可以修改了

9. grub引导win11启动

  • 由于TPM导致grub找不到win11的引导,需要手动添加
  • 在grub引导界面,按c进入命令行,使用ls命令查看磁盘情况
1
grub> ls -l
  • 找到windows的fat分区地方,如hd0,gpt1
  • 查看是否有此文件bootmgfw.efi
1
grub> ls (hd0,gpt1)/efi/Microsoft/Boot/bootmgfw.efi
  • 启动linux,修改grub的配置/etc/grub.d/40_custom如下
1
2
3
4
5
6
7
8
9
10
11
12
13
=> cat /etc/grub.d/40_custom
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
menuentry 'Win11' {
insmod part_gpt
insmod chain
insmod ntfs
set root= '(hd0, gpt1)'
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}
  • 执行grub-mkconfig -o /boot/grub/grub.cfg更新grub配置即可找到win11

10. ssh报错Bad owner or permissions on C:\Users\xxx\.ssh\config

  • 需要编辑文件属性>安全>高级,config不允许未知用户有任何权限,id_rsa同样