Hello China应用程序开发指南

概述

一个完整的操作系统,必须能够提供一套完整的工具和方法支持应用程序的开发。一般情况下,操作系统提供一组系统调用接口(API接口),程序员可以通过这一组API接口访问操作系统提供的服务。同时提供一个开发环境和开发流程,程序员在这个开发环境中完成应用程序的开发和编译工作。

作为一个面向智能设备的嵌入式操作系统,Hello China已经发展到1.75版。该版本提供了一组相对完整的API函数,供应用程序开发使用。这一组API函数包括线程/进程管理、内存管理、设备访问、文件管理、图形界面等方方面面,API函数数量超过了100个。这组API通过系统调用的方式,实现了操作系统内核和应用程序代码的完全分离。即应用程序和操作系统内核都是独立的文件,完全分离,之间无需连接在一起,这大大增加了系统的可伸缩性。

同时Hello China V1.75版本提供了一组辅助开发工具,可辅助程序员快速方便的完成基于Hello China操作系统的应用开发。但是当前版本的Hello China并未提供集成开发环境,需要程序员借助已有的集成开发环境来完成代码的编译和链接工作,比如可以使用Microsoft的Visual Studio系列开发环境。

本文首先介绍了Hello China应用程序的体系结构和加载原理,然后以Visual Studio 2008为例,详细介绍了应用程序的开发步骤和注意事项。

HCX文件的结构和加载过程

HCX是Hello China可执行文件(Hello China eXecutable)的缩写,是Hello China定义的一个文件结构。所有Hello China可执行程序,都必须以该文件定义的格式进行存储,否则不能被Hello China加载。

HCX文件的格式

HCX文件包含了可执行代码、初始化的全局数据、应用程序版本信息、应用程序图标等信息。HCX文件会被GUI shell读取,并以图标的方式显示在应用程序列表内。一旦用户点击应用程序图标,则应用程序就会被加载并执行。

当前HCX文件格式版本是V1.0,主要为Hello China V1.75版本定制。后续版本的HCX文件格式可能会有变动,但是会保持前向兼容性。下面是HCX V1.0文件的格式描述:

首先是一个HCX文件格式头,这个文件头定义如下:

 

struct__HCX_HEADER{

         DWORD          dwHcxSignature; //HCX文件签名,x86 CPU上为0xE9909090

         DWORD          dwEntryOffset;    //入口函数地址相对于文件头的偏移

         DWORD          dwBmpOffset;      //程序图标相对于文件头的偏移

         DWORD          dwBmpWidth;       //程序图标的宽度,以像素表示

         DWORD          dwBmpHeight;      //程序图标的高度,以像素表示

         DWORD          dwColorBits;      //图标颜色深度

         CHAR           AppName[16];      //应用程序的可视化名字

         CHAR           MajorVersion;     //应用程序主版本号

         CHAR           MinorVersion;     //应用程序次版本号

         CHAR           OsMajorVersion;   //可运行该程序的操作系统的主版本号

         CHAR           OsMinorVersion;   //可运行该程序的操作系统的次版本号

};

其中HCX签名,用户标识一个合法的HCX文件。操作系统在试图执行一个HCX文件时,首先把该文件读入内存,然后就检查该文件的签名是不是0xE9909090。如果是,则认为是一个合法的HCX文件,并试图执行。否则认为不是一个合法的HCX文件,放弃进一步的执行。

在x86 CPU为处理器的平台上,HCX签名实际上是三个nop指令加一个跳转指令(跳转指令的目标地址,就是dwEntryOffset)。这样安排的目的,是操作系统完成HCX文件的合法性检查之后,可直接跳转到文件的开头除执行,无需进一步检索入口点。

另外一个需要解释的是AppName,这是应用程序的可视化名字,即显示在GUI shell中的应用程序列表中的名字。这个名字与HCX文件名可以不一样。建议取一个能够直接显示应用程序本身功能的名字。

应用程序主版本号和次版本号构成了一个管理应用程序版本的机制。在升级应用程序的时候,Hello China会判断新应用程序的版本是否高于当前应用程序。如果是,则允许升级,否则会给出提示。

最后的目标操作系统版本号,指明了能够运行当前HCX文件的最低操作系统版本。如果当前操作系统的版本低于该版本号,则会拒绝HCX文件的执行。因为HCX文件有可能应用了高版本操作系统的一些特性。

紧跟HCX头,就是可执行二进制代码和初始化的全局数据。这是HCX文件的主要内容,所有可执行指令和相关数据,都存放在这个部分中。这部分内容是由编译器生成的。

最后是一个应用程序图标,以RGB方式存放,当前只支持128乘以128大小的BMP文件,且颜色深度必须是24位。GUI shell会在应用程序列表中显示这个图标(以及应用程序的可视化名字)。

 

HCX文件的生成方式

HCX文件是由一个叫做hcxbuild的程序生成的。首先程序员使用某种编译工具(比如VS 2008),编译生成一个二进制可执行文件(比如DLL文件),然后再准备一个BMP格式的图标文件,把这两个文件作为hcxbuild的输入。

Hcxbuild程序会根据上述两个文件(DLL和BMP文件)的信息以及用户输入信息(比如可视化名字等),自动生成一个HCX头,然后提取DLL文件中的可执行代码和全局数据,再分析BMP文件,提取图片数据,最后把上述信息整合起来,形成一个hcx文件。这个hcx文件即是Hello China操作系统可加载运行的应用程序。

下图(图一)说明了上述过程:

 


HCX文件的加载和执行

GUI Shell启动后,会在C:\HCGUIAPP目录下检索所有后缀是.HCX(或小写的hcx)的文件。一旦发现一个HCX文件,则GUI Shell会读取该文件的相关信息(主要是应用程序图标和可视化名字),然后把这个应用程序显示在程序列表中。

一旦用户点击一个应用程序,该程序对应的HCX文件就会被Hello China读入内存,并做检查。当前版本的Hello China主要检查HCX的签名是否正确,HCX的尺寸是否符合要求,操作系统的版本信息和HCX目标操作系统版本信息是否匹配等。如果检查通过,则操作系统会创建一个核心线程,以HCX文件的起始位置作为线程的入口点,启动应用程序的运行。

需要说明的是,Hello China V1.75版本的应用程序加载功能比较简单,未实现复杂的应用程序加载功能(比如代码重新定位、加载资源等)。但由于Hello China定位于嵌入式应用,这种加载功能在大部分应用场景下足够应用了。下面是V1.75版本应用程序加载器的一些限制:

1、        未实现可执行代码的重新定位,而是把所有应用程序都加载到内存地址0x1E0000开始处。这样就要求在编译应用程序的时候,必须设置其链接基地址为0x1E0000,否则会运行失败;

2、        限制应用程序的可执行部分(包括二进制代码和全局数据,不包括图标等辅助数据)不能大于64K。这是由于在0x1E0000开始处,只有64K的空闲空间可以使用。实际表明,这个限制也不是大问题,64K的纯代码空间已经非常大,可以容纳数万行C语言代码的编译结果。如果应用程序的大小超过了64K,可以通过修改内核的加载地址来解决该问题。Hello China的后续版本将在保持兼容的情况下解决该问题。

 

Hello China应用程序开发步骤

下面以Visual Studio2008为例,介绍如何开发一个基于HelloChina的应用程序。对于其它版本的VisualStudio开发环境,开发步骤基本一致。

步骤一:建立应用程序开发环境

把Hello China SDK(应用程序开发套件)中的sdklib.lib文件,拷贝到VS 2008的lib目录下,把kapi.h文件拷贝到VS 2008的include目录下。如果采用缺省安装,VS 2008的lib和include目录分别为:C:\Program Files\Microsoft Visual Studio9.0\VC\lib 和C:\ProgramFiles\Microsoft Visual Studio 9.0\VC\include。

这样在编写应用程序的时候,直接在源代码文件中包含KAPI.H文件即可,无需指明路径。同样地,在链接程序的时候,也无需指明sdklib.lib文件,VS 2008会在LIB目录中自动搜索。

KAPI.H文件包含了Hello China应用开发相关的所有类型定义、数据结构定义、函数接口定义等,类似与Windows操作系统的windows.h文件。任何应用程序源代码文件,必须包含该头文件。

而sdklib.lib则是编译后的二进制代码库。所有Hello China提供的API函数的实现,都被提前编译到该文件中。这样就无需把API源文件包含到项目中,链接器会自动到sdklib.lib文件中拷贝二进制代码。

步骤二:启动VS 2008,建立一个新的应用程序

选择VS 2008集成开发环境的“文件->新建->项目”菜单,在弹出的对话框中,项目类型选择Visual C++->Win 32,在模版窗口中选择“Win32项目”,输入一个应用程序名称和解决方案名称(比如“hcnhello”,这两者缺省是相同的,但是也可以分别指定不同的名字,但貌似没有必要这样做。),指定应用程序的存放路径,如下图(图二):

 

点击“确定”按钮,即可进入Win 32应用程序创建向导。点击“下一步…”按钮,在出现的对话框中,选择“应用程序类型”为“DLL”,勾选中“空项目”选项,如下图(图三):

 

点击确定,即可建立一个全新的解决方案。

步骤三:在应用程序中添加源代码

在新建的应用程序中添加源代码文件(.CPP文件),使得应用程序至少包含一个C/C++语言源代码文件。这是因为如果不包含源代码文件,VS 2008将不显示编译器选项,从而无法对应用程序进行设置(即第四步工作)。

当然,也可以在这一步中直接编写源代码,编写完成后再进入第四步(设置编译/链接选项)和第五步。

添加源代码文件的步骤比较简单,选择“文件->新建->文件…“菜单,在出现的对话框中选择”C++文件“即可。输入代码后保存该文件,然后添加到新建的项目中。VS 2008在缺省情况下不会把新建的文件加入项目,这与VC 6.0不同。个人感觉这样非常不方便,不知道VS 2008是基于何种考虑。

 

步骤四:对新建的应用程序进行设置

新应用程序创建完成之后,VS 2008会采用缺省设置对其进行配置。这些缺省设置都是针对Windows操作系统做出的,与windows操作系统关联密切,但是与Hello China操作系统不兼容。为了使新建的应用程序适应Hello China操作系统的运行环境,必须对其进行合理设置。这也是Hello China开发中最重要的一个步骤。

第一个要做的设置,是编译器生成代码的方式。缺省情况下,VS 2008会在代码中插入诸如“异常处理”、“缓冲区检查”等等确保应用程序安全运行的代码。这些代码对程序员是透明的,即程序的源文件中看不到这些代码,只有在编译的时候,才由编译器插入。这些代码的实现机制,往往依赖于Windows操作系统机制,因此必须禁止编译器插入这些代码。具体设置方式为:选择“项目->属性”菜单,在弹出的对话框中,选择“配置属性”,左上角的“配置“中,选择”Release“,如下图(图四):

 

选择“C/C++->代码生成”,在右面的配置列表中,“启用C++异常”选项修改为“否”,“缓冲区安全检查”选项设置为“否(/GS-)”,如上图(图四)。

再选择“链接器->高级”选项,在右面的选项列表中做如下配置:

入口点:输入“HCNMain”,即程序的入口函数名称;

基址:设置为“0x1E0000“,即应用程序的加载地址。

所有其它选项保持默认值即可,如下图(图五):

 

再选择“链接器->命令行“配置项,在右面的”附件选项“编辑框中,输入如下附加选项:sdklib.lib /ALIGN:16。

其中sdklib.lib告诉链接器要到该文件中寻找相关函数的目标代码。所有Hello China操作系统相关的功能函数的二进制代码,都是在该文件中。而/ALIGN选项,则是告诉链接器,在链接应用程序的时候,节(section)与节之间的间隔应该按照16字节对齐。缺省情况下,是按照4K字节对齐的,这不符合Hello China对应用程序的要求。

设置后的结果如下图(图六):

 

至此编译链接选项设置完毕。

步骤五:编写应用程序代码,并进行编译链接

编写代码是应用应用开发的最核心步骤,也是工作量最大的步骤。具体的代码与应用程序的功能相关,无法统一描述。但是Hello China应用程序的大致架构是相同的,每个应用程序必须包含下列关键要素:

1、        一个消息循环,循环从应用程序(线程)的消息队列中获取消息,并进行分发;

2、        至少一个窗口,用于显示所有用户界面元素,完成用户交互;

3、        至少一个窗口函数,对应上面的窗口,处理所有窗口相关的消息和用户动作;

4、        一个入口点(入口函数,即HCNMain),操作系统加载应用程序,并从该点开始运行。

熟悉Windows API编程的朋友很容易发现,这个程序逻辑结构与Windows应用程序结构类似。实际上,Hello China也实现了基于消息的驱动机制,由外部消息(用户输入)来驱动程序的运行。下面是一个简单应用程序的代码,包含了上述各个要素:

#include <kapi.h>

 

//主窗口函数,处理各类窗口消息。

static DWORDHelloWndProc(HANDLE hWnd,UINT message,WORD wParam,DWORD lParam)

{

         staticHANDLE hDC = GetClientDC(hWnd);

          __RECT rect;

         switch(message)

         {

         caseWM_CREATE:    //Willreceive this message when the window is created.

             break;

         caseWM_TIMER:     //Onlyone timer can be set for one window in current version.

             break;

         caseWM_DRAW:

               TextOut(hDC,0,0,"Hello,world!");

             break;

         caseWM_CLOSE:

             PostQuitMessage(0);  //一旦用户关闭主窗口,则向应用程序的消息队列中发送结束消息。

             break;

         default:

             break;

         }

         returnDefWindowProc(hWnd,message,wParam,lParam); //必须调用缺省窗口函数。

}

 

//入口点函数。

extern "C"

{

DWORD HCNMain(LPVOIDpData)

{

         MSG msg;

         HANDLE hMainFrame = NULL;

         __WINDOW_MESSAGE wmsg;

 

         //创建应用程序主窗口。

         hMainFrame =CreateWindow(WS_WITHBORDER | WS_WITHCAPTION,

                   "Mainwindow of the demonstration application",//窗口标题。

                   150,//窗口在屏幕上的位置。

                   150,

                   600,

                   400,

                   HelloWndProc,  //窗口函数

                   NULL,

                   NULL,

                   0x00FFFFFF,    //窗口背景颜色,纯白色。

                   NULL);

         if(NULL== hMainFrame)

         {

                   MessageBox(NULL,"Can not create the main frame window.","Error",MB_OK);

                   goto__TERMINAL;

         }

 

         //消息循环,一个线程只有一个消息循环,从线程消息队列中获取消息。

         while(TRUE)

         {

                   if(GetMessage(&msg))

                   {

                            switch(msg.wCommand)

                            {

                            case KERNEL_MESSAGE_WINDOW:

                                    DispatchWindowMessage((__WINDOW_MESSAGE*)msg.dwParam);

                                     break;

                            case KERNEL_MESSAGE_TERMINAL:  //Post byPostQuitMessage.

                                     goto __TERMINAL;

                            default:

                                     break;

                            }

                   }

         }

 

__TERMINAL:

         if(hMainFrame)

         {

                   DestroyWindow(hMainFrame);

         }

         return0;

}

}

 

上述代码只是创建了一个应用程序主窗口,并在窗口的左上角输出了“Hello,world!“字符串。

代码编写完毕后,即可进行编译链接了。如果仅仅是编译一个C/C++源文件,可以直接按“CTRL +F7“组合键,即可完成编译。如果希望构建整个应用程序,形成最终的二进制模块并在Hello China上运行,则必须选择”生成->批生成…“菜单,在弹出的对话框中勾选”Release|Win32“,然后点击”重新生成“按钮即可。

这样生成的DLL文件,存放在项目的Release目录下。需要注意的是,这个生成的DLL是不能直接被Hello China执行的,必须对其进行处理,也就是下一步的工作。

步骤六:对生成的DLL进行处理,形成HCX文件

VS 2008编译链接生成的DLL文件不能被Hello China直接运行,而必须对其进行设置。SDK中携带的hcxbuild工具,就是完成这个处理工作的。在处理之前,请准备一个大小是128*128、颜色深度是24位的位图文件,作为应用程序的图标。如果没有符合要求的位图文件,可以使用windows自带的画图程序进行制作,非常方便。

准备好位图文件后,即可启动hcxbuild程序,来生成HCX文件了。下面是(图七)hcxbuild的运行截图:

 

其中“二进制可执行文件“就是刚刚编译完成的DLL文件,”应用程序图标文件“则是刚才准备好的位图文件。一旦这两个文件被选择,”原始文件概要信息“中就会输出这两个文件的相关信息,其中对DLL文件,会输出其入口地址、所有节的数量、每个节的文件开始地址和长度等信息。对于位图文件,则直接显示其内容。

“应用程序可视化的名称“,是该应用程序显示在Hello China操作系统的图形shell中的名称,这个名称与应用程序文件的名字不同。程序主要/次要版本两个参数,主要用于应用程序版本控制。”而目标文件路径及名称“,则是待生成的HCX文件的存放位置和名称。注意,文件名称后缀一定要为全部大写的HCX或全部小写的hcx,否则会提示错误。

所有信息输入完毕后,点击“构建“按钮,即可生成HCX文件。如果提示错误,请根据提示修改相应参数。

生成的HCX文件就是Hello China可加载和运行的应用程序文件了。

步骤七:运行生成的HCX文件

把上述步骤生成的HCX文件,拷贝到Hello China所在硬盘(或虚拟硬盘)的HCGUIAPP目录下,重新启动Hello China,进入字符命令行模式后,再输入gui命令并回车,即可进入图形模式,在图形shell中就可看到新开发的应用程序了。点击应用程序图标,即可运行该应用程序。下列是helloworld应用程序的运行结果(图八):

 

点击“HelloWorld“图标后的运行结果(图九):

 


相关资源和支持渠道

SDK工具包和Hello China V1.75安装程序、源代码,可从下列地址进行下载:

http://download.csdn.net/detail/hellochina15/4091779

Hello China在PC或Virtual PC上的安装,请参考下列blog:

http://blog.csdn.net/hellochina15/article/details/7105464

http://blog.csdn.net/hellochina15/article/details/7253350

同时欢迎加入Hello China开发技术QQ群:38467832



  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值