Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1534969
  • 博文数量: 114
  • 博客积分: 10010
  • 博客等级: 上将
  • 技术积分: 1357
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-19 18:13
文章分类
文章存档

2010年(8)

2009年(9)

2008年(27)

2007年(62)

2006年(8)

我的朋友

分类: C/C++

2008-01-08 12:35:13

北京理工大学  20981  陈罡
 
在symbian开发中我们经常会用到手机系统自带的“程序管理”这个软件。
这个软件的功能在于它会忠实地把程序的安装操作记录下来,在删除
程序的时候它也会忠实地把程序给删除。这种做法对于symbian来说,
无疑是最好的选用第三方软件的选择,既可以安装到手机上,又可以
无条件的将软件卸载掉。
 
但是这个所谓的“程序管理”,也有很多弊端。例如,每次都需要把程序
的安装包拷贝到“手机存储”上去,这样安装包一旦大于2M,对于多数s60
手机来说,这个程序极有可能引起“手机内存不足,请关闭一些程序”这样
的错误提示,最终导致安装失败。再有就是程序的升级,有的时候不需要
整个将sis包重新安装一遍,只是覆盖掉几个dll文件即可,但是很多情况
下,开发者都是选择将程序全部重新安装一遍,如果打包的时候升级过sis
包的版本,那么将在“程序管理”中看到多个安装记录。另外目前很多公司
都在寻找手机程序预装的方法,其实从其本质来说就是希望程序安装到
用户的手机上以后,无法被用户使用普通的“程序管理”程序卸载。
 
在这里我要讨论一种方式,可以绕过程序管理器的限制,在“程序管理”器
里面没有记录,也无法把程序从程序管理器里面卸载,这种方式虽然比较
有效,但是程序的卸载操作就需要使用其它的单独的卸载程序才能卸载了。
绕过程序管理器的方法其实很简单,自己编写一个程序管理器即可。很多
朋友会想编写一个程序管理器多么多么的复杂,需要熟悉sis文件格式之类
的内容。其实一点也不复杂,sis本身就是s60自带的程序管理器支持的文件
格式,只有nokia的程序管理器才能够识别。既然我们自己编写程序管理器
的话,就不必拘泥于sis格式了。自己的程序可以读取的文件格式就可以自己
说得算了。
 
我们知道在创建pkg文件的时候,在需要安装后立即运行的程序后面通常只要
指定一个RI,FI,就可以保证程序在安装后可以立即执行,例如:
"marm\myapp.exe"-"!:\System\Apps\MyApp\Myapp.exe",RI,FI
这样就提供了一个方法摆脱当前的程序管理器的方法,大致的思路如下:
编写一个exe文件,该文件可以将某个.zip或者.dat的包解压缩到手机的
e:\system\apps目录下面即可。
 
整体的写下来,大概是这个样子的:
"marm\my.zip"-"!:\System\Apps\MyApp\my.zip"
"marm\myapp.exe"-"!:\System\Apps\MyApp\myapp.exe",RI,FI
在myapp.exe运行的时候,可以给它加入适当的1秒至3秒的延时,用来确保
手机的程序管理器已经把zip包释放到某个目录下面去了,然后再开始运行
myapp.exe,它的作用在于直接把my.zip包中的文件解压缩到system\apps目录
或者希望可以开机自动运行的可以把相关的mdl文件考入c:\system\recogs目录。
注意:
利用mdl在手机启动的时候自动载入的特性实现的所谓“开机自动运行”,在
symbian 3rd平台中已经不再适用,以下是官方的issues说明:
这样一来,只有my.zip和myapp.exe这两个文件是纳入手机的应用程序管理器
的控制范畴的,可以很容易地通过应用程序管理器删除,但是通过myapp.exe
从my.zip中解压缩出来的,放入system\apps里面的目录则成功的逃脱了程序
管理器的限制,保留了下来。这样就基本上实现了,程序脱离应用程序管理器
的限制了。如果在my.zip中加入自动运行的mdl,然后调用自动登陆、下载zip、
自动解压缩的程序的话,就可以实现程序的自动更新了。每次让开机自动运行
的程序,在收到更新短信时启动,联网,下载更新包,然后解压缩安装。这
一切都是以后台的方式运行的,不会对用户产生困扰,也不需要用户每次都通过
nokia pc套件来下载,安装程序的繁琐过程。
 
对用户来说,只是某天突然发现不知道什么时候手机中多了一个应用程序的
图标 :),或者发现某个程序的图标不见了(可以通过网络自动删除手机中的某个
无效的应用)。相当于自己实现了一个OTA了。
 
相关实验我已经完全测试成功,呵呵。但是这种OTA是一把双刃剑
不希望落入某些居心不良的人的手中,扰乱这个技术的发展。所以就暂时不开放
代码了,只是把解压缩my.zip的myapp.exe代码开放一下,希望对有兴趣的朋友
有用:

// --------------------------------------------------------------------------
// zagzip.cpp
//
// programmer : wayne
// (1)get zip file exactly pathname
// (2)set path where package need to be extracted
// (3)check whether the object directory exists
// (4)if directory exists, perform extract operaion
// (5)if not exists, create one, then, goto step (4)
// (6)call outer command, delete zip file and quit smoothly
// --------------------------------------------------------------------------
#include
#include
#include   // RFs and RFile
#include   // CZipFile
#include // CApaCommandLine
#include    // EDll::StartApp(...)
#include
#include
#include     // RFileReadStream, RFileWriteStream
 
// use 4k buffer size
#define BUF_SIZE  1024 * 4
 
// the specified zip config file name
#ifndef __WINS__
_LIT(KZipPathnameC,  "c:\\my.zip") ;
_LIT(KZipPathnameE,  "e:\\my.zip") ;
_LIT(KExtractPath,   "c:\\system\\apps\\abc\\") ;
_LIT(KSrcPathname,   "c:\\system\\apps\\abc\\abc.mdl") ;
_LIT(KObjPathname,   "c:\\system\\recogs\\abc.mdl") ;
_LIT(KOutCmd,   "c:\\system\\apps\\abc\\abc.app") ;
#else
_LIT(KZipPathnameC,  "c:\\my.zip") ;
_LIT(KZipPathnameE,  "c:\\my.zip") ;
_LIT(KExtractPath,   "c:\\system\\apps\\abc\\") ;
_LIT(KSrcPathname,   "c:\\system\\apps\\abc\\abc.mdl") ;
_LIT(KObjPathname,   "c:\\recogs\\abc.mdl") ;
_LIT(KOutCmd,    "c:\\system\\apps\\abc\\abc.app") ;
#endif
 
TBuf8  g_buf ;
TBuf<100>   g_zip_pathname ;
TBuf<100>   g_target_path ;
TBuf<100>   g_copy_src_pathname ;
TBuf<100>   g_copy_obj_pathname ;
TBuf<100>   g_run_command ;
 
// Constants
LOCAL_C TBool check_file_exist(const TDesC & path_name) ;
LOCAL_C TBool check_dir_exist(const TDesC & dir_name) ;
LOCAL_C TBool extract_zipfile(const TDesC & zip_pathname, const TDesC & target_path) ;
LOCAL_C TBool extract_single(RFs& fs,
        CZipFile * zip_file,
        const TDesC& target_path,
        const TDesC& file_name) ;
LOCAL_C TBool run_command(TDesC& preset_command) ;
LOCAL_C TBool copy_file(TDesC& obj_pathname, TDesC& src_pathname) ;
LOCAL_C TBool get_const_string(TDes & res_str,const TDesC & const_str) ;
LOCAL_C TBool main_proc() ;
 
//检查文件是否存在
LOCAL_C TBool check_file_exist(const TDesC & path_name)
{
 RFs fs ;
 RFile f ;
 TInt res ;
 User::LeaveIfError(fs.Connect()) ;
 res = f.Open(fs, path_name, EFileRead) ;
 f.Close() ;
 fs.Close() ;
 return (res == KErrNone) ? ETrue : EFalse ; 
}
 
// 检查目录是否存在
LOCAL_C TBool check_dir_exist(const TDesC & dir_name)
{
 RFs  fs ;
 RDir dir ;
 TInt res ;
 User::LeaveIfError(fs.Connect()) ;
 res = dir.Open(fs, dir_name, KEntryAttNormal) ;
 dir.Close() ;
 fs.Close() ;
 return (res == KErrNone) ? ETrue : EFalse ;
}
 
// 解压缩zip包了
LOCAL_C TBool extract_zipfile(const TDesC& zip_pathname, const TDesC& target_path)
{
 // Connect to the file server.
 RFs fs ;
 User::LeaveIfError(fs.Connect()) ;
 // Create an instance of CZipFile.
 CZipFile* zip_file = CZipFile::NewL(fs, zip_pathname) ;
 CleanupStack::PushL(zip_file) ;
 
 // Iterate all the files inside the .zip file and then decompress it
 CZipFileMemberIterator* members = zip_file->GetMembersL();
 CZipFileMember* member = NULL ;
 CleanupStack::PushL(members);
 // 这里是确保解压缩的目的目录存在,如果不存在就创建一个
 if(!check_dir_exist(target_path)) {
  // target path doesn't exist, create one
  fs.MkDir(target_path) ;
 }
 // iterator one by one
 while ((member = members->NextL()) != 0) {
  // extract the compressed file into the specified directory
  if(check_file_exist(*member->Name())) {
   TParse parse ;
   parse.Set(*member->Name(), NULL, NULL) ;
   // 如果有被占用的rsc,则跳过,继续运行
   // 这一点主要针对程序正在运行中的情况,rsc不可写
   if(parse.Ext().Find(_L("rsc")) != KErrNotFound) continue ;
  }
  extract_single(fs, zip_file, target_path, *member->Name()) ;
  delete member;
 }
 CleanupStack::PopAndDestroy(); // members
 CleanupStack::PopAndDestroy(); // zip_file
 fs.Close();
 return 0 ;
}
 
// 解压缩一个文件
LOCAL_C TBool extract_single(RFs& fs,
        CZipFile * zip_file,
        const TDesC& target_path,
        const TDesC& file_name)

 TInt total_size = 0 ;
 TUint uncompressed_size = 0 ;
 
 // Get the input stream of aFileName.
 CZipFileMember* member = zip_file->CaseInsensitiveMemberL(file_name);
 CleanupStack::PushL(member);
 RZipFileMemberReaderStream* stream;
 zip_file->GetInputStreamL(member, stream);
 CleanupStack::PushL(stream);
 // Extracts file_name to a buffer.
 TFileName target_pathname ;
 RFile file ;
 target_pathname.Append(target_path) ;
 target_pathname.Append(file_name) ;
 User::LeaveIfError(file.Replace(fs, target_pathname, EFileWrite));
 CleanupClosePushL(file);
 
 total_size = member->UncompressedSize() ;
 while(total_size > 0) {
  // if the file is quite huge, then read the file in streaming mode.
  // use 4KB buffer and save binary raw data into uncompressed file
  // 这里使用了4K的缓冲区去分段解压缩大的zip文件
  g_buf.SetLength(0) ;
  
  if(total_size >= BUF_SIZE) uncompressed_size = BUF_SIZE ;
  else uncompressed_size = total_size ;
  User::LeaveIfError(stream->Read(g_buf, uncompressed_size)) ;
  User::LeaveIfError(file.Write(g_buf)) ;
  total_size -= uncompressed_size ;
 }
 // Release all the resources.
 file.Flush() ;
 CleanupStack::PopAndDestroy(3); // file, stream, member
 return 0 ;
}
 
// 这是执行外部命令了
LOCAL_C TBool run_command(TDesC& preset_command)
{
 if(check_file_exist(preset_command)) {
  CApaCommandLine * command_line = CApaCommandLine::NewLC();
  command_line->SetLibraryNameL(preset_command) ;
  command_line->SetCommandL(EApaCommandRun);
  User::LeaveIfError(EikDll::StartAppL(*command_line));
  CleanupStack::PopAndDestroy(command_line) ;
  return ETrue ;
 }
 return EFalse ;
}
 
// 复制文件,貌似应该有更好的方法,这里自己写了一个了
// 应对recogs目录不存在的情况
LOCAL_C TBool copy_file(TDesC& obj_pathname, TDesC& src_pathname)
{
 RFs     fs ;
 RFile    fsrc ;
 RFile    fobj ;
 TInt    total_bytes ;
 TInt    used_bytes ;
 TParse    pathname_parse ;
 TBuf<50>   copy_dir ;
 
 User::LeaveIfError(fs.Connect()) ;
 // check whether the object dir is exist
 pathname_parse.Set(obj_pathname, NULL, NULL) ;
 copy_dir = pathname_parse.DriveAndPath() ;
 if(!check_dir_exist(copy_dir)) {
  fs.MkDir(copy_dir) ;  
 }
 
 fsrc.Open(fs, src_pathname, EFileStream | EFileRead) ;
 fobj.Replace(fs, obj_pathname, EFileStream | EFileWrite) ;
 
 fsrc.Size(total_bytes) ;
 
 while(total_bytes > 0) {
  if(total_bytes >= BUF_SIZE) used_bytes = BUF_SIZE ;
  else used_bytes = total_bytes ;
  fsrc.Read(g_buf) ;
  fobj.Write(g_buf) ;
  total_bytes -= used_bytes ;  
 }
 fs.Close() ;
 return ETrue;
}
 
LOCAL_C TBool get_const_string(TDes & res_str,const TDesC & const_str)
{
 res_str.SetLength(0) ;
 if(check_file_exist(const_str)) {
  res_str.Copy(const_str) ;
  return ETrue ;
 }
 return EFalse ;
}
LOCAL_C TBool main_proc()
{
 TBool    has_running_app = EFalse ;
 RFs     fs ;
 RFile    f ;
 TBuf8<10>   s ;
 // 检查文件
 if(check_file_exist(KOuterCmd)) has_running_app = ETrue ;
 User::LeaveIfError(fs.Connect()) ;
 f.Replace(fs, KQuitFile, EFileWrite) ;
 s.Format(_L8("quit")) ;
 f.Write(s) ;
 f.Flush() ;
 f.Close() ;
 fs.Close() ;
 // 确定zip文件存在在C盘还是E盘,把路径存入g_zip_pathname
 if(!get_const_string(g_zip_pathname, KZipPathnameE)) {
  get_const_string(g_zip_pathname, KZipPathnameC) ;
 }
 // 解压缩后文件的目标存放路径
 g_target_path.Copy(KExtractPath) ;
  
 // 解压缩后mdl文件的存放路径
 g_copy_src_pathname.Copy(KSrcPathname) ;
 // 解压缩后将mdl文件拷贝到的目标路径
 g_copy_obj_pathname.Copy(KObjPathname) ;
 // 这是都执行完毕后需要运行的外部命令,类似FI,RI的功能
    g_run_command.Copy(KOuterCmd) ;
 
 // 这就是解压的过程了
 extract_zipfile(g_zip_pathname, g_target_path) ;
 // 这里主要是为了把mdl文件拷贝到c:\\system\\recogs这个目录下而加入的
 copy_file(g_copy_obj_pathname, g_copy_src_pathname) ;
 // 最后运行常驻内存的那个exe或app
 if(!has_running_app) run_command(g_run_command) ;
 // 删除zip文件和mdl文件
 User::LeaveIfError(fs.Connect()) ;
 fs.Delete(g_zip_pathname) ;
 fs.Delete(g_copy_src_pathname) ;
 fs.Close() ;
 return 0 ;
}
 
//  从这里跑到自己定义的那个函数里面去
LOCAL_C void MainL(const TDesC& /*aArgs*/)
 {
  main_proc() ;
 }
 
LOCAL_C void DoStartL()
 {
 // 没法子,在exe中要使用活动对象,只能自己创建调度器
 CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
 CleanupStack::PushL(scheduler);
 CActiveScheduler::Install(scheduler);
 // 调用MainL函数,开始解压缩
 TBuf<256> cmdLine;
 RProcess().CommandLine(cmdLine);
 MainL(cmdLine);
 // 删除调度器
 CleanupStack::PopAndDestroy(scheduler);
 }

// 这个是整个程序的入口点了
GLDEF_C TInt E32Main()
 {
 // 连异常处理栈都要自己创建
 __UHEAP_MARK;
 CTrapCleanup* cleanup = CTrapCleanup::New();
 // Run application code inside TRAP harness, wait keypress when terminated
 TRAPD(mainError, DoStartL());
 
 delete cleanup;
 __UHEAP_MARKEND;
 return KErrNone;
 }
// End of File
 
稍后我会发布一个关于symbian下面使用zip类的封装。
这篇文章只是一个探讨,希望能够抛砖引玉,得到更好的思路,谢谢!
 
阅读(2298) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~