HelloWorldBasic项目分析杂记

Neurocomputing 投稿指南 Generation Information:选择论文所属领域。上传附件(利益声明,手稿,摘要)审稿人偏好:可以选择期待的审稿人。 阅读详情

Symbian是一个广泛运行于手机和移动设备上的操作系统,由于手机和PC不同,它没有统一的标准,其硬件配置及其所导致的用户界面都差异巨大(譬如有的手机有触笔而有的没有),Symbian提供基本服务和一套比较通用的UI层(UIKON),取得Symbian授权的手机厂家一般都会针对自己具体型号的手机设计自己的用户界面,比较著名的是Nokia的Series 60平台(用于Nokia 7650、Nokia N-Gage、Siemens SX1等)和Sony Ericssion的UIQ平台(UIQ平台本身是Symbian的原生UI,不过现在Symbian把它卖给了Sony Ericssion)。前者针对单手操作的按键式手机,没有触摸屏和手写笔,一般有一个4方向导航键,后者运行于有较大屏幕,带有触摸屏的手机。
 

一、模块分析

AVKON是Nokia在Symbian的UIKON UI层基础上开发出来的专用于S60的UI层,和MFC有点相似之处。HelloWorld项目是基于此框架开发的。

首先,每个编译出来的GUI应用程序(*.app)实际上是一种多态dll,不是一个通常意义上的类似于exe那样的可执行模块。当执行一个应用程序时,OS把app文件名作为参数传递给apprun.exe,由apprun.exe创建应用程序进程并把*.app加载到新创建的进程的地址空间,因此,每个app都导出了一个函数NewApplication(),它是用序号导出的。以Helloworld工程为例,察看目录%SDKROOT%/6.1/Series60/Epoc32/BUILD/SYMBIAN/6.1/SERIES60/SERIES60EX/HELLOWORLD/GROUP/HELLOWORLD/WINS下面的HELLOWORLD.def文件可以看出这一点。NewApplication的函数体在Helloworld.cpp文件中,它所做的工作很简单,仅仅是new一个CHelloWorldApplication对象然后返回其指针。在这个文件中还有另一个全局函数E32Dll,此函数意义等同于Windows中dll编程的DllMain函数,是DLL的Entry Point,在此可以进行初始化TLS(Thread Local Storage)的动作,每个Symbian程序都必须有这个函数。当应用程序准备运行的时候,E32Dll会最先被框架所调用,框架会传进来一个参数aReason,此参数有4种可能值:EDllProcessAttach, EDllThreadAttach, EDllThreadDetach or EDllProcessDetach,在这里直接返回KErrNone,表示没有错误。

接下来分析应用程序类CHelloWorldApplication。这个类按照官方文档的说法就是“An Application that creates the new blank document and defines the application UID”,意思就是这个类是负责new出一个空白文档,并定义应用程序的UID。这个类只有两个成员函数:AppDllUid和CreateDocumentL,分别考察之。AppDllUid仅仅返回一个预先定义写死的一个UID,CreateDocumentL函数用CHelloWorldApplication应用程序对象的this指针new出一个文档对象出来CHelloWorldDocument(注:函数名后面加L表示此函数可以异常退出)。这个应用程序类并没有提供构造函数,按照C++语言规范,编译器将生成一个默认的构造函数,我想,可能是因为CHelloWorldApplication类没有增加任何数据成员(仅仅多了两个函数成员),所以无需自己提供构造函数来完成额外的构造动作吧。追寻到其祖先类CEikApplication,可以发现其构造函数是Protected的,这是采用两步构造的典型特征。通过将构造函数声明为Protected,可以防止用户绕过两步构造来生成一个C类对象(这个小trick和MFC中Dynamic Create是一样的),迫使用户必须通过静态函数NewL或者NewLC来生成对象。

然后是文档类CHelloWorldDocument,这个类的作用是“A Document object that represents the data model and is used to construct the App UI”,感觉有点类似于MFC中的文档类,负责表示数据,创建UI。首先映入眼帘的是构造函数/析构函数。这一对函数在这里是空函数,先不去管它。剩下的3个成员函数,NewL/NewLC和ConstructL用于完成两步构造。所谓两段构造,是Symbian里面引入的一个概念,因为C++的构造函数和析构函数如果失败,是不允许抛出异常的,如果直接把大量的初始化代码放在构造函数里的话,会使得构造函数失败的几率增加,一旦构造失败,就很难对构造过程中半途而废的“烂尾楼”进行收拾,Symbian提出的两步构造就是把所有可能导致失败的代码全部移出构造函数,放在成员函数ConstructL()里进行,在构造函数执行完毕后再调用该ConstructL完成后续构造动作,以保证构造函数绝对不会失败,这一过程称为“两步构造”。与此相关,Symbian的一些类经常添加了一对函数:NewL和NewLC,来实现两步构造,这两个函数被声明为static的,回忆C++的语法定义,static成员函数实际上是独立于类之外的,它们可以在类的任何一个实例存在之前被调用,因此Symbian中往往用显式调用这两个函数的办法来创建类的实例,我们先看一下代码:

CHelloWorldDocument* CHelloWorldDocument::NewL(CEikApplication& aApp) 
{ 
CHelloWorldDocument* self = NewLC(aApp); 
//构造过程成功,把指针从Cleanup Stack中弹出,因为已无保护必要 
CleanupStack::Pop(self); 
return self; 
} 

CHelloWorldDocument* CHelloWorldDocument::NewLC(CEikApplication& aApp) 
{ 
CHelloWorldDocument* self = new (ELeave) CHelloWorldDocument(aApp); //第一步构造 

//self指向一个构造了一半的实例,将其推入Cleanup Stack,防止后续构造失败 
CleanupStack::PushL(self); 
self->ConstructL(); //第二步构造 
return self; 
} 

 

可以看出,NewL调用NewLC,NewLC先new出一个CHelloWorldDocument对象的实例(这是第一步构造,new已经被重载了,ELeave是它的参数,表示当new失败的时候会异常退出),然后将指针推入Cleanup Stack,紧接着再调用ConstructL(这是第二步构造),NewL和NewLC的区别是:NewL在堆上创建实例,当出现内存不足错误时,就异常退出;NewLC在堆上创建实例并将其推入到Cleanup Stack中。如果内存不足就异常退出。(注:后缀L就是Leave的意思,表示可能异常退出,C是Cleanup Stack的意思,表示会将在堆上创建的对象推入Cleanup Stack)。

最后剩下一个函数CreateAppUiL,这个函数负责创建UI,向框架返回一个指向UI对象的指针,值得注意的是UI类的构造过程并不是两步构造,它的构造函数在CreateAppUiL中被调用后,框架得到UI对象的指针,接着框架再主动调用UI类的ConstructL函数完成UI对象的全部构造工作,UI对象的所有权也转交给框架,因此文档类并不否则销毁UI对象。

第3个类是UI类CHelloWorldAppUi,如前所述,UI对象不是基于两步构造,没有提供NewL和NewLC函数。官方帮助中对它的描述是“An App Ui (Application User Interface) object that handles the commands generated from menu options”。可见它是专用于处理用户命令输入的。我们先分析ConstructL函数,它先调用基类的BaseConstructL()函数,完成一些诸如读取资源一类的工作;接着,用两步构造创建View类的实例(View类是负责在屏幕上进行显示的,下面会有介绍),View类由UI类拥有,在CHelloWorldAppUi类中有一个指针成员iAppView指向所构造的View对象,View类的析构在UI类的析构函数中完成;最后调用AddToStackL(iAppView)把View对象加到Control Stack上(当UI对象被销毁的时候必须把View对象从Control Stack上拿下来,参见CHelloWorldAppUi类的析构函数),这样做是为了确保应用程序能响应用户的按键动作,只要View对象在Control Stack上,无论用户什么时候按下按键,OfferKeyEventL 函数就会被调用,这个函数有两个参数分别表示按键事件的类型(Key down、Key press或者Key up)以及所按下的按键的编码。接下来要讲UI的主要任务——处理用户命令输入。这是在HandleCommandL成员函数中进行的。这个函数大体框架类似于Windows SDK编程中的窗口函数——一个大的switch结构,整体结构还是很好理解的,基本上望文知义,几个aCommand定义,比如EHelloWorldCommand1和EAknSoftkeyExit,是在Helloworld.rss(这是资源文件,有点类似于VC里的res文件)里定义的,EHelloWorldCommand1指左软键Option弹出菜单中的“Hello”菜单项,EAknSoftkeyExit指“Hello”下面的“Exit”菜单项,唯一是EEikCmdExit没有找到定义所在,可能是框架预定义的。_LIT宏定义了一个TLitC类的实例message,并初始化为第二个参数给出的串,接着new出一个CAknInformationNote对象(这个对象的作用大概有点象MessageBox),显示message中的字符串。需要特别指出的是,在最后的Default分支中有一个Panic函数,Panic的字面意思是“惊慌, 恐慌”,我的理解,panic code大概就是error code的意思,这个函数大概就是一个返回一个error code,在Helloworld.pan文件中定义了EHelloWorldBasicUi=1。

第4个类是View类,专门用于在屏幕上显示数据的。这个类一共6个成员函数,构造函数和析构函数用于第一步构造,此处是空的,NewL和NewLC的作用如前所述,这几个老面孔就不提了。我们分析的重点在Draw函数,它类似MFC的OnPaint函数,框架在需要重绘的时候会去调用它,程序员不应该手动调用它,因为在调用Draw之前必须先激活(Activated)系统的GC(Graphics Context)——类似DC的一个概念。如果我们想重绘窗口怎么办呢?答案是使用DrawNow函数,这样会激发框架去调用Draw,(当然如果非要手动直接调用Draw也是可以的,但是必须先ActivateGc,Draw完之后再DeactivateGc)。最后一点要注意的是,Draw函数是绝不允许异常退出(Leave)的,因为前面讲过,Draw函数是程序员编写的,在程序运行过程中,有可能被框架自动调用,如果Draw函数向框架抛出异常,框架不可能未卜先知地知道发生了什么异常,又如何处理错误呢?所以Draw函数必须使用TRAP宏来主动捕获错误。

 

二、启动顺序

1.应用程序被启动,框架加载应用程序dll(即生成的app文件),调用其E32Dll函数,这个过程与Windows下加载Dll的过程极其类似。

2.框架调用应用程序dll导出的NewApplication函数。此函数创建一个CHelloWorldApplication类的实例,向调用它的框架返回一个指向该应用程序对象的指针,接着框架用此指针完成应用程序的后续创建工作。

3.框架调用AppDllUid取得此程序的UID。UID的一个作用是用于检查此程序是否已经有一个实例在运行中了,若是,则不再重复启动一个新实例,而是切换到已经在运行的应用程序。

 4.框架调用CHelloWorldApplication 的成员函数CreateDocumentL,此函数创建一个Document类的实例并返回一个指向被创建的Document对象的指针。这样框架就可以直接调用Document类的成员函数。在此,Document类的创建是基于Symbian OS的两步创建,使用了Document类的静态成员函数NewL。

5.框架再次调用AppDllUid,检查是否需要从文件系统中加载文件。HelloWorld项目因为不需要对任何信息进行持久化保存,所以没有相关联的文件。

6.框架调用Document对象的CreateAppUiL函数,创建一个UI对象并取得其指针(注意CreateAppUiL函数仅仅是new出了一个UI对象,也就是只调用了UI对象的构造函数,按照Symbian的两步构造语意,UI对象尚未真正构造完毕)。

7.框架调用UI对象的ConstructL函数来完成UI对象的构造(在这里,框架通过分别调用UI对象的构造函数和ConstructL函数来完成UI对象的构造,这样可以使得框架可以在UI对象完全诞生之前完成任何必须的初始化工作),在ConstructL函数中,先调用了基类的BaseConstructL函数,完成诸如读取和应用程序相关联的资源等一类的工作;接着,调用View类的NewL函数创建View对象(使用两步构造)。

8.框架调用View对象的Draw函数,此处的Draw函数会在显示一个空白的屏幕。

9.当用户选择Option菜单的时候,框架就调用UI对象的HandleCommandL函数,并向此函数传递一个aCommand参数,以表明用户选取的是哪个菜单项。UI针对不同的菜单项执行相应的动作,此处的动作是创建一个Information note并显示之。
52、基于格的具有解密密钥暴露抗性的可撤销(分层)身份基加密方案 本文提出了首个基于格的具有解密密钥暴露抗性(DKER)的可撤销分层身份基加密(RHIBE)方案。通过引入分层密文、分层解密密钥和级别转换密钥等创新工具,克服了格结构与传统密钥重新随机化属性不匹配的难题。该方案不仅支持可扩展的密钥撤销机制,还具备密钥委托功能,为后量子密码学领域的发展提供了新的思路和方法。 阅读详情

相关推荐

ComfyUI工作流换脸节点报错ReActorFaceSwap

找到自己ComfyUI安装目录的custom_nodes下是否有这个comfyui-reactor-node-main。大家在借鉴别人工作流进行AI换脸的时候,如果遇到ReActorFaceSwap报错提示,莫慌,看我的,两步解决问题。这里千万注意不要嵌套文件夹,保证点击去这个文件就可以看到内置的配置文件!找到自己ComfyUI安装目录的facerestore_models。如果有这个文件,直接跳过,去下一步。如果没有,可以去Git官网下载。

qq_70810809的博客 9016

Symbian学习(一)——分析HelloWorldBasic

       Symbian OS环境下有两类主要的应用才程序——控制台程序和GUI程序。HelloWorldBasic属于控制台程序。      在控制台程序中,有三个重要的文件:group/bld.inf(有一个组件定义文件)、group/HelloWorldBasic.mmp(项目定义文件)、src/HelloWorldBasic.cpp,在每个开发项目,都有组件定义文件和项目定义文件,

badcitizen的专栏 954

控制台模拟前端请求实现快速刷网课时长

本教程仅用于学习前端技术和网页开发,旨在提供教育与技术指导。对于任何未经授权或违反规定的使用行为,本人不承担任何责任。注意到那个serive后面有timestamp时间戳,暗示它很可能就是每30秒汇报一次进度和播放时长的命令,我们右键——复制——复制为fetch。有的网站上的网课需要的不仅仅是进度,而是时长,所以倍速插件失效,但我们可以使用控制台命令来模拟请求实现快速刷网课时长。尝试修改即可,例如我修改time为800,然后复制粘贴到控制台执行。播放视频,等待前端请求出现,然后复制前端请求为fetch。

m0_74823408的博客 2068

helloworldbasic工程总结(上)

Symbian中的文件类别:.h c++的头文件.inL c++内联函数实现文件.cpp c++源文件.mmp symbian 操作系统工程文件.hrh 资源与C++程序的通用头文件bld.inf 编译的信息文件.mak 构建文件.rh 资源头文件.rss 资源文件.loc 本地化字符串头文件.rsc 被编译的资源文件(不...

diansu5840的博客 126

VTK vtkLookupTable vtkScalarBarActor 颜色条

有时需要给数据做一个 vtkScalarBarActor, 我们把显示的数据的一个 坐标系 来显示 颜色条1.以 Z 显示颜色 效果如下。

q610098308的专栏 4041

有限时间 vs 固定时间 vs 预定时间滑模:稳定性分析与仿真验证方法对比(中)

有限时间滑模控制(FTSMC)和固定时间滑模控制(FixTSMC)是两种重要的控制策略,旨在实现系统状态的快速收敛。FTSMC通过设计滑模面和控制律,确保系统状态在有限时间内收敛到原点,但其收敛时间与初始状态相关。FixTSMC则进一步优化,使收敛时间与初始状态无关,适用于高动态环境,具有更强的鲁棒性和更平滑的控制信号。两种方法均通过李雅普诺夫函数证明其稳定性,并通过仿真验证其有效性。FixTSMC在工程应用中更为可靠,尤其适合安全关键系统。

Lyajpunov的博客 3225

helloworldbasic研究总结(下)

DLL入口点说明:当一个应用程序启动时,E32Dll就被调用并带有一个参数aReason.这个参数可能下面几种中的一种EDllProcessAttach, EDllThreadAttach, EDllThreadDetach or EDllProcessDetach.E32Dll是一个全局函数,别作为DLL入口点来引用。这个函数是必须出现在symbian程序中。在这个工程中,该函数只是简...

diansu5840的博客 153

tree_sitter多语言解析器配置实战指南

本文是一份详细的Tree-sitter多语言解析器配置实战指南。文章从零开始,手把手指导如何搭建Python环境、安装指定版本的tree-sitter库、下载并编译多种语言的语法规则,最终构建一个统一的解析器库。通过实战代码演示了如何初始化解析器、解析代码并遍历语法树,旨在帮助开发者高效处理多语言代码分析任务,并分享了高级技巧与常见问题排坑经验。

weixin_29245767的博客 268

详解HelloWorldBasic实例

转载于:http://www.sm82.com/blog/article.asp?id=101LeeFJ 翻译整理 Detail Of HelloWorldBasic Example About this example HelloWorld 这个简单的应用程序展示了在Symbian OS 60 上开发开发交互式应用程序的过程,虽然它很简单仅显示了“HelloWorld”这样一个字符串,但是...

weixin_34320724的博客 196

详解卷积神经网络(CNN)

卷积神经网络(Convolutional Neural Network, CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。

qq_25762497的博客 25万+

JavaFx 教程

JavaFx 教程

2012年开始工作,全栈开发老兵,目前已是一个老师,分享这么多年的心得体会 784

Helloworldbasic.rss 浅析

/** ==============================================================================*  Name        : Helloworldbasic.rss*  Part of      : Helloworldbasic*  Description : 这里只是在讲RSS这个文件 *  Autho

qxj19870501的专栏 530

揭秘大厂智能生产调度AI系统架构:架构师拆解中台化设计3大优势

智能生产调度AI系统是基于AI算法(如遗传算法、强化学习、深度学习),结合生产数据(如订单、设备、库存、人员),自动生成最优生产计划与调度方案的系统。最大化设备利用率(减少停机时间);最小化生产周期(快速交付订单);优化库存水平(降低积压与短缺);提升准时交货率(满足客户需求)。维度传统调度系统智能调度AI系统决策逻辑规则引擎+人工经验AI算法(预测+优化)数据处理手工汇总+静态数据实时数据整合+动态更新适应能力固定场景(如单一产品、单一工厂)

AI Python 编程之道的博客 759

S60 sample project 之 Helloworldbasic

 1. Brief IntroductionHelloworldbasic project实现了一个比较简单的S60 GUI 应用程序的。通过实现App类,Doc类,View类,Ui类,Dialog类,实现了S60应用程序的框架。我们应该重点了解各个Class之间的调用关系,如何用资源文件来描述一个UI,以及如何添加菜单的响应代码。2. Design不要被类图的繁冗的继承结构所吓倒,我们只需要研究

moonson的专栏 1045

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

用S60操作系统SDK开发NOKIA手机应用程序-学习笔记(1)

前些日子看到有朋友买的N记手机,顿生休现在所用N记5510的想法,也对S60产生兴趣。先弄了个Series 60 SDK 2.0 for Symbian OS开始解压安装,提示我系统缺少active perl ,还要java runtime,先装了再说,缺什么再装就是。完全安装要300多兆。装好了当然先运行模拟器,呵呵,穷人都这样模拟器自带了一个helloworldbasic程序在模拟器里的程序管

coolstar的调侃 4979

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

用S60 SDK工具编译工程和分发软件

搭建好开发环境后,我们可以试着编程SDK自带的一些例子工程.如:HelloWorldBasic.开启CMD命令模式,进入目录:C:/Symbian/9.2/ S60_3rd_FP1/S60Ex/HelloWorldBasic/group/;输入命令:bldmake bldfiles;将会在../group/下产生abld.bat批处理文件;接着输入命令:abld build winsc

LiuQiuMing编程日记 1725

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

一、 编译命令

1.    bldmake bldfiles2.    abld build wins udeb3.    abld makefile vc64.    epoc5.    abld reallyclean有了以上的基础,我们就可以编译sis文件了. 一共分为2步:1. 进入到/group目录下, 输入bldmake bldfiles, 和以前讲过的作用一样, 然后: abld

yangtang_newton的专栏 1009

Symbian按帮助运行后 提示的错误和解决方法

makmake /Series60Ex/helloworldbasic/group/helloworldbasic.mmp vc7进入vs.net 编译可是失败提示HELLOWORLDBASIC fatal error LNK1103: debugging information corrupt; recompile moduleHELLOWORLDBASIC fatal error LNK118

1260

WinXP PRO平台下VS.NET+Series60开发环境配置指南(转)

CPU:AMD Athlon XP 3200+ RAM:Kingston DDR400 256M*2 Dual Channel MotherBoard:Epox 8RDA3+ OS:Microsoft WindowsXP Pro...

cuankuangzhong6373的博客 180

helloworld 伤害位置_最难搞定的HelloWorld(编译)

终于到编译了,在网上我没有找到什么,两条命令bldmake bldfilesabld makefile vc6不过还是出错,晕倒!第一个命令就出错了EPOCROOT environment variable must be capitalisedBEGIN failed--compilation aborted at C:/Symbian/8.1a/S60_2nd_FP3/epoc32/tools...

weixin_39543773的博客 164

Symbian OS开发入门(二) :VS2003环境下Symbian工程的导入与建立

原文地址:http://www.360doc.com/content/070510/08/13049_491500.html 本文讲述怎样导入项目,怎样创建S60项目。这些内容都是我今天花一天时间查阅资料并摸索出来的,中间很可能有不少错误是我没有发现的,欢迎大家指正。阅读本文以前,请保证你的开发环境已经设置好,而且经过验证没有问题。若这部分的内容你不清...

weixin_34008805的博客 137

[转载]Symbian OS开发入门(二) :VS2003环境下Symbian工程的导入与建立

Symbian OS开发入门(二) :VS2003环境下Symbian工程的导入与建立QUOTE:    本文讲述怎样导入项目,怎样创建S60项目。这些内容都是我今天花一天时间查阅资料并摸索出来的,中间很可能有不少错误是我没有发现的,欢迎大家指正。阅读本文以前,请保证你的开发环境已经设置好,而且经过验证没有问题。我将讲解4个部分的内容,前3部分内容是独立的,没有顺序之分。1、将已有的S60

spearous的专栏 1499

VS2003环境下Symbian工程的导入与建立

本文讲述怎样导入项目,怎样创建S60项目。这些内容都是我今天花一天时间查阅资料并摸索出来的,中间很可能有不少错误是我没有发现的,欢迎大家指正。阅读本文以前,请保证你的开发环境已经设置好,而且经过验证没有问题。若这部分的内容你不清楚,请阅读我的另外一篇文章Symbian OS开发入门(一) :基于VS.Net 2003的Symbian开发环境的准备我将讲解4个部分的内容,前3部分内容是独立的,没

风生水起 1521

基于VS.Net 2003的Symbian开发环境的准备-II

本文讲述怎样导入项目,怎样创建S60项目。这些内容都是我今天花一天时间查阅资料并摸索出来的,中间很可能有不少错误是我没有发现的,欢迎大家指正。阅读本文以前,请保证你的开发环境已经设置好,而且经过验证没有问题。若这部分的内容你不清楚,请阅读我的另外一篇文章Symbian OS开发入门(一) :基于VS.Net 2003的Symbian开发环境的准备我将讲解4个部分的内容,前3部分内容是独立的,没

阳光下 1188
上一篇: 又开学啦,今天开始blog正式重新开张@_@
下一篇: 深入理解和使用Windows NT驱动程序的执行上下文(一)
会思考的草
博客等级 码龄25年 208粉丝 55原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值