CheckMenuItem()函数,EnumPrinters()枚举打印机AppendMenu(),添加菜单 printerPropertites()GetMenuString()CreateIC()

/*****************************************************
078.C  
	第78个列子:获取显示器及打印机设备信息
	WM_SETTINGCHANG 消息:系统设置变化
	CheckMenuItem 函数
	EnumPrinters():			枚举打印机
	AppendMenu():			添加菜单
	Openprinter ():			打开打印机
	printerPropertites() :	打印机属性
	GetMenuString():		获取菜单字符串
	CreateIC():				获取当前设备环境的信息和CreateDC不一样				

	此程序只能运行在32位上,64位debug版本存在bug
(c) 2023
*****************************************************/
#include<Windows.h>
#include"resource.h"
#include<VersionHelpers.h>
//#pragma warning(disable:4996),把这个警告信息屏蔽掉

LRESULT  CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void DoBasicInfo(HDC, HDC, int, int);//基本信息
void DoOtherInfo(HDC, HDC, int, int);//其他信息
void DoBitCodedCaps(HDC, HDC, int, int, int);//位图信息

//设备其他信息
typedef struct
{
	int iMask;//标识符
	TCHAR* szDesc;//描述信息
}
BITS;
#define IDM_DEVMODE 1000 //预定义值  

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance,
	PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("DEVCAPS2");//移植你更改的地方
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass;

	wndclass.style = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc = WndProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hinstance;
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName = szAppName;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("this program requires Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName, TEXT("Get System Metrics No.3"),//更新
		WS_OVERLAPPEDWINDOW,//增加水平滚动条WS_HSCROLL
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hinstance, NULL);

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

LRESULT  CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static TCHAR szDevice[32], szWindowText[64];
	static int cxChar, cyChar, nCurrentDevice = ID_DEVICE_SCREEN,
		nCurrentInfo = ID_CAPABILITIES_BASICINFORMATION;

	static DWORD	dwNeeded, dwReturned;
	static PRINTER_INFO_4* pinfo4;//NT构架打印机信息数据结构
	static PRINTER_INFO_5* pinfo5;//DOS构架打印机信息数据结构

	DWORD i;
	HDC hdc, hdcInfo;
	HMENU hMenu;
	HANDLE hPrint;
	PAINTSTRUCT ps;
	TEXTMETRIC tm;
	switch (message)
	{
	case WM_CREATE:
		hdc = GetDC(hwnd);//获取设备环境句柄
		SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
		GetTextMetrics(hdc, &tm);
		cxChar = tm.tmAveCharWidth;
		cyChar = tm.tmHeight + tm.tmExternalLeading;
		ReleaseDC(hwnd, hdc);
		//fall through
		//更改系统参数后
	case WM_SETTINGCHANGE:
		hMenu = GetSubMenu(GetMenu(hwnd), 0);
		//获取DEVICE惨淡下的子菜单
		while (GetMenuItemCount(hMenu) > 1)//确定指定菜单中的项目数,并清空
			DeleteMenu(hMenu, 1, MF_BYPOSITION);//从指定菜单中删除项目
		//获取所有本地和原创打印机的李彪
		//首先确定数组的大小---保存在dwNeeded中
		//接下来,为info数组分配空间并填充它
		//讲打印机名称添加到下拉菜单中
		//获取所有本地和远程打印机
		if(!IsWindowsXPOrGreater())//xp一下
		//if (GetVersion() & 0x80000000)//windows 98
		{
			//枚举可用的打印机,打印服务
			/*
			BOOL EnumPrinters(
				  _In_  DWORD   Flags,	函数应枚举的打印对象的类型。 此值可以是以下一个或多个值。
				  _In_  LPTSTR  Name,
				  _In_  DWORD   Level,
				  _Out_ LPBYTE  pPrinterEnum,
				  _In_  DWORD   cbBuf,
				  _Out_ LPDWORD pcbNeeded,
				  _Out_ LPDWORD pcReturned
				);
			*/
			EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 5, NULL,
				0, &dwNeeded, &dwReturned);
			//返回PRINTER_INFO_5结构数量
			pinfo5 = malloc(dwNeeded);

			EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 5, (PBYTE)
				pinfo5,dwNeeded, &dwNeeded, &dwReturned);

			for ( i = 0; i < dwReturned; i++)
			{
				AppendMenu(hMenu, (i + 1) % 16 ? 0 : 
					MF_MENUBARBREAK, i+1,
					pinfo5[i].pPrinterName);
			}
			free(pinfo5);
		}
		else
		{
			//windows nt
			EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL,
				0, &dwNeeded, &dwReturned);

			pinfo4 = malloc(dwNeeded);

			EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, (PBYTE)
				pinfo4,dwNeeded, &dwNeeded, &dwReturned);

			for ( i = 0; i < dwReturned; i++)
			{
				AppendMenu(hMenu, (i + 1) % 16 ? 0 : 
					MF_MENUBARBREAK, 1+i,
					pinfo4[i].pPrinterName);
			} 
			free(pinfo4);
		}

		//将新项目追加到指定菜单栏,
		AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
		//添加属性从菜单,
		AppendMenu(hMenu, 0, IDM_DEVMODE, TEXT("Properties"));

		wParam = ID_DEVICE_SCREEN;
		//fall through

	case WM_COMMAND:
		hMenu = GetMenu(hwnd);
		//选择屏幕或者打印机
		if (LOWORD(wParam)==ID_DEVICE_SCREEN||	
			LOWORD(wParam)<IDM_DEVMODE)
		{
			//将复选标记属性设置为清除状态
			CheckMenuItem(hMenu, nCurrentDevice, MF_UNCHECKED);
			//更新当前设备
			nCurrentDevice = LOWORD(wParam);
			//	将复选标记属性设置为所选状态。
			CheckMenuItem(hMenu, nCurrentDevice, MF_CHECKED);
		}
		//选择属性菜单项
		else if (LOWORD(wParam) == IDM_DEVMODE)	//Properties selection
		{
			//将打印机名字存入szDevice字符数组
			GetMenuString(hMenu, nCurrentDevice, szDevice,
				sizeof(szDevice) / sizeof(TCHAR), MF_BYCOMMAND);
			//显示打印机属性对话框
			if (OpenPrinter(szDevice, &hPrint, NULL))
			{
				//有打印机驱动程序产生间接生成对话框
				PrinterProperties(hwnd, hPrint);
				//关闭打印机句柄
				ClosePrinter(hPrint);
			}
		}
		else//Capabilities下的菜单项设置
		{
			CheckMenuItem(hMenu, nCurrentInfo, MF_UNCHECKED);
			nCurrentInfo = LOWORD(wParam);
			CheckMenuItem(hMenu, nCurrentInfo, MF_CHECKED);
		}
		InvalidateRect(hwnd, NULL, TRUE);
		return 0;

	case WM_INITMENUPOPUP://lParam菜单ID
		if (lParam == 0)//Device菜单
			EnableMenuItem(GetMenu(hwnd), IDM_DEVMODE,
				//启用,禁用,或显示指定的菜单项
				nCurrentDevice == ID_DEVICE_SCREEN ? MF_GRAYED : MF_ENABLED);
		return 0;

	case WM_PAINT:
		//窗口标题
		lstrcpy(szWindowText, TEXT("Device Capabilities:"));

		//SCREEN菜单
		if (nCurrentDevice==ID_DEVICE_SCREEN)
		{
			lstrcpy(szDevice, TEXT("DISPLAY"));
			//函数为指定设备创建信息上下文。
			//信息上下文提供了一种快速获取有关设备的信息的方法,
			//而无需创建设备上下文(DC) 。 
			//但是,GDI 绘图函数不能接受信息上下文的句柄。

	
			hdcInfo = CreateIC(szDevice, NULL, NULL, NULL);
		}
		//其他菜单
		else
		{
			hMenu = GetMenu(hwnd);
			//将指定菜单项的文本字符串复制到指定的缓冲区中。
			GetMenuString(hMenu, nCurrentDevice, szDevice,
				sizeof(szDevice), MF_BYCOMMAND);
			hdcInfo = CreateIC(NULL, szDevice, NULL, NULL);
		}

		lstrcat(szWindowText, szDevice);
		//更改指定窗口标题栏的文本
		SetWindowText(hwnd, szWindowText);

		hdc = BeginPaint(hwnd, &ps);
		SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));

		if (hdcInfo)
		{
			switch (nCurrentInfo)
			{
			case ID_CAPABILITIES_BASICINFORMATION:
				DoBasicInfo(hdc, hdcInfo, cxChar, cyChar);
				break;

			case ID_CAPABILITIES_OTHERINORMATION:
				DoOtherInfo(hdc, hdcInfo, cxChar, cyChar);
				break;

			case ID_CAPABILITIES_CURVECAPABILITIES://曲线
			case ID_CAPABILITIES_LINECAPABILITIES://直线
			case ID_CAPABILITIES_POLYGONALCAPABILITIES://多边形
			case ID_CAPABILITIES_TEXT://文本
				DoBitCodedCaps(hdc, hdcInfo, cxChar, cyChar,
					nCurrentInfo-ID_CAPABILITIES_CURVECAPABILITIES);
				break;
			}

			EndPaint(hwnd, &ps);
			return 0;
		}
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

	return DefWindowProc(hwnd, message, wParam, lParam);
}

//基本信息
void DoBasicInfo(HDC hdc, HDC hdcInfo, int cxChar, int cyChar)
{
	struct
	{
		int nIndex;//索引
		TCHAR* szDesc;//表述
	}
	info[] =//结构数组
	{
	HORZSIZE,			TEXT("HORZSIZE           width in millimeters: "),
	VERTSIZE,			TEXT("VERTSIZE           Height in millimeters:"),
	HORZRES,			TEXT("HORZRES            width in pixels:"),
	VERTRES,			TEXT("VERTRES            height in raster lines:"),
	BITSPIXEL,			TEXT("BITSPIXEL          color bits per pixel:"),
	PLANES,				TEXT("PLANES             number of color planes:"),
	NUMBRUSHES,			TEXT("NUMBRUSHES         number of device brushes:"),
	NUMPENS,			TEXT("NUMPENS            number of device pens:"),
	NUMMARKERS,			TEXT("NUMMARKERS         number of device fonts:"),
	NUMFONTS,			TEXT("NUMFONTS           number of device colors:"),
	PDEVICESIZE,		TEXT("PDEVICESIZE        size of devicestructure:"),
	ASPECTX,			TEXT("ASPECTX            relative width of pixel:"),
	ASPECTY,			TEXT("ASPECTY            relative height of pixel:"),
	ASPECTXY,			TEXT("ASPECTXY           relative diagonal of pixel:"),
	LOGPIXELSX,			TEXT("LOGPIXELSX         horizontal dots per inch:"),
	LOGPIXELSY,			TEXT("LOGPIXELSY         vertical dots per inch:"),
	SIZEPALETTE,		TEXT("SIZEPALETTE        number of palette entries:"),
	NUMRESERVED,		TEXT("NUMRESERVED        reserved palette entries:"),
	COLORRES,			TEXT("COLORRES           actual color resolution:"),
	PHYSICALHEIGHT,		TEXT("PHYSICALHEIGHT     printer page pixel width:"),
	PHYSICALWIDTH,		TEXT("PHYSICALWIDTH      printfer page pixel height:"),
	PHYSICALOFFSETX,	TEXT("PHYSICALOFFSETX    printfer page x offset:"),
	PHYSICALOFFSETY,	TEXT("PHYSICALOFFSETY    printfer page y offset:")
	};

	int i;
	TCHAR szBuffer[80];

	for (i = 0; i < sizeof(info) / sizeof(info[0]); i++)
		TextOut(hdc, cxChar, (i + 1) * cyChar, szBuffer,
			wsprintf(szBuffer, TEXT("%-45s%8d"), info[i].szDesc,
				GetDeviceCaps(hdcInfo, info[i].nIndex)));
}

//其他信息
void DoOtherInfo(HDC hdc, HDC hdcInfo, int cxChar, int cyChar)
{
	static BITS clip[] =
	{
		CP_RECTANGLE,TEXT("CP_RECTANGLE Can Clip To Rectangle:")
	};

	static BITS raster[] =//结构数组
	{
	RC_BITBLT,			TEXT("HORZSIZE     Capable of simple BitBlt:"),
	RC_BANDING,			TEXT("VERTSIZE     Requires banding support:"),
	RC_SCALING,			TEXT("HORZRES      Requires scaling support:"),
	RC_BITMAP64,		TEXT("VERTRES      Supports bitmaps>64k:"),
	RC_GDI20_OUTPUT,	TEXT("BITSPIXEL    has 2.0 output calls:"),
	RC_DI_BITMAP,		TEXT("PLANES       supports dib to memory:"),
	RC_PALETTE,			TEXT("NUMBRUSHES   supports a palette:"),
	RC_DIBTODEV,		TEXT("NUMPENS      supports bitmap conversion:"),
	RC_BIGFONT,			TEXT("NUMMARKERS   Supports fonts >64k:"),
	RC_STRETCHBLT,		TEXT("NUMFONTS     Supports StretchBlt:"),
	RC_FLOODFILL,		TEXT("PDEVICESIZE  Supports FloodFill:"),
	RC_STRETCHDIB,		TEXT("ASPECTX      Supports StretchDIBits:")
	};

	static TCHAR* szTech[] = {
		TEXT("DT_PLOTTER     (Vector plotter)"),//矢量绘图仪 
		TEXT("DT_RASDISPLAY  (DT_RASDISPLAY)"),//矢量绘图仪 
		TEXT("DT_RASPRINTER  (DT_RASPRINTER)"),//矢量绘图仪 
		TEXT("DT_RASCAMERA   (DT_RASCAMERA)"),//矢量绘图仪 
		TEXT("DT_CHARSTREAM  (DT_CHARSTREAM)"),//矢量绘图仪 
		TEXT("DT_METAFILE    (DT_METAFILE)"),//矢量绘图仪 
		TEXT("DT_DISPFILE    (DT_DISPFILE)")//矢量绘图仪 
	};
	int i;
	TCHAR szBuffer[80];
	//在第1行显示驱动程序版本
	/*-------------------------------------------
	BOOL TextOutA(
		[in] HDC    hdc,
		[in] int    x,			系统用来对齐字符串的引用点的 x 坐标(以逻辑坐标为单位)。
		[in] int    y,			系统用来对齐字符串的引用点的 y 坐标(以逻辑坐标为单位)。
		[in] LPCSTR lpString,	指向要绘制的字符串的指针。 字符串不需要为零终止,因为 cchString 指定字符串的长度。
		[in] int    c			由 lpString 指向的字符串的长度(以字符为单位)。
	);
	-------------------------------------------*/
	/*-------------------------------------------
BOOL TextOutA(
	int WINAPIV wsprintfA(
  [out] LPSTR  unnamedParam1,	要接收格式化输出的缓冲区。 缓冲区的最大大小为 1,024 字节。
  [in]  LPCSTR unnamedParam2,	格式控制规范。 除了普通 ASCII 字符,此字符串中还显示了每个参数的格式规范。 有关格式规范的详细信息,请参阅“备注”部分。
        ...						一个或多个可选参数。 参数参数的数量和类型取决于 lpFmt 参数中的相应格式控制规范。
);

如果函数成功,则返回值是存储在输出缓冲区中的字符数,而不是计算终止 null 字符。
-------------------------------------------*/
/*-------------------------------------------
int GetDeviceCaps(
  [in] HDC hdc,
  [in] int index
);返回值指定所需项的值。
-------------------------------------------*/

	TextOut(hdc, cxChar, cyChar, szBuffer,
		wsprintf(szBuffer, TEXT("%-24s%-04XH"), TEXT("DriverVersion:"),
			GetDeviceCaps(hdcInfo, DRIVERVERSION)));
	//在第2行显示设备技术
	TextOut(hdc, cxChar, 2*cyChar, szBuffer,
		wsprintf(szBuffer, TEXT("%-24s%-40s"), TEXT("Technology:"),
			szTech[GetDeviceCaps(hdcInfo, TECHNOLOGY)]));

	//在第4行显示设备支持剪切性能标志
	TextOut(hdc, cxChar, 4 * cyChar, szBuffer,
		wsprintf(szBuffer, TEXT("CLIPCAPS(Clipping capabilities):")));
	//在第6行开始显示是否支持Clippiing capabilities
	for (int i = 0; i < sizeof(clip) / sizeof(clip[0]); i++)
		TextOut(hdc, 9 * cxChar, (i + 6) * cyChar, szBuffer,
			wsprintf(szBuffer, TEXT("%-45s %3s"), clip[i].szDesc,
				GetDeviceCaps(hdcInfo, CLIPCAPS) & clip[i].iMask ? 
					TEXT("Yes") : TEXT("No")));

	//在第8行
	TextOut(hdc, cxChar, 8 * cyChar, szBuffer,
		wsprintf(szBuffer, TEXT("RASTERCAPS(Raster capabilities)")));


	//在第10行显示光栅性能
	for (i = 0; i < sizeof(raster) / sizeof(raster[0]); i++)
		TextOut(hdc, 9 * cxChar, (i + 10) * cyChar, szBuffer,
			wsprintf(szBuffer, TEXT("%-45s %3s"), raster[i].szDesc,
				GetDeviceCaps(hdcInfo, RASTERCAPS) & raster[i].iMask ?
				TEXT("Yes") : TEXT("No"))); 
}

//位图信息
void DoBitCodedCaps(HDC hdc, HDC hdcInfo, int cxChar, int cyChar, int iType)
{
	static BITS curves[] =
	{
		CC_CIRCLES,		TEXT("CC_CIRCLES       Can do circles:"),
		CC_PIE,			TEXT("CC_PIE           Can do pie wedges:"),
		CC_CHORD,		TEXT("CC_CHORD         Can do chord arcs:"),
		CC_ELLIPSES,	TEXT("CC_ELLIPSES      Can do ellipses:"),
		CC_WIDE,		TEXT("CC_WIDE          Can do wide borders:"),
		CC_STYLED,		TEXT("CC_STYLED        Can do styled borders:"),
		CC_WIDESTYLED,	TEXT("CC_WIDESTYLED    Can do wide and styled borders:"),
		CC_INTERIORS,	TEXT("CC_INTERIORS     Can do interiors:")
	};

	static BITS lines[] =
	{
		LC_POLYLINE,	TEXT("LC_POLYLINE      Can do polyline:"),
		LC_MARKER,		TEXT("LC_MARKER        Can do markers:"),
		LC_POLYMARKER,	TEXT("LC_POLYMARKER    Can do polymarkers:"),
		LC_WIDE,		TEXT("LC_WIDE          Can do wide lines:"),
		LC_STYLED,		TEXT("LC_STYLED        Can do styled lines:"),
		LC_WIDESTYLED,	TEXT("LC_WIDESTYLED    Can do wide and styled lines:"),
		LC_INTERIORS,	TEXT("LC_INTERIORS     Can do interiors:")
	};

	static BITS poly[] =
	{
		PC_POLYGON,		TEXT("PC_POLYGON       Can do alternate fill polygon: "),
		PC_RECTANGLE,	TEXT("PC_RECTANGLE     Can do rectangle: "),
		PC_WINDPOLYGON,	TEXT("PC_WINDPOLYGON   Can do winding number fill polygon:"),
		PC_SCANLINE,	TEXT("PC_SCANLINE      Can do scanlines:"),
		PC_WIDE,		TEXT("PC_WIDE          Can do wide borders:"),
		PC_WIDESTYLED,	TEXT("PC_WIDESTYLED    Can do wide and styled borders:"),
		PC_INTERIORS,	TEXT("PC_INTERIORS     Can do interiors:")
	};

	static BITS text[] =
	{
		TC_OP_CHARACTER,	TEXT("TC_OP_CHARACTER  Can do charcter output precision:"),
		TC_OP_STROKE,		TEXT("TC_OP_STROKE     Can do stroke output precision:"),
		TC_CP_STROKE,		TEXT("TC_CP_STROKE     Can do charcter clip precision:"),
		TC_CR_90,			TEXT("TC_CR_90         Can do 90 degree charcter output precision:"),
		TC_CR_ANY,			TEXT("TC_CR_ANY        Can do charcter ratation:"),
		TC_SF_X_YINDEP,		TEXT("TC_SF_X_YINDEP   Can doscaling independent of x and y:"),
		TC_SA_DOUBLE,		TEXT("TC_SA_DOUBLE     Can do doubled character for scaling:"),
		TC_SA_INTEGER,		TEXT("TC_SA_INTEGER    Can do integer multiples ofr scaling:"),
		TC_SA_CONTIN,		TEXT("TC_SA_CONTIN     Can do any multiples ofr exact scaling:"),
		TC_EA_DOUBLE,		TEXT("TC_EA_DOUBLE     Can do double weight characters:"),
		TC_IA_ABLE,			TEXT("TC_IA_ABLE       Can do italicizing:"),
		TC_UA_ABLE,			TEXT("TC_UA_ABLE       Can do underlining:"),
		TC_SO_ABLE,			TEXT("TC_SO_ABLE       Can do strikeouts:"),
		TC_RA_ABLE,			TEXT("TC_OP_CHARACTER  Can do raster fonts:"),
		TC_VA_ABLE,			TEXT("TC_VA_ABLE       Can do vector fonts:")
	};

	static struct
	{
		int     iIndex;
		TCHAR* szTitle;
		BITS(*pbits)[];
		int     iSize;
	}
	bitinfo[] =
	{
		 CURVECAPS,  TEXT("CURVCAPS (Curve Capabilities)"),
			  (BITS(*)[]) curves, sizeof(curves) / sizeof(curves[0]),
		 LINECAPS,   TEXT("LINECAPS (Line Capabilities)"),
			  (BITS(*)[]) lines, sizeof(lines) / sizeof(lines[0]),
		 POLYGONALCAPS, TEXT("POLYGONALCAPS (Polygonal Capabilities)"),
			  (BITS(*)[]) poly, sizeof(poly) / sizeof(poly[0]),
		 TEXTCAPS,   TEXT("TEXTCAPS (Text Capabilities)"),
			  (BITS(*)[]) text, sizeof(text) / sizeof(text[0])
	};

	static TCHAR szBuffer[80];
	BITS(*pbits)[] = bitinfo[iType].pbits;
	int          i, iDevCaps = GetDeviceCaps(hdcInfo, bitinfo[iType].iIndex);

	TextOut(hdc, cxChar, cyChar, bitinfo[iType].szTitle,
		lstrlen(bitinfo[iType].szTitle));

	for (i = 0; i < bitinfo[iType].iSize; i++)
		TextOut(hdc, cxChar, (i + 3) * cyChar, szBuffer,
			wsprintf(szBuffer, TEXT("%-70s %3s"), (*pbits)[i].szDesc,
				iDevCaps & (*pbits)[i].iMask ? TEXT("Yes") : TEXT("No")));
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值