使用Carbide.vs与VS.NET2003构建Symbian开发平台-S60 平台
1.简介
在过去的几年里从事Symbian OS/C++的开发,选择什么样的IDE开发环境是一件很让人郁闷的事。微软的Visual C++ 6.0 缺乏人性化的设计,而VS.NET却不能很好地支持Symbian Os/C++的开发,Borland C++ BuilderX Mobile Edition 还有Metrowerks CodeWarrior也并不是每个人都会喜欢的,幸运的是自从诺基亚的Carbide.vs出现后,开发Symbian OS/C++的应用程序变得非常方便与简单。
什么是Carbide.vs呢,正确地说Carbide.vs并不是一个类似 VS.NET或Codewarrior 一样的IDE开发环境,Carbide.vs是一个插件,一个能够处理Symbian OS Sdk命令行并改善VS.NET编写的Symbian os c++ 应用程序代码的一个插件,同时Carbide.vs也很好地集成到了VS.NET的IDE开发环境中,有了Carbide.vs我们编写起Symbian os c++应用程序将会变得更容易、更方便、更快捷。
本文适合于想学习Symbian C++ 应用程序开发的的初学者,如果你对SDK还有IDE的选择感到疑惑或者你已经对VS.NET的集成开发环境很熟的话,建议你采用Carbide.vs,你会发现Carbide.vs+VS.NET 2003的搭配开发起来会更顺手,更容易。
2.准备工作
在你准备编写此教程的实验时,请确保你的电脑满足了以下的软件环境(开发symbian os c++ 必备)
1.Microsoft Visual Studio.Net 2003 :
这个是必备的,我们将会使用VC++.NET 2003进行Symbian os c++的开发,所以VC++.NET是必装项目。
2. Java JRE:
Carbide.vs和Symbian os 的SDK都要求要Java JRE的运行环境 ,不然无法安装,请到 http://sun.java.com 下载最新版本的JRE
3.ActivePerl:
必备的软件 请到http://www.activestate.com/Products/ActivePerl/ 下载
4.Symbian OS Series 60 SDK:
这个是最重要的,SDK自带了Symbian 的手机模拟器与编译连接环境,至于选择哪个版本的SDK要具体看你要开发的手机机型 ,如果不清楚要选择哪个SDK的话,请到 http://www.forum.nokia.com/devices 查看机型对应的SDK并进行下载,在这里,我们面向的是 Series 60 第二版的SDK。在这里可以下载到S60系列的所有SDK http://forum.nokia.com/info/sw.nokia.com/id/4a7149a5-95a5-4726-913a-3c6f21eb65a5/S60-SDK-0616-3.0-mr.html
5.Carbide.vs:
我们的主角,请到http://forum.nokia.com/carbide 选择Carbide.vs下载
在用VS.NET 2003开发Symbian 项目的时候可能有些人会碰到 类似 “Error Spawning CL.exe” 的错误,可以通过这种方法来解决 ,依次打开菜单 工具->选项->->项目->VC++目录 在右边可执行目录中确保
C:/Symbian/8.0a/S60_2nd_FP2_SC/epoc32/tools
C:/Program Files/Microsoft Visual Studio .NET 2003/Vc7/bin
C:/Program Files/Microsoft Visual Studio .NET 2003/Common7/IDE
三项的存在,如果不存在的话,请添加进去(请对应SDK与VS.NET的路径进行修改)
3.开始使用carbide.vs
打开VS.NET 2003 依次打开菜单 文件 新建->项目 在项目名称里填入 HelloWorld ,选择合适的保存目录,请注意保存的目录路径中不能有空格的存在,并且最好把项目保存在跟Symbian os sdk 相同的驱动器下,最后按确定
接下来你会看到Carbide.vs的设置向导 在这里。你可以设置要使用的SDK,本教程里是使用S60 2.X FP2的SDK,主要是面向操作系统是Symbian os 8.0a 的手机开发的,你可以选择特定的SDK开发平台开发你的应用。在此向导里,你还可以设置此程序的其它参数,比如项目名称,项目的目录结构,UID等等信息。在这里我们选择了S60 2.X FP2的SDK并用了 S60 Viewed based application的项目模板,用于开发多视图的s60 应用程序。
运行向导设置完毕后按Finish按钮,Carbide.vs就帮我们把项目相关的文件生成好了并显示在VS.NET 2003的项目资源管理器中了,想看看运行效果?按F5,VS.NET便开始帮你生成应用程序并自动调用手机模拟器,打开后定位到HelloWorld软件,打开,是不是一个简单的多视图S60应用程序出现了,恭喜你,你现在已经开始你的Symbian os c++软件开发之旅了。
在这里我要说明一下,也许有网友会问我UID是什么东西,UID其实就是标识一个软件的一种序列号,关于UID的说明不在教程范围内,请在网上搜索相关的资料。
也有人会问我怎么他的模拟器跟我的很不一样啊?他那个是默认的蓝色的很单调的模拟器,而且也是没有主题的。而我却是有一个诺基亚6630的模拟器而且也带了漂亮皮肤的,Symbian sdk的模拟器其实是可以换肤的,至于模拟器内部操作系统的主题也可以更换,具体请浏览本站的相关文章 给Symbian的模拟器换皮肤(换成我们喜欢的手机皮肤) 下载此你所喜欢的皮肤并配置模拟器,再次启动时你就可以看到新的皮肤界面了,以后就不用再对着那又蓝又丑的模拟器界面了。呵呵呵
4.在HelloWorld里面显示图像
接下来我们将让HelloWorld项目显示一个简单的图像。第一步,制作 一张 bmp 的图像文件,并保存到你的项目的路径下的 data 目录下,在教程里的项目是保存在C:/Symbian/Dev/HelloWorld/中的,所以我们制作 了一张 名为 Picture.bmp 的图像文件并保存在 C:/Symbian/Dev/HelloWorld/data 目录下,或者你可以直接通过打开VS.NET 2003的项目资源管理器,在data目录上右击选择 添加->添加现有项->选择Picutre.bmp以添加到项目中去。
对于位图文件,Symbian 建议把所有的位图都打包进一种扩展名为 *.mbm 的文件里面,*.mbm 其实是一种位图集文件,里面可以包含很多的位图,类似于windows平台的资源文件,将程序里要用到的位图打包进 *.mbm 文件里后,我们在程序里就可以很方便 地使用这些位图文件。在还没有第三方辅助工具的应用前,要打包位图生成 *.mbm 需要自己编写脚本去实现,现在有了Carbide.vs我们可以很方便地将我们的位图打包进 *.mbm 文件里面,只要我们在 项目名.mmp (在教程里是HelloWorld.mmp) 文件上点击右键选择。Bitmap Collection Tool ,打开后选择 Current Directory 指定你的data目录,就会在左下角的Available bitmaps 列表中显示可用的位图文件,然后再把你所需要的位图文件移到右边的 Selected bitmaps 中,Display size:在这里我们设置成了 176 x 208 因为我们是要生成S60 2.x的应用程序,所以我们选择 176 x 208的分辨率
编辑完成后编译生成一下项目,这样就会在SYMBIAN 的模拟器目录中生成 一个所谓的 HelloWorld.mbm 与 HelloWorld.mbg 文件,在SYMBIAN的SDK目录下搜索找到 HelloWorld.mbg并用记事本打开,你可以看到以下的类似内容
enum TMbmHelloworld
{
EMbmHelloworldPicture
};
这个枚举类型TMbmHelloworld就是HelloWorld项目的位图定义了,刚才我们已经添加了一个名为Picutre.bmp的位图文件,EMbmHelloworldPicture就是对应了我们的那个Picutre.bmp位图文件,接下来我们的任务就是让HelloWorld显示这个位图。
在这之前我们提过HelloWorld.mbm文件,其实这个才我们程序里真正要载入的位图资源文件。打开HelloWorldContainer.h,在CEikLabel类的定义前面输入以下代码
#include "HelloWorld.mbg"
_LIT(KMbmFileName,"HelloWorld.mbm");
刚看到 _LIT 很多人会问起这是一个什么函数啊,其实这个不是函数,这个是一个预定义宏,在这里我们通过_LIT宏将"HelloWorld.mbm"这个字串赋值给KMbmFileName常量,其实在Symbian 里面没有类似windows平台的字符串类型(string),取得代之的是被称做 描述符(descriptor)的对象 。关于描述符的更多帮助请查看相关的资料。
Symbian os 手机操作系统的文件系统与windows的文件系统是类似的,所以只给出一个"HelloWorld.mbm"文件不足以让程序找到这个文件的具体位置并装载进程序里,此时我们需要取得这个文件在操作系统里的绝对路径,请打开 HelloWorldContainer.cpp 文件,在CHelloWorldContainer::ConstructL 函数里添加以下的代码,
TFileName fullName(KMbmFileName);
CompleteWithAppPath(fullName);//自动为文件名添加文件路径
在这里我们创建了一个标准的可修改标识符fullName,包含了我们的mbm文件名,接下去的第二行代码则把应用程序的路径添加到这个fullName中,使fullName成为一个绝对的文件路径。估计到这里,你应该可以猜出ConstructL函数是什么意思了吧?呵呵,好了,让我们编译一下程序,跟踪一下fullName是一个什么路径吧,按上F5,等待............不是吧,出错了,VS.NET报出了
error C3861: “CompleteWithAppPath”: 即使使用参数相关的查找,也未找到标识符 的错误,有过一定编程基础的人会想到肯定是哪个文件或库没有给引进来,猜对了,我们需要把一个 aknutils.h 的头文件包含进我们的源代码中,请打开 HelloWorldContainer.h 并加入 #include "aknutils.h"。加完后再试试,是不是已经不会报错了?
如果你想知道fullName到底会是一个什么样的值,你可以在 CompleteWithAppPath(fullName);的下一行代码处设置一个断点,按F5编译生成并运行模拟器,打开你的程序,运行到了断点处时,程序会停下来,光标定位在了IDE窗口,通过IDE的自动窗口我们可以看到fullName此时的值 。
此时我们发现fullName的值为 Z:/System/Apps/helloworld/HelloWorld.mbm,(如果你没有发现以上的窗口,请依次打开VS.NET的菜单 调试->窗口->自动窗口)。在这里 Z 代表了手机模拟器的驱动器,当你安装到了目标手机上后,这个驱动器就会变成C,或者是E了。
好了,接下来我们来让程序显示出我们添加的位图。首先我们在HelloWorldContainer.h 头文件中添加以下代码
CFbsBitmap* iImage;
接着定位到HelloWorldContainer.cpp 的ConstructL函数中,在我们之前编写的代码下面输入
iImage = new (ELeave) CFbsBitmap();
User::LeaveIfError(iImage->Load(fullName,EMbmHelloworldPicture));
再定位到 HelloWorldContainer.cpp 的Draw()函数 并在最后面输入
gc.BitBlt(TPoint(0,0),iImage);
这样就通过了图形上下文(graphics context,gc)将你的位图复制到了屏幕的左上角。
编译一下,OH,MY GOD ,又出错。具体错误信息为
HelloWorld error LNK2019: 无法解析的外部符号 "public: __thiscall CFbsBitmap::CFbsBitmap(void)" (??0CFbsBitmap@@QAE@XZ) ,该符号在函数 "public: void __thiscall CHelloWorldContainer::ConstructL(class TRect const &)" (?ConstructL@CHelloWorldContainer@@QAEXABVTRect@@@Z) 中被引用
HelloWorld error LNK2019: 无法解析的外部符号 "public: int __thiscall CFbsBitmap::Load(class TDesC16 const &,long,int)" (?Load@CFbsBitmap@@QAEHABVTDesC16@@JH@Z) ,该符号在函数 "public: void __thiscall CHelloWorldContainer::ConstructL(class TRect const &)" (?ConstructL@CHelloWorldContainer@@QAEXABVTRect@@@Z) 中被引用
还是同样的原理, 我们要引入一个库文件才能解决这个问题,请在项目资源管理器中右击项目->属性->配置属性->链接器->命令行 ,在右边的 附加选项 中输入 fbscli.lib
再次编译,OK了,好现在我们运行这个程序,哈哈,图像在我们的程序里显示出来啦。好高兴。
可是当我们退出程序时却出现了程序已关闭的错误。
我的天哪,怎么会这样呢,为什么我的程序不能正常退出呢,遗憾的是模拟器只提示了很简单的错误提示,并没有更详细的错误报告,我们可以通过在 C:/Symbian/8.0a/S60_2nd_FP2_SC/epoc32/wins/c/System/Bootdata 下创建一个 ErrRd 的空文件以让模拟器显示详细的错误信息(请在相应的SDK目录下操作),此时我们再次运行模拟器打开HelloWorld并关闭它,现在是不是提示信息多了一点呢?
模拟器报出了 ALLOC:17B18158 的错误,像这种类型的错误大多数情况下是因为我们使用了某个对象后忘记关闭它并释放此对象的内存导致的,为了保证程序的正常运行,我们要在使用一个对象后及时将它删除掉,于是我们定位到了HelloWorldContainer.cpp的~CHelloWorldContainer (析构函数) 中 输入以下代码
delete iImage;
当我们再次编译运行程序后,就不会再出现那讨厌的出错对话框了。
5.让我们添加一些功能
我们已经实现了在程序里显示位图的功能了,接下来我们将实现一个登陆框的功能,到时将会用到资源文件。
5.1 为菜单添加项目
打开 HelloWorld.loc 文件,定义菜单的文本
#define qtn_view1_login_item "Login"
打开HelloWorld.hrh ,修改THelloWorldCommandIds 的枚举定义,改成以下
enum THelloWorldCommandIds
{
EHelloWorldCmdAppTest = 1,
EHelloWorldCmdLogin
};
EHelloWorldCmdLogin其实就是对应了菜单项 "Login"
程序的菜单资源定义在了 HelloWorld.rss 文件中,我们打开这个文件,找到以下的定义
RESOURCE MENU_PANE r_helloworld_app_menu
{
items =
{
MENU_ITEM { command = EHelloWorldCmdAppTest; txt = qtn_appl_option_item; },
MENU_ITEM { command = EAknCmdExit; txt = qtn_appl_exit; }
};
}
把EHelloWorldCmdAppTest 替换成EHelloWorldCmdLogin,再把qtn_appl_option_item替换成qtn_view1_login_item ,这样我们就把程序选项菜单的第一项替换成 "Login" 了。
5.2 创建登陆框
在这里我们要创建一个登陆框,用于生成用户名和密码的对话框,按照传统的Symbian OS C++开发,我们本来应该在HelloWorld.rss 里定义资源,但是有了Carbide.vs后我们却可以利用 Carbide.vs提供的功能非常方便地生成我们所要的资源,请打开 HelloWorld.rss 定位到文件的最后,点击右键->Add Fragment 将会出现Carbide.vs提供的生成资源窗口,在Template 处选择 S60 Multiline query dialog ,在下方会出现此对话框的效果图,就是我们所要的登陆框样子,按下一步,指定一个比较有效的名字,r_login_query ,最后按Finish生成资源,你将会发现HelloWorld.rss多了几行内容,这就是r_login_query的资源定义。
RESOURCE DIALOG r_login_query {
flags = EGeneralQueryFlags;
buttons = R_AVKON_SOFTKEYS_OK_CANCEL;
items = {
DLG_LINE {
type = EAknCtMultilineQuery;
id = EMultilineFirstLine;
control = AVKON_DATA_QUERY {
layout = EMultiDataFirstEdwin;
label = "Username:";
control = EDWIN { maxlength = 8; };
};
},
DLG_LINE {
type = EAknCtMultilineQuery;
id = EMultilineSecondLine;
control = AVKON_DATA_QUERY {
layout = EMultiDataSecondSecEd;
label = "Password:";
control = SECRETED { num_letters = 8; };
};
}
};
}
为了要让程序更通用,本地化起来,我们有必要将UserName与Password的值定义到.loc文件中,打开HelloWorld.loc文件,加入以下定义:
#define qtn_username "UserName:"
#define qtn_password "Password:"
接下来我们来编写代码让这个登陆框显示出来,请打开HelloWorldView.h 先加下以下文件的引用
#include <AknQueryDialog.h>
#include <aknnotewrappers.h>
#include <StringLoader.h>
#include "HelloWorld.hrh"
再加入处理函数的声明
void HandleLoginL();
接着打开HelloWorld.loc 我们还要定义一些要显示的文本
#define qtn_login_success "Congretulation You Have Loged in"
#define qtn_login_fail "Sorry you have the wrong username or password"
#define qtn_login_cancel "You have canceled the login"
分别定义了登陆成功,登陆失败,与取消登陆的三种显示文本
打开HelloWorld.rss文件,加入资源定义
RESOURCE TBUF r_login_success { buf = qtn_login_success; }
RESOURCE TBUF r_login_fail { buf = qtn_login_fail; }
RESOURCE TBUF r_login_cancel { buf = qtn_login_cancel; }
这样我们就能在程序中动态装入这些资源了,继续打开HelloWorldView.cpp文件,实现HandleLoginL函数的定义
void CHelloWorldView::HandleLoginL()
{
_LIT(KCorrectLogin,"bention");//定义正确的用户名
_LIT(KCorrectPwd,"123456");//定义正确的密码
//显示对话框
TBuf<8> username(_L(""));
TBuf<8> password(_L(""));
CAknMultiLineDataQueryDialog* dialog=CAknMultiLineDataQueryDialog::NewL(username,password);//声明登陆对话框对象
if (dialog->ExecuteLD(R_LOGIN_QUERY)) {//调用登陆对话框
if (username.Compare(KCorrectLogin)==0 && password.Compare(KCorrectPwd)==0) {
//登陆成功
CAknConfirmationNote* note = new (ELeave) CAknConfirmationNote();//定义一个信息提示框
HBufC* notePrompt=StringLoader::LoadLC(R_LOGIN_SUCCESS);//装载R_LOGIN_SUCCESS文本资源,以显示登陆成功信息
note->ExecuteLD(*notePrompt);//打开对话框
CleanupStack::PopAndDestroy(notePrompt);
}
else {
//登陆失败
CAknErrorNote* note = new (ELeave) CAknErrorNote();//定义一个错误提示框
HBufC* notePrompt=StringLoader::LoadLC(R_LOGIN_FAIL);//装载R_LOGIN_FAIL文本资源,以显示登陆失败信息
note->ExecuteLD(*notePrompt);
CleanupStack::PopAndDestroy(notePrompt);
}
}
else {
//取消登陆
CAknWarningNote* note = new (ELeave) CAknWarningNote();//定义一个警告提示框
HBufC* notePrompt=StringLoader::LoadLC(R_LOGIN_CANCEL);//装载R_LOGIN_CANCEL文本资源,以显示取消登陆警告信息
note->ExecuteLD(*notePrompt);
CleanupStack::PopAndDestroy(notePrompt);
}
}
接下去我们还差啥?就差把HandleLoginL放在处理菜单命令的函数中了,定位到HandleCommandL 中,HandleCommandL 是用来专门处理事件的,我们在switch结构中加入
case EHelloWorldCmdLogin:
{
HandleLoginL();
break;
}
其中的EHelloWorldCmdLogin 就是我们的登陆按钮啦,这样就实现了当我们点击了Login按钮后就会调用HandleLoginL去做相应的处理。
好了编译一下,我顶,又出错,呵呵,别急,你还得在项目里引入 commonengine.lib 文件呢,具体做法与 引入fbscli.lib 文件一样,记得要跟fbscli.lib之间隔开一个空格哟。
好了,大功告成,现在再次编译,成功,运行,打开软件,点击Login菜单项,输入,是不是成功了?兴奋?郁闷?
现在我们的程序全都是英文的,或许有人会问我为什么不用中文的啊,比如UserName为什么不写成用户名?呵呵,说实在的,我蛮懒 的,因为我们不能直接在资源文件里直接定义一个中文文本,在我写的文章中有一篇关于在Symbian中如何显示中文的文章, 关于SymbianSeries 60开发的中文显示问题 有兴趣的可以查看 ,按照文章的步骤去做相应的修改后你的程序就直接显示中文啦。至此,本文的实战代码也到一段落了。
6.导入已有的Symbian os c++项目
利用 Carbide.vs我们可以很方便 地导入现有的Symbian os c++项目,在打开VS.NET 2003后我们依次点击 文件->Import Symbian Project .出现 导出向导,只要选择项目的 .mmp 文件就可以导入了,剩下的不用我废话了吧,聪明的你一定可以非常轻易地完成 。
7.后记
Carbide.vs的确是一个非常不错的VS.NET 2003辅助开发Symbian Os c++ 应用的工具,有了它,你还会用vc++ 6.0 吗,让我很爽的一点是用Carbide.vs基本上不用去手动配置SDK路径了与EPOCROOT此类变量了。用Carbide.vs懒得有理,哈哈,写起应用来也非常方便 。希望大家在看了本文后会喜欢上这个工具。
8.项目源文件下载
为了方便大家查看, 我把这 个helloworld项目的所有源文件打包供大家下载,大家在使用时只要导入mmp文件就可以使用了。
代码下载:点击下载此文件
声明:本文是我在参考了《Getting Started with Nokia's Carbide.vs 2.0 Development Tools》 Andreas Jakl / Mopius 写的英文教程后自己修改了部分东西并翻译成中文而写成的,原版大家可以到http://www.mopius.com 下载。写这份教程是为了方便不喜欢E文或E文水平不高的同学方便学习的,由于本人表达能力有限,不足之处请大家多多指教
转载请注明出处,谢谢合作。
Made in 蓝色忧郁(Bention,翁培铖