Windows系统kernel32.dll核心函数编程

kernel32.dll核心函数详细使用示例重点讲解

每个函数的参数构建方法(包括参数含义、取值规则、构建逻辑

一、进程管理类函数

1. CreateProcessW - 创建新进程(启动外部程序)
作用说明

创建一个新进程和主线程,可启动外部可执行文件(如记事本、浏览器),是Windows启动进程的核心函数。

参数构建(共10个参数,核心参数标注★)
参数名 类型 含义与构建规则
lpApplicationName★ LPCWSTR 要启动的程序路径(如L"notepad.exe"),NULL则从lpCommandLine提取
lpCommandLine LPWSTR 命令行参数(如L"notepad.exe test.txt"),优先级高于lpApplicationName
lpProcessAttributes LPSECURITY_ATTRIBUTES 进程安全属性,NULL表示默认(不可继承)
lpThreadAttributes LPSECURITY_ATTRIBUTES 线程安全属性,NULL表示默认(不可继承)
bInheritHandles BOOL 是否继承父进程句柄,FALSE=不继承(推荐)
dwCreationFlags DWORD 创建标志:0=默认,CREATE_NEW_CONSOLE=新建控制台,CREATE_NO_WINDOW=无窗口
lpEnvironment LPVOID 环境变量,NULL=继承父进程环境变量
lpCurrentDirectory LPCWSTR 进程当前工作目录,NULL=父进程工作目录
lpStartupInfo★ LPSTARTUPINFOW 进程启动信息(窗口位置、显示方式等),需初始化结构体大小
lpProcessInformation★ LPPROCESS_INFORMATION 输出参数,返回进程/线程句柄、PID/TID,需初始化
完整示例(启动记事本并打开test.txt)
cpp 复制代码
#include <windows.h>
#include <iostream>
#pragma comment(lib, "kernel32.lib")

int main() {
    // 1. 构建STARTUPINFOW结构体(必须初始化cb大小)
    STARTUPINFOW si = {0};
    si.cb = sizeof(STARTUPINFOW); // 核心:设置结构体大小
    si.dwFlags = STARTF_USESHOWWINDOW; // 使用wShowWindow参数
    si.wShowWindow = SW_SHOW; // 窗口显示方式:正常显示

    // 2. 构建PROCESS_INFORMATION结构体(输出进程/线程信息)
    PROCESS_INFORMATION pi = {0};

    // 3. 调用CreateProcessW启动进程
    BOOL bRet = CreateProcessW(
        L"notepad.exe",                // 要启动的程序
        L"notepad.exe test.txt",       // 命令行参数(打开test.txt)
        NULL,                          // 进程安全属性(默认)
        NULL,                          // 线程安全属性(默认)
        FALSE,                         // 不继承句柄
        0,                             // 默认创建标志
        NULL,                          // 继承父进程环境变量
        NULL,                          // 继承父进程工作目录
        &si,                           // 启动信息
        &pi                            // 输出进程信息
    );

    // 4. 错误处理与结果输出
    if (bRet) {
        std::cout << "进程创建成功!" << std::endl;
        std::cout << "进程PID:" << pi.dwProcessId << std::endl;
        std::cout << "线程TID:" << pi.dwThreadId << std::endl;

        // 5. 等待进程退出(可选)
        WaitForSingleObject(pi.hProcess, 5000); // 等待5秒

        // 6. 释放句柄(必须!否则资源泄漏)
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    } else {
        std::cout << "进程创建失败,错误码:" << GetLastError() << std::endl;
    }

    return 0;
}
注意事项
  • lpApplicationName为NULL,lpCommandLine必须以可执行文件路径开头(如L"notepad.exe");
  • STARTUPINFOWcb成员必须初始化,否则函数调用失败;
  • 进程/线程句柄使用后必须用CloseHandle释放。
2. OpenProcess - 打开已有进程(获取操作权限)
作用说明

根据进程ID(PID)打开指定进程,获取进程句柄,用于后续的内存读写、进程控制等操作。

参数构建(共3个参数)
参数名 类型 含义与构建规则
dwDesiredAccess★ DWORD 期望的访问权限:PROCESS_ALL_ACCESS=所有权限(需管理员),PROCESS_VM_READ=只读内存,PROCESS_VM_WRITE=写内存
bInheritHandle BOOL 句柄是否可继承,FALSE=不可继承(推荐)
dwProcessId★ DWORD 目标进程的PID(可通过任务管理器、CreateProcessW、EnumProcesses获取)
完整示例(打开记事本进程并获取句柄)
cpp 复制代码
#include <windows.h>
#include <iostream>
#pragma comment(lib, "kernel32.lib")

int main() {
    // 1. 假设记事本PID为1234(需替换为实际PID)
    DWORD dwPid = 1234;

    // 2. 构建参数并调用OpenProcess
    HANDLE hProcess = OpenProcess(
        PROCESS_ALL_ACCESS,  // 申请所有权限(需管理员运行程序)
        FALSE,               // 句柄不可继承
        dwPid                // 目标进程PID
    );

    // 3. 错误处理
    if (hProcess != NULL) {
        std::cout << "进程打开成功,句柄:" << hProcess << std::endl;
        
        // 4. 后续操作(如读写内存)...
        
        // 5. 释放句柄
        CloseHandle(hProcess);
    } else {
        std::cout << "进程打开失败,错误码:" << GetLastError() << std::endl;
        std::cout << "可能原因:1.PID错误 2.无管理员权限 3.进程已退出" << std::endl;
    }

    return 0;
}
注意事项
  • PROCESS_ALL_ACCESS需要程序以管理员身份运行,否则会返回权限不足(错误码5);
  • 若仅需读取内存,建议使用PROCESS_VM_READ(低权限,无需管理员);
  • 打开的进程句柄必须用CloseHandle释放。
3. CreateThread - 创建新线程
作用说明

在当前进程中创建一个新线程,用于执行异步任务(如后台处理、循环检测)。

参数构建(共6个参数)
参数名 类型 含义与构建规则
lpThreadAttributes LPSECURITY_ATTRIBUTES 线程安全属性,NULL=默认(不可继承)
dwStackSize SIZE_T 线程栈大小,0=使用默认大小(1MB)
lpStartAddress★ LPTHREAD_START_ROUTINE 线程入口函数(回调函数),必须是DWORD WINAPI Func(LPVOID)格式
lpParameter★ LPVOID 传递给线程函数的参数(任意类型,需强制转换)
dwCreationFlags DWORD 创建标志:0=立即运行,CREATE_SUSPENDED=创建后挂起(需ResumeThread启动)
lpThreadId LPDWORD 输出参数,返回新线程的TID,NULL=不获取TID
完整示例(创建线程执行后台任务)
cpp 复制代码
#include <windows.h>
#include <iostream>
#pragma comment(lib, "kernel32.lib")

// 1. 定义线程入口函数(必须符合格式)
DWORD WINAPI ThreadProc(LPVOID lpParam) {
    // 获取传递的参数
    std::string strMsg = (const char*)lpParam;
    for (int i = 0; i < 5; i++) {
        std::cout << "线程执行中:" << strMsg << ",次数:" << i+1 << std::endl;
        Sleep(1000); // 暂停1秒
    }
    return 0; // 线程退出码
}

int main() {
    // 2. 构建线程参数
    const char* szParam = "Hello Thread";

    // 3. 创建线程
    HANDLE hThread = CreateThread(
        NULL,               // 安全属性默认
        0,                  // 默认栈大小
        ThreadProc,         // 线程入口函数
        (LPVOID)szParam,    // 传递给线程的参数
        0,                  // 立即运行
        NULL                // 不获取TID
    );

    // 4. 错误处理
    if (hThread != NULL) {
        std::cout << "线程创建成功!" << std::endl;
        
        // 5. 等待线程执行完成(可选)
        WaitForSingleObject(hThread, INFINITE); // 无限等待
        
        // 6. 释放线程句柄
        CloseHandle(hThread);
    } else {
        std::cout << "线程创建失败,错误码:" << GetLastError() << std::endl;
    }

    std::cout << "主线程执行完成!" << std::endl;
    return 0;
}
注意事项
  • 线程入口函数的参数lpParam可传递任意类型数据(如结构体、字符串),需做好类型转换;
  • 线程执行完成后必须释放句柄,否则会造成句柄泄漏;
  • 若线程中操作主线程的变量,需加锁(如临界区)避免竞态条件。
4. WaitForSingleObject - 等待内核对象触发
作用说明

等待指定的内核对象(进程、线程、事件、互斥量等)进入"已触发"状态(如进程退出、线程完成),是同步的核心函数。

参数构建(共3个参数)
参数名 类型 含义与构建规则
hHandle★ HANDLE 要等待的内核对象句柄(进程、线程、事件等)
dwMilliseconds★ DWORD 等待超时时间:INFINITE=无限等待,0=立即返回,数值=毫秒数(如5000=5秒)
完整示例(等待进程退出)
cpp 复制代码
#include <windows.h>
#include <iostream>
#pragma comment(lib, "kernel32.lib")

int main() {
    STARTUPINFOW si = {0};
    si.cb = sizeof(STARTUPINFOW);
    PROCESS_INFORMATION pi = {0};

    // 启动记事本进程
    CreateProcessW(L"notepad.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
    if (pi.hProcess == NULL) {
        std::cout << "进程启动失败!" << std::endl;
        return 1;
    }

    std::cout << "等待记事本进程退出(最多10秒)..." << std::endl;
    
    // 等待进程退出(超时10秒)
    DWORD dwRet = WaitForSingleObject(
        pi.hProcess,    // 进程句柄
        10000           // 超时10秒
    );

    // 解析等待结果
    switch (dwRet) {
        case WAIT_OBJECT_0:
            std::cout << "记事本进程已退出!" << std::endl;
            break;
        case WAIT_TIMEOUT:
            std::cout << "等待超时,强制终止进程!" << std::endl;
            TerminateProcess(pi.hProcess, 0); // 强制终止进程
            break;
        case WAIT_FAILED:
            std::cout << "等待失败,错误码:" << GetLastError() << std::endl;
            break;
    }

    // 释放句柄
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    return 0;
}
注意事项
  • 等待的对象必须是内核对象(进程、线程、事件、互斥量等),普通GDI对象(画笔、画刷)无效;
  • WAIT_OBJECT_0表示对象正常触发,WAIT_TIMEOUT表示超时,WAIT_FAILED表示等待失败;
  • 无限等待(INFINITE)需谨慎使用,避免程序卡死。

二、内存操作类函数

1. VirtualAlloc - 分配虚拟内存
作用说明

在当前进程的地址空间中分配虚拟内存,可用于大块内存分配(如缓存、数据存储),是Windows底层内存分配函数。

参数构建(共5个参数)
参数名 类型 含义与构建规则
lpAddress LPVOID 要分配的内存起始地址,NULL=系统自动分配(推荐)
dwSize★ SIZE_T 分配的内存大小(字节),需是页面大小的整数倍(通常4096字节)
flAllocationType★ DWORD 分配类型:MEM_COMMIT=提交内存(可用),MEM_RESERVE=保留地址空间(不可用),MEM_COMMIT
flProtect★ DWORD 内存保护属性:PAGE_READWRITE=可读可写,PAGE_READONLY=只读,PAGE_EXECUTE_READWRITE=可执行可读可写
完整示例(分配可读写虚拟内存)
cpp 复制代码
#include <windows.h>
#include <iostream>
#include <string.h>
#pragma comment(lib, "kernel32.lib")

int main() {
    // 1. 构建参数并分配虚拟内存(4KB)
    LPVOID pMem = VirtualAlloc(
        NULL,                           // 系统自动分配地址
        4096,                           // 分配4KB(页面大小)
        MEM_COMMIT | MEM_RESERVE,       // 提交+保留
        PAGE_READWRITE                  // 可读可写
    );

    // 2. 错误处理
    if (pMem != NULL) {
        std::cout << "内存分配成功,地址:" << pMem << std::endl;
        
        // 3. 使用内存(写入数据)
        const char* szData = "Hello VirtualAlloc";
        memcpy(pMem, szData, strlen(szData) + 1); // 写入字符串(含结束符)
        
        // 4. 读取内存并输出
        std::cout << "内存内容:" << (char*)pMem << std::endl;
        
        // 5. 释放内存(必须!)
        BOOL bFree = VirtualFree(
            pMem,    // 要释放的内存地址
            0,       // 0表示释放整个区域
            MEM_RELEASE // 释放保留的地址空间
        );
        if (bFree) {
            std::cout << "内存释放成功!" << std::endl;
        } else {
            std::cout << "内存释放失败,错误码:" << GetLastError() << std::endl;
        }
    } else {
        std::cout << "内存分配失败,错误码:" << GetLastError() << std::endl;
    }

    return 0;
}
注意事项
  • 分配的内存大小建议为页面大小(4096字节)的整数倍,否则系统会自动向上取整;
  • PAGE_EXECUTE_READWRITE权限需要管理员权限,用于分配可执行的内存(如动态代码);
  • 释放时dwSize必须为0,且dwFreeTypeMEM_RELEASE,否则释放失败。
2. ReadProcessMemory - 读取其他进程的内存
作用说明

从指定进程的内存地址中读取数据到当前进程的内存空间,需先通过OpenProcess获取目标进程的句柄和读写权限。

参数构建(共5个参数)
参数名 类型 含义与构建规则
hProcess★ HANDLE 目标进程的句柄(需有PROCESS_VM_READ权限)
lpBaseAddress★ LPCVOID 目标进程中要读取的内存起始地址(需知道具体地址,可通过逆向、调试获取)
lpBuffer★ LPVOID 当前进程中接收数据的缓冲区地址
dwSize★ SIZE_T 要读取的字节数
lpNumberOfBytesRead SIZE_T* 输出参数,返回实际读取的字节数,NULL=不获取
完整示例(读取记事本进程的内存)
cpp 复制代码
#include <windows.h>
#include <iostream>
#pragma comment(lib, "kernel32.lib")

int main() {
    // 1. 打开目标进程(假设记事本PID为1234,需替换)
    DWORD dwPid = 1234;
    HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, dwPid);
    if (hProcess == NULL) {
        std::cout << "打开进程失败,错误码:" << GetLastError() << std::endl;
        return 1;
    }

    // 2. 构建参数(假设目标内存地址为0x00400000,需替换为实际地址)
    LPCVOID pRemoteAddr = (LPCVOID)0x00400000; // 目标进程内存地址
    char szBuf[1024] = {0};                   // 接收缓冲区
    SIZE_T dwRead = 0;                        // 实际读取字节数

    // 3. 读取目标进程内存
    BOOL bRet = ReadProcessMemory(
        hProcess,        // 目标进程句柄
        pRemoteAddr,     // 目标内存地址
        szBuf,           // 接收缓冲区
        sizeof(szBuf),   // 要读取的字节数
        &dwRead          // 实际读取字节数
    );

    // 4. 结果处理
    if (bRet) {
        std::cout << "内存读取成功,实际读取:" << dwRead << "字节" << std::endl;
        std::cout << "内存内容:" << szBuf << std::endl;
    } else {
        std::cout << "内存读取失败,错误码:" << GetLastError() << std::endl;
        std::cout << "可能原因:1.内存地址无效 2.无读取权限 3.进程已退出" << std::endl;
    }

    // 5. 释放句柄
    CloseHandle(hProcess);
    return 0;
}
注意事项
  • 目标内存地址必须是有效地址(可通过调试器、逆向工具获取),否则读取失败;
  • 若目标进程是64位,当前进程也需编译为64位,否则地址空间不匹配;
  • 仅能读取已提交的内存(MEM_COMMIT),保留内存(MEM_RESERVE)无法读取。
3. WriteProcessMemory - 写入其他进程的内存
作用说明

将当前进程的数据写入指定进程的内存地址,需目标进程有PROCESS_VM_WRITEPROCESS_VM_OPERATION权限。

参数构建(共5个参数)
参数名 类型 含义与构建规则
hProcess★ HANDLE 目标进程句柄(需有PROCESS_VM_WRITE
lpBaseAddress★ LPVOID 目标进程中要写入的内存起始地址
lpBuffer★ LPCVOID 当前进程中要写入的数据缓冲区地址
dwSize★ SIZE_T 要写入的字节数
lpNumberOfBytesWritten SIZE_T* 输出参数,返回实际写入的字节数,NULL=不获取
完整示例(写入数据到记事本进程内存)
cpp 复制代码
#include <windows.h>
#include <iostream>
#include <string.h>
#pragma comment(lib, "kernel32.lib")

int main() {
    // 1. 打开目标进程(需管理员权限)
    DWORD dwPid = 1234;
    HANDLE hProcess = OpenProcess(
        PROCESS_VM_WRITE | PROCESS_VM_OPERATION, // 写内存+操作权限
        FALSE,
        dwPid
    );
    if (hProcess == NULL) {
        std::cout << "打开进程失败,错误码:" << GetLastError() << std::endl;
        return 1;
    }

    // 2. 构建参数
    LPVOID pRemoteAddr = (LPVOID)0x00400000; // 目标内存地址
    const char* szData = "Hello WriteProcessMemory"; // 要写入的数据
    SIZE_T dwWrite = 0; // 实际写入字节数

    // 3. 写入目标进程内存
    BOOL bRet = WriteProcessMemory(
        hProcess,        // 目标进程句柄
        pRemoteAddr,     // 目标内存地址
        szData,          // 要写入的数据
        strlen(szData) + 1, // 写入字节数(含结束符)
        &dwWrite         // 实际写入字节数
    );

    // 4. 结果处理
    if (bRet) {
        std::cout << "内存写入成功,实际写入:" << dwWrite << "字节" << std::endl;
    } else {
        std::cout << "内存写入失败,错误码:" << GetLastError() << std::endl;
    }

    // 5. 释放句柄
    CloseHandle(hProcess);
    return 0;
}
注意事项
  • 必须以管理员身份运行程序,否则权限不足;
  • 目标内存地址需有可写权限(PAGE_READWRITE),否则写入失败;
  • 写入的数据长度不能超过目标内存区域的大小,否则会导致目标进程崩溃。

三、文件IO类函数

1. CreateFileW - 创建/打开文件/设备
作用说明

Windows中所有"可读写的对象"(文件、管道、串口、磁盘)都可通过该函数打开/创建,是文件IO的核心入口。

参数构建(共7个核心参数)
参数名 类型 含义与构建规则
lpFileName★ LPCWSTR 要打开/创建的文件路径(如L"test.txt"
dwDesiredAccess★ DWORD 访问权限:GENERIC_READ=只读,GENERIC_WRITE=只写,GENERIC_READ
dwShareMode★ DWORD 共享模式:0=独占(其他程序无法打开),FILE_SHARE_READ=允许其他程序读,FILE_SHARE_WRITE=允许其他程序写
lpSecurityAttributes LPSECURITY_ATTRIBUTES 安全属性,NULL=默认
dwCreationDisposition★ DWORD 创建方式:CREATE_NEW=新建(文件存在则失败),CREATE_ALWAYS=新建(覆盖已有),OPEN_EXISTING=打开(不存在则失败),OPEN_ALWAYS=打开(不存在则新建)
dwFlagsAndAttributes★ DWORD 文件属性:FILE_ATTRIBUTE_NORMAL=普通文件,FILE_ATTRIBUTE_HIDDEN=隐藏文件,FILE_FLAG_OVERLAPPED=异步IO
hTemplateFile HANDLE 模板文件句柄,NULL=无
完整示例(创建并打开test.txt文件)
cpp 复制代码
#include <windows.h>
#include <iostream>
#pragma comment(lib, "kernel32.lib")

int main() {
    // 1. 构建参数并打开/创建文件
    HANDLE hFile = CreateFileW(
        L"test.txt",                          // 文件路径
        GENERIC_READ | GENERIC_WRITE,         // 读写权限
        0,                                    // 独占模式
        NULL,                                 // 安全属性默认
        CREATE_ALWAYS,                        // 新建(覆盖已有)
        FILE_ATTRIBUTE_NORMAL,                // 普通文件
        NULL                                  // 无模板文件
    );

    // 2. 错误处理
    if (hFile != INVALID_HANDLE_VALUE) {
        std::cout << "文件打开/创建成功!" << std::endl;
        
        // 3. 写入数据
        const char* szData = "Hello CreateFileW";
        DWORD dwWrite = 0;
        WriteFile(hFile, szData, strlen(szData) + 1, &dwWrite, NULL);
        std::cout << "写入字节数:" << dwWrite << std::endl;
        
        // 4. 关闭文件句柄(必须!)
        CloseHandle(hFile);
    } else {
        std::cout << "文件打开失败,错误码:" << GetLastError() << std::endl;
    }

    return 0;
}
注意事项
  • 函数返回INVALID_HANDLE_VALUE表示失败,而非NULL;
  • CREATE_ALWAYS会覆盖已有文件,慎用,建议优先使用OPEN_ALWAYS
  • 打开文件后必须用CloseHandle关闭句柄,否则文件会被锁定。
2. FindFirstFileW & FindNextFileW - 遍历文件/目录
作用说明

FindFirstFileW查找指定路径下的第一个文件/目录,FindNextFileW遍历剩余文件/目录,是批量处理文件的核心函数。

参数构建
函数名 参数名 类型 含义与构建规则
FindFirstFileW lpFileName★ LPCWSTR 查找路径(支持通配符,如L"*.txt"
lpFindFileData★ LPWIN32_FIND_DATAW 输出参数,返回文件/目录信息,需初始化
FindNextFileW hFindFile★ HANDLE FindFirstFileW返回的查找句柄
lpFindFileData★ LPWIN32_FIND_DATAW 输出参数,返回下一个文件/目录信息
完整示例(遍历当前目录下的所有txt文件)
cpp 复制代码
#include <windows.h>
#include <iostream>
#pragma comment(lib, "kernel32.lib")

int main() {
    // 1. 构建查找参数
    WIN32_FIND_DATAW fd = {0}; // 存储文件信息
    HANDLE hFind = FindFirstFileW(
        L"*.txt",    // 查找所有txt文件
        &fd          // 输出第一个文件信息
    );

    // 2. 错误处理
    if (hFind == INVALID_HANDLE_VALUE) {
        std::cout << "未找到txt文件,错误码:" << GetLastError() << std::endl;
        return 1;
    }

    // 3. 遍历所有txt文件
    std::cout << "找到的txt文件:" << std::endl;
    do {
        // 排除.和..目录
        if (wcscmp(fd.cFileName, L".") != 0 && wcscmp(fd.cFileName, L"..") != 0) {
            // 判断是否为文件(非目录)
            if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
                std::wcout << L"  " << fd.cFileName << std::endl;
            }
        }
    } while (FindNextFileW(hFind, &fd)); // 遍历下一个文件

    // 4. 检查遍历结束原因(正常结束=ERROR_NO_MORE_FILES)
    if (GetLastError() != ERROR_NO_MORE_FILES) {
        std::cout << "遍历文件失败,错误码:" << GetLastError() << std::endl;
    }

    // 5. 关闭查找句柄(必须!)
    FindClose(hFind);
    return 0;
}
注意事项
  • 查找路径支持通配符(*匹配所有,?匹配单个字符);
  • 遍历结果会包含...目录,需手动排除;
  • FindClose必须调用,否则会造成句柄泄漏。

四、异步IO类函数

1. CreateIoCompletionPort - 创建IO完成端口
作用说明

IO完成端口(IOCP)是Windows高性能异步IO的核心,用于管理多个文件/套接字的异步IO事件,适用于高并发场景(如服务器)。

参数构建(共4个参数)
参数名 类型 含义与构建规则
FileHandle HANDLE 要关联的文件/套接字句柄,INVALID_HANDLE_VALUE=创建空的IOCP(不关联任何句柄)
ExistingCompletionPort HANDLE 已存在的IOCP句柄,NULL=创建新的IOCP
CompletionKey★ ULONG_PTR 完成键(自定义数据,如客户端ID),用于标识IO事件归属
NumberOfConcurrentThreads★ DWORD 并发线程数,0=系统自动分配(推荐,等于CPU核心数)
完整示例(创建IOCP并关联文件句柄)
cpp 复制代码
#include <windows.h>
#include <iostream>
#pragma comment(lib, "kernel32.lib")

int main() {
    // 1. 创建空的IOCP(不关联任何句柄)
    HANDLE hIOCP = CreateIoCompletionPort(
        INVALID_HANDLE_VALUE,  // 不关联句柄
        NULL,                  // 创建新的IOCP
        0,                     // 完成键默认0
        0                      // 系统自动分配并发线程数
    );

    if (hIOCP == NULL) {
        std::cout << "IOCP创建失败,错误码:" << GetLastError() << std::endl;
        return 1;
    }
    std::cout << "IOCP创建成功,句柄:" << hIOCP << std::endl;

    // 2. 打开文件并关联到IOCP
    HANDLE hFile = CreateFileW(
        L"test.txt",
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // 启用异步IO
        NULL
    );

    if (hFile != INVALID_HANDLE_VALUE) {
        // 关联文件句柄到IOCP
        HANDLE hAssoc = CreateIoCompletionPort(
            hFile,         // 要关联的文件句柄
            hIOCP,         // 已创建的IOCP句柄
            (ULONG_PTR)1,  // 完成键=1(标识该文件)
            0              // 并发线程数不变
        );
        if (hAssoc == hIOCP) {
            std::cout << "文件句柄关联IOCP成功!" << std::endl;
        }

        CloseHandle(hFile);
    }

    // 3. 关闭IOCP句柄
    CloseHandle(hIOCP);
    return 0;
}
注意事项
  • 关联的句柄必须启用异步IO(FILE_FLAG_OVERLAPPED),否则IOCP无法捕获事件;
  • 完成键(CompletionKey)可自定义(如客户端ID、文件ID),用于区分不同的IO事件;
  • IOCP句柄需最后释放,且释放前需确保所有异步IO操作已完成。

总结

  1. 核心参数规则
    • kernel32.dll函数的核心参数(标★)是调用成功的关键,尤其是结构体的cb成员(如STARTUPINFOW.cb)必须初始化;
    • 权限类参数(如dwDesiredAccess)需根据实际需求选择最小权限(如只读内存用PROCESS_VM_READ),避免权限过高导致调用失败。
  2. 资源释放规则
    • 所有句柄(进程、线程、文件、IOCP、查找句柄)必须手动释放(CloseHandle/FindClose),否则造成资源泄漏;
    • 虚拟内存分配后需用VirtualFree释放,且dwSize必须为0,dwFreeTypeMEM_RELEASE
  3. 错误处理规则
    • 调用函数后必须检查返回值,通过GetLastError()获取错误码定位问题;
    • 跨进程操作(如OpenProcessReadProcessMemory)需管理员权限,否则返回错误码5(权限不足)。

你想详细了解ReadProcessMemory函数的所属动态链接库、参数构建、完整使用示例以及关键注意事项------这个函数是Windows跨进程内存读取的核心API,隶属于kernel32.dll,也是逆向分析、进程监控、调试工具开发的核心接口。下面我会从基础信息、参数拆解、实战示例、注意事项四个维度完整讲解,确保你能理解并正确使用。

ReadProcessMemory 核心函数

项目 详情
所属DLL kernel32.dll(Windows内核基础库)
导入库(编译链接) kernel32.lib(Visual Studio默认自动链接,无需手动添加)
头文件 <windows.h>
函数原型 BOOL ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T dwSize, SIZE_T* lpNumberOfBytesRead);
核心作用 从指定的远程进程内存地址中,读取数据到当前进程的内存缓冲区中
返回值 TRUE=读取成功,FALSE=读取失败(可通过GetLastError()获取具体错误码)

二、参数构建(逐参数拆解,核心参数标★)

ReadProcessMemory的参数直接决定读取是否成功,以下是每个参数的含义、构建规则和取值要求:

参数名 类型 含义与构建规则
hProcess★ HANDLE 远程进程的句柄(必须通过OpenProcess获取,且需包含PROCESS_VM_READ权限)
lpBaseAddress★ LPCVOID 远程进程中要读取的内存起始地址(需是有效、已提交的内存地址,可通过调试/逆向获取)
lpBuffer★ LPVOID 当前进程中接收数据的缓冲区地址 (需提前分配,大小不小于dwSize
dwSize★ SIZE_T 要从远程进程读取的字节数(需≤缓冲区大小,且≤远程内存区域的有效大小)
lpNumberOfBytesRead SIZE_T* 输出参数:返回实际读取的字节数(可传NULL,但建议传入以校验读取结果)

三、完整使用示例(读取记事本进程的内存)

这个示例实现"定位记事本进程→打开进程句柄→读取指定内存地址数据",步骤完整且包含错误处理,可直接编译运行:

cpp 复制代码
#include <windows.h>
#include <iostream>
#include <cstring>
#pragma comment(lib, "kernel32.lib")

// 读取远程进程内存的封装函数
BOOL ReadRemoteMemory(DWORD dwPid, LPCVOID pRemoteAddr, LPVOID pLocalBuf, SIZE_T dwReadSize, SIZE_T& dwActualRead) {
    // 1. 打开远程进程(申请只读内存权限)
    HANDLE hProcess = OpenProcess(
        PROCESS_VM_READ,  // 仅申请读内存权限(最小权限原则)
        FALSE,            // 句柄不可继承
        dwPid             // 目标进程PID
    );
    if (hProcess == NULL) {
        std::cout << "打开进程失败,错误码:" << GetLastError() << std::endl;
        return FALSE;
    }

    // 2. 初始化实际读取字节数
    dwActualRead = 0;

    // 3. 调用ReadProcessMemory读取远程内存(核心步骤)
    BOOL bRet = ReadProcessMemory(
        hProcess,            // 远程进程句柄
        pRemoteAddr,         // 远程内存起始地址
        pLocalBuf,           // 本地接收缓冲区
        dwReadSize,          // 要读取的字节数
        &dwActualRead        // 输出实际读取的字节数
    );

    // 4. 结果校验与错误处理
    if (!bRet) {
        std::cout << "读取内存失败,错误码:" << GetLastError() << std::endl;
        CloseHandle(hProcess);
        return FALSE;
    }

    if (dwActualRead != dwReadSize) {
        std::cout << "警告:读取字节数不匹配!请求读取" << dwReadSize << "字节,实际读取" << dwActualRead << "字节" << std::endl;
    }

    // 5. 释放进程句柄(必须!)
    CloseHandle(hProcess);
    return TRUE;
}

int main() {
    // ========== 需替换为实际值 ==========
    DWORD dwNotepadPid = 1234;          // 记事本进程的PID(任务管理器查看)
    LPCVOID pRemoteAddr = (LPCVOID)0x00401000; // 远程进程中要读取的内存地址(需有效)
    SIZE_T dwReadSize = 1024;           // 要读取的字节数(1KB)
    // ===================================

    // 1. 分配本地缓冲区(接收读取的数据)
    char szLocalBuf[1024] = {0};
    SIZE_T dwActualRead = 0;

    // 2. 调用封装函数读取远程内存
    if (ReadRemoteMemory(dwNotepadPid, pRemoteAddr, szLocalBuf, dwReadSize, dwActualRead)) {
        std::cout << "内存读取成功!" << std::endl;
        std::cout << "实际读取字节数:" << dwActualRead << std::endl;
        std::cout << "读取的内存内容(前100字节):" << std::endl;
        
        // 3. 输出读取的内容(十六进制+字符形式,便于分析)
        for (SIZE_T i = 0; i < min(dwActualRead, 100); i++) {
            printf("%02X ", (BYTE)szLocalBuf[i]);
            if ((i + 1) % 16 == 0) std::cout << std::endl; // 每16字节换行
        }
        std::cout << std::endl;
        
        // 4. 尝试以字符串形式输出(若内存是文本)
        std::cout << "字符串形式(仅有效ASCII):" << szLocalBuf << std::endl;
    }

    return 0;
}

四、关键注意事项(避坑核心)

  1. 权限要求

    • 调用OpenProcess时必须申请PROCESS_VM_READ权限(只读),若需同时写内存则加PROCESS_VM_WRITE
    • 程序需以管理员身份运行,否则可能因权限不足读取失败(错误码5:ACCESS_DENIED)。
  2. 内存地址有效性

    • lpBaseAddress必须是远程进程中已提交的内存地址(MEM_COMMIT),保留内存(MEM_RESERVE)或无效地址会导致读取失败(错误码299:仅部分读取,或998:INVALID_ACCESS);
    • 可通过VirtualQueryEx先查询远程内存的状态,确认地址有效后再读取。
  3. 32/64位匹配

    • 32位程序只能读取32位进程的内存,64位程序只能读取64位进程的内存;
    • 若32位程序读取64位进程,会因地址空间(32位最大4GB)限制导致地址无效。
  4. 常见错误码及解决方法

    错误码 含义 解决方法
    5 权限不足 以管理员身份运行程序,或确认OpenProcess的权限参数正确
    299 仅部分读取成功 检查远程内存地址是否跨页,或目标地址后续内存未提交
    998 无效的内存访问 确认lpBaseAddress是远程进程的有效地址
    6 句柄无效 检查hProcess是否为OpenProcess返回的有效句柄(非NULL)
  5. 资源释放

    • OpenProcess获取的进程句柄必须用CloseHandle释放,否则会造成句柄泄漏;
    • 本地缓冲区若为动态分配(如malloc/VirtualAlloc),读取完成后需释放。

五、进阶扩展(可选)

若需读取"不确定是否有效"的内存地址,可先调用VirtualQueryEx查询远程内存状态:

cpp 复制代码
// 检查远程内存地址是否有效
MEMORY_BASIC_INFORMATION mbi = {0};
VirtualQueryEx(hProcess, pRemoteAddr, &mbi, sizeof(mbi));
if (mbi.State != MEM_COMMIT || (mbi.Protect & PAGE_NOACCESS)) {
    std::cout << "远程内存地址无效(未提交/不可访问)" << std::endl;
    CloseHandle(hProcess);
    return FALSE;
}

CreateRemoteThread 核心函数

项⽬ 详情
所属DLL kernel32.dll
导入库(编译链接) kernel32.lib(Visual Studio默认链接,无需手动添加)
头文件 <windows.h>
函数原型(Unicode) HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
核心作用 指定的远程进程中创建一个新线程(区别于CreateThread:仅创建当前进程线程)

二、参数构建(逐参数拆解,核心参数标★)

参数名 类型 含义与构建规则
hProcess★ HANDLE 远程进程的句柄(需通过OpenProcess获取,且必须包含PROCESS_CREATE_THREAD权限)
lpThreadAttributes LPSECURITY_ATTRIBUTES 线程安全属性,NULL=默认(不可继承)
dwStackSize SIZE_T 线程栈大小,0=使用系统默认大小(1MB)
lpStartAddress★ LPTHREAD_START_ROUTINE 远程进程中线程入口函数的地址(最常用:LoadLibraryW的地址,用于DLL注入)
lpParameter★ LPVOID 传递给远程线程入口函数的参数(如DLL路径的内存地址,需先写入远程进程)
dwCreationFlags DWORD 创建标志:0=立即运行,CREATE_SUSPENDED=创建后挂起(需ResumeThread启动)
lpThreadId LPDWORD 输出参数,返回远程线程的TID,NULL=不获取

三、典型使用示例(DLL注入,CreateRemoteThread最常用场景)

这个示例实现"将自定义DLL注入到记事本进程",完整展示参数构建和函数调用流程:

cpp 复制代码
#include <windows.h>
#include <iostream>
#include <string>
#pragma comment(lib, "kernel32.lib")

// 注入DLL到远程进程的函数
BOOL InjectDll(DWORD dwPid, const std::wstring& strDllPath) {
    // 1. 打开远程进程(需足够权限)
    HANDLE hProcess = OpenProcess(
        PROCESS_CREATE_THREAD |    // 创建线程权限
        PROCESS_VM_WRITE |         // 写内存权限
        PROCESS_VM_OPERATION,      // 内存操作权限
        FALSE,
        dwPid
    );
    if (hProcess == NULL) {
        std::cout << "打开进程失败,错误码:" << GetLastError() << std::endl;
        return FALSE;
    }

    // 2. 在远程进程中分配内存,存储DLL路径
    LPVOID pRemoteBuf = VirtualAllocEx(
        hProcess,
        NULL,
        (strDllPath.length() + 1) * sizeof(wchar_t),  // 包含结束符的字节数
        MEM_COMMIT | MEM_RESERVE,
        PAGE_READWRITE
    );
    if (pRemoteBuf == NULL) {
        std::cout << "远程内存分配失败,错误码:" << GetLastError() << std::endl;
        CloseHandle(hProcess);
        return FALSE;
    }

    // 3. 将DLL路径写入远程进程的内存
    SIZE_T dwWrite = 0;
    BOOL bWrite = WriteProcessMemory(
        hProcess,
        pRemoteBuf,
        strDllPath.c_str(),
        (strDllPath.length() + 1) * sizeof(wchar_t),
        &dwWrite
    );
    if (!bWrite) {
        std::cout << "写入DLL路径失败,错误码:" << GetLastError() << std::endl;
        VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }

    // 4. 获取LoadLibraryW的地址(kernel32.dll导出,所有进程地址相同)
    LPTHREAD_START_ROUTINE pStartAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(
        GetModuleHandleW(L"kernel32.dll"),
        "LoadLibraryW"
    );
    if (pStartAddr == NULL) {
        std::cout << "获取LoadLibraryW地址失败,错误码:" << GetLastError() << std::endl;
        VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }

    // 5. 调用CreateRemoteThread创建远程线程,加载DLL(核心步骤)
    HANDLE hRemoteThread = CreateRemoteThread(
        hProcess,                // 远程进程句柄
        NULL,                    // 线程安全属性默认
        0,                       // 默认栈大小
        pStartAddr,              // 线程入口:LoadLibraryW
        pRemoteBuf,              // 参数:远程进程中DLL路径的地址
        0,                       // 立即运行线程
        NULL                     // 不获取线程TID
    );
    if (hRemoteThread == NULL) {
        std::cout << "创建远程线程失败,错误码:" << GetLastError() << std::endl;
        VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }

    // 6. 等待远程线程执行完成(LoadLibraryW执行完毕)
    WaitForSingleObject(hRemoteThread, INFINITE);

    // 7. 释放资源
    CloseHandle(hRemoteThread);
    VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
    CloseHandle(hProcess);

    std::cout << "DLL注入成功!" << std::endl;
    return TRUE;
}

int main() {
    // 替换为记事本的实际PID(可通过任务管理器查看)
    DWORD dwNotepadPid = 1234;
    // 替换为你的DLL绝对路径
    std::wstring strDllPath = L"C:\\MyInject.dll";

    InjectDll(dwNotepadPid, strDllPath);
    return 0;
}

四、关键注意事项

  1. 权限要求
    • 调用OpenProcess时必须申请PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION权限,且程序需以管理员身份运行,否则会返回错误码5(权限不足)。
  2. 地址兼容性
    • LoadLibraryWkernel32.dll中,而kernel32.dll在所有进程中的加载地址相同,因此可直接用GetProcAddress获取本地地址作为远程线程入口。
  3. 64/32位匹配
    • 32位程序只能注入32位进程,64位程序只能注入64位进程,否则地址空间不匹配,调用失败。
  4. 资源释放
    • 远程线程句柄、远程进程句柄、远程分配的内存必须全部释放,避免资源泄漏。
  5. 替代函数
    • Windows Vista及以上系统,微软推荐用CreateRemoteThreadEx(功能更强,支持扩展参数),但核心所属库仍为kernel32.dll

kernel32.dll动态链接库的函数名列表

此库有数千个函数**(覆盖进程、线程、内存、文件、系统交互等所有底层能力),开发中高频使用的核心函数**(优先标注Unicode版本/W后缀)

kernel32.dll 核心函数列表(按功能分类)

功能分类 函数名 核心作用
进程管理 CreateProcessW 创建新进程(启动外部可执行文件)
OpenProcess 根据PID打开进程,获取进程句柄(用于跨进程操作)
CloseHandle 释放进程/线程/文件等内核对象句柄
TerminateProcess 强制终止指定进程
GetCurrentProcess 获取当前进程的伪句柄
GetCurrentProcessId 获取当前进程的PID(进程ID)
GetProcessId 根据进程句柄获取PID
GetProcessHandleCount 获取指定进程的句柄数量
GetProcessPriorityClass 获取进程的优先级类别(如高/普通/低优先级)
SetProcessPriorityClass 设置进程的优先级类别
CreateProcessAsUserW 以指定用户身份创建进程(需权限)
GetExitCodeProcess 获取进程的退出码(判断进程是否运行)
DuplicateHandle 复制进程/线程等内核对象的句柄
线程管理 CreateThread 在当前进程中创建新线程
CreateRemoteThread 在远程进程中创建线程(用于DLL注入、远程代码执行)
CreateRemoteThreadEx 扩展版远程线程创建(支持扩展参数)
OpenThread 根据TID打开线程,获取线程句柄
GetCurrentThread 获取当前线程的伪句柄
GetCurrentThreadId 获取当前线程的TID(线程ID)
GetThreadId 根据线程句柄获取TID
TerminateThread 强制终止指定线程(慎用,易泄漏资源)
SuspendThread 挂起指定线程(暂停执行)
ResumeThread 恢复挂起的线程(继续执行)
GetThreadPriority 获取线程的优先级
SetThreadPriority 设置线程的优先级
Sleep 暂停当前线程指定毫秒数
SwitchToThread 主动让出CPU时间片给其他线程
QueueUserAPC 将APC函数排队到指定线程(异步调用)
内存操作 VirtualAlloc 在当前进程分配虚拟内存
VirtualAllocEx 在远程进程分配虚拟内存
VirtualFree 释放当前进程的虚拟内存
VirtualFreeEx 释放远程进程的虚拟内存
VirtualProtect 修改当前进程内存的保护属性(读/写/执行)
VirtualProtectEx 修改远程进程内存的保护属性
VirtualQuery 查询当前进程内存的状态(提交/保留/空闲)
VirtualQueryEx 查询远程进程内存的状态
HeapAlloc 从进程堆分配内存
HeapFree 释放HeapAlloc分配的堆内存
HeapCreate 创建自定义堆
HeapDestroy 销毁自定义堆
HeapReAlloc 重新分配堆内存(扩容/缩容)
HeapSize 获取堆内存块的实际大小
GetProcessHeap 获取当前进程的默认堆句柄
ReadProcessMemory 读取远程进程的内存数据
WriteProcessMemory 写入数据到远程进程的内存
GlobalAlloc 分配全局内存(兼容16位系统,少用)
GlobalFree 释放全局内存
文件IO CreateFileW 打开/创建文件、管道、串口、磁盘等内核对象
ReadFile 同步读取文件/设备数据
ReadFileEx 异步读取文件/设备数据(重叠IO)
WriteFile 同步写入文件/设备数据
WriteFileEx 异步写入文件/设备数据(重叠IO)
CloseHandle 关闭文件句柄(复用,核心释放函数)
SetFilePointer 设置文件指针位置(随机读写)
SetFilePointerEx 扩展版文件指针设置(支持64位偏移)
GetFileSize 获取文件大小(32位)
GetFileSizeEx 获取文件大小(64位,推荐)
FlushFileBuffers 刷新文件缓冲区(强制写入磁盘)
FindFirstFileW 查找指定路径下的第一个文件/目录
FindNextFileW 遍历剩余文件/目录
FindClose 关闭文件查找句柄
CopyFileW 复制文件
MoveFileW 移动/重命名文件
DeleteFileW 删除指定文件
CreateDirectoryW 创建单个目录
RemoveDirectoryW 删除空目录
GetFileAttributesW 获取文件/目录的属性(隐藏/只读/系统等)
SetFileAttributesW 设置文件/目录的属性
CreateFileMappingW 创建文件映射(内存映射文件/共享内存)
MapViewOfFile 将文件映射到进程内存空间
UnmapViewOfFile 解除文件映射的内存视图
系统信息 GetVersion 获取系统版本信息(兼容旧系统)
GetVersionExW 扩展版系统版本获取(推荐)
GetNativeSystemInfo 获取原生系统信息(区分32/64位)
GetSystemInfo 获取系统硬件信息(CPU核心数、页面大小等)
GetComputerNameW 获取计算机名称
GetUserNameW 获取当前登录用户名(复用,也在advapi32.dll中)
GetSystemDirectoryW 获取系统目录路径(如C:\Windows\System32)
GetWindowsDirectoryW 获取Windows目录路径
GetCurrentDirectoryW 获取当前进程的工作目录
SetCurrentDirectoryW 设置当前进程的工作目录
同步操作 CreateEventW 创建事件对象(同步/异步)
SetEvent 设置事件为已触发状态
ResetEvent 重置事件为未触发状态
CreateMutexW 创建互斥量(进程/线程同步)
ReleaseMutex 释放互斥量
CreateSemaphoreW 创建信号量
ReleaseSemaphore 释放信号量
WaitForSingleObject 等待单个内核对象触发(进程/线程/事件等)
WaitForMultipleObjects 等待多个内核对象触发
WaitForMultipleObjectsEx 扩展版多对象等待(支持异步)
CreateCriticalSection 创建临界区(线程同步,用户态)
EnterCriticalSection 进入临界区
LeaveCriticalSection 离开临界区
DeleteCriticalSection 销毁临界区
模块加载 LoadLibraryW 加载DLL模块到进程地址空间
FreeLibrary 释放已加载的DLL模块
GetModuleHandleW 获取已加载模块的句柄(NULL=当前模块)
GetProcAddress 获取DLL导出函数的地址
EnumProcessModules 枚举指定进程的所有加载模块(复用,也在psapi.dll中)
错误处理 GetLastError 获取最近一次API调用的错误码
SetLastError 设置自定义错误码
FormatMessageW 将错误码转换为可读的错误描述
时间操作 GetLocalTime 获取本地系统时间(年月日时分秒)
GetSystemTime 获取UTC系统时间
GetTickCount 获取系统启动后的毫秒数
GetTickCount64 64位版本的系统启动毫秒数(推荐)
QueryPerformanceCounter 获取高精度性能计数器(用于计时)
QueryPerformanceFrequency 获取性能计数器的频率
环境变量 GetEnvironmentVariableW 获取指定环境变量的值
SetEnvironmentVariableW 设置/删除环境变量
ExpandEnvironmentStringsW 展开环境变量字符串(如%PATH%)
IO完成端口 CreateIoCompletionPort 创建IO完成端口(高性能异步IO核心)
GetQueuedCompletionStatus 获取IO完成端口的完成事件
PostQueuedCompletionStatus 手动投递IO完成事件
CloseIoCompletionPort 关闭IO完成端口
其他核心 GetCommandLineW 获取进程的命令行参数
ExitProcess 终止当前进程
ExitThread 终止当前线程
IsDebuggerPresent 判断进程是否被调试器附加
OutputDebugStringW 输出调试字符串到调试器

总结

  1. 命名规则 :带W后缀的为Unicode版本(推荐使用),A后缀为ANSI版本(兼容旧系统),无后缀函数多为通用接口;
  2. 调用前提 :使用这些函数需包含<windows.h>头文件,链接kernel32.lib(Visual Studio默认自动链接);
  3. 资源管理 :所有返回"句柄"的函数(如CreateProcessW/CreateFileW),使用后必须调用CloseHandle释放,避免资源泄漏;
  4. 权限注意 :跨进程操作函数(如OpenProcess/ReadProcessMemory)需管理员权限,否则会返回权限不足(错误码5)。

若需查询kernel32.dll完整函数列表 ,可通过Windows SDK的dumpbin工具(dumpbin /exports C:\Windows\System32\kernel32.dll)或微软官方文档(Kernel32.dll 函数参考)查看。

相关推荐
Project_Observer2 小时前
Zoho Projects自动化:状态变更时自动创建依赖任务
linux·数据库·windows
夕除2 小时前
js-20
开发语言·javascript·windows
Coisinilove3 小时前
数通第三次培训
网络·windows·数通数据通信
dust_and_stars3 小时前
Windows 11 RDP Wrapper 配置教程与常见问题解决方法
运维·windows
软件资深者4 小时前
Windows11 26H1官方原版下载含x64中文版、繁体版和arm64中文版苹果M1-M4可用
windows·系统安装·win11·系统重装·26h1
此刻觐神5 小时前
Windows学习笔记-17(使用MFC读取程序信息并显示)
windows·笔记·学习
人间打气筒(Ada)5 小时前
SQL Server 之创建与管理视图索引
运维·服务器·数据库·windows·sql语句·sql server·acid
人间打气筒(Ada)5 小时前
SQL Server 之创建和管理数据表
运维·服务器·数据库·windows·sql语句·sql server·windows server
编码者卢布5 小时前
【Azure App Service】32位 Windows App Service 最大能使用多少内存?
windows·microsoft·azure