VC++ 用于调试的printf显示控件

习惯了单片机上面的C语言,使用printf进行输出调试,上位机虽然可以使用日志进行调试,但是很多时候做通信,需要实时显示16进制HEX编码,很不方便,因此自己写了一个使用richTextBox显示的自定义控件,用于刷新格式化的数据到界面,这个地方千万不用使用textBox,会非常卡的,长时间运行各种不稳定,基本的原理就是自定义一个printf函数,将格式化的字符串写入到FIFO中,使用一个异步线程将char转换为string,再使用异步委托显示到richTextBox中,这样可以高效的显示数据,并且耗用极低的CPU,但是内存占用会增加10-40MB,因为string特别占用内存,效果如下:


显示的调试信息效果

下面看使用方法,需要以下4个文件


1.将自定义控件添加到一个容器中。

DebugPrintfControl ^mDebugPrintfControl;			//调试
//调试界面初始化
this->mDebugPrintfControl = gcnew DebugPrintfControl(2*1024*1024);
this->mDebugPrintfControl->Dock = System::Windows::Forms::DockStyle::Fill;					//填充
this->panel7->Controls->Add(this->mDebugPrintfControl);
this->mDebugPrintfControl->SetDisplay(false);			//默认关闭显示打印
2.使用方法,使用有2种,一种是专用的数据包打印,一种就是通用的printf打印

USER_DEBUG.Printf("程序启动\r\n");
sprintf_s(buff, 8 * 1024, "\r\n->收到数据(%d字节)\r\n", Data->DataLen);
USER_DEBUG.PrintfDataPack(buff, Data->DataBuff, Data->DataLen);

3.代码如下

DebugPrintf.c

#include "StdAfx.h"
#include "DebugPrintf.h"
#include <stdio.h>   
#define WIN32_LEAN_AND_MEAN
#include <windows.h> 
#include <MyFIFO.h> 
#include <stdlib.h>     
#include <stdarg.h>	//定义成一个可变参数列表的指针  
#include "crtdbg.h"
//2017-11-29 修复C++异常处理
//2017-12-23 增加缓冲区为5K,并且增加数据包打印输出


DebugPrintf USER_DEBUG;	//调试输出

DebugPrintf::DebugPrintf()
{
	this->pDebugFifo = new MyFIFO(128, 5*1024 + 32);
}


DebugPrintf::~DebugPrintf()
{
	delete(this->pDebugFifo);
}


//调试信息输出-注意单次长度不要超过5K
DWORD DebugPrintf::Printf(const char * format, ...)
{
	char *buff = new char[1024*5 + 32];
	DWORD len;
	va_list ap;

	try
	{
		va_start(ap, format);
		len = vsnprintf(buff, 1024*5+32, format, ap);
		va_end(ap);
		this->pDebugFifo->FIFO_Write((BYTE *)buff, len);
	}
	catch (...)
	{
		len = 0;
	}

	delete []buff;

	return len;
}


//数据包打印输出
DWORD DebugPrintf::PrintfDataPack(char *pInfo, BYTE *pDataPack, WORD DataLen)
{
	char *buff = new char[1024 * 5 + 32];
	DWORD len = 0;
	if (pDataPack == nullptr) return 0;

	try
	{
		if (pInfo != nullptr)
		{
			len = strlen(pInfo);
			if (len > 400)
			{
				len = 400;
				pInfo[400] = 0;	//限制长度
			}
			if (len > 0)
			{
				len = sprintf_s(buff, 5 * 1024, pInfo);	//先添加信息头
			}
		}
		else len = 0;
		//循环打印报文
		if (DataLen > 1500) DataLen = 1500;	//限制长度
		for (int i = 0; i < DataLen; i++)
		{
			len += sprintf_s(&buff[len], 5 * 1024 - len, "%02X ", pDataPack[i]);
		}
		this->pDebugFifo->FIFO_Write((BYTE *)buff, len); //写入到FIFO中
	}
	catch (...)
	{
		len = 0;
	}

	delete []buff;

	return len;
}



DebugPrintf.h

扫描二维码关注公众号,回复: 1373974 查看本文章
#pragma once
#ifndef	_DEBUG_PRINTF_
#define _DEBUG_PRINTF_
#define WIN32_LEAN_AND_MEAN
#include <windows.h> 
#include <MyFIFO.h> 




class DebugPrintf
{
private:MyFIFO *pDebugFifo;

public:
	DebugPrintf();
	~DebugPrintf();
	DWORD Printf(const char * format, ...);	//调试输出
	DWORD PrintfDataPack(char *pInfo, BYTE *pDataPack, WORD DataLen);//数据包打印输出
	MyFIFO *GetFifo() //获取调试数据FIFO
	{
		return this->pDebugFifo;
	}
};

extern DebugPrintf USER_DEBUG;	//调试输出

#endif //_DEBUG_PRINTF_
自定义控件

DebugPrintfControl.c

#include "StdAfx.h"
#include "DebugPrintfControl.h"
#include "DebugPrintf.h"
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#include <MyFIFO.h> 
#include <userlib.h> 
#include <SystemLog.h> 

#define  CLASS_NAME  WindowsFormsApplication_c01::DebugPrintfControl		//类名称定义

//异步线程数据打印处理
void CLASS_NAME::BackgroundWorker1_DoWork(void)
{
	MyFIFO *pFifo = USER_DEBUG.GetFifo();								//获取调试FIFO缓冲区
	BYTE *p;
	DWORD len;
	DWORD cnt;
	DWORD i;

	while (1)
	{
		try
		{
			cnt = pFifo->FIFO_GetDataNumber();							//获取缓冲区中数据数量
			if (cnt > 30)
			{
				cnt = 30;
			}
			if (cnt > 0)
			{
				this->mStringBuilder->Clear();			//清空
				for (i = 0; i < cnt; i++)				//将数据集中到一起,一次打印
				{
					if (pFifo->FIFO_ReadNotCopy(&p, &len) == true)
					{
						try
						{
							if (this->isShow == true)	//开启了显示才显示数据
							{
								p[len] = 0;
								this->mStringBuilder->Append(CharToString(p));
							}
						}
						catch (Exception^ e)
						{
							SYS_LOG.Write(__FILE__ + __LINE__ + e->Message);
							Sleep(10);
						}
						pFifo->FIFO_ReduceOne();
					}
				}
				this->DebugPrintString(this->mStringBuilder->ToString());	//一次打印
			}
			
			Sleep(300);		//降低刷新率,尽量一次刷新,保证系统的稳定性
		}
		catch (Exception^ e)
		{
			SYS_LOG.Write(__FILE__ + __LINE__ + e->Message);
			Sleep(100);
		}	
	}
}



//存储数据为txt
void CLASS_NAME::SaveDataToText(void)
{
	if (this->richTextBox1->Text->Length == 0)
	{
		System::Windows::Forms::MessageBox::Show("数据为空,无法进行存储!", "错误", System::Windows::Forms::MessageBoxButtons::OK,
			System::Windows::Forms::MessageBoxIcon::Error);
		return;
	}
	//进行数据存储
	//弹出保存对话框
	this->saveFileDialog1->Filter = "文本文件(*.txt)|*.txt|所有文件(*.*)|*.*";	//支持的扩展名
	this->saveFileDialog1->FileName = "调试日志记录文件.txt";
	//主设置默认文件extension(可以不设置)
	this->saveFileDialog1->DefaultExt = "txt";
	System::Windows::Forms::DialogResult result = this->saveFileDialog1->ShowDialog();	//显示保存对话框
	if (result == System::Windows::Forms::DialogResult::OK)	//点击了保存
	{
		array<BYTE> ^data;
		System::Text::Encoding^ unicode = System::Text::Encoding::UTF8;
		try
		{
			System::IO::FileStream ^fs = System::IO::File::Create(this->saveFileDialog1->FileName->ToString());
			String ^str = this->richTextBox1->Text->Replace("\n", "\r\n"); //替换换行符
			data = unicode->GetBytes(str); 
			if (data == nullptr || data->Length == 0)
			{
				System::Windows::Forms::MessageBox::Show("数据为空,存储失败!", "错误", System::Windows::Forms::MessageBoxButtons::OK,
					System::Windows::Forms::MessageBoxIcon::Error);
				return;
			}
			fs->Write(data, 0, data->Length);	//写入数据
			fs->Close();						//关闭文件
			if (System::Windows::Forms::MessageBox::Show("保存数据成功,是否打开文件!", "存储成功", System::Windows::Forms::MessageBoxButtons::YesNo,
				System::Windows::Forms::MessageBoxIcon::Question) == System::Windows::Forms::DialogResult::Yes)
			{

				//打开文件
				//检查文件是否存在
				if (!System::IO::File::Exists(this->saveFileDialog1->FileName->ToString()))
				{
					System::Windows::Forms::MessageBox::Show("打开文件失败,文件不存在!", "错误", System::Windows::Forms::MessageBoxButtons::OK,
						System::Windows::Forms::MessageBoxIcon::Error);
					return;
				}
				//调用默认程序打开文件
				System::Diagnostics::Process::Start(this->saveFileDialog1->FileName->ToString());
			}

		}
		catch (System::IO::IOException^ e)
		{
			System::Windows::Forms::MessageBox::Show("文件被占用,请关闭文件或修改导出文件名!", "错误", System::Windows::Forms::MessageBoxButtons::OK,
				System::Windows::Forms::MessageBoxIcon::Error);
			return;
		}
	}

}



//显示开关设置
void CLASS_NAME::SetDisplay(bool isShow)
{
	this->isShow = isShow;
}

DebugPrintfControl.h

#pragma once
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#include "DebugPrintf.h"
#include "SystemLog.h"
//2017-12-23 增加删除超出部分文本功能,增加显示开关,增加自动滚动设置
//2018-01-10 优化TextBox占用率

using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Text;
using namespace System::Drawing;


namespace WindowsFormsApplication_c01 {

	/// <summary>
	/// DebugPrintfControl 摘要
	/// </summary>
	public ref class DebugPrintfControl : public System::Windows::Forms::UserControl
	{
		String ^NormalInfo;	//正常打印信息
		String ^ErrorInfo;	//故障信息
	private: System::Windows::Forms::ToolStripMenuItem^  显示开ToolStripMenuItem;
			 delegate void Delegate_DebugString(String ^pString);//UI托管
		Delegate_DebugString ^mDataDebug;					//数据包调试
	private: System::Windows::Forms::Timer^  timer1;
	private: System::Windows::Forms::TextBox^  textBox2;
			 bool isShow;		//是否显示
	private: System::Windows::Forms::ToolStripMenuItem^  自动滚动开ToolStripMenuItem;
			 bool isLogAutoScroll;							//是否自动滚动
			 StringBuilder ^mStringBuilder;
	private: System::Windows::Forms::RichTextBox^  richTextBox1;
			 DWORD ShowStrSize;								//显示的字符串最大长度
	public:
		DebugPrintfControl(DWORD ShowStrSize)
		{
			this->ShowStrSize = ShowStrSize;
			if (this->ShowStrSize < 200) this->ShowStrSize = 200;
			if (this->ShowStrSize > 100 * 1024 * 1024) this->ShowStrSize = 100 * 1024 * 1024;
			InitializeComponent();
			//
			//TODO:  在此处添加构造函数代码
			//
			this->isShow = true;									//默认开启显示
			this->isLogAutoScroll = true;							//是否自动滚动
			this->mStringBuilder = gcnew StringBuilder(1024*1024);

			mDataDebug = gcnew Delegate_DebugString(this, &WindowsFormsApplication_c01::DebugPrintfControl::DebugToString);		//数据包调试
			this->backgroundWorker1->RunWorkerAsync();	//执行异步线程
		}

	protected:
		/// <summary>
		/// 清理所有正在使用的资源。
		/// </summary>
		~DebugPrintfControl()
		{
			if (components)
			{
				delete components;
			}
		}

		//任务
		void BackgroundWorker1_DoWork(void);
		//存储数据为txt
		void SaveDataToText(void);

		//打印debug信息,打印string
		void DebugToString(String ^pStr)
		{
			int temp;

			if (pStr == nullptr) return;


			try
			{
				
				temp = this->richTextBox1->TextLength + pStr->Length;	//计算总长度
				if (temp > (this->ShowStrSize - 100))
				{
					temp -= (this->ShowStrSize - 100);
					//删掉最前面的
					this->richTextBox1->Select(0, temp);				//选择超出部分
					this->richTextBox1->SelectedText = "";				//设置超出部分为空,相当于删掉超出部分的数据
				}
				//使用 AppendText 后会自动滑动到最后面,不受控制
				this->richTextBox1->AppendText(pStr);					//可以极大的降低CPU占用率
			}
			catch (Exception^ e)
			{
				SYS_LOG.Write(__FILE__ + __LINE__ + e->Message);
				Sleep(100);		//延时5秒,防止不停崩溃消耗电脑资源
			}



			


			//限制长度
			/*temp = this->textBox1->TextLength + pStr->Length;	//计算总长度
			if (temp > (1024*1000 - 100))
			{
				temp -= (1024*1000 - 100);
				//删掉最前面的
				this->textBox1->Select(0, temp);				//选择超出部分
				this->textBox1->SelectedText = "";				//设置超出部分为空,相当于删掉超出部分的数据
			}

			this->textBox1->Text += pStr;

			//下面两行代码可以让数据一直显示在最下面
			if (this->isLogAutoScroll == true) //自动滚动开启了
			{
				this->textBox1->SelectionStart = this->textBox1->Text->Length;
				this->textBox1->ScrollToCaret();
			}*/		
		}

		//调用托管打印数据
		void DebugPrintString(String ^pStr)
		{
			try
			{
				this->BeginInvoke(mDataDebug, pStr);		//打印实时日志
			}
			catch (Exception^ e)
			{
				SYS_LOG.Write(__FILE__ + __LINE__ + e->Message);
				Sleep(100);		//延时5秒,防止不停崩溃消耗电脑资源
			}
			
		}
	public:
		void SetDisplay(bool isShow);					//显示开关设置



	protected:
	private: System::Windows::Forms::ContextMenuStrip^  contextMenuStrip1;
	private: System::Windows::Forms::ToolStripMenuItem^  另存为ToolStripMenuItem;
	private: System::Windows::Forms::ToolStripMenuItem^  清空显示ToolStripMenuItem;
	private: System::Windows::Forms::SaveFileDialog^  saveFileDialog1;
	private: System::ComponentModel::BackgroundWorker^  backgroundWorker1;
	private: System::ComponentModel::IContainer^  components;

	private:
		/// <summary>
		/// 必需的设计器变量。
		/// </summary>


#pragma region Windows Form Designer generated code
		/// <summary>
		/// 设计器支持所需的方法 - 不要
		/// 使用代码编辑器修改此方法的内容。
		/// </summary>
		void InitializeComponent(void)
		{
			this->components = (gcnew System::ComponentModel::Container());
			this->contextMenuStrip1 = (gcnew System::Windows::Forms::ContextMenuStrip(this->components));
			this->另存为ToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->清空显示ToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->显示开ToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->自动滚动开ToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->saveFileDialog1 = (gcnew System::Windows::Forms::SaveFileDialog());
			this->backgroundWorker1 = (gcnew System::ComponentModel::BackgroundWorker());
			this->timer1 = (gcnew System::Windows::Forms::Timer(this->components));
			this->textBox2 = (gcnew System::Windows::Forms::TextBox());
			this->richTextBox1 = (gcnew System::Windows::Forms::RichTextBox());
			this->contextMenuStrip1->SuspendLayout();
			this->SuspendLayout();
			// 
			// contextMenuStrip1
			// 
			this->contextMenuStrip1->Items->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(4) {
				this->另存为ToolStripMenuItem,
					this->清空显示ToolStripMenuItem, this->显示开ToolStripMenuItem, this->自动滚动开ToolStripMenuItem
			});
			this->contextMenuStrip1->Name = L"contextMenuStrip1";
			this->contextMenuStrip1->Size = System::Drawing::Size(149, 92);
			this->contextMenuStrip1->Opening += gcnew System::ComponentModel::CancelEventHandler(this, &DebugPrintfControl::contextMenuStrip1_Opening);
			// 
			// 另存为ToolStripMenuItem
			// 
			this->另存为ToolStripMenuItem->Name = L"另存为ToolStripMenuItem";
			this->另存为ToolStripMenuItem->Size = System::Drawing::Size(148, 22);
			this->另存为ToolStripMenuItem->Text = L"另存为(.txt)";
			this->另存为ToolStripMenuItem->Click += gcnew System::EventHandler(this, &DebugPrintfControl::另存为ToolStripMenuItem_Click);
			// 
			// 清空显示ToolStripMenuItem
			// 
			this->清空显示ToolStripMenuItem->Name = L"清空显示ToolStripMenuItem";
			this->清空显示ToolStripMenuItem->Size = System::Drawing::Size(148, 22);
			this->清空显示ToolStripMenuItem->Text = L"清空显示";
			this->清空显示ToolStripMenuItem->Click += gcnew System::EventHandler(this, &DebugPrintfControl::清空显示ToolStripMenuItem_Click);
			// 
			// 显示开ToolStripMenuItem
			// 
			this->显示开ToolStripMenuItem->Name = L"显示开ToolStripMenuItem";
			this->显示开ToolStripMenuItem->Size = System::Drawing::Size(148, 22);
			this->显示开ToolStripMenuItem->Text = L"显示:开";
			this->显示开ToolStripMenuItem->Click += gcnew System::EventHandler(this, &DebugPrintfControl::显示开ToolStripMenuItem_Click);
			// 
			// 自动滚动开ToolStripMenuItem
			// 
			this->自动滚动开ToolStripMenuItem->Name = L"自动滚动开ToolStripMenuItem";
			this->自动滚动开ToolStripMenuItem->Size = System::Drawing::Size(148, 22);
			this->自动滚动开ToolStripMenuItem->Text = L"自动滚动:开";
			this->自动滚动开ToolStripMenuItem->Visible = false;
			this->自动滚动开ToolStripMenuItem->Click += gcnew System::EventHandler(this, &DebugPrintfControl::自动滚动开ToolStripMenuItem_Click);
			// 
			// backgroundWorker1
			// 
			this->backgroundWorker1->WorkerReportsProgress = true;
			this->backgroundWorker1->WorkerSupportsCancellation = true;
			this->backgroundWorker1->DoWork += gcnew System::ComponentModel::DoWorkEventHandler(this, &DebugPrintfControl::backgroundWorker1_DoWork);
			this->backgroundWorker1->ProgressChanged += gcnew System::ComponentModel::ProgressChangedEventHandler(this, &DebugPrintfControl::backgroundWorker1_ProgressChanged);
			this->backgroundWorker1->RunWorkerCompleted += gcnew System::ComponentModel::RunWorkerCompletedEventHandler(this, &DebugPrintfControl::backgroundWorker1_RunWorkerCompleted);
			// 
			// timer1
			// 
			this->timer1->Enabled = true;
			this->timer1->Interval = 1000;
			this->timer1->Tick += gcnew System::EventHandler(this, &DebugPrintfControl::timer1_Tick);
			// 
			// textBox2
			// 
			this->textBox2->Anchor = static_cast<System::Windows::Forms::AnchorStyles>((System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Right));
			this->textBox2->BackColor = System::Drawing::SystemColors::ScrollBar;
			this->textBox2->BorderStyle = System::Windows::Forms::BorderStyle::None;
			this->textBox2->Font = (gcnew System::Drawing::Font(L"微软雅黑", 11.25F, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point,
				static_cast<System::Byte>(134)));
			this->textBox2->ForeColor = System::Drawing::Color::FromArgb(static_cast<System::Int32>(static_cast<System::Byte>(192)), static_cast<System::Int32>(static_cast<System::Byte>(0)),
				static_cast<System::Int32>(static_cast<System::Byte>(0)));
			this->textBox2->Location = System::Drawing::Point(787, 8);
			this->textBox2->Name = L"textBox2";
			this->textBox2->Size = System::Drawing::Size(68, 20);
			this->textBox2->TabIndex = 1;
			this->textBox2->Text = L"显示关闭";
			this->textBox2->TextAlign = System::Windows::Forms::HorizontalAlignment::Center;
			this->textBox2->Visible = false;
			// 
			// richTextBox1
			// 
			this->richTextBox1->ContextMenuStrip = this->contextMenuStrip1;
			this->richTextBox1->DetectUrls = false;
			this->richTextBox1->Dock = System::Windows::Forms::DockStyle::Fill;
			this->richTextBox1->HideSelection = false;
			this->richTextBox1->Location = System::Drawing::Point(0, 0);
			this->richTextBox1->Name = L"richTextBox1";
			this->richTextBox1->ReadOnly = true;
			this->richTextBox1->ScrollBars = System::Windows::Forms::RichTextBoxScrollBars::ForcedVertical;
			this->richTextBox1->Size = System::Drawing::Size(882, 426);
			this->richTextBox1->TabIndex = 2;
			this->richTextBox1->Text = L"";
			// 
			// DebugPrintfControl
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->Controls->Add(this->textBox2);
			this->Controls->Add(this->richTextBox1);
			this->Name = L"DebugPrintfControl";
			this->Size = System::Drawing::Size(882, 426);
			this->contextMenuStrip1->ResumeLayout(false);
			this->ResumeLayout(false);
			this->PerformLayout();

		}
#pragma endregion
	private: System::Void 清空显示ToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
		this->richTextBox1->Clear();
	}
	private: System::Void 另存为ToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
		this->SaveDataToText();
	}
			 //异步线程
	private: System::Void backgroundWorker1_DoWork(System::Object^  sender, System::ComponentModel::DoWorkEventArgs^  e) {
		this->BackgroundWorker1_DoWork();
	}
			 //状态改变,刷新UI
private: System::Void backgroundWorker1_ProgressChanged(System::Object^  sender, System::ComponentModel::ProgressChangedEventArgs^  e) {
}
			//结束
private: System::Void backgroundWorker1_RunWorkerCompleted(System::Object^  sender, System::ComponentModel::RunWorkerCompletedEventArgs^  e) {
}
		 //显示开关切换
private: System::Void 显示开ToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
	if (this->isShow == true)	//开启了显示
	{
		this->isShow = false;
		this->显示开ToolStripMenuItem->Text = "显示:关";
	}
	else
	{
		this->isShow = true;
		this->显示开ToolStripMenuItem->Text = "显示:开";		
	}
}
		 //弹出时更新菜单显示开关名称
private: System::Void contextMenuStrip1_Opening(System::Object^  sender, System::ComponentModel::CancelEventArgs^  e) {
	if (this->isShow == true)	//开启了显示
	{
		this->显示开ToolStripMenuItem->Text = "显示:开";
	}
	else
	{
		this->显示开ToolStripMenuItem->Text = "显示:关";
	}
}
		 //1秒定时器,如果显示关闭后进行提示
private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
	if (isShow == false) //显示关闭了,闪烁提示
	{
		if (this->textBox2->Visible == false)
		{
			this->textBox2->Visible = true;
		}
		else
		{
			this->textBox2->Visible = false;
		}
	}
	else //影藏提示
	{
		this->textBox2->Visible = false;
	}
}
		 //自动滚动设置
private: System::Void 自动滚动开ToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
	if (this->isLogAutoScroll == true) //自动滚动开启了
	{
		this->isLogAutoScroll = false;
		this->自动滚动开ToolStripMenuItem->Text = "自动滚动:关";
	}
	else
	{
		this->isLogAutoScroll = true;
		this->自动滚动开ToolStripMenuItem->Text = "自动滚动:开";
	}
}
};
}



猜你喜欢

转载自blog.csdn.net/cp1300/article/details/79033074
今日推荐