MFC创建进程和进程的管理

为什么有这篇文章

操作系统实验的时候,第一个简单的程序就看的我傻眼,里面的很多语法从来没碰到过,这篇文章聚集了很多初学者可能不太懂得地方,算是我自己查资料的一个过程,也希望可以帮助到大家

#include <windows.h>
//_tmain()是一个宏,支持unicode版本的main
int _tmain(int argc,_TCHAR *argv[])
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si,sizeof(si)); //分配内存
	si.cb = sizeof(si);
	ZeroMemory(&pi,sizeof(pi));
	if(!CreateProcess(_T("C:\\Windows\\System32\\mspaint.exe"),
		NULL,
		NULL,
		NULL,
		FALSE,
		0,
		NULL,
		NULL,
		&si,
		&pi))  //指定可执行模块的而字符串
	{
		fprintf(stderr,"Create Process Falied");
		return -1;
	}
	WaitForSingleObject(pi.hProcess,INFINITE);  //等待进程结束
	printf("child Compelete");
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	return 0;
}

STARTUPINFO

typedef struct _STARTUPINFO 
{ 
	DWORD cb;			 	 //包含STARTUPINFO结构中的字节数.如果Microsoft将来扩展该结构,它可用作版本控制手段.应用程序必须将cb初始化为sizeof(STARTUPINFO) 
    PSTR lpReserved;		 //保留。必须初始化为NULL
    PSTR lpDesktop;			 //用于标识启动应用程序所在的桌面的名字。如果该桌面存在,新进程便与指定的桌面相关联。如果桌面不存在,便创建一个带有默认属性的桌面,并使用为新进程指定的名字。如果lpDesktop是NULL(这是最常见的情况 ),那么该进程将与当前桌面相关联 
    PSTR lpTitle;			 //用于设定控制台窗口的名称。如果lpTitle是NULL,则可执行文件的名字将用作窗口名.This parameter must be NULL for GUI or console processes that do not create a new console window.
    DWORD dwX;				 //用于设定应用程序窗口相对屏幕左上角位置的x 坐标(以像素为单位)。 
    DWORD dwY;				 //对于GUI processes用CW_USEDEFAULT作为CreateWindow的x、y参数,创建它的第一个重叠窗口。若是创建控制台窗口的应用程序,这些成员用于指明相对控制台窗口的左上角的位置
    DWORD dwXSize;			 //用于设定应用程序窗口的宽度(以像素为单位)
    DWORD dwYSize;			 //子进程将CW_USEDEFAULT 用作CreateWindow 的nWidth、nHeight参数来创建它的第一个重叠窗口。若是创建控制台窗口的应用程序,这些成员将用于指明控制台窗口的宽度 
    DWORD dwXCountChars;	 //用于设定子应用程序的控制台窗口的宽度(屏幕显示的字节列)和高度(字节行)(以字符为单位) 
    DWORD dwYCountChars; 
    DWORD dwFillAttribute;   //用于设定子应用程序的控制台窗口使用的文本和背景颜色 
    DWORD dwFlags;           //请参见下一段和表4-7 的说明 
    WORD wShowWindow;        //用于设定如果子应用程序初次调用的ShowWindow 将SW_*作为nCmdShow 参数传递时,该应用程序的第一个重叠窗口应该如何出现。本成员可以是通常用于ShowWindow 函数的任何一个SW_*标识符,除了SW_SHOWDEFAULT. 
    WORD cbReserved2;        //保留。必须被初始化为0 
    PBYTE lpReserved2;       //保留。必须被初始化为NULL
    HANDLE hStdInput;        //用于设定供控制台输入和输出用的缓存的句柄。按照默认设置,hStdInput 用于标识键盘缓存,hStdOutput 和hStdError用于标识控制台窗口的缓存 
    HANDLE hStdOutput; 
    HANDLE hStdError; 
} STARTUPINFO, *LPSTARTUPINFO;

PROCESS_INFORMATION

  1. 调用Createprocess ()函数后,会自动地对该结构进行填充.
  2. 创建新进程可使系统建立一个进程内核对象和一个线程内核对象。在创建进程的时候,系统为每个对象赋予一个初始使用计数值1 。
  3. 关闭句柄只是告诉系统,你对进程或线程的统计数据不感兴趣。进程或线程将继续运行,直到它自己终止运行。
  4. 当进程内核对象创建后,系统赋予该对象一个独一无二的标识号,系统中的其他任何进程内核对象都不能使用这个相同的ID号。线程内核对象的情况也一样。
  5. 进程I D和线程I D共享相同的号码池。这意味着进程和线程不可能拥有相同的I D 。

ZeroMemory

ZeroMemory是美国微软公司的软件开发包SDK中的一个宏。 其作用是用0来填充一块内存区域。定义式如下

#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))  
#define ZeroMemory RtlZeroMemory 
  1. ZeroMemory实际是用memset实现的。
  2. ZeroMemory只能用于windows平台。

memset

void *memset(void *s,int ch,size_t n);
s字符串的前n个用ch字符串代替
是由C Run-time Library提供的提供的函数,作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。

typedef struct _PROCESS_INFORMATION { 
    HANDLE hProcess; //存放每个对象的与进程相关的句柄 
    HANDLE hThread;        //返回的线程句柄。 
    DWORD dwProcessId;    //用来存放进程ID号 
    DWORD dwThreadId;      //用来存放线程ID号 
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;

lpctstr

LPCTSTR用来表示你的字符是否使用UNICODE, 如果你的程序定义了UNICODE或者其他相关的宏,那么这个字符或者字符串将被作为UNICODE字符串,否则就是标准的ANSI字符串。

LPCTSTR类型:

L表示long指针 这是为了兼容Windows 3.1等16位操作系统遗留下来的,在win32中以及其他的32位操作系统中, long指针和near指针及far修饰符都是为了兼容的作用。没有实际意义。
P表示这是一个指针
C表示是一个常量
T表示在Win32环境中, 有一个_T宏
STR表示这个变量是一个字符串

bool CreateProcess 
( 
	LPCTSTR lpApplicationName, //指向一个NULL结尾的、用来指定可执行模块的字符串。 
	LPTSTR lpCommandLine,     //指向一个NULL结尾的、用来指定要运行的命令行。
	//如果lpApplicationName和lpCommandLine参数都不为空,那么lpApplicationName参数指定将要被运行的模块,lpCommandLine参数指定将被运行的模块的命令行 
	//新运行的进程可以使用GetCommandLine函数获得整个命令行。 
	LPSECURITY_ATTRIBUTES lpProcessAttributes。 //指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpProcessAttributes参数为空(NULL) ,那么句柄不能被继承。 
	LPSECURITY_ATTRIBUTES lpThreadAttributes, 
	BOOL bInheritHandles, //指示新进程是否从调用进程处继承了句柄。如果参数的值为真,调用进程中的每一个可继承的打开句柄都将被子进程继承。被继承的句柄与原 进程拥有完全相同的值和访问权限。 
	DWORD dwCreationFlags, //指定附加的、用来控制优先类和进程的创建的标志。 
	LPVOID lpEnvironment, //指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境。 一个环境块存在于一个由以NULL结尾的字符串组成的块中,这个块也是以NULL结尾的。每个字符串都是name=value的形式。 
	LPCTSTR lpCurrentDirectory, //指向一个以NULL结尾的字符串,这个字符串用来指定子进程的工作路径。这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数 为空,新进程将使用与调用进程相同的驱动器和目录。这个选项是一个需要启动启动应用程序并指定它们的驱动器和工作目录的外壳程序的主要条件。 
	LPSTARTUPINFO lpStartupInfo, //指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。 
	LPPROCESS_INFORMATION lpProcessInformation //指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。
);
CreateProcess( 
appName,//应用程序名称 
pCmdLine, //命令行 
NULL, //进程句柄不能被继承 
NULL, //线程句柄不能被继承 
FALSE, 
NULL, 
NULL, 
NULL, 
&stStartUpInfo, 
&pProcessInfo); 
CloseHandle

最常见的 Windows 数据类型

在这里插入图片描述

typedef unsignedlong      DWORD;
typedef int                BOOL;
typedef unsignedchar      BYTE;
typedef unsignedshort     WORD;
typedef float              FLOAT;
typedef FLOAT              *PFLOAT;
typedef BOOLnear          *PBOOL;
typedef BOOLfar           *LPBOOL;
typedef BYTEnear          *PBYTE;
typedef BYTE far           *LPBYTE;
typedef intnear           *PINT;
typedef intfar            *LPINT;
typedef WORDnear          *PWORD;
typedef WORDfar           *LPWORD;
typedef longfar           *LPLONG;
typedef DWORDnear         *PDWORD;
typedef DWORDfar          *LPDWORD;
typedef voidfar           *LPVOID;
typedef CONST voidfar     *LPCVOID;
#include "iostream"
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
using namespace std;
static LPCTSTR g_szMutexName=_T("w2kdg.ProcTerm.mutex.Suicide");
//创建当前进程的克隆进程的简单方法
void StartClone()
{
	//提取当前可执行文件的文件名
	TCHAR szFilename[MAX_PATH];
	GetModuleFileName(NULL,szFilename,MAX_PATH);
	//格式化用于子进程的命令行,指明他是一个EXE文件和子进程
	TCHAR szCmdLine[MAX_PATH];
	//sprintf_s(szCmdLine,MAX_PATH,_T("\"%s\"child"),szFilename);
	sprintf(szCmdLine,_T("\"%s\"child"),szFilename);
	//子进程的启动信息结构
	STARTUPINFO si;
	::ZeroMemory((void*)(&si),sizeof(si));
	//应当是此结构的大小
	si.cb = sizeof(si);
	//返回的用于子进程的进程信息
	PROCESS_INFORMATION pi;
	//用同样的可执行文件名和命令行创建进程,并指明他是一个子进程
	BOOL bCreateOK = CreateProcess(
		szFilename,      //产生的应用程序名称(本EXE文件)
		szCmdLine,       //告诉人们这是一个子进程的标志
		NULL,            //用于进程的默认的安全性
		NULL,            //用于线程的默认的安全性
		FALSE,           //不继承句柄
		NULL,            //创建新窗口,使输出更直观
		NULL,            //新环境
		NULL,            //当前目录
		&si,             //启动信息结构
		&pi              //返回的进程的信息
		);
	//释放指向子进程的引用
	if(bCreateOK)
	{
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	}
}
void Parent()
{
	//创建"自杀"互斥程序体
	HANDLE hMutexSuicide = ::CreateMutex(
		NULL,                //默认的安全性
		TRUE,                //最初拥有的
		g_szMutexName);      //为其命名
	if(hMutexSuicide != NULL)
	{
		//创建子进程
		cout << "Creating the child process." <<endl;
		StartClone();
		//暂停
		Sleep(5000);
		//令子进程"杀"掉自身
		cout << "Telling the child process to quit." << endl;
		ReleaseMutex(hMutexSuicide);
		//消除句柄
		CloseHandle(hMutexSuicide);
	}
}
void Chlid()
{
	//打开"自杀"互斥体
	HANDLE hMutexSuicide=OpenMutex(
		SYNCHRONIZE,              //打开用于同步
		FALSE,                    //不需要向下传递
		g_szMutexName);           //名称
	if(hMutexSuicide != NULL)
	{
		//报告正在等待指令
		cout << "Child waiting for suicide instructions." << endl;
		WaitForSingleObject(hMutexSuicide,INFINITE);
		//报告准备好终止,消除句柄
		cout << "Child quiting." << endl;
		CloseHandle(hMutexSuicide);
		Sleep(1000);
	}
}
int _tmain(int argc,_TCHAR* argv[])
{
	//决定其行为是父进程还是子进程
	if(argc>1 && strcmp(argv[1],"child")==0)
	{
		Chlid();
	}
	else
	{
		Parent();
	}
	return 0;
}

TCHAR

定义

TCHAR是通过define定义的字符串宏

使用原理

微软将这两套字符集及其操作进行了统一,通过条件编译(通过_UNICODE和UNICODE宏)控制实际使用的字符集,这样就有了_T("")这样的字符串,对应的就有了_tcslen这样的函数
为了存储这样的通用字符,就有了TCHAR:
当没有定义_UNICODE宏时,TCHAR = char,_tcslen =strlen
当定义了_UNICODE宏时,TCHAR = wchar_t , _tcslen = wcslen
当我们定义了UNICODE宏,就相当于告诉了编译器:我准备采用UNICODE版本。这个时候,TCHAR就会摇身一变,变成了wchar_t。而未定义UNICODE宏时,TCHAR摇身一变,变成了unsignedchar。这样就可以很好的切换宽窄字符集。
tchar可用于双字节字符串,使程序可以用于中日韩等国 语言文字处理、显示。使编程方法简化。

MAX_PATH

MAX_PATH 这个变量是windows自己宏定义的变量

在这里插入图片描述

GetModuleFileName

GetModuleFileName是计算机应用中的一个函数,用以获取当前进程已加载模块文件的完整路径。

DWORD GetModuleFileName(

    HMODULE hModule,
	//HMODULE hModule 装载一个程序实例的句柄。如果该参数为NULL,该函数返回该当前应用程序全路径。
	LPTSTR lpFilename,
	//LPTSTR lpFileName 是你存放返回的名字的内存块的指针,是一个输出参数

    DWORD nSize
	//DWORD nSize,装载到缓冲区lpFileName的最大值
);

返回值

如果返回为成功,将在lpFileName的缓冲区当中返回相应模块的路径,如果所设的nSize过小,那么返回仅按所设置缓冲区大小返回相应字符串内容。

如果函数失败,返回值将为0,利用GetLastError可获得异常代码。

WaitForSingleObject 的用法

DWORD WaitForSingleObject(
                     HANDLE hHandle, 
                     DWORD dwMilliseconds				
                  );
 //参数 hHandle 是一个事件的句柄
 //第二个参数 dwMilliseconds 是时间间隔
 //如果时间是有信号状态返回 WAIT_OBJECT_0 
 //如果时间超过 dwMilliseconds 值但时间事件还是无信号状态则返回 WAIT_TIMEOUT

WaitForSingleObject 函数用来检测 hHandle 事件的信号状态,当函数的执行时间超过 dwMilliseconds 就返回,但如果参数 dwMilliseconds 为 INFINITE 时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到 WaitForSingleObject 有返回直才执行后面的代码。

_T和_L

_T("")是一个宏,他的作用是让你的程序支持Unicode编码,因为Windows使用两种字符集ANSI和UNICODE,
前者就是通常使用的单字节方式,但这种方式处理象中文这样的双字节字符不方便,容易出现半个汉字的情况。
而后者是双字节方式,方便处理双字节字符。
LPSTR:32bit指针指向一个字符串,每个字符占1字节
LPCSTR:32-bit指针指向一个常字符串,每个字符占1字节
LPCTSTR:32-bit指针指向一个常字符串,每字符可能占1字节或2字节,取决于Unicode是否定义
LPTSTR:32-bit指针每字符可能占1字节或2字节,取决于Unicode是否定义
参考:https://blog.csdn.net/piaoliangjinjin/article/details/80800233

sprintf_s

在这里插入图片描述
在这里插入图片描述
sprintf_s是一个函数,其函数功能是将数据格式化输出到字符串。sprintf_s对于格式化string中的格式化的字符的有效性进行了检查,sprintf_s也携带着接收格式化字符串的缓冲区的大小。
sprintf_s将格式化字符串存到缓冲区,如果格式化字符串过大,则sprintf_s会返回一个空string和设置无效参数句柄为激活。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
新闻网页贴吧知道MP3图片视频百科文库 帮助设置 首页 自然 文化 地理 历史 生活 社会 艺术 人物 经济 科学 体育 欧冠 核心用户 进程管理 百科名片 引是正在运行的程序实体,并且包括这个运行的程序中占据的所有系统资源,比如说CPU(寄存器),IO,内存,网络资源等。很多人在回答进程的概念的时候,往往只会说它是一个运行的实体,而会忽略掉进程所占据的资源。比如说,同样一个程序,同一时刻被两次运行了,那么他们就是两个独立的进程。linux下查看系统进程的命令是ps。 目录 进程的分类1.基本系统进程 2.常见系统进程解释 (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) 进程管理进程的分类 1.基本系统进程 2.常见系统进程解释 (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) 进程管理 展开 编辑本段进程的分类 1.基本系统进程   Csrss.exe:这是子系统服务器进程,负责控制Windows创建或删除线程以及16位的虚拟DOS环境。   System Idle Process:这个进程是作为单线程运行在每个处理器上,并在系统不处理其它线程的时候分派处理器的时间。   Smss.exe:这是一个会话管理子系统,负责启动用户会话。   Services.exe:系统服务的管理工具。   Lsass.exe:本地的安全授权服务。   Explorer.exe:资源管理器。   Spoolsv.exe:管理缓冲区中的打印和传真作业。   Svchost.exe:这个进程要着重说明一下,有不少朋友都有这种错觉:若是在“任务管理器”中看到多个Svchost.exe在运行,就觉得是有病毒了。其实并不一定,系统启动的时候,Svchost.exe将检查注册表中的位置来创建需要加载的服务列表,如果多个Svchost.exe同时运行,则表明当前有多组服务处于活动状态;多个DLL文件正在调用它。 2.常见系统进程解释 (1)   system process   进程文件: system process   进程名称: Windows内存处理系统进程   描述: Windows页面内存管理进程,拥有0级优先。   是否为系统进程: 是 (2)   alg.exe   进程文件: alg or alg.exe   进程名称: 应用层网关服务   描述: 这是一个应用层网关服务用于网络共享。   是否为系统进程: 是 (3)   csrss.exe   进程文件: csrss or csrss.exe   进程名称: Client/Server Runtime Server Subsystem   描述: 客户端服务子系统,用以控制Windows图形相关子系统。   是否为系统进程: 是 (4)   ddhelp.exe   进程文件: ddhelp or ddhelp.exe   进程名称: DirectDraw Helper   描述: DirectDraw Helper是DirectX这个用于图形服务的一个组成部分。   是否为系统进程: 是 (5)   dllhost.exe   进程文件: dllhost or dllhost.exe   进程名称: DCOM DLL Host进程   描述: DCOM DLL Host进程支持基于COM对象支持DLL以运行Windows程序。   是否为系统进程: 是 (6)   inetinfo.exe   进程文件: inetinfo or inetinfo.exe   进程名称: IIS Admin Service Helper   描述: InetInfo是Microsoft Internet Infomation Services (IIS)的一部分,用于Debug调试除错。   是否为系统进程: 是 (7)   internat.exe   进程文件: internat or internat.exe   进程名称: Input Locales   描述: 这个输入控制图标用于更改类似国家设置、键盘类型和日期格式。   是否为系统进程: 是 (8)   kernel32.dll   进程文件: kernel32 or kernel32.dll   进程名称: Windows壳进程   描述: Windows壳进程用于管理多线程、内存和资源。   是否为系统进程: 是 (9)   lsass.exe   进程文件: lsass or lsass.exe   进程名称: 本地安全权限服务   描述: 这个本地安全权限服务控制Windows安全机制。   是否为系统进程: 是 (10)   mdm.exe   进程文件: mdm or mdm.exe   进程名称: Machine Debug Manager   描述: Debug除错管理用于调试应用程序和Microsoft Office中的Microsoft Script Editor脚本编辑器。   是否为系统进程: 是 (11)   mmtask.tsk   进程文件: mmtask or mmtask.tsk   进程名称: 多媒体支持进程   描述: 这个Windows多媒体后台程序控制多媒体服务,例如MIDI。   是否为系统进程: 是 (12)   mprexe.exe   进程文件: mprexe or mprexe.exe   进程名称: Windows路由进程   描述: Windows路由进程包括向适当的网络部分发出网络请求。   是否为系统进程: 是 (13)   msgsrv32.exe   进程文件: msgsrv32 or msgsrv32.exe   进程名称: Windows信使服务   描述: Windows信使服务调用Windows驱动和程序管理在启动。   是否为系统进程: 是 (14)   mstask.exe   进程文件: mstask or mstask.exe   进程名称: Windows计划任务   描述: Windows计划任务用于设定继承在什么时间或者什么日期备份或者运行。   是否为系统进程: 是 (15)   regsvc.exe   进程文件: regsvc or regsvc.exe   进程名称: 远程注册表服务   描述: 远程注册表服务用于访问在远程计算机的注册表。   是否为系统进程: 是 (16)   rpcss.exe   进程文件: rpcss or rpcss.exe   进程名称: RPC Portmapper   描述: Windows 的RPC端口映射进程处理RPC调用(远程模块调用)然后把它们映射给指定的服务提供者。   是否为系统进程: 是 (17)   services.exe   进程文件: services or services.exe   进程名称: Windows Service Controller   描述: 管理Windows服务。   是否为系统进程: 是 (18)   smss.exe   进程文件: smss or smss.exe   进程名称: Session Manager Subsystem   描述: 该进程为会话管理子系统用以初始化系统变量,MS-DOS驱动名称类似LPT1以及COM,调用Win32壳子系统和运行在Windows登陆过程。   是否为系统进程: 是 (19)   snmp.exe   进程文件: snmp or snmp.exe   进程名称: Microsoft SNMP Agent   描述: Windows简单的网络协议代理(SNMP)用于监听和发送请求到适当的网络部分。   是否为系统进程: 是 (20)   spool32.exe   进程文件: spool32 or spool32.exe   进程名称: Printer Spooler   描述: Windows打印任务控制程序,用以打印机就绪。   是否为系统进程: 是 (21)   spoolsv.exe   进程文件: spoolsv or spoolsv.exe   进程名称: Printer Spooler Service   描述: Windows打印任务控制程序,用以打印机就绪。   是否为系统进程: 是 (22)   stisvc.exe   进程文件: stisvc or stisvc.exe   进程名称: Still Image Service   描述: Still Image Service用于控制扫描仪和数码相机连接在Windows。   是否为系统进程: 是 (23)   svchost.exe   进程文件: svchost or svchost.exe   进程名称: Service Host Process   描述: Service Host Process是一个标准的动态连接库主机处理服务。   是否为系统进程: 是 (24)   system   进程文件: system or system   进程名称: Windows System Process   描述: Microsoft Windows系统进程。   是否为系统进程: 是 (25)   taskmon.exe   进程文件: taskmon or taskmon.exe   进程名称: Windows Task Optimizer   描述: windows任务优化器监视你使用某个程序的频率,并且通过加载那些经常使用的程序来整理优化硬盘。   是否为系统进程: 是 (26)   tcpsvcs.exe   进程文件: tcpsvcs or tcpsvcs.exe   进程名称: TCP/IP Services   描述: TCP/IP Services Application支持透过TCP/IP连接局域网和Internet。   是否为系统进程: 是 (27)   winlogon.exe   进程文件: winlogon or winlogon.exe   进程名称: Windows Logon Process   描述: Windows NT用户登陆程序。   是否为系统进程: 是 (28)   winmgmt.exe   进程文件: winmgmt or winmgmt.exe   进程名称: Windows Management Service   描述: Windows Management Service透过Windows Management Instrumentation data (WMI)技术处理来自应用客户端的请求。   是否为系统进程: 是 编辑本段进程管理   操作系统的职能之一,主要是对处理机进行管理 。为了提高CPU的利用率而采用多道程序技术。通过进程管理来协调多道程序之间的关系,使CPU得到充分的利用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值