Process Hacker项目开发指南:构建规范与编码约定详解
项目概述
Process Hacker是一个功能强大的系统监控工具,它提供了对进程、线程、服务等系统资源的深入查看和管理能力。作为开源项目,它遵循严格的编码规范和构建流程,确保代码质量和跨版本兼容性。
构建环境要求
编译器选择
Process Hacker必须使用Microsoft C编译器进行构建。尝试使用其他编译器可能导致各种兼容性问题,需要花费大量时间进行修复。项目目前仅在Visual Studio 2015开发环境中进行过完整测试。
开发工具依赖
构建Process Hacker需要安装Windows SDK 10。特别需要注意的是,如果要创建兼容Windows XP的驱动程序组件KSystemInformer,必须使用WDK v7进行构建,而不是最新版本的WDK。
编码规范详解
命名约定
命名风格
- 函数、函数参数和全局变量:采用大驼峰式命名法(CamelCase)
- 局部变量:采用小驼峰式命名法(lowerCamelCase)
- 结构体、枚举和联合体:使用全大写加下划线命名法(CAPS_WITH_UNDERSCORES)
前缀规则
所有名称都应带有适当的前缀(少数例外情况除外):
- 公共名称使用"Ph"或"PH_"(结构体)前缀
- 私有名称使用"Php"或"PHP_"前缀
- 某些变体如"Pha"也被使用
- 私有前缀通过在公共前缀后追加"p"创建,例如"Ph"变为"Php","Pha"变为"Phap"
特殊规则
- 没有前缀的函数和全局变量必须声明为"static"
- "static"名称不能有公共前缀
- 带有私有前缀的名称不必声明为"static"
- 没有前缀的结构体必须在".c"文件中声明
数据类型规范
基础类型
除非用于Win32 API,否则应使用以下标准类型:
- 1字节布尔值:
BOOLEAN
- 4字节布尔值:
LOGICAL
- 1字节:
UCHAR
- 2字节:
SHORT
/USHORT
- 4字节:
LONG
/ULONG
- 8字节:
LONG64
/ULONG64
- 1字节字符:
CHAR
- 2字节字符:
WCHAR
- 1字节字符串:
PSTR
- 2字节字符串:
PWSTR
布尔值使用规范
测试布尔值时,应使用以下简洁形式:
if (booleanVariable) {
// 正确用法
}
而不是冗长的if (booleanVariable == TRUE)
形式。
代码注释与修饰
注解规范
- 所有函数都应使用SAL注解,如
_In_
、_Inout_
、_Out_
等 - 除非编译器能明显优化(如内联),否则不要使用
const
- 不要在定义中使用
volatile
,必要时可转换为volatile指针
函数返回值处理
Process Hacker采用三种主要的函数返回值指示方式:
- NTSTATUS返回值:使用
NT_SUCCESS
宏检查是否成功 - BOOLEAN返回值:
TRUE
表示成功 - 直接返回结果:特殊值(如
NULL
)表示失败
除非特别说明,失败的函数保证不会修改任何输出参数(_Out_
、_Out_opt_
等)。对于接收回调函数的函数,不保证失败函数未执行回调函数。
多线程编程规范
线程例程签名
所有线程启动例程必须遵循以下签名:
NTSTATUS ThreadRoutineName(
_In_ PVOID Parameter
);
线程创建
应使用PhCreateThread
函数创建线程,这确保了线程管理的统一性和安全性。
数据结构与集合
Process Hacker提供了多种高效的数据结构实现:
| 数据结构类型 | 实现方式 | 特点说明 | |---------------------|-------------------------|-------------------| | 动态数组 | PH_ARRAY
, PH_LIST
| 非侵入式实现 | | 双向链表 | LIST_ENTRY
| 侵入式实现 | | 单向链表 | SINGLE_LIST_ENTRY
| 侵入式实现 | | 指针数组 | PH_POINTER_LIST
| 非侵入式实现 | | AVL树 | RTL_AVL_TABLE
| 非侵入式实现 | | 哈希表 | PH_HASHTABLE
| 非侵入式实现 | | 循环缓冲区 | PH_CIRCULAR_BUFFER
| 非侵入式实现 |
同步机制
锁的选择
推荐使用队列锁(queued lock)进行同步,因为它体积小且性能优异。虽然队列锁是读写锁,但可以通过独占获取/释放函数作为互斥锁使用。
事件对象
可通过PH_EVENT
使用事件对象。这种实现方式在需要时才创建内核事件对象,状态检查非常高效。
其他同步机制
- 运行保护:通过
PH_RUNDOWN_PROTECT
实现 - 条件变量:使用队列锁实现,配合
PhPulse(All)Condition
和PhWaitForCondition
函数 - 自定义低开销锁:基于队列锁的唤醒事件机制
异常处理规范
Process Hacker主要采用返回值(NTSTATUS
、BOOLEAN
等)进行错误处理。异常仅用于无法轻易恢复的特殊情况,如:
- 锁获取函数无法阻塞
- 对象引用计数为负
例外情况
PhAllocate
在分配失败时抛出异常PhProbeAddress
在地址超出范围时抛出异常- 不应到达的代码路径抛出
STATUS_NOT_IMPLEMENTED
异常
内存管理规范
基本规则
使用PhAllocate
/PhFree
进行内存分配/释放。对于复杂对象,使用引用计数系统。
自动引用计数
提供类似Apple的NSAutoreleasePool
的自动解引用池机制:
- 使用
PhAutoDereferenceObject
将对象添加到线程池 - 对象将在未来某个不确定时间解引用
- 保证当前函数执行期间不会解引用
引用规则
在以下情况必须引用对象:
- 对象指针存储在全局可见位置
- 对象指针传递给其他线程
传递给函数的对象必须保证在整个调用期间保持有效引用。
字符串处理规范
字符串对象
使用PH_STRING
类型,采用引用计数管理:
PPH_STRING myString = PhCreateString(L"My string");
wprintf(L"My string is \"%s\", and uses %Iu bytes.\n",
myString->Buffer,
myString->Length
);
字符串特性
- 所有字符串对象都内嵌长度信息(以字节为单位)
- 为兼容性考虑,字符串额外以null结尾
- 字符串对象应视为不可变对象
字符串操作
- 连接字符串:
PPH_STRING newString = PhConcatStrings(4,
L"Part1", L"Part2", strVar, L"Part4");
- 双字符串连接:
PPH_STRING newString = PhConcatStrings2(L"First", L"Second");
- 格式化字符串:
PPH_STRING newString = PhFormatString(
L"%d: %s, %#x", 100, L"test", 0xff);
实用技巧
- 使用
!!
运算符将值转换为布尔类型 - 注意对象创建/销毁的命名一致性
- 区分长度(length)、计数(count)和索引(index)的使用场景
通过遵循这些严格的开发规范,Process Hacker项目保持了高度的代码一致性和可维护性,同时也为开发者提供了清晰的编码指导。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考