当前位置: 首页 > news >正文

【第40节】windows编程:仿造MFC版本QQ安全卫士

目录

前言

一、实现功能

二、附加功能

三、开发环境

四、数据库简单字段设计

五、代码架构

六、软件界面

七、功能架构

八、部分功能截图

九、相关实现细节概要

9.1 获取文件信息

9.2 清理电脑垃圾信息

9.2.1 回收站

9.2.2 清理指定数据下的文件

9.3 数据库与网络运用

9.3.1 数据库

9.3.2 网络应用

9.4 注册表操作

9.4.1 软件卸载

9.4.1 管理启动项

9.5 遍历服务,启动,关闭服务

9.6.1 获取服务控制管理器的句柄

9.6.2 枚举所有服务

9.6.3 遍历服务


前言

        接下来我们来实现一个MFC版本QQ安全卫士的仿造品,我们需要掌握的前置知识点如下:

        (1)熟悉windows原理,学会windowsAPI解析PE文件
        (2)熟悉windows的权限管理和hook注入的相关知识
        (3)理解MFC界面编程和python网络编程
        (4)python结合mysql开发

        还不会的同学请关注本专栏,尽快学习前面的章节知识点,下面开始介绍本项目。

一、实现功能

1. 任务管理器功能:能够全面遍历进程、线程以及模块,同时对桌面窗口进行有效管理,方便用户清晰掌握系统运行状态。
2. 系统资源监控与优化:精准监测CPU和内存的使用率,并具备内存优化功能,提升系统整体运行效率。
3. 垃圾清理功能:涵盖系统垃圾、浏览器缓存垃圾以及VS开发环境产生的垃圾文件清理,释放磁盘空间。
4. 服务管理功能:可遍历系统内的所有服务,并支持启动和关闭特定服务,满足用户对系统服务的定制化管理需求。
5. 杀毒功能模块:
    - MD5查杀:通过对比文件MD5值识别病毒文件。
    - 全路径查杀:依据文件路径特征进行病毒排查。
    - 白名单查杀:基于白名单机制,识别并处理未在名单内的进程。
6. 数据库与网络应用:
    - 云查杀:利用网络连接服务器,实现云端病毒查杀。
    - 提交样本:支持用户提交可疑文件样本,助力病毒库更新。
    - 更新病毒库:及时从服务器获取最新病毒信息,保障查杀能力。
7. 进程保护功能:对关键进程进行防护,防止其被恶意终止或篡改。
8. PE文件解析:深入分析PE文件结构,辅助病毒检测和系统维护。

二、附加功能

1. 老板键功能:设置便捷老板键,快速隐藏特定窗口,保护隐私。
2. 系统控制功能:提供关机、重启、休眠等系统操作快捷入口。
3. 文件信息查看:可查询文件的创建时间、修改时间以及MD5值,方便用户了解文件属性。
4. 启动项与软件管理:能够管理系统启动项,同时支持软件卸载操作。
5. 内存优化小火箭及界面优化:以直观的小火箭形式展示内存优化功能,注重界面友好度设计,采用自定义控件提升用户体验。

三、开发环境

- 操作系统:Windows 10
- 数据库:MySQL 5.6
- Python版本:Python 3.6.2 32bit
- 开发工具:VS 2015或更高版本

四、数据库简单字段设计

- 病毒库:包含ID和MD5字段,用于存储病毒文件的唯一标识和对应的MD5值。
- 黑名单库:同样设置ID和MD5字段,记录黑名单中的文件标识及MD5信息。
- 白名单库:通过ID和MD5字段,保存白名单内文件的相关信息。
- 用户表备用:预留用户表,可用于后续扩展用户相关功能 。

五、代码架构

        客户端在相应窗口位置发送消息,在特定位置接收消息,开启线程发送更新消息,线程维护,同时保留socket统一接收接口。

六、软件界面

七、功能架构

八、部分功能截图

解析PE文件信息
PE头
区段信息
目录信息
导入表
导出表
资源表
重定位表
延迟加载表
TLS表

集成任务管理器

遍历进程线程模块

遍历文件信息

遍历窗口信息

VS工程垃圾清理

老板键

关机重启等

九、相关实现细节概要

        关于任务管理器的实现细节请看上一节,下面介绍本项目剩余部分细节实现。

9.1 获取文件信息

(1)获取文件的创建时间、修改时间和文件大小

        要是我们知道了文件的路径,就可以用FindFirstFile()函数来获取单个文件的信息。用这个函数能得到文件的好多信息,这些信息都存放在一个结构体里。下面是这个结构体的原型和注解:

typedef struct _WIN32_FIND_DATAW {DWORD   dwFileAttributes;    //文件属性FILETIME ftCreationTime;    //文件创建时间FILETIME ftLastAccessTime;  //文件最后的访问时间FILETIME ftLastWriteTime;   //文件最后写入的时间DWORD nFileSizeHigh;        //文件字节数的高32位DWORD nFileSizeLow;         //文件字节数低32位DWORD dwReserved0;          //保留DWORD dwReserved1;          //保留_Field_z_WCHAR cFileName[MAX_PATH ];//文件名_Field_z_WCHAR cAlternateFileName[14 ];
#ifdef _MACDWORD dwFileType;DWORD dwCreatorType;WORD WFinderFlags;
#endif
}WIN32_FIND_DATAW,*PWIN32_FIND_DATAW,*LPWIN32_FIND_DATAW;

        由于我们只打算获取一个文件的信息,所以文件路径不用加通配符,也不用调用FindNextFile()函数去逐个查找文件。具体做法如下: 

WIN32_FIND_DATA stcFData={0};
HANDLE hFind =FindFirstFile(L"c:\\123.exe",&stcFData);
if(hFind ==INVALID_HANDLE_VALUE)return FALSE;

        最后,就可以使用stcFData结构体中的内容了。

(2)获取文件的MD5值

        没有现成的API能直接算出文件的MD5值,不过网上有开源代码可以做这个计算。

9.2 清理电脑垃圾信息

9.2.1 回收站

(1)相关函数及结构体

typedef struct {DWORD     cbSize;    //本结构体的大小int64 i64Size;    //回收站的大小int64 i64NumItems;//回收站中文件的数量
}SHQUERYRBINFO,*LPSHQUERYRBINFO;

- 获取回收站信息

HRESULT SHQueryRecycleBin(LPCTSTR pszRootPath,            //文件或文件夹的路径LPSHQUERYRBINFO pSHQueryRBInfo //返回SHQUERYRBINFO结构体信息
);

- 清空回收站信息

- `pszRootPath`:这个参数是回收站在根驱动器里的路径地址。它可以是用字符串表示的驱动器、文件夹和子文件夹的名称,也能是空字符串或者NULL。要是为空,就意味着会清空所有驱动器上的回收站。
- `dwFlags`:这是清空回收站时的一些操作设置。
    - `SHERB_NOCONFIRMATION`:删除时不会弹出确认删除的对话框。
    - `SHERB_NOPROGRESSUI`:删除时不显示删除进度条。
    - `SHERB_NOSOUND`:删除完成后不会有提示音。

 

(2)思路

1. 初始化SHQUERYRBINFO结构体

SHQUERYRBINFO RecycleBinInfo ={};
RecycleBinInfo.cbSize =sizeof (RecycleBinInfo);

2. 查询回收站信息

SHQueryRecycleBin(NULL,&RecycleBinInfo);
//SHQueryRecycleBin第一参数为要查询回收站的盘符或者文件夹

3. 清空回收站

SHEmptyRecycleBin(NULL,NULL,SHERB_NOCONFIRMATION | SHERB_NOPROGRESSUI | SHERB_NOSOUND);

9.2.2 清理指定数据下的文件

(1)相关函数及结构体

typedef struct _WIN32_FIND_DATA {DWORD    dwFileAttributes;    //文件属性FILETIME    ftCreationTime;    //文件创建时间FILETIME    ftLastAccessTime;    //文件最后一次访问时间FILETIME    ftLastWriteTime;    //文件最后一次修改时间DWORD    nFileSizeHigh;    //文件长度(高32位)DWORD    nFileSizeLow;    //文件长度(低32位)DWORD    dwReserved0;    //系统保留DWORD    dwReserved1;    //系统保留TCHAR    cFileName[MAX_PATH];    //文件名TCHAR    cAlternateFileName[14];    //类似于短路径
}WIN32_FIND_DATA,*PWIN32_FIND_DATA,*LPWIN32_FIND_DATA;typedef struct _WIN32_FILE_ATTRIBUTE_DATA {DWORD    dwFileAttributes;  //文件系统文件或目录的属性信息。FILETIME ftCreationTime;    //创建文件和文件夹的时间FILETIME ftLastAccessTime;  //文件最后一次访问时间FILETIME ftLastWriteTime;   //文件最后一次修改时间DWORD    nFileSizeHigh;     //文件长度(高32位)DWORD    nFileSizeLow;      //文件长度(低32位)
}WIN32_FILE_ATTRIBUTE_DATA,*LPWIN32_FILE_ATTRIBUTE_DATA;

1. 查找第一个文件

HANDLE WINAPI FindFirstFile(LPCTSTR lpFileName,  //要查询的文件路径LPWIN32_FIND_DATA lpFindFileData  //指向文件信息结构体
);

2. 获取文件属性

BOOL GetFileAttributesEx(LPCTSTR lpFileName,                 //文件路径GET_FILEEX_INFO_LEVELS fInfoLevelId,//指定要获取的属性信息的设置LPVOID lpFileInformation             //指向WIN32_FIND_DATA结构体。
);

        也可以通过FindFirstFile函数返回的结构体信息确定文件的属性

3. 获取文件的后缀名

PTSTR PathFindExtension(PTSTR pszPath    //文件的路径
);

4. 获取下一个文件

BOOL FindNextFile(HANDLE hFindFile,  //FindFirstFile的返回值LPWIN32_FIND_DATA lpFindFileData  //指向文件信息结构体
);

(2)思路

实现删除C盘根目录下指定类型的文件

LARGE_INTEGER EnumFoldAndDeleteFile(WCHAR *lpFoldPath,WCHAR *1pFileType)
{//1. 初始化路径字符串WCHAR    szFoldPath[MAX_PATH]=L"C:\\";wcscat_s(szFoldPath, L"*");//在路径字符串追加通配符L"\\*"//2.获取第一个文件的信息ULARGE_INTEGER qwFileTotalSize ={};          //文件总大小WIN32_FIND_DATA w32FindData ={};HANDLE      hFindFile       =FindFirstFile(szFoldPath,&w32FindData);//3.循环遍历获取当前目录中的文件信息do{//去掉两个特殊目录if((!wcscmp(w32FindData.cFileName,L"."))|| (!wcscmp(w32FindData.cFileName,L"..")))continue;if(w32FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){//文件夹,继续删除文件夹里面的内容WCHAR szSubfoldPath[MAX_PATH];StringCchPrintf(szSubfoldPath,MAX_PATH,L"%s\\",lpFoldPath);//追加反斜杠StringCchCat(szSubfoldPath,MAX_PATH,w32FindData.cFileName);//子目录名qwFileTotalSize =EnumFoldAndDeleteFile(szSubfoldPath,1pFileType);}else{//获取文件的后缀WCHAR szFullPath[MAX_PATH];StringCchPrintf(szFullPath, MAX_PATH, L"%s\\%s", lpFoldPath, w32FindData.cFileName);LPWSTR FileSuffix=PathFindExtension(szFullPath);if((!lstrcmp(FileSuffix,L".tlog")) || (!lstrcmp(FileSuffix,      L".obj"))|| (!lstrcmp(FileSuffix,     L".log"))|| (!lstrcmp(FileSuffix,L".pch"))        || (!lstrcmp(FileSuffix,L".ilk"))|| (!lstrcmp(FileSuffix,       L".pdb"))){ULARGE_INTEGER  fileSize;         //记录文件的大小fileSize.HighPart                    =w32FindData.nFileSizeHigh;fileSize.LowPart                 =w32FindData.nFileSizeLow;qwFileTotalSize.QuadPart                     +=fileSize.QuadPart;DeleteFile(szFullPath);          //删除文件}}}while(FindNextFile(hFindFile,&w32FindData));return            qwFileTotalSize;
}

        要是想获取文件大小,由于WIN32_FIND_DATA结构体里文件长度分高位和低位,我们可以借助另一个结构体把它们拼接起来得到完整的文件大小,最后直接用fileSize.QuadPart就行。

像系统临时文件:C:\Windows\Temp

用户临时文件:C:\Users\kevin\AppData\Local\Temp

Windows错误报告:C:\Users\kevin\AppData\Local\Microsoft\Windows\WER\ReportQueue

        至于其他的垃圾信息路径,就得自己去收集了,可以参考电脑管家垃圾清理功能里涉及的文件路径。接下来讲讲9.3杀毒功能,包括MD5查杀、全路径查杀和白名单查杀。

(1)相关函数及结构体

HANDLE WINAPI CreateFile(_In_      LPCTSTR  lpFileName,         //要打开的文件名_In_      DWORD dwDesiredAccess,      //打开方式_In_      DWORD  dwShareMode,          //是否共享读_In_opt   LPSECURITY_ATTRIBUTES lpSecurityAttributes,//安全设置_In_      DWORD dwCreationDisposition,//操作文件属性_In_      DWORD dwFlagsAndAttributes,//文件本身的属性_In_opt_  HANDLE hTemplateFile         //另一个文件句柄,模板文件
);BOOL WriteFile(HANDLE hFile,                  //文件句柄LPCVOID lpBuffer,              //要写入的数据缓冲区DWORD nNumberOfBytesToWrite,   //要写入缓冲区的大小LPDWORD lpNumberOfBytesWritten,//实际写入文件的字节数LPOVERLAPPED lpOverlapped       //指向OVERLAPPED结构体
);BOOL ReadFile(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped
);

(2)思路
1. 将MD5值手动保存在文件中(.txt)
2. 打开文件

HANDLE hFile =CreateFile(L"5.txt",   //名为"5.txt"GENERIC_READ,          //以读方式打开0,                      //不能被共享NULL,                   //默认安全描述子,不能被继承OPEN_EXISTING,          //只打开以存在的文件FILE_ATTRIBUTE_NORMAL,  //常规文件属性NULL);                  //无模板

3. 读取文件中的信息

char ch[100]={};
DWORD dwReads;
ReadFile(hFile,ch,100,&dwReads,NULL);

4. 关闭文件句柄

CloseHandle(hFile);

- MD5查杀:先在一个文件里随意存上几个软件或者文件的MD5值,之后获取需要检测文件的MD5值,再把它和之前存好的MD5值对比,以此判断文件是否安全。
- 全路径查杀:采用逐个查找文件的方式,把找到的每个文件的MD5值和文件路径都进行分析比较。打个比方,要是在C盘根目录下发现有QQ.exe这个文件,就判定它是病毒,这算是一种很基础的文件查杀手段 。
- 白名单查杀:挨个检查进程,看看正在运行的进程是不是在自己预先设定好的白名单里面,如果不在,就把这个进程关掉。

9.3 数据库与网络运用

(云杀毒,从服务器获取查杀的信息)

9.3.1 数据库

(1)病毒信息存于数据库思路
1. 创建数据库

create database 病毒数据库

2. 创建病毒数据表

create table 病毒信息表
(NAME nchar(50),            --病毒名MD5 nchar(50)not null,    --病毒MD5值
)

3. 插入病毒数据(手动在数据库引擎中添加)

Insert Into病毒信息表(NAME,MD5)
values('QQScLauncher.exe','9800BDO8FCF2F15E74B88F3359CC0420')
Insert Into病毒信息表(NAME,MD5)
values('QQScLauncher.exe','9800BD08FCF2F15E74B88F3359CC0420')

4. 用ADO编程的办法来添加和查找数据:要是想知道具体怎么查找和添加,去看上课时发的关于ADO的资料,那里边讲得很详细。

注意:你可以自己在http://www.virscan.org这个网站上找几个你觉得是病毒的信息,然后保存下来。之后在数据库里要是能查到这些信息,那就说明对应的文件是病毒。

5. 创建两个账户,它们的权限不一样,一个账户只有读取数据的权限,另一个账户既能读取又能写入数据,这就是权限管理。

9.3.2 网络应用

(1)数据库在服务器上运行,我们从服务器获取病毒信息:

1. 在服务器那边,用ADO来连接自身服务器,就是把对数据库的各种访问操作都放在服务端进行。接着选一种网络模型(比如消息模型),用来接收客户端发过来的信息。

2. 在客户端这边,先获取文件的MD5值,然后把它发给服务端。服务端查完相关结果后,再把对应的信息返回给客户端。关于网络通信的具体内容,参考课上的资料(比如消息模型部分)。

(2)提交样本信息:

1. 客户端向服务端发送数据,服务端要判断收到的数据,到底是提交的样本信息,还是查询信息。判断方式有:
    - 在网络编程里,通过数据名字前面加特殊符号的方法来区分。
    - 把客户端要发的数据定义成结构体(结构体里包含数据类型、数据长度、结构体自身长度等信息),这样每次发送的数据就是结构体指针。服务端也用同样的结构体来接收数据。这里有个问题,当发送的数据太长时,没办法一次接收完。这时候结构体里的数据长度就很关键了。用recv接收数据后,会返回当前实际收到的数据长度,如果这个长度小于结构体里保存的数据长度,那就得再接收一次,并且把新收到的数据存到之前数据缓冲区的后面。


例子:
客户端:

//发给服务器的数据包,包括消息头,大小和MD5值
struct MessageContent
{DWORD dwMessageType;    //消息类型ULARGE_INTEGER ulFileSize;    //MD5值的数据大小char szMD5[36];                //MD5值
};
MessageContent msg;
send(socket,(char *)&msg,sizeof (msg),0);

        服务端:用`recv()`函数接收到数据后,把它转成MessageContent类型就行。接着对收到的数据做判断,然后根据判断结果操作数据库,进行增加、删除、修改、查询这些操作。 

9.4 注册表操作

(启动项和软件卸载)

9.4.1 软件卸载

(1)相关结构体和函数
1. 打开子句键句柄

LONG RegOpenKeyEx(_In_          HKEY hKey,        //根键句柄_In_opt_      LPCTSTR  lpSubKey, //子键路径_Reserved_    DWORD ul0ptions,  //保留NULL_In_          REGSAM samDesired,//打开键句柄的权限_0ut_         PHKEY phkResult    //子键句柄
);

2. 枚举获取Uninstall文件夹下的子文件名称

LONG RegEnumKeyEx(_In_         HKEY hKey,  //RegOpenKeyEx获取到的子键句柄_In_         DWORD dwIndex,  //指定被枚举键下子键的索引,从0开始_0ut_        LPTSTR lpName,  //保存子键的名称_Inout       LPDWORD  lpcName,  //指向szKeyName内存的大小_Reserved    LPDWORD lpReserved,//保留 必须为0_Inout_      LPTSTR  lpClass,   //DWORD变量地址,用于获取子键的类型_Inout_opt_  LPDWORD lpcClass, //指向一块内存,用于获取子键值数据_Out_opt_    PFILETIME lpftLastWriteTime //上一个参数所向的内存大小
);

3. 获取注册表项指定值的名称和数据类型
 

LONG RegQueryValueEx(_In_        HKEY hKey,         //子键句柄_In_opt_    LPCTSTR lpValueName,//要查询的键值名称_Reserved   LPDWORD lpReserved,//保留 必须为0_0ut_opt    LPDWORD lpType,    //键值的类型_0ut_opt_   LPBYTE  lpData,    //保存得到的结果_Inout_opt_LPDWORD lpcbData ); //缓冲的大小每次查询时都初始化一下

(2)思路
软件卸载信息有两处,通常系统版本为x64则遍历x64子键
- 主键:HKEY_LOCAL_MACHINE
  - 32位下:
    子键:Software\Microsoft\Windows\CurrentVersion\Uninstall
  - 64位下:
    子键:Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

//自定义结构体
typedef struct _SOFTINFO
{WCHAR szSoftName[50];           //软件名称WCHAR szSoftVer[50];             //软件版本号WCHAR szSoftDate[20];           //软件安装日期WCHAR szSoftSize[MAX_PATH];     //软件大小WCHAR strSoftInsPath[MAX_PATH]; //软件安装路径WCHAR strSoftUniPath[MAX_PATH]; //软件卸件路径WCHAR strSoftVenRel[50];        //软件发布厂商WCHAR strSoftIco[MAX_PATH];     //软件图标路径
}SOFTINFO,*PSOFTINFO;vector<SOFTINFO>m_vectSoftInfo;     //保存软件相关信息
HKEY RootKey =HKEY_LOCAL_MACHINE;  //主键
//子键名称(x86)
LPCTSTR lpSubKey =
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
HKEY hkResult =0;                        //接收将要打开的键的句柄//1.打开一个己经存在的注册表键
LONG lReturn =RegOpenKeyEx(RootKey, lpSubKey, 0,KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,  //指定打开键句柄的权限&hkResult);        //子键句柄//2.循环遍历Uninstall目录下的子键
while(true)
{DWORD dwIndex =0;DWORD dwKeyLen =255;WCHAR szNewKeyName[MAX_PATH]={};  //注册表项名称LONG lReturn =RegEnumKeyEx(hkResult,  //子键句柄dwIndex,  //指定被枚举键下子键的索引,从0开始szNewKeyName,  //指向一块内存保存子键的名称&dwKeyLen,  //指向szKeyName内存的大小0,       //保留 必须为0NULL,    //用于获取子键值的类型NULL,    //指向一块内存,用于获取子键值数据NULL);   //上一个参数所向的内存大小//2.1通过得到的子键名称重新组合成新的子键路径WCHAR strMidReg[MAX_PATH]={};swprintf_s(strMidReg,L"%s%s%s",lpSubKey,L"\\",szNewKeyName);//2.2打开新的子键,获取其句柄HKEY hkValueKey =0;                //子键句柄RegOpenKeyEx(RootKey,strMidReg,0,KEY_QUERY_VALUE,&hkValueKey);//2.3获取键值DWORD dwNameLen     =255;           //指向szBuffer内存的大小//获取软件名称RegQueryValueEx(hkValueKey,L"DisplayName",0,&dwType,(LPBYTE)m_vectSoftInfo[0].szSoftName,&dwNameLen);dwNameLen     =255;     //如果没有重新赋值下一次将获取不到信息//拆卸路径RegQueryValueEx(hkValueKey,L"UninstallString",0,&dwType,(LPBYTE)m_vectSoftInfo[0].strSoftUniPath,&dwNameLen);dwNameLen    =255;dwIndex++;  //子键的索引
}

        最后一步卸载软件只需要将得到的拆卸路径以OpenFile打开即可。

9.4.1 管理启动项

(1)相关函数
1. 删除键值

LONG WINAPI RegDeleteValue(_In_        HKEY hKey,               //打开要删除键值所属的子健_In_opt_    LPCTSTR lpValueName      //键值名
);


2. 枚举键值

LONG WINAPI RegEnumValue(_In_          HKEY    hKey,           //主键_In_         DWORD   dwIndex,        //索引,第1个_0ut_         LPTSTR  lpValueName,    //键值的名称_Inout        LPDWORD lpcchValueName,//键值的大小_Reserved     LPDWORD lpReserved,     //保留_0ut_opt_    LPDWORD lpType,         //类型_0ut_opt_    LPBYTE  lpData,         //保存数据_Inout_opt   LPDWORD lpcbData        //lpData的长度
);

(2)思路
注册表启动项在HKEY_CURRENT_USER和HKEY_LOCAL_MACHINE下面的:
- X86:
  - L"Software\\Microsoft\\Windows\\CurrentVersion\\Run",
  - L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run",
  - L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
  - L"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices0nce",
  - L"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
  - L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx",
- X64:
  - L"Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run"
  - L"Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnce"

//HKEY_CURRENT_USER下的指定键值
WCHAR RegBootStartItemInHKCU[REG_BOOT_START_ITEM_HKCU][MAX_PATH]={L"Software \\Microsoft\\WindowsNT\\CurrentVersion\\Windows",L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"
};

        获取启动程序相关信息:前面的操作和拆卸软件的一样,先枚举有子键,再枚举子键内的值。

DWORD dwIndex =0;
RegEnumValue(hSubKey,dwIndex,szKeyValueName,&dwValueNameLen,0,NULL,(PBYTE)szValue,&dwValueLen);

1. 打开要删除键值所属的子健

HKEY hSubkey;
RegOpenKeyEx(hKey,lpSubkey,0,KEY_SET_VALUE,&hSubkey);

2. 删除指定键值

RegDeleteValue(hSubkey,lpKeyValueName);

9.5 遍历服务,启动,关闭服务

        在Windows系统里,有个服务控制管理器,它存着电脑上所有服务的信息和状态。只要能操作这个服务控制管理器,就能获取所有服务的信息和状态,还能加载、启动、停止、关闭服务。下面是操作服务控制管理器的方法:

9.6.1 获取服务控制管理器的句柄

        操作服务控制管理器,就跟读写文件一样,都得有个句柄。下面是获取服务控制管理器句柄的API原型和注解:

SC_HANDLE OpenSCManagerW(LPCWSTR lpMachineName, //主机名LPCWSTR lpDatabaseName, //数据库名DWORD dwDesiredAccess //访问方式
);

- `lpMachineName`:这是主机名,它可以是远程主机的名字。要是填NULL,就表示打开本地主机。
- `lpDatabaseName`:这个参数要设置成SERVICES_ACTIVE_DATABASE,如果填NULL,系统会自动把它设成这个宏的值。
- `dwDesiredAccess`:这是访问权限,有下面这些宏可以用:
  - `SC_MANAGER_ALL_ACCESS`:拥有所有权限。
  - `SC_MANAGER_CREATE_SERVICE`:创建服务的权限,使用CreateService()函数时必须要有这个权限。
  - `SC_MANAGER_CONNECT`:连接服务控制管理器的权限。
  - `SC_MANAGER_ENUMERATE_SERVICE`:枚举所有服务的权限,使用EnumServicesStatus()函数和EnumServicesStatusEx()函数时需要这个权限。
  更多详细信息可以自己去查MSDN(在函数名上按F1就能查到)。

9.6.2 枚举所有服务

        如果想获取所有服务的信息,那么可以使用枚举服务的API。枚举服务的API原型和注解如下:

BOOL EnumServicesStatusEx(SC_HANDLE hSCManager,     //SCM数据库句柄SC_ENUM_TYPE InfoLevel, //要返回的属性DWORD dwServiceType,    //服务类型DWORD dwServiceState,   //服务器状态LPBYTE lpServices,      //接收信息缓冲区DWORD cbBufSize,        //缓冲区大小LPDWORD pcbBytesNeeded, //需要的大小LPDWORD lpServicesReturned, //缓冲区中的服务个数LPDWORD lpResumeHandle,    //NULLLPCTSTR pszGroupName       //NULL
);

- `hSCManager`:这个是OpenSCManagerW函数的返回值。
- `InfoLevel`:一般填SC_ENUM_PROCESS_INFO。
- `dwServiceType`:这是要枚举的服务类型,一般填SERVICE_WIN32,有下面这些宏可以选:
  - `SERVICE_DRIVER`:驱动服务。
  - `SERVICE_FILE_SYSTEM_DRIVER`:文件系统驱动服务。
  - `SERVICE_KERNEL_DRIVER`:内核驱动服务。
  - `SERVICE_WIN32`:应用进程的服务,相当于下面两个宏的组合。
  - `SERVICE_WIN32_OWN_PROCESS`
  - `SERVICE_WIN32_SHARE_PROCESS`
- `lpServices`:用来存枚举出来的服务信息的缓冲区。
- `cbBufSize`:缓冲区的实际大小。
- `pcbBytesNeeded`:需要的缓冲区大小。
- `lpServicesReturned`:获取到的服务信息数量。

        这个函数的用法和枚举模块的函数用法差不多。通常先传一个无效的缓冲区去调用这个函数,得到所需缓冲区的字节数,然后申请动态内存,再调用一次这个函数,把有效的缓冲区传进去,这样就能得到所有服务的信息了。

        其实,这个缓冲区是一个ENUM_SERVICE_STATUSW结构体的数组,`lpServicesReturned`说的就是这个数组里元素的个数。

9.6.3 遍历服务

下面是获取服务信息的示例:

//1.打开远程计算机服务控制管理器
SC_HANDLE hSCM=OpenSCManagerW(NULL,NULL,SC_MANAGER_ALL_ACCESS);//2.第一次调用,获取需要的内存大小
DWORD dwServiceNum =0;
DWORD dwSize =0;
EnumServicesStatusEx(hSCM,SC_ENUM_PROCESS_INFO,SERVICE_WIN32,SERVICE_STATE_ALL, //  所有服务状态NULL,                           // 缓冲区0,                            //缓冲区大小&dwSize,            //需要的大小&dwServiceNum,          // 缓冲区中的服务个数NULL,NULL
);//3. 申请需要的内存,第二次调用
LPENUM_SERVICE_STATUS_PROCESS pEnumSerice =(LPENUM_SERVICE_STATUS_PROCESS)new char[dwSize];//4 . 第二次枚举
bool    bStatus    =FALSE;
bStatus=EnumServicesStatusEx(hSCM,SC_ENUM_PROCESS_INFO,SERVICE_WIN32,SERVICE_STATE_ALL, //    所有服务状态(PBYTE)pEnumSerice, //          缓冲区dwSize,                 //缓冲区大小&dwSize,               //需要的大小&dwServiceNum, //    缓冲区中的服务个数NULL,NULL
);//5 . 遍历信息
for(DWORD i=0;i<  dwServiceNum;i ++) {//获取基础信息// 服 务 名pEnumSerice[i].lpServiceName;//服务状态有已停止,正在运行,正在暂停//(根据得到的值手动输出字符串,具体值的含义可以在该结构体上按F1 查 MSDN)pEnumSerice[i].ServiceStatus.dwCurrentState;//服务类型//有文件系统驱动服务,驱动服务,独立进程服务//更多详细的信息查MSDNpEnumSerice[i].ServiceStatus.dwServiceType;//6 . 获取服务的详细信息这里将只给出函数// 打 开 服 务SC_HANDLE    hService    = OpenService(      hSCM, //      服务控制管理器的句柄pEnumSerice[i].lpServiceName, //      服务名SERVICE_QUERY_CONFIG     // 打开权限);//第一次调用获取需要的缓冲区大小QueryServiceConfig(hService,NULL,0,&dwSize);//分配内存LPQUERY_SERVICE_CONFIG pServiceConfig =     \(LPQUERY_SERVICE_CONFIG)new                 char[dwSize];//第二次调用,获取信息QueryServiceConfig(hService,pServiceConfig,dwSize,&dwSize);//通过上面获取到的结构体信息具体得到想要的值//获取启动类型pServiceConfig->dwStartType;//类型有:"自启动","手动启动,"已禁用"//获取路径信息pServiceConfig->lpBinaryPathName;
}

项目代码:https://download.csdn.net/download/linshantang/90591342

相关文章:

【第40节】windows编程:仿造MFC版本QQ安全卫士

目录 前言 一、实现功能 二、附加功能 三、开发环境 四、数据库简单字段设计 五、代码架构 六、软件界面 七、功能架构 八、部分功能截图 九、相关实现细节概要 9.1 获取文件信息 9.2 清理电脑垃圾信息 9.2.1 回收站 9.2.2 清理指定数据下的文件 9.3 数据库与网…...

BOE(京东方)旗下控股子公司“京东方能源”成功挂牌新三板 以科技赋能零碳未来

2025年4月8日,BOE(京东方)旗下控股子公司京东方能源科技股份有限公司(以下简称“京东方能源”)正式通过全国中小企业股份转让系统审核,成功在新三板挂牌(证券简称:能源科技,证券代码:874526),成为BOE(京东方)自物联网转型以来首个独立孵化并成功挂牌的子公司。此次挂牌是BOE(京…...

【汽车产品开发项目管理——端到端的汽车产品诞生流程】

MPU&#xff1a;集成运算器、寄存器和控制器的中央处理器芯片 MCU&#xff1a;微控制单元&#xff0c;将中央处理器CPU、存储器ROM/RAM、计数器、IO接口及多种外设模块集成在单一芯片上的微型计算机系统。 汽车产品开发项目属性&#xff1a;临时性、独特性、渐进明细性、以目标…...

Visual Studio 2019 配置VTK9.3.1

文章目录 参考博客1、 VTK下载和编译2、vs2019配置vtk9.3.1参考博客 Visual Studio 2022 配置VTK9.3.0 1、 VTK下载和编译 见博客 CMake编译VTK 2、vs2019配置vtk9.3.1 新建一个项目 写入以下代码 #include <vtkActor.h> #include <vtkAssembly.h> #include…...

【含文档+PPT+源码】基于小程序的智能停车管理系统设计与开发

项目视频介绍&#xff1a; 毕业作品基于小程序的智能停车管理系统设计与开发 课程简介&#xff1a; 本课程演示的是一款基于小程序的智能停车管理系统设计与开发&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;…...

科技自立+产业周期:透视人工智能的配置机遇

最近&#xff0c;全球市场因关税政策调整引发震荡&#xff0c;科技板块波动尤为明显。在此背景下&#xff0c;中国人工智能产业经历了一轮回调。 不过&#xff0c;《一点财经》注意到&#xff0c;4月9日上证科创板人工智能指数一度上涨3.7%。拉长周期看&#xff0c;Wind数据显…...

linux网络配置

今天我们来了解一下linux的网络配置,这个是我们进行网络传输的基础,保证网络资源的使用的手段.那么来看. 网络配置原理图&#xff1a; 查看网络ip和网关 windows&#xff1a;ipconfig linux&#xff1a;ifconfig ping测试主机之间网络联通性 ⭐️ip地址要在同一个网段下才…...

机器学习 | 强化学习方法分类汇总 | 概念向

文章目录 &#x1f4da;Model-Free RL vs Model-Based RL&#x1f407;核心定义&#x1f407;核心区别 &#x1f4da;Policy-Based RL vs Value-Based RL&#x1f407;核心定义&#x1f407; 核心区别 &#x1f4da;Monte-Carlo update vs Temporal-Difference update&#x1f…...

git仓库迁移包括提交记录日志

网上找了很多资料都不好用&#xff0c;直到看到一个亲测有效后&#xff0c;整理如下&#xff1a; 1、进入仓库目录下&#xff0c;并且切换到要迁移的分支上 前提是你本地已有旧仓库的代码&#xff1b;如果没有的话&#xff0c;先拉取。 2、更改仓库地址 git remote set-url …...

Docker部署.NetCore8项目

在VS.net新建.netCore8项目&#xff0c;生成项目的发布文件&#xff0c;之后添加Dockerfile&#xff0c;内容如下&#xff1a; FROM mcr.microsoft.com/dotnet/aspnet:8.0 # 设置工作目录 WORKDIR /app # 挂载临时卷&#xff08;类似于 VOLUME /tmp&#xff09; VOLUME /tmp …...

xv6部分源码阅读-1

xv6部分源码阅读 前言 在lab2中&#xff0c;我们会为了完成attack这个实验&#xff0c;而花费大量的时间去阅读相关的系统调用源码&#xff0c;以此来分析出我们最终secret所在的页表的位置&#xff0c;而我写lab2中&#xff0c;重点并没有关注其中的逻辑关系&#xff0c;有很…...

CentOS中离线安装DockerCompos并用其部署Rabbitmq(使用离线导入导出docker镜像方式)

场景 DockerDockerCompose实现部署jenkins,并实现jenkinsfile打包SpringBootVue流水线项目过程详解、踩坑记录(附镜像资源、离线包资源下载)&#xff1a; DockerDockerCompose实现部署jenkins,并实现jenkinsfile打包SpringBootVue流水线项目过程详解、踩坑记录(附镜像资源、离…...

基于 OpenHarmony 5.0 的星闪轻量型设备应用开发——Ch2 OpenHarmony LiteOS-M 内核应用开发

写在前面&#xff1a; 此篇是系列文章《基于 OpenHarmony5.0 的星闪轻量型设备应用开发》的第 2 章。本篇介绍了如何在 OpenHarmony 5.0 框架下&#xff0c;针对 WS63 进行 LiteOS-M 内核应用工程的开发。 为了方便读者学习&#xff0c;需要OpenHarmony 5.0 WS63 SDK 的小伙伴可…...

2025年4月9日-华为暑期实习-第二题-200分

📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 02. 智能导航系统 问题描述 K小姐生活在一个被称为"未来之城"的智能城市,这个城市拥有高效的无人驾驶运输网络。城市内的智能车辆可以在不同的交通枢纽之间穿行,每个枢…...

抖音视频下载工具

抖音视频下载工具 功能介绍 这是一个基于Python开发的抖音视频下载工具&#xff0c;可以方便地下载抖音平台上的视频内容。 主要特点 支持无水印视频下载自动提取视频标题作为文件名显示下载进度条支持自动重试机制支持调试模式 使用要求 Python 3.10Chrome浏览器必要的P…...

基于大模型预测儿童急性淋巴细胞白血病诱导达完全缓解患者综合治疗方案研究报告

目录 一、引言 1.1 研究背景与意义 1.2 研究目的 1.3 国内外研究现状 二、儿童急性淋巴细胞白血病及大模型相关理论基础 2.1 儿童急性淋巴细胞白血病概述 2.2 大模型技术原理及特点 三、大模型在术前评估中的应用 3.1 患者基本信息与病情数据收集 3.2 大模型对病情严…...

项目合同从专家到小白

文章目录 按项目范围划分项目总承包合同项目单项承包合同项目分包合同 按项目付款方式划分总价合同固定总价合同总价加激励费用合同&#xff08;FPIF&#xff09;总价加经济价格调整合同订购单 \ 单边合同 成本补偿合同工料合同&#xff08;混合型&#xff09; 基础概念目标成本…...

【windows10】基于SSH反向隧道公网ip端口实现远程桌面

【windows10】基于SSH反向隧道公网ip端口实现远程桌面 1.背景2.SSH反向隧道3.远程连接电脑 1.背景 ‌Windows 10远程桌面协议的简称是RDP&#xff08;Remote Desktop Protocol&#xff09;‌。 RDP是一种网络协议&#xff0c;允许用户远程访问和操作另一台计算机。 远程桌面功…...

学习海康VisionMaster之四边形查找

一&#xff1a;进一步学习了 今天学习下VisionMaster中的四边形查找&#xff0c;这个还是拟合直线的衍生应用&#xff0c;可以同时测量四条直线并且输出交点或者判定是否有交点 二&#xff1a;开始学习 1&#xff1a;什么是四边形查找&#xff1f; 按照传统的算法&#xff0c;…...

菊风RTC 2.0 开发者文档正式发布,解锁音视频新体验!

重磅发布&#xff01; 开发者们&#xff0c;菊风实时音视频2.0文档已正式发布上线&#xff0c;为您提供更清晰、更高效的开发支持&#xff01;让菊风实时音视频2.0为您的音视频应用加速~ 菊风实时音视频2.0聚焦性能升级、体验升级、录制服务升级&#xff0c;助力视频通话、语…...

用Python和OpenCV开启图像处理魔法之旅

你是否曾好奇计算机是如何“看懂”这个世界的&#xff1f;从人脸识别到自动驾驶&#xff0c;计算机视觉技术正日益渗透到我们的生活中。而 OpenCV (Open Source Computer Vision Library)&#xff0c;作为一个强大的开源计算机视觉库&#xff0c;正是我们探索这个奇妙世界的强大…...

初识MySQL · 复合查询(内外连接)

目录 前言&#xff1a; 基本查询回顾 笛卡尔积和子查询 笛卡尔积 内外连接 子查询 单行子查询 多行子查询 多列子查询 from中使用子查询 合并查询 前言&#xff1a; 在前文我们学习了MySQL的基本查询&#xff0c;就是简单的套用了select语句&#xff0c;最多不过是…...

Devops系列之对接Gerrit的设计与实现(三)-- Java编程实现

一、背景 上文讲述了如何使用shell命令实现创建gerrit项目&#xff0c;本文介绍如何使用java语言编程实现。 二、java语言实现 1、引入jar包 <dependency><groupId>com.urswolfer.gerrit.client.rest</groupId><artifactId>gerrit-rest-java-client…...

深入理解全排列算法:DFS与回溯的完美结合

全排列问题是算法中的经典问题&#xff0c;其目标是将一组数字的所有可能排列组合列举出来。本文将详细解析如何通过深度优先搜索&#xff08;DFS&#xff09;和回溯法高效生成全排列&#xff0c;并通过模拟递归过程帮助读者彻底掌握其核心思想。 问题描述 给定一个正整数 n&a…...

服务器(一种管理计算资源的计算机)

服务器是在网络环境中提供计算能力并运行软件应用程序的特定IT设备&#xff0c;它在网络中为其他客户机&#xff08;如个人计算机、智能手机、ATM机等终端设备&#xff09;提供计算或者应用服务, 一般来说服务器都具备承担响应服务请求、承担服务、保障服务的能力。服务器相比普…...

时态--02--一般过去时

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一般过去时1.肯定句am/is — wasare — were 2.否定句3.⼀般疑问句4.特殊疑问句5.there be 过去式 practice过去分词 一般过去时 1.肯定句 am/is — was are — wer…...

WSA(Windows Subsystem for Android)安装LSPosed和应用教程

windows安卓子系统WSA的Lsposed和shamiko的安装教程 WSA(Windows Subsystem for Android)安装LSPosed和应用教程 一、环境准备 在开始之前,请确保: 已经安装好WSA(Windows Subsystem for Android)已经安装好ADB工具下载好LSPosed和Shamiko框架安装包 二、连接WSA 首先需要…...

Opencv计算机视觉编程攻略-第十三节 跟踪视频中的物品

这是opencv系列的最后一节&#xff0c;主要学习视频序列&#xff0c;上一节介绍了读取、处理和存储视频的工具&#xff0c;本文将介绍几种跟踪图像序列中运动物体的算法。可见运动或表观运动&#xff0c;是物体以不同的速度在不同的方向上移动&#xff0c;或者是因为相机在移动…...

10 个最新 CSS 功能已在所有主流浏览器中得到支持

前言 CSS 不断发展&#xff0c;新功能使我们的工作更快、更简洁、更强大。得益于最新的浏览器改进&#xff08;Baseline 2024&#xff09;&#xff0c;许多新功能现在可在所有主要引擎上使用。以下是您可以立即开始使用的10 CSS新功能。 1. Scrollbar-Gutter 和 Scrollbar-Co…...

[特殊字符] 企业级Docker私有仓库实战:3步搭建Harbor安全仓库,镜像管理从此高效无忧

本文提供 一站式Docker私有仓库部署指南&#xff0c;聚焦企业级镜像管理需求&#xff0c;深入解析Harbor私有仓库的搭建、运维与安全加固全流程。内容涵盖 轻量级Registry快速部署与 Harbor企业级方案对比&#xff0c;手把手演示SSL证书配置、多租户权限控制、镜像漏洞扫描等核…...

一个基于Django的进销存管理系统Demo实现

第一步&#xff1a;创建 Django 项目 bash 复制 django-admin startproject inventory_system cd inventory_system python manage.py startapp erp 第二步&#xff1a;定义数据模型&#xff08;models.py&#xff09; python 复制 from django.db import models from d…...

wsl2+ubuntu22.04安装blender教程(详细教程)

本章教程介绍,如何在Windows操作系统上通过wsl2+ubuntu安装blender并运行教程。Blender 是一款免费、开源的 ​​3D 创作套件​​,广泛应用于建模、动画、渲染、视频编辑、特效制作等领域。它由全球开发者社区共同维护,支持跨平台(Windows、macOS、Linux),功能强大且完全…...

netty中的ChannelPipeline详解

Netty中的ChannelPipeline是事件处理链的核心组件,负责将多个ChannelHandler组织成有序的责任链,实现网络事件(如数据读写、连接状态变化)的动态编排和传播。以下从核心机制、执行逻辑到应用场景进行详细解析: 1. 核心结构与组成 双向链表结构 组成单元:ChannelPipeline…...

使用多进程和 Socket 接收解析数据并推送到 Kafka 的高性能架构

使用多进程和 Socket 接收解析数据并推送到 Kafka 的高性能架构 在现代应用程序中&#xff0c;实时数据处理和高并发性能是至关重要的。本文将介绍如何使用 Python 的多进程和 Socket 技术来接收和解析数据&#xff0c;并将处理后的数据推送到 Kafka&#xff0c;从而实现高效的…...

WinForm真入门(14)——ListView控件详解

一、ListView 控件核心概念与功能 ‌ListView‌ 是 WinForm 中用于展示结构化数据的多功能列表控件&#xff0c;支持多列、多视图模式及复杂交互&#xff0c;常用于文件资源管理器、数据报表等场景‌。 核心特点‌&#xff1a; 支持 ‌5种视图模式‌&#xff1a;Details&…...

FastAPI用户认证系统开发指南:从零构建安全API

前言 在现代Web应用开发中&#xff0c;用户认证系统是必不可少的功能。本文将带你使用FastAPI框架构建一个完整的用户认证系统&#xff0c;包含注册、登录、信息更新和删除等功能。我们将采用JWT&#xff08;JSON Web Token&#xff09;进行身份验证&#xff0c;并使用SQLite作…...

【BUG】阿里云服务器数据库远程连接报错

当你遇到 ERROR 2003 (HY000): Cant connect to MySQL server on 47.100.xxx.xx (10061) 错误&#xff0c;这个错误代码 10061 通常意味着客户端无法连接到指定的 MySQL 服务器&#xff0c;原因可能有多种&#xff0c;下面为你分析可能的原因及对应的解决办法。 1. 网络连接问…...

【前端】【React】性能优化三件套useCallback,useMemo,React.memo

一、总览&#xff1a;性能优化三件套 useCallback(fn, deps)&#xff1a;缓存函数&#xff0c;避免每次渲染都新建函数。useMemo(fn, deps)&#xff1a;缓存值&#xff08;计算结果&#xff09;&#xff0c;避免重复执行计算。React.memo(Component)&#xff1a;缓存组件的渲染…...

Vue3性能优化终极指南:编译策略、运行时调优与全链路监控

一、Vue3性能优化体系框架 1.1 性能优化全景图谱 1.2 关键性能指标定义表 指标测量方式优化目标核心影响因子FCPLighthouse<1.5s资源加载速度LCPPerformance API<2.5s关键资源大小TTIWebPageTest<3.5s主线程阻塞时间Memory UsageChrome DevTools<50MB对象引用策略…...

FISCO BCOS技术架构解析:从多群组设计到性能优化实践

目录 FISCO BCOS整体架构设计 多群组架构与数据隔离机制 交易流程与执行机制 安全架构与隐私保护 性能优化与压测实践 应用案例与生态工具 FISCO BCOS作为中国领先的金融级开源联盟链平台,自2017年由金链盟开源工作组推出以来,已在政务、金融、医疗、版权等众多领域实现…...

Ceph异地数据同步之- S3对象异地同步复制

#作者&#xff1a;闫乾苓 文章目录 关键组件说明数据流说明部署步骤配置主区域配置次要区域S3对象文件同步测试 关键组件说明 在Ceph RGW的多站点复制架构中&#xff0c;Realm、Zonegroup 和 Zone 是关键的组织结构&#xff0c;用于管理多站点的配置和数据同步 Realm(领域)&a…...

iOS按键精灵辅助工具在游戏开发中的创新应用

一、iOS自动化测试辅助工具 在移动游戏开发领域&#xff0c;iOS按键精灵类辅助工具不同于传统的安卓自动化方案&#xff0c;iOS环境下的自动化测试面临更严峻的技术挑战&#xff0c;但通过创新方法仍可实现精准控制。 # 基于图像识别的智能定位算法示例 def find_button(butt…...

3D案例丨多个3D工业相机拼接检测 开启360°新视界

在高速生产线上&#xff0c;经常需要在极短的时间内对工件进行全方位的外观检测&#xff0c;如&#xff1a;线缆直径和直线度检测、锂电池外观缺陷检测、铁轨截面尺寸检测等。 这需要传感器完整还原被测物的截面面轮廓形状&#xff0c;并获取精准的截面轮廓数据。但单一相机的…...

打分函数分类

在分子对接中&#xff0c;打分函数用于评估配体与受体结合的亲和力。不同类型的打分函数有各自的优势和应用场景。常见的打分函数主要分为以下几类&#xff1a; 1. 基于物理&#xff08;力场&#xff09;的打分函数 (Force/physics-field-based scoring functions) 这种打分…...

实践 DevOps 项目:使用 Terraform、Helm、SonarQube 和 GitLab CI/CD 在 AWS EKS 上实践全栈部署

在当今快节奏的软件开发领域&#xff0c;自动化至关重要。在本文中&#xff0c;我将向您展示如何构建一个全面的 DevOps 流水线&#xff0c;该流水线能够&#xff1a; 使用 Terraform 预置完整的 AWS 基础设施。部署一个包含私有子网和公共子网、RDS PostgreSQL 以及完整配置的…...

EFT干扰和共模干扰

EFT干扰本质上属于共模干扰的一种具体表现形式&#xff0c;但严格来说不能简单等同于共模干扰。以下从原理、特征及区别角度展开分析&#xff1a; 1. EFT干扰的原理 定义&#xff1a;EFT&#xff08;Electrical Fast Transient&#xff0c;电快速瞬变脉冲群&#xff09;干扰是…...

android 下提示 SQLITECIPHER driver not loaded

问题描述: 在android下出现 SQLITECIPHER driver not loaded 错误 解决办法: 在QT的Android目录下面放入 libplugins_sqldrivers_sqlitecipher_arm64-v8a.so...

[D1,2]回溯刷题

文章目录 组合 组合 回溯的基础结构 #组合总和 注意startIndex的更新是用i来更新的&#xff0c;不然会产生重复的组合...

使用 VBA 宏创建一个选择全部word图片快捷指令,进行图片格式编辑

使用 VBA 宏批量选择图片 ✅ 第一步&#xff1a;创建 .dotm 加载项文件 1、使用环境 office word 365&#xff0c;文件格式为.docx 图片格式为.PNG 2、创建 .dotm 加载项文件 打开 Word&#xff0c;新建一个空白文档。 按下 Alt F11 打开 VBA 编辑器。 点击菜单栏&#xff…...

SQL 关键字

SQL 包含许多关键字&#xff0c;这些关键字用于执行各种数据库操作。以下是主要的 SQL 关键字分类&#xff1a; 数据查询语言 (DQL) SELECT - 从数据库中选择数据 FROM - 指定要查询的表 WHERE - 指定查询条件 GROUP BY - 对结果集进行分组 HAVING - 对分组结果进行过滤 …...