43
Lập trình với Symbian OS ập trình với Symbian OS ập trình với Symbian OS ập trình với Symbian OS Ra đời với sự hậu thuẫn của những “ông lớn” trong làng điện thoại di động, hệ điều hành Symbian (Symbian OS) đang ngày càng chứng tỏ khả năng của mình. Những chiếc smartphone chạy trên nền Symbian OS ngày càng được ưa chuộng và doanh số của các hãng ở thị phần này liên tiếp tăng mạnh. * Gii thiu vhđiu hành Symbian - Trong thp k1980, Symbian OS vn được biết nhiu trong gii công nghvi tên gi EPOC, do hãng Psion thiết kế. Hđiu hành này ban đầu được viết cho các máy vi tính đời cũ vi mc tiêu phát trin để có thvn hành nhng dòng máy có kích thước nh, tài nguyên (bnh, CPU…) có gii hn. EPOC được sdng đầu tiên trên chính các sn phm PDA đời đầu ca Psion. - Đến năm 1998, thy được tim năng ca hđiu hành này, Nokia, Ericsson, Motorola, Matsushita quyết định cùng liên kết vi Psion thành lp mt liên danh chuyên sn xut hđiu hành cho PDA và đin thoi di động. EPOC lúc này đã phiên bn 5. - Năm 1999, EPOC xut hin trong mt vài model đin thoi di động ca Ericsson và được chính thc đổi tên thành Symbian OS, theo tên ca liên danh 5 hãng, khi phiên bn 6 ra đời. Tuy nhiên, vào thi đim đó hđiu hành này không được xem là mt “hđiu hành thân thin” vì không htrngười dùng cài đặt thêm các phn mm ng dng. - Đến năm 2001, chiếc đin thoi Nokia đầu tiên chy hđiu hành Symbian OS ra đời. Người dùng có thcài đặt nhng phn mm ng dng vào máy cũng như gkhá ddàng. Cùng giao din dsdng, Symbian OS bt đầu chng tsc mnh ca vic được hu thun tt. - Hin nay, Symbian là hđiu hành chiếm thphn ln nht trong các smartphone trên thtrường, bao gm nhng dòng Series 40, 60, 80, 90, UIQ và các dòng máy ca nhà cung cp mng DoCoMo ti Nht Bn. * Mđóng - Symbian không phi là mt hđiu hành mnhư Linux trên máy vi tính hay MobiLinux trên đin thoi di động. Tuy nhiên, mã ngun ca Symbian OS được sn sàng cung cp cho bt cnhà sn xut đin thoi di động hay thiết kế chương trình ng dng nào có nhu cu. Bên cnh đó, người dùng cũng không thcan thip để sa cha mã ngun ca máy. Chduy nht các ng dng viết bng ngôn nglp trình Java mi có thcan thip mt phn nào đó vào các bước vn hành ca hđiu hành này. * Các phiên bn Symbian - Series 40: Nhng đin thoi chy Symbian OS series 40 có màn hình vuông, độ phân gii 128x128, thường chcài được nhc, hình phim và các ng dng Java. Mt sdòng máy tiêu biu: Nokia 6100, 6610, 6230, 7250… - Series 60: Có màn hình ln hơn, độ phân gii 176x208, có thcài đặt được nhiu

Symbian Programing

Embed Size (px)

Citation preview

Page 1: Symbian Programing

LLLLập trình với Symbian OSập trình với Symbian OSập trình với Symbian OSập trình với Symbian OS Ra đời với sự hậu thuẫn của những “ông lớn” trong làng điện thoại di động, hệ điều hành Symbian (Symbian OS) đang ngày càng chứng tỏ khả năng của mình. Những chiếc smartphone chạy trên nền Symbian OS ngày càng được ưa chuộng và doanh số của các hãng ở thị phần này liên tiếp tăng mạnh.

* Giới thiệu về hệ điều hành Symbian - Trong thập kỉ 1980, Symbian OS vốn được biết nhiều trong giới công nghệ với tên

gọi EPOC, do hãng Psion thiết kế. Hệ điều hành này ban đầu được viết cho các máy

vi tính đời cũ với mục tiêu phát triển để có thể vận hành những dòng máy có kích

thước nhỏ, tài nguyên (bộ nhớ, CPU…) có giới hạn. EPOC được sử dụng đầu tiên trên

chính các sản phẩm PDA đời đầu của Psion.

- Đến năm 1998, thấy được tiềm năng của hệ điều hành này, Nokia, Ericsson,

Motorola, Matsushita quyết định cùng liên kết với Psion thành lập một liên danh

chuyên sản xuất hệ điều hành cho PDA và điện thoại di động. EPOC lúc này đã ở

phiên bản 5.

- Năm 1999, EPOC xuất hiện trong một vài model điện thoại di động của Ericsson và

được chính thức đổi tên thành Symbian OS, theo tên của liên danh 5 hãng, khi phiên

bản 6 ra đời. Tuy nhiên, vào thời điểm đó hệ điều hành này không được xem là một

“hệ điều hành thân thiện” vì không hỗ trợ người dùng cài đặt thêm các phần mềm ứng

dụng.

- Đến năm 2001, chiếc điện thoại Nokia đầu tiên chạy hệ điều hành Symbian OS ra

đời. Người dùng có thể cài đặt những phần mềm ứng dụng vào máy cũng như gỡ bõ

khá dễ dàng. Cùng giao diện dễ sử dụng, Symbian OS bắt đầu chứng tỏ sức mạnh của

việc được hậu thuẫn tốt.

- Hiện nay, Symbian là hệ điều hành chiếm thị phần lớn nhất trong các smartphone

trên thị trường, bao gồm những dòng Series 40, 60, 80, 90, UIQ và các dòng máy của

nhà cung cấp mạng DoCoMo tại Nhật Bản.

* Mở mà đóng - Symbian không phải là một hệ điều hành mở như Linux trên máy vi tính hay

MobiLinux trên điện thoại di động. Tuy nhiên, mã nguồn của Symbian OS được sẵn

sàng cung cấp cho bất cứ nhà sản xuất điện thoại di động hay thiết kế chương trình

ứng dụng nào có nhu cầu. Bên cạnh đó, người dùng cũng không thể can thiệp để sửa

chữa mã nguồn của máy. Chỉ duy nhất các ứng dụng viết bằng ngôn ngữ lập trình

Java mới có thể can thiệp một phần nào đó vào các bước vận hành của hệ điều hành

này.

* Các phiên bản Symbian

- Series 40: Những điện thoại chạy Symbian OS series 40 có màn hình vuông, độ

phân giải 128x128, thường chỉ cài được nhạc, hình phim và các ứng dụng Java. Một

số dòng máy tiêu biểu: Nokia 6100, 6610, 6230, 7250…

- Series 60: Có màn hình lớn hơn, độ phân giải 176x208, có thể cài đặt được nhiều

Page 2: Symbian Programing

chương trình, ứng dụng như từ điển, game dung lượng lớn,… Rất nhiều model điện

thoại Nokia chạy bằng phiên bản này như: 3650, 7650, 6600, 7610, N-Gage, các máy

thuộc N series…

- Series 80: Số điện thoại chạy trên Symbian series 80 hiện chưa nhiều, gồm: 9210,

9290, 9300, 9300i, 9500. Hệ điều hành này hỗ trợ bàn phím QWERTY trên điện thoại

di động, nhiều ứng dụng văn phòng, truy cập internet bằng trình duyệt Opera…

- Serie 90: Hiện chỉ có 2 model Nokia sử dụng phiên bản hệ điều hành này là 7700 và

7710. Các điện thoại này không sử dụng bàn phím điện thoại truyền thống mà người

dùng tương tác với máy qua màn hình cảm ứng hoặc chương trình nhận diện chữ viết

tay (7710). Các phần mềm hỗ trợ Series 60 và UIQ hoàn toàn không tương thích với

phiên bản hệ điều hành này trong khi một số chương trình ít dành cho Series 80 có thể

hoạt động trên 7700 và 7710.

- UIQ: Đây là phiên bản dành cho những điện thoại di động có màn hình cảm ứng và

người dùng có thể tương tác với máy qua cả bàn phím thật lẫn bàn phím ảo. Motorola

có các model A920, A1000, M1000… sử dụng UIQ. Có thể nói Sony Ericsson hiện là

hãng có nhiều mẫu điện thoại chạy trên nền UIQ nhất với các máy dòng P (800, 900,

910, 990, P1i), M600, W950.

* Những thử thách

Tuy đang chiếm lĩnh thị phần lớn nhất trong những chiếc điện thoại di động thông

minh nhưng Symbian OS đang gặp khá nhiều thách thức:

- Các virus máy tính tác oai tác quái thế nào thì cũng đang lăm le đe dọa điện thoại di

động như thế. Dĩ nhiên, “miếng mồi” ngon nhất không gì khác hơn là thị phần lớn

nhất. Từ sau sự xuất hiện của Cabir – virus đầu tiên tấn công vào những điện thoại

chạy Symbian OS , người ta nhận ra rằng việc bảo vệ cho những chiếc điện thoại vốn

không được quan tâm đúng mức. Tuy nhiên, thực tế là những virus này lây lan đều do

sự chủ quan của người dùng. Nếu không bấm phím kích hoạt nhận file lạ từ máy

khác, Cabir hoàn toàn không lây nhiễm vào điện thoại được. Vì thế, trong khi những

“nhà phát minh” tiếp tục viết ra những virus mới, vẫn còn đủ thời gian để những nhà

sản xuất tạo thêm thành trì bảo vệ người dùng.

- Có lẽ thử thách lớn nhất hiện nay của Symbian là những hệ điều hành nguồn mở

khác. Tuy cùng góp sức tạo dựng nên Symbian nhưng Motorola gần đây lại chuyển

hướng sang dùng MobiLinux cho những chiếc điện thoại mới xuất xưởng của mình.

Theo nhiều người, bên cạnh tính mở hơn, MobiLinux còn giúp những nhà lập trình dễ

dàng sửa đổi và tùy biến hơn Symbian khá nhiều.

- Theo một số dự báo, Symbian có thể sẽ thất thế khi các hệ điều hành khác cho điện

thoại di động ngày xuất hiện càng nhiều, với nhiều hứa hẹn ứng dụng cực kì hấp dẫn.

Nổi trội trong số này là Android của Google. Tuy nhiên, tương lai này có lẽ vẫn còn

khá xa khi những chiếc điện thoại chạy trên nền Android vẫn chưa chính thức xuất

hiện còn Nokia đã thâu tóm toàn bộ Symbian và nhiều ông lớn của ngành điện thoại

di động vẫn tiếp tục đều đặn cho ra đời những chiếc smartphone chạy trên nền hệ điều

hành này.

Ở phần trên, tôi nói qua về Symbian OS. Trước khi nói về lập trình Symbian, tôi xin

đưa ra một vài tip nhỏ giúp bạn dễ dàng hơn trong việc học lập trình trên Symbian:

- Bạn đọc các sách về lập trình Symbian. Nếu bạn mới học, hãy bắt đầu với cuốn

"Wiley S60 Programming - A Tutorial Guide (Apr - 2007).pdf” – Bạn có thể

download ở một trong các địa chỉ sau: Tại Rapidshare hoặc Tại Megaupload.

- Bạn xem các example của SDK. Có rất nhiều ví dụ hữu ích trong SDK về nhiều vấn

đề khác nhau.

Page 3: Symbian Programing

- Bạn có thể tra cứu trong Help của SDK

- Bạn có thể tìm và tham khảo ở trang NewLC, một forum khá nổi tiếng dành cho lập

trình Symbian. Bạn sẽ tìm thấy rất nhiều thứ mình cần ở trang này.

- …

Sau đây tôi xin giới thiệu loạt bài để giúp các bạn có thể lập trình được với hệ điều

hành này. Ở đây chủ yếu tôi nói tới phiên bản Series 60 dành cho rất nhiều máy điện

thoại hiện nay.

- Quản lý các tệp thực thi trên Symbian

- Cấu trúc Project trên Symbian OS

- Hướng dẫn cài đặt và lập trình Symbian S60 3rd với Visual Studio 2005

- Hướng dẫn cài đặt và lập trình Symbian S60 1st & 2nd với Visual Studio 6.0

- Cấu trúc chương trình trên Symbian S60

- Quy ước và cách đặt tên khi lập trình với Symbian OS

- Xử lý ngoại lệ trên Symbian (Leave-Symbian exeption)

- An toàn hơn với Cleanup stack

- Khởi tạo hai pha (Two-phase construction) trong Symbian

- Sử dụng chuỗi (Descriptor) trên Symbian

- Một số thao tác vẽ cơ bản với đồ họa trong Symbian

- Sử dụng font và vẽ chữ trên Symbian

- Xử lý phím nhấn

- Sự kiện cho Menu

- Một số lỗi liên quan đến lập trình và cài đặt trên Symbian

- Một số mã lỗi trong Symbian OS

...

Quản lý các tệp thực thi trên Symbian

* Tệp thực thi Trên Symbian hỗ trợ 2 hệ thống chương trình thực thi với các kiểu file khác nhau:

+ Chương trình .exe: được lưu trữ trong các file thực thi có phần mở rộng là exe.

Đây là chương trình với một đầu vào chính từ hàm E32Main(). Khi hệ thống nạp một

chương trình .exe mới, đầu tiên nó tạo một tiến trình mới. Trong tiểu trình chính của

tiến trình này, điểm vào sẽ được gọi để thực thi chương trình đó. Thông thường đây là

các server hay các ứng dụng console.

+ Thư viện liên kết động (Dynamic link library-DLL): một thư viện chứa các mã

chương trình với nhiều điểm đầu vào. Hệ thống sẽ nạp một DLL vào trong ngữ cảnh

hoạt động của tiểu trình. Có 2 loại DLL quan trọng:

- Shared DLL: cung cấp một nhóm API nhất định cho một hay nhiều chương trình sử

dụng. Hầu hết các thư viện này nằm trong các file có phần mở rộng là .dll. Một

chương trình thực thi sẽ được nối với thư viện dùng chung mà nó yêu cầu và khi hệ

thống nạp chương trình thực thi, thư viện dùng chung cần cho chương trình này sẽ

được nạp tự động.

- Polymorphic DLL: Cung cấp một nhóm hàm API được lưu trữ trong các file có

phần mở rộng khác nhau phục vụ cho các chức năng riêng như điều khiển máy in

(.prn), giao thức socket (.prt), hay đó là một ứng dụng đồ họa GUI (.app). Trong hệ

điều hành Symbian, polymorphic DLL thường chỉ có một điểm vào, nó khai báo và

khởi tạo một lớp dẫn xuất từ các lớp cơ sở trong DLL này. Thư viện DLL loại này

được nạp bởi chương trình sử dụng nó.

Page 4: Symbian Programing

Chú ý: Chương trình .exe là không thể chia sẻ trong khi DLL thì hoàn toàn có thể.

* Nạp chương trình khi thực thi Trong Symbian thì ổ C chính là RAM, ổ Z là ROM và thẻ nhớ thường là ổ D hoặc E.

+ Chương trình .exe: Một chương trình .exe được lưu trữ ở RAM hoặc trên thẻ nhớ,

khi chạy, chương trình sẽ được nạp vào RAM, được cấp một vùng nhớ riêng cho mã,

dữ liệu chỉ đọc, dữ liệu động. Nếu một phiên bản thứ 2 của chương trình được nạp

vào RAM thì một vùng nhớ mới sẽ được cấp cho nó. Với file chương trình .exe chứa

trong ROM thì chỉ có dữ liệu động được nạp vào RAM, mã chỉ thị và dữ liệu chỉ đọc

được đọc trực tiếp từ ROM.

+ Thư viện DLL: Khi một thư viện DLL lần đầu tiên được nạp vào RAM, nó được

cấp một vùng nhớ riêng, khi được yêu cầu sử dụng lần thứ hai, nó không nạp tiếp

DLL này vào RAM mà đơn giản chỉ gắn địa chỉ nó trên RAM cho tiểu trình yêu cầu.

Hệ điều hành Symbian kiểm tra số lượng tiểu trình tham khảo DLL này và giải phóng

nó khi không còn tiểu trình nào sử dụng nó nữa. Đó là lý do mà các ứng dụng đồ họa

Symbian (một loại polymorphic DLL), không hề có chức năng exit, nhất là các ứng

dụng hệ thống vì việc thoát nó sẽ do hệ thống đảm trách khi thiếu RAM cho các ứng

dụng khác) Với các DLL chứa trên ROM thì nó không cần nạp vào RAM nữa mà

được sử dụng trực tiếp trên ROM.

=> Việc các ứng dụng lưu trữ trên ROM không cần nạp vào RAM khi thực thi là đặc

điểm của Symbian để phù hợp với tài nguyên bộ nhớ giới hạn của điện thoại. Ngoài ra

để tối ưu hóa kích thước chương trình, hệ điều hành Symbian sử dụng điểm vào của

DLL là một số thứ tự, trên các hệ điều hành khác có thể dùng số thứ tự hay tên. Do đó

khi nâng cấp DLL thì số thứ tự phải giống như phiên bản trước.

* Server và việc thực thi ứng dụng

+ Các server được lưu trữ trong các file .exe, như ewsrv.exe là window server, hay

efsrv.exe là file server. Để giảm chi phí chuyển đổi ngữ cảnh các server có cùng

nhóm chức năng được dùng chung một tiến trình. Một server chính sẽ tạo tiến trình và

các server khác sẽ thực thi tiểu trình của nó với tiểu trình của server chính.

+ Ứng dụng console (không có giao diện đồ họa) được thực thi qua file chương trình

.exe. Các ứng dụng dạng này phải tạo một console riêng để tương tác với người dùng.

+ Các ứng dụng có giao diện đồ họa (GUI) là những thư viện polymorphic DLL với

phần mở rộng là .app. Điểm vào của ứng dụng này là NewApplication() tạo và trả về

một đối tượng dẫn xuất từ lớp CEikApplication (Series 80/9200Series/Series90) hay

các lớp dẫn xuất từ CEikApplication phù hợp theo từng dòng điện thoại Symbian như

CQikApplication (UIQ), CAknApplication (Series 60). Tiến trình ứng dụng được

tạo bởi một chương trình nhỏ .exe, Apprun.exe, và tên của file chương trình ứng

dụng .app được chuyển làm tham số cho Apprun.exe.

* Định danh tệp

Symbian không quản lý các file dựa trên tên và phân biệt loại file dựa trên phần mở

rộng như các hệ điều hành khác vẫn làm mà quản lý dựa trên một tổ hợp 3 số 32-bit.

Mỗi một số như vậy được gọi là định danh tệp (Unique Identifier - UID). UID được

dùng để phân biệt và xác nhận, chọn lựa đúng các loại đối tượng khác nhau tại thời

điểm nạp và thực thi, như phân biệt ứng dụng console, DLL, server, v.v... UID cũng

là thành phần cơ bản để liên kết ứng dụng với tài liệu, ví dụ tài liệu ứng với một ứng

dụng sẽ yêu cầu hệ thống nạp ứng dụng khi tài liệu đó được mở.

Page 5: Symbian Programing

Ba UID này (UID1, UID2 và UID3) có giá trị hằng ứng với các tên gọi do Symbian

quy định, nhưng cũng có thể sử dụng số hệ 10 hay hệ 16.

- UID1: Định danh cấp hệ thống, chương trình thực thi .exe hay DLL được phân biệt

nhờ UID1. Với các giá trị tương ứng KExecutableImageUid=0x1000007A và

KDynamicLibraryUid=0x10000079.

- UID2: Định danh cấp giao tiếp, phân biệt các đối tượng cùng UID1. Ví dụ, UID2

được dùng để phân biệt thư viện dùng chung .dll và thư viện polymorphic (như .app,

.mdl, .fep hay .ctl) qua các giá trị: KSharedLibraryUid=0x1000008d cho thư viện

dùng chung và KUidApp=0x100039CE cho một ứng dụng đồ họa .app,

recognizer(auto start)=0x10003A19, front-end procesors=0x10005E32, hay control

panel=0x10003A34.

- UID3: Định danh cấp chương trình thực thi, phân biệt các đối tượng có cùng UID2,

chẳng hạn các ứng dụng đồ họa khác nhau sẽ có UID3 khác nhau. Do đó, có một tổ

chức quản lý UID3 này cho toàn môi trường Symbian. Để có nó, lập trình viên phải

gởi mail về [email protected] để xin một số UID3 duy nhất trên môi trường

Symbian.

=> Tổ hợp 3 số UID sẽ là duy nhất trên toàn môi trường Symbian. Nếu bạn sử dụng

UID3 tùy tiện thì chương trình của bạn vẫn có thể chạy được nhưng nếu trên 1 máy

nào đó có sẵn chương trình khác cùng loại và có cùng UID3 (nghĩa là trùng cả 3 số)

thì chương trình của bạn sẽ không chạy vì chương trình cài trước đó sẽ được ưu tiên.

Một đối tượng hay một file trong Symbian có thể có một, hai, ba hay không cần

UID.

- Để sử dụng thuận tiện trong việc tương tác và chuyển đổi dữ liệu với các hệ thống

khác, hệ điều hành cho phép không cần sử dụng UID. Khi không có UID, Symbian sẽ

phân biệt dựa vào quy ước đặt tên.

- Ứng dụng thực thi .exe thường chỉ có UID1 với giá trị KExecutableImageUid.

- Ứng dụng DLL: Các ứng dụng này có UID1 là KDynamicLibraryUid. Với các thư

viện dùng chung .dll, UID2 sẽ là KSharedLibraryUid. Với các thư viện polymorphic,

UID2 sẽ có nhiều giá trị khác nhau tùy từng loại. UID3 thì các DLL hầu như không

cần, chỉ có các loại thư viện polymorphic là cần đến.

- Đối với các loại tài liệu thì UID1 là KDirectFileStoreLayoutUid hoặc

KPermanentFileStoreLayoutUid ứng với tài liệu độc lập và tài liệu cơ sở dữ liệu.

UID2 và UID3 phụ thuộc ứng dụng mà tài liệu phục vụ.

=> Vì UID là giá trị được sử dụng để phân biệt nên cần sự chính xác. Đối với UID3

dùng trong ứng dụng đồ họa, trong quá trình phát triển, có thể sử dụng một giá trị bất

kỳ trong khoảng 0x01000000 và 0x0fffffff. Nhưng khi cài ứng dụng vào điện thoại thì

nhất định đó phải là con số được cấp chính xác và duy nhất.

Cấu trúc Project trên Symbian OS

Thông thường các project được xây dựng trên các IDE hỗ trợ nhưng trên Symbian thì

khác. Vì có nhiều loại điện thoại, nhiều nền hệ thống và nhiều bộ công cụ phát triển

khác nhau nên hệ điều hành Symbian đã cho phép project được đặc tả trong một định

dạng độc lập. Sau đó, với các công cụ đi kèm trong các bộ công cụ phát triển hay trên

các IDE hỗ trợ, các file project này được định dạng lại thành các file project phù hợp

Page 6: Symbian Programing

với IDE cho dòng điện thoại cụ thể và bộ SDK cho điện thoại đó.

* File định nghĩa project (.mmp)

File này mô tả các thông tin của project. Đây là một file project độc lập, nó sẽ được

chuyển thành file phù hợp môi trường phát triển cụ thể với các công cụ makmake

hay lệnh abld.bat. Nó định nghĩa các file tài nguyên và file thông tin ứng dụng cần

cho quá trình biên dịch.

Cấu trúc file .mmp gồm: các dòng khai báo với các loại câu khai báo khác nhau.

Thông thường chỉ một số ít khai báo được dùng. Sau đây là cú pháp các khai báo

thông dụng qua ví dụ project HelloWorld với file HelloWorld.mmp:

- Aif:

Mẫu khai báo:

aif target-file source-path resource [color-depth] source-

bitmap-list

Với:

target-file: Tên file đích, thường viết luôn phần đuôi và nằm trong thư mục ứng dụng.

source-path: Đường dẫn đến nơi chứa file tài nguyên mà aif cần

resource: Tên các file tài nguyên mà aif cần với tên đầy đủ.

color-depth: Đặc tả cho tất cả các file bitmap và ở dạng [c][digit] với c là color bitmap

và "digit" thể hiện độ sâu.

Ví dụ:

aif helloworld.aif \helloworld\aif\ helloaif.rss c8 hello.bmp

hellom.bmp

- Target:

target filename.ext

Ví dụ:

target HelloWorld.app

- TargetType:

Mẫu khai báo:

targettype target-type

Với target-type được hỗ trợ bao gồm: ani, app, ctl, dll, ecomiic, epocexe, exe, exedll,

fsy, kdll, kext, klib, ldd, lib, mda, mdl, notifier, opx, pdd, pdl rdl, var, wlog.

Ví dụ:

targettype app

- UID:

Mẫu khai báo:

uid uid2 [uid3]

Page 7: Symbian Programing

Mỗi ứng dụng thực thi có 3 loại UID, UID thứ nhất là targettype ở trên. Loại thứ hai

và thứ ba là tùy chọn. UID được viết dưới dạng số hệ 10 hoặc hệ 16.

Ví dụ:

uid 0x100039CE 0x10004299

- TargetPath:

Mẫu khai báo:

targetpath target-path

Ví dụ:

targetpath \system\apps\HelloWorld

- SourcePath:

Mẫu khai báo:

sourcepath directory

Có thể có nhiều sourcepath nhưng đối với file mã và tài nguyên công cụ biên dịch chỉ quan tâm đến trong khai báo sourcepath cuối cùng.

Ví dụ:

sourcepath ..\group

- Source:

Mẫu khai báo:

source source-file-list

Ví dụ:

source HelloWorld_Main.cpp

- UserInclude:

Mẫu khai báo:

userinclude directory-list

Ví dụ:

userinclude ..\inc

- SystemInclude:

Mẫu khai báo:

systeminclude directory-list

Ví dụ:

Page 8: Symbian Programing

systeminclude \epoc32\include

- Resource:

Mẫu khai báo:

resource resource-file-list

Khai báo tên nên đầy đủ phần mở rộng.

Ví dụ:

resource HelloWorld.rss

- Library:

Mẫu khai báo:

library filename-list

Ví dụ:

library euser.lib apparc.lib cone.lib eikcore.lib

=> Tệp HelloWorld.mmp hoàn chỉnh:

TARGET HelloWorld.app

TARGETTYPE app

UID 0x100039CE 0x10004299

TARGETPATH \system\apps\HelloWorld

SOURCEPATH .

SOURCE HelloWorld_Main.cpp

SOURCE HelloWorld_Application.cpp

SOURCE HelloWorld_Document.cpp

SOURCE HelloWorld_AppUi.cpp

SOURCE HelloWorld_AppView.cpp

USERINCLUDE .

SYSTEMINCLUDE \epoc32\include

RESOURCE HelloWorld.rss

LIBRARY euser.lib apparc.lib cone.lib eikcore.lib

AIF helloworld.aif \helloworld\aif\ helloaif.rss c8 hello.bmp

hellom.bmp

Page 9: Symbian Programing

* File mô tả thành phần bld.inf

File này luôn luôn có tên là bld.inf. Nó liệt kê danh sách các file project (thường chỉ 1), file xuất, các nền hệ thống và các file xuất với phần kiểm tra. Nó được công cụ

bldmake thực thi để tạo ra file bó abld.bat và các file thực thi khác. Thông thường

chỉ có khai báo prj_mmpfiles cho các file project được sử dụng.

Ví dụ: Với project HelloWorld trên, file bld.inf có cấu trúc như sau:

// Project files

prj_mmpfiles

HelloWorld.mmp

Chú ý: - Mỗi câu khai báo xuất hiện trên một hàng riêng

- Sử dụng cách ghi chú của C++ cho phần ghi chú(// hoặc /* */)

- Các file nên khai báo đầy đủ phần mở rộng.

- Dấu \ được sử dụng để xác định sự liên tục dòng (dòng dưới cũng thuộc câu lệnh với

dòng trên, do dài được cắt xuống), do đó khi khai báo đường dẫn, dấu \ sau cùng phải

bỏ đi. Ví dụ nên viết SYSTEMINCLUDE \epoc32\include chứ không phải là

SYSTEMINCLUDE \epoc32\include\.

Page 10: Symbian Programing

Hướng dẫn cài đặt và lập trình Symbian S60 3rd với VS2005

Dòng Symbian S60 3rd là hệ điều hành cho rất nhiều con điện thoại mạnh như Nokia

3250, Nokia E60, Nokia N91/N91 ME, N95, N95-8GB, N6290, N71, N73, N73 ME,

N75, N76, N92, N93, N93i, N6110 navigator, N5700 Xpress Music, N6120 classic,

N6121 classic, N81-MicroSD, N81-8GB, E50, E65, E90, E61/E61i, Nokia E63,

Nokia E70, Nokia E71, Nokia N80, Nokia N90, Nokia N77, Nokia N82... Vì vậy tôi

ưu tiên hướng dẫn cài đặt để lập trình cho dòng này trước.

Để cài đặt Symbian S60 3rd Edition tích hợp với IDE Microsoft Visual Studio

2005, thì đầu tiên bạn phải download Carbide.vs 3.0, bạn có tìm trên mạng chương

trình này hoặc download từ một trong hai địa chỉ sau:

- Download tại Rapidshare

- Download tại Megaupload

Sau khi download xong, bạn chạy chương trình này. Chương trình sẽ hướng bạn chi

tiết cần cài những gì và cả địa chỉ để download những thứ này. Cụ thể bạn phải cài đặt

những thứ sau:

1. Bạn cài Active Perl 5.6.1. Bạn hãy download tại địa chỉ Download Active Perl

5.6.1.638. Tôi cài nó vào thư mục C:\Symbian\Perl

2. Bạn cài SDK S60 3rd Edition. Bạn download SDK S60 tại địa chỉ Download SDK

S60. Ở đây tôi download và cài bản 3rd Edition, Maintenance Release. Tôi cài vào

thư mục C:\Symbian\9.1. Trong khi cài đặt, chương trình có hỏi bạn có cài đặt CSL

ARM Q1C Toolchain, thì bạn nhấn Yes để cài đặt nó. Và tôi cài nó vào thư mục

C:\Symbian\CSL Arm Toolchain 3. Bạn cài Java Runtime. Bạn download chương trình này trực tiếp tại trang chủ của

Java Sun

4. Bạn cài Visual Studio 2005. Sau khi cài xong Visual Studio 2005, bạn phải cài

Visual Studio 2005 SP1.

=> Các chương trình trên, bạn cài cái nào trước cũng được. Sau khi đã cài hết bạn

chạy lại Carbide.vs 3.0 và cài đặt bình thường. Ở đây tôi cài đặt vào thư mục

C:\Symbian\Carbide_vs30 Sau khi cài đặt xong, bạn restart lại máy tính.

Bây giờ bạn bật Visual Studio 2005, khi đó Carbide.vs 3.0 sẽ tự động chạy, nó hỏi

bạn đăng ký hoặc dùng 14 ngày. Nếu bạn lập trình bạn nên đăng ký luôn nhưng để

đăng ký được bạn phải đăng ký account trên trang Nokia Forum. Để đăng ký bạn chỉ cần chọn "I don't have serial number" rồi nhấn Next. Nếu không có mạng, bạn chọn "I

don't have Internet Connection" nhấn Next và làm theo hướng dẫn. Nếu bạn có mạng

bạn chọn "I have Internet Connection" và nhấn next, nó sẽ tự động link đến trang để

lấy key, bạn đăng nhập xong, bạn sẽ nhập được Serial Number. Bạn quay lại

Carbide.vs và nhập Username (Là Username mà bạn đăng nhập

http://www.forum.nokia.com) và nhập Serial Number vào để đăng ký.

Như vậy bạn đã hoàn thành cài đặt. Bây giờ bạn thử tạo Project Symbian mới. Bạn

vào File/New/Project, trong Visual C++ bạn chọn Symbian. Bạn chọn New

Symbian OS Project trong mục chọn Template, đánh tên Project (HelloWorld

chẳng hạn) và chọn thư mục. Các Project của Symbian tôi để trong thư mục

Page 11: Symbian Programing

C:\Symbian\Projects. Bạn nhấn Next, và chọn SDK (S60 3.0 Maint) rồi nhấn OK.

Bây giờ xuất hiện hộp thoại, bạn chọn:

- Project type: Symbian 9

- Project template: S60 3rd Ed. Hello World Application

- Bạn chọn S60 3.0 Maint, bạn chọn cả:

- WINSCW (Để lập trình và chạy trên máy ảo, luôn được chọn)

- GCCE (Để bạn build file sis chạy trên máy thật)

Bây giờ bạn nhấn Next để tùy chình thêm hoặc Finish để hoàn thành.

Bây giờ bạn để chế độ Debug, build và chạy thử. Máy ảo tự động được bật, nhưng

chương trình không tự động chạy được. Bạn phải vào mục Installations, bạn thấy

chương trình HelloWorld mà bạn vừa viết. Bạn hãy chạy thử xem.

Bây giờ bạn chọn chế độ Release, build lại Project. Trong thư mục Project của bạn,

bạn sẽ nhận được file HelloWorld.SIS trong thư muc sis. Bạn chỉ cần Sign file sis

này là có thể cài được trên máy thật sử dụng Symbian 3rd.

Page 12: Symbian Programing

Bạn nên tìm hiểu và tham khảo các ví dụ của SDK trong thư mục:

C:\Symbian\9.1\S60_3rd_MR\Examples.

Dòng Symbian S60 3rd và Symbian UIQ 3.x được thiết kế với chế độ bảo mật cao

hơn hẳn các dòng Symbian S60 1st và 2rd. Dòng này yêu cầu ứng dụng của bạn phải

được Sign trước khi bạn cài đặt nó lên máy thật. Với mỗi ứng dụng tương ứng với

một IMEI, bạn có thể vào trang SymbianSigned.com để Sign, và bạn phải chờ đợi để

nhận được ứng dụng đã được sign. Nếu bạn đã cài SDK, tôi xin hướng dẫn bạn tự ký

ứng dụng của mình (self-sign Symbian software) và ứng dụng của bạn đã sign sẽ chạy

trên tất cả các máy Symbian S60 3rd và Symbian UIQ 3.x mà không phân biệt từng

IMEI khác nhau. Bây giờ tôi hướng dẫn cách sign thông qua việc sign ứng dụng

HelloWorld.SIS của chúng ta:

- Đầu tiên, bạn bật hộp thoại Run, đánh cmd rồi Enter để vào màn hình Command

Line.

- Trong màn hình Command, bạn đánh lệnh:

cd \

cd "C:\Symbian\Projects\HelloWorld\HelloWorld\sis"

để vào thư mục chưa file HelloWorld.SIS.

- Bạn đánh lệnh sau để tạo ra hai file .key và .cer:

makekeys -cert -password 123456 -len 1024 -dname "CN=HelloWorld

OU=ThangDao OR=ThangDao CO=VN [email protected]" helloworld.key

helloworld.cer

Bạn di chuyển chuột trên màn hình command line để lấy dữ liệu ngẫu nhiên cho việc

tạo tệp certificate.

- Bây giờ bạn đánh lệnh sau để thực hiện Sign tệp SIS:

signsis HelloWorld.SIS HelloWorld_Signed.SIS helloworld.cer

helloworld.key 123456

Page 13: Symbian Programing

Bây giờ bạn lấy tệp HelloWorld_Signed.SIS (đã được Sign) để cài đặt trên máy thật.

Chú ý: - Bạn làm tương tự để signed cho ứng dụng khác.

- Bạn có thể dùng trực tiếp tệp helloworld.cer và helloworld.key để sign cho ứng

dụng khác, khi đó bạn chỉ cần dùng lệnh signsis mà thôi. Bạn chỉ phải thay tên file sis

dùng để sign và file sis tạo ra sau khi sign.

- Chứng chỉ của bạn (.cer và .key) chỉ có thời hạn trong một năm, kể từ lúc bạn tạo

hai tệp này.

- Với các ứng dụng tự sign, khi cài đặt trên máy thì sẽ có cảnh báo Warning. Bạn

chọn Continue để cài đặt.

Hướng dẫn cài đặt và lập trình Symbian S60 1st & 2nd với VC6

Để lập trình cho các dòng Symbian đời cũ như S60 1st và S60 2nd, nếu bạn không sử

dụng các hàm nào đặc biệt thì bạn nên cài bản 1st Edition, FP1, Wins. Khi đó ứng

dụng của bạn sẽ tương thích với tất cả các máy sử dụng dòng Symbian S60 1st và

2nd.

Để cài đặt và lập trình cho dòng này, bạn thực hiện như sau:

1. Bạn cài đặt ActivePerl-5.6.1 (Nếu bạn chưa cài). Bạn hãy download tại địa chỉ Download Active Perl 5.6.1.638. Tôi cài nó vào thư mục C:\Symbian\Perl

2. Bạn cài đặt S60 SDK 1st Edition. Bạn download SDK S60 tại địa chỉ Download

SDK S60. Ở đây tôi download và cài bản 1st Edition, FP1, Wins. Tôi cài vào thư

mục C:\Symbian\6.1.

3. Bạn cài Visual Studio 6.0 để làm IDE lập trình. IDE này tôi cài vào thư mục mặc

định.

Trong thư mục “C:\Symbian\6.1\Series60\Epoc32Ex” chứa các ví dụ sẵn có của

SDK, bạn có thể vào đây để xem và tham khảo. Ở đây, chúng ta bắt đầu thử với

project đầu tiên “Hello World”. Các Projects cho Symbian tôi để ở thư mục:

C:\Symbian\Projects - Để bắt đầu với ví dụ này, bạn copy thư mục helloworld trong

“C:\Symbian\6.1\Series60\Epoc32Ex” sang thư mục C:\Symbian\Projects.

- Bây giờ bạn bật hộp thoại Run, sau đó đánh cmd, rồi Enter để vào màn hình

Command Line. Bạn đánh lệnh sau để sang chuyển sang thư mục Project:

cd \

cd c:\symbian\projects\helloworld

- Tiếp bạn đánh lệnh:

bldmake bldfiles

khi đó tệp ABLD.BAT sẽ được tạo trong thư mục project helloworld.

- Bây giờ bạn đánh tiếp lệnh:

Page 14: Symbian Programing

abld makefile vc6

để tạo ra tệp Project (HelloWorld.dsw) trên VC6. Bạn đừng đóng màn hình

Command Line vội. Tí nữa bạn sẽ còn phải dùng tiếp.

- Bây giờ bạn search file “helloworld.dsw” trong thư mục cài đặt SDK

(C:\Symbian\6.1), chính xác thì nó ở trong thư mục

C:\Symbian\6.1\Series60\Epoc32\BUILD\SYMBIAN\PROJECTS\HELLOWOR

LD\HELLOWORLD\WINS

- Bạn mở tệp “helloworld.dsw” bằng Visual Studio 6.0, bạn chon chế độ Debug

(Release cũng vậy thôi), và nhấn F7 để build thử. Không lỗi gì đúng không bạn. Bây

giờ bạn ấn Ctrl+F5 để chạy thử chương trình trên máy ảo. Nếu nó xuất hiện hộp thoại

thì bạn chỉ đường dẫn đến tệp epoc.exe cho nó:

+ Nếu dịch Debug bạn chỉ đến

C:\Symbian\6.1\Series60\Epoc32\Release\wins\udeb\epoc.exe + Nếu dịch Release thì bạn chỉ đến thư mục

C:\Symbian\6.1\Series60\Epoc32\Release\wins\urel\epoc.exe

Bạn nhấn OK, máy ảo sẽ được bật lên. Bạn dùng phím mũi tên di chuyển xuống dưới,

bạn sẽ thấy ứng dụng helloworld mà bạn vừa build. Bạn hãy chọn nó để chạy thử:

Page 15: Symbian Programing

- Chạy máy ảo vậy là okie. Bây giờ bạn sẽ build để chạy máy thật. Bạn đánh lệnh sau:

abld build armi urel

- Bây giờ bạn sẽ thấy trong thư mục

C:\Symbian\6.1\Series60\Epoc32\Release\armi\urel có các tệp

HELLOWORLD.APP và HELLOWORLD.RSC

- Bạn copy hai tệp này vào thư mục nào đó trong ổ C:, chẳng hạn tôi copy vào thư

mục C:\Symbian\Apps\helloworld

Page 16: Symbian Programing

-Trong thư mục C:\Symbian\Apps\helloworld bạn tạo thêm tệp helloworld.pkg như

sau:

; helloworld.pkg

;

; standard SIS file header

#{"Helloworld"},(0X10008ACE),1,0,0,TYPE=SISAPP

;Supports Series 60 v2.0

(0x101F6F88), 0, 0, 0, {"Series60ProductID"}

;Tep lien quan den ung dung

"HELLOWORLD.APP"-"!:\system\apps\HelloWorld\HelloWorld.app"

"HELLOWORLD.RSC"-"!:\system\apps\MDictPro\HelloWorld.rsc"

- Sau đó bạn đánh lệnh sau để vào thư mục chứa các tệp này. Sau đó đánh các lệnh

sau:

cd \

cd "C:\Symbian\Apps\helloworld"

makesis helloworld.pkg

Bây giờ bạn đã có file helloworld.SIS để cài đặt và chạy trên máy thật.

=> Vậy là Okie rồi. Chúng ta đã cài đặt và chạy thử thành công.

Upload lại links cho các bạn down:

ActivePerl-5.6.1.638 (8 MB): http://downloads.activestate.com/ActivePerl/Windows/5.6/

ActivePerl-5.8.8.819 (15 MB): http://oldapps.com/Perl.php

Sau đây là chương trình Helloworld đã được viết và đóng gói lại thành file *sis

Download tại đây: http://www.mediafire.com/file/cmtmkwinz ... oworld.rar

Page 17: Symbian Programing

Cấu trúc chương trình trên Symbian S60

Bây giờ chúng ta đi sau phân tích cấu trúc của một chương trình trên Symbian S60

thông qua ví dụ HelloWorld ở trên. Đây là ứng dụng dạng GUI có đuôi .APP. Để

thống nhất tên lớp thì trên Symbian S60 3rd, bạn tạo Project với tên là Example chứ

không phải HelloWorld như trước nữa.

Chúng ta thấy rằng, ứng dụng HelloWorld bao gồm các lớp như sau:

- Lớp CExampleApplication: Đây chính là lớp Application và kế thừa từ

CEikApplication (trên Symbian S60 1st) hoặc lớp CAknApplication (trong

Symbian S60 3rd). Lớp này chịu trách nhiệm thiết lập và thực thi ứng dụng.

- Lớp CExampleDocument: Đây là lớp Document của ứng dụng. Lớp này được kế

thừa từ lớp CEikDocument (trên Symbian S60 1st) hoặc lớp CAknDocument (trên

Symbian S60 3rd). Lớp này được tạo bởi lớp Application, nó quản lý dữ liệu của ứng

dụng. Lớp này cũng có nhiệm vụ khởi tạo lớp giao diện ứng dụng AppUi.

- Lớp CExampleAppUi: Đây là giao diện ứng dụng AppUi. Lớp này kế thừa từ

CEikAppUi (Symbian S60 1st) hoặc CAknAppUi (Symbian S60 3rd), và có nhiệm

vụ điều khiển các sự kiện. Lớp này sẽ nhận các sự kiện như chọn menu, phím bấm, …

và gửi sự kiện này tới các View và Container.

Lớp này điều khiển sự kiện chọn menu thông qua hàm

void HandleCommandL(TInt aCommand);

và điều khiển sự kiện phím nhấn thông qua hàm:

void HandleWsEventL(const TWsEvent &aEvent, CCoeControl

*aDestination)

- Lớp CExampleAppView: Đây chính là view để hiển thị ra màn hình, nó kế thừa từ

lớp CCoeControl. Bạn hãy thực hiện thao tác vẽ trong hàm:

void Draw(const TRect& /*aRect*/) const;

của lớp view.

Như vậy chúng ta thấy cấu trúc ứng dụng GUI trên Symbian S60 như sau:

Page 18: Symbian Programing

Khi ứng dụng được chọn thực thi, chương trình apprun.exe sẽ hoạt động với tên ứng

dụng và tên file ứng dụng làm tham số. Chương trình apprun sẽ sử dụng kiến trúc

ứng dụng APPARC để nạp ứng dụng qua việc kiểm tra UID2 là KUiApp

(0x100039ce) và tạo đối tượng ứng dụng đồ họa qua hàm NewApplication(). Các

hàm này bao gồm hàm [color=#0000FF]NewApplication()[/color] và hàm

E32Dll(TdllReason) (một hàm chỉ cài đặt, không sử dụng). Từ khóa EXPORT_C để

báo hàm NewApplication là đầu vào của một DLL.

EXPORT_C CApaApplication* NewApplication()

{

return new CExampleApplication;

}

GLDEF_C TInt E32Dll(TDllReason)

{

Page 19: Symbian Programing

return KErrNone;

}

Khi NewApplication() được gọi, đối tượng CExampleApplication sẽ được tạo, đối

tượng này tạo CExampleDocument, và lớp CExampleDocument sẽ tạo lớp giao

diện ứng dụng CExampleAppUi. Khi lớp CExampleAppUi được tạo, hàm khởi tạo

ConstructL của AppUi sẽ được gọi, và trong hàm này lớp CExampleAppView được

tạo thông qua lệnh:

iAppView = CExampleAppView::NewL(ClientRect());

Khi view được tạo, ngoài các hàm khởi tạo ContructL, nó gọi thêm hàm

void Draw(const TRect& /*aRect*/) const;

để thực hiện vẽ lên màn hình hiển thị.

Trong lớp CExampleAppUi, thì bạn dùng hàm

void HandleCommandL(TInt aCommand);

để điều khiển sự kiện cho menu. Nhưng trong ứng dụng trên Symbian S60 1st của

chúng ta không có menu nên bạn không thể thoát khỏi ứng dụng. Bây giờ tôi thực

hiện điều khiển sự kiện phím nhấn để thực hiện thoát khỏi ứng dụng khi nhấn phím

trái. Ở đây tôi sử dụng hàm HandleWsEventL để điều khiển nhận sự kiện phím trái để

thoát khỏi ứng dụng. Để thực hiện được điều này, bạn làm như sau:

- Bạn thêm khai báo vào phần khai báo của lớp CExampleAppUi:

void HandleWsEventL(const TWsEvent &aEvent, CCoeControl

*aDestination);

ngay sau khai báo hàm HandleWsEventL

- Trong phần mã lệnh của lớp CExampleAppUi bạn thêm đoạn mã sau:

void CExampleAppUi::HandleWsEventL(const TWsEvent &aEvent,

CCoeControl *aDestination)

{

if (aEvent.Type()==EEventKey && aEvent.Key()-

>iCode==EKeyDevice0)

Exit();

CEikAppUi::HandleWsEventL(aEvent, aDestination); // Tren

Symbian S60 1st

//CAknAppUi::HandleWsEventL(aEvent, aDestination); // Tren

Symbian S60 3rd

}

Bây giờ bạn chạy ứng dụng, và dùng phím chức năng bên trái để thoát khỏi ứng dụng.

Việc bạn bắt sự kiện phím trên Symbian OS 3rd cũng tương tự.

+ Mô hình MVC trong Symbian Như vậy một ứng dụng GUI trên Symbian tuân theo mô hình MVC (Model - View -

Control). Mô hình này bao gồm:

Page 20: Symbian Programing

- Model: Dữ liệu của ứng dụng, nó đảm nhận việc lưu trữ các thông tin dữ liệu của

ứng dụng.

- View: Nơi thể hiện dữ liệu của ứng dụng, người dùng chỉ có thể biết ứng dụng thông

qua nó.

- Controller: Phần này có nhiệm vụ thao tác trên dữ liệu ứng dụng: cập nhật model

sau đó yêu cầu view thể hiện lại phần cập nhật.

=> Tuy nhiên không phải lúc nào cũng phải đầy đủ cả phần này. Tùy theo tính chất

của ứng dụng mà có thể ranh giới giữa model và view không rõ ràng hay có thể thiếu

đi phần controller. Đây chính nguyên tắc cho các ứng dụng đồ họa: "Những gì thể

hiện trên màn hình giao tiếp với người dùng sẽ do các hàm vẽ (draw) đảm nhận.

Chúng chỉ có nhiệm vụ đơn giản là vẽ lại dữ liệu của ứng dụng lên màn hình, chúng

không thay đổi dữ liệu. Nếu bạn muốn thay đổi gì đó thì bạn phải sử dụng hàm khác

và rồi gọi lại hàm vẽ này để vẽ lại dữ liệu đã thay đổi".

Mô hình MVC và Symbian có mối quan hệ rất mật thiết, nó là mô hình thiết kế chủ

đạo trong Symbian. Nếu để ý kỹ bạn sẽ thấy lớp document là hiện thân của model,

lớp AppView chính là view, còn AppUi sẽ đóng vai trò là controller trong mô hình

MVC. Với những ứng dụng phức tạp thì sẽ có nhiều lớp đảm nhận một thành phần

trong MVC.

Không những vậy, hầu hết các control trong Symbian đều được thiết kế theo mô hình

MVC. Nắm bắt được điều này, bạn sẽ dễ dàng thao tác với các control trong

Symbian. Tôi nhớ là có khá nhiều người mới lập trình Symbian khi làm quen với

listbox đều đặt câu hỏi: "Làm sao để lấy dữ liệu một item trong listbox đây bởi trong

lớp CEikListbox không thể tìm thấy hàm nào đảm nhận việc này". Đó là vì listbox

trong Symbian cũng được thiết kế theo mô hình MVC nên nếu muốn lấy dữ liệu, bạn

phải đến lớp MListBoxModel thông qua hàm Model() trong lớp CEikListbox.

Quy ước và cách đặt tên khi lập trình với Symbian OS

Symbian đưa ra một số quy ước trong lập trình. Một số quy ước bạn không nhất thiết

phải theo nhưng nhưng một số thì bạn nên tuân thủ để phục vụ cho việc lập trình của

bạn thuận lợi, tránh sai sót và dễ nâng cấp sau này.

1. Tên lớp Symbian sử dụng các quy ước đặt tên sau để xác định đặc tính cơ bản của một lớp:

- Lớp T: Lớp đơn giản (tựa như typedef) thường xây dựng từ các kiểu dữ liệu cơ sở

hay kết hợp chúng lại, có thể so sánh lớp T với struct đơn giản bao gồm các dữ liệu

public. Nó không có destructor (có thể có constructor nhưng hiếm) và thường được

lưu trên stack, có thể lưu trên heap. Kiểu liệt kê (enum) cũng thường khai báo dưới

dạng lớp T. Ví dụ: TInt, TBool, TPoint, TDes, TMonthsOfYear ...

- Lớp C: Lớp có constructor và destructor và tất cả đều là dẫn xuất từ CBase. Các đối

tượng của chúng được tạo bằng new và luôn được lưu trữ trên heap. Ví dụ:

CConsoleBase, CActive,...

- Lớp R: Lớp R (đại diện cho Resource), thường đại diện cho một loại tài nguyên,

quản lý một sesion kết nối với một server phục vụ một tài nguyên. Đối tượng lớp R

thường có một hàm khởi tạo (Open() hoặc Create() hay Initialize()) và một hàm kết

Page 21: Symbian Programing

thúc (Close() hay Reset()) để giải phóng tài nguyên. Quên gọi hàm kết thúc khi dùng

đối tượng lớp R là một lỗi thường gặp và kết quả là sẽ bị leak bộ nhớ. Nó có thể được

lưu trên heap, nhưng thường là trên stack. Ví dụ: RFile, RTimer, RWindow,...

- Lớp M (Mix-ins): Lớp ảo (abstract) giống như interface trong Java, nó chỉ bao

gồm các phương thức ảo rỗng và không có dữ liệu cũng như constructor. Việc kế thừa

nhiều lớp trong Symbian là cho phép tuy nhiên phải theo quy tắc là kế thừa chính từ 1

lớp C (bắt buộc phải có và viết đầu tiên) và nhiều lớp M. Ví dụ:

MGraphicsDeviceMap, MGameViewCmdHandler,...

=> Việc phân biệt giữa T, C và R lớp là rất quan trọng, nó ảnh hưởng tới việc giải

phóng bộ nhớ khi sử dụng cũng như cách thức xử lý các đối tượng thuộc các lớp này.

Ngoài ra trong Symbian còn có các lớp tĩnh (static) phục vụ cho một số chức năng

riêng như lớp User hay lớp Mem. Một ngoại lệ khác là lớp HBufC, chúng ta sẽ nói

đến nó trong bài viết về sử dụng xâu trên Symbian.

2 Tên dữ liệu Tương tự, Symbian cũng dùng chữ cái đầu để phân biệt các loại dữ liệu:

- Hằng liệt kê (Enumerated constant): Bắt đầu với ký tự E, nó đại diện cho một giá

trị hằng trong một dãy liệt kê. Nó có thể là một phần của lớp T. Ví dụ: (ETrue,

EFalse) của TBool hay EMonday là một thành phần của TDayOfWeek.

- Hằng (constant): Bắt đầu với ký tự K, thường được dùng trong các khai báo

#define hay các giá trị hằng do Symbian quy định. Ví dụ: KMaxFileName hay

KErrNone.

- Biến thành phần (member variable): Bắt đầu với chữ cái i (instance), được dùng

khi sử dụng các biến động là thành viên của một lớp. Đây là quy ước quan trọng,

dùng cho việc hủy vùng nhớ trên heap của các đối tượng này trong destructor. Tôi

thường chỉ dùng quy ước này nếu biến này sẽ được lưu trên heap, còn trên stack thì

không. Ví dụ: iDevice, iX, …

- Tham số (argument): Bắt đầu bằng chữ a (argument), được dùng khi các biến làm

tham số. Ví dụ: aDevice, aX, …

- Macro: Không có quy ước đặc biệt. Tất cả đều viết hoa và dùng dấu gạch dưới để

phân tách từ. Ví dụ: IMPORT_C, _TEST_INVARIANT, _ASSERT_ALWAYS,

v.v…

- Biến cục bộ (automatic): Chữ cái đầu nên viết thường.

- Biến toàn cục (global): Nên viết hoa chữ cái đầu nhưng để tránh nhầm lẫn nên bắt

đầu tên bằng chữ cái “g”. Tuy nhiên trên Symbian không khuyến khích dùng biến

toàn cục.

3. Tên hàm Tên hàm bắt đầu bằng ký tự hoa. Khác với 2 trường hợp trên, quy ước đặt tên hàm lại

dựa trên ký tự cuối cùng:

- Hàm không ngắt giữa chừng (non-leaving function): Đó là hàm mà trong quá

trình thực thi nó đều diễn ra suông sẻ, chi tiết tôi sẽ nói sau. Ví dụ: Draw() hay

Intersects().

- Hàm ngắt giữa chừng (leaving function): Là hàm bị ngắt ngang vì một lý do nào

đó: lỗi, thiếu tài nguyên, ... Hàm này kết thúc bằng ký tự L. Ví dụ: DrawL() hay

RunL().

- Hàm LC: Kết thúc với cặp ký tự LC. Các hàm này trong lòng nó có khai báo một

đối tượng mới, và có đặt đối tượng này lên cleanup stack (ngăn xếp chứa các đối

tượng cần xóa khi có ngắt xảy ra, sẽ nói rõ sau) và có khả năng xuất hiện ngắt trong

khối xử lý hàm. Bạn lưu ý là sau khi gọi hàm này sẽ phải gọi Cleanup:PopAnd

Page 22: Symbian Programing

Destroy(), lý do tôi sẽ nói trong phần về cleanup stack, nếu quên gọi nó chắc chắn bạn

sẽ bị lỗi 3 mà không hiểu tại sao. Ví dụ: AllocLC(), CreateLC(), OpenLC() hay

NewLC(),...

- Các hàm Get và Set: Trong trường hợp đơn giản thường là các hàm thành viên của

một lớp. Set dùng cho việc xác lập giá trị cho một biến thành viên của lớp. Get được

dùng cho các hàm sẽ trả về giá trị trên tham số. Khi hàm có giá trị trả về thì thường

không dùng Get.

Ví dụ: SetThing(aData); GetThing(aData); nhưng iData = Thing();

4. Cấu trúc thư mục project Tuy không bắt buộc nhưng Symbian khuyến khích lập trình viên xây dựng thư mục

project ứng dụng thành các thư mục con với chức năng riêng biệt. Thông thường thư

mục project có cấu trúc như sau:

- Thư mục project: Chứa các file project .mmp, bld.inf, file tài nguyên .rss. Thư mục

này cũng sẽ lưu trữ các file thông tin cụ thể cho chương trình dùng với các IDE. Thư

mục này thường được đặt tên là: group.

- Thư mục các file khai báo: Chứa các file khai báo cho file tài nguyên và các file

mã nguồn. Thư mục này thường có tên là: inc.

- Thư mục mã nguồn: Chứa các file cài đặt các lớp chương trình. Thư mục này

thường có tên là: src.

- Thư mục dữ liệu: Chứa dữ liệu cần cho chương trình ứng dụng và có tên là data.

- Thư mục thông tin ứng dụng: Chứa file tài nguyên .rss để tạo file .aif và các hình

ảnh, tài nguyên phục vụ cho ứng dụng. Tậo hợp các hình này được lưu trữ trong một

file .mbm (multi bitmap). Thư mục này có tên là aif.

- Thư mục cài đặt: Chứa các file .pkg, các thành phần cài đặt bổ sung cho ứng dụng.

Thư mục này thường có tên là: install.

- Thư mục chương trình: Lưu trữ file cài đặt .sis. Thường nó được gộp với thư mục

install. Thư mục này có tên là release.

=> Tuy nhiên các project thường chỉ gồm các thư mục: group, inc và src.

5. Trình bày code Nếu lập trình trên C và Java thấy 2 phong cách trình bày quen thuộc là:

void Example()

{

.........

.........

}

void Example(){

.........

.........

}

thì Symbian đề xuất cách trình bày sau:

void Example()

->{

->.........

->........

->}

Page 23: Symbian Programing

Xử lý ngoại lệ trên Symbian (Leave-Symbian exeption)

1. Cơ chế bắt lỗi trên Symbian Nếu bạn đã quen với lập trình C++ hay Java thì exeption handling là một khái niệm

chẳng xa lạ gì. Đây là cơ chế giúp ta quản lý các lỗi phát sinh. Lúc Symbian được

thiết kế thì cơ chế exeption chưa được giới thiệu trong C++ hơn nữa sau này khi được

giới thiệu thì nó cũng tỏ ra không phù hợp trong môi trường hạn chế về xử lý và bộ

nhớ như Symbian bởi chúng làm tăng đáng kể kích thước mã biên dịch và tốn nhiều

RAM, lại không thật sự hiệu quả.

Vì vậy Symbian đã đưa ra một cơ chế quản lý lỗi cho riêng mình được biết dưới tên

gọi "leave". Do đó tuy Symbian sử dụng cú pháp C++ nhưng không hề có từ khóa try,

catch hay throw đâu, các bạn nên chú ý điều này.

Trong một môi trường mà tài nguyên hạn hẹp như Symbian thì một cơ chế bắt lỗi hiệu

quả và ít tốn kém sẽ rất cần thiết. "Leave" đã đáp ứng điều này. Cơ chế hoạt động

của "leave" như sau: "Khi xảy ra một lỗi nào đó (thiếu bộ nhớ để cấp phát, thiếu vùng

nhớ để ghi, lỗi trong truyền thông hay thiếu năng lượng cho các tài nguyên,...) thì

hàm đang hoạt động sẽ bị ngắt lại, quyền điều khiển sẽ được chuyển đến phần chỉ thị sửa lỗi".

Xét về mặt cú pháp thì cơ chế "leave" này khá tương đồng với cơ chế của C++. Hàm

đang thực thi bị ngắt bởi một cuộc gọi đến hàm User::Leave() hay

User::LeaveIfError() khá giống với throw trong C++ còn 2 marco TRAP và TRAPD

trên Symbian thì tương đồng với try và catch trên C++.

Ví dụ: TInt result;

TRAP(result, MyLeaveL());

if (KErrNone==result)

{

//Code

}

User::LeaveIfError(result);

2. Hàm leave Như tôi đã nói trong phần quy ước trên Symbian, hàm có thể leave thì sẽ kết thúc

bằng chữ L. Một hàm có thể leave nếu nó:

- Gọi hàm có thể leave mà không được gọi kèm với các trap harness như TRAP hay

TRAPD.

- Gọi một trong các hàm hệ thống đảm nhận leave như User::Leave() hay

User::LeaveIfError(),...

- Có dùng toán tử new(Eleave).

Chắc có lẽ có nhiều bạn sẽ thắc mắc tại sao tôi lại quá chú trọng đến "leave" như vậy.

Thật ra "leave" là một khái niệm rất cơ bản trên Symbian bởi vì:

- Thứ nhất, nguồn tài nguyên trên Symbian khá hạn hẹp nên lỗi thiếu tài nguyên hay

xảy ra

Page 24: Symbian Programing

- Thứ 2, nếu bạn không chú ý kỹ đến nó, nhất là phần thế nào là một hàm leave thì

bạn sẽ gặp phải lỗi rất lớn trong lập trình trên Symbian: gây ra "leak" bộ nhớ.

An toàn hơn với Cleanup stack

Khi hàm của bạn có leave xảy ra thì tại thời điểm leave, điều khiển sẽ được chuyển

đến phần xử lý lỗi, lúc này vùng stack cho hàm có leave này sẽ được giải phóng, các

biến khai báo cục bộ trong hàm này sẽ bị xóa đi. Đối với các biến khai báo kiểu T trên

stack thì không sao nhưng đối với các biến kiểu C khai báo trên heap hay các biến

kiểu R thì đây là vấn đề nghiêm trọng. Bởi lẽ theo đúng quy trình thực thi, nếu không

có gì xảy ra thì vào cuối hàm, chúng ta sẽ hủy vùng nhớ đối tượng trên heap qua toán

tử delete hay gọi hàm Close() cho các biến kiểu R nhưng nếu giữa chừng hàm bị ngắt

trước khi ta gọi các hàm hủy này thì rõ ràng các đối tượng này sẽ không được giải

phóng hoàn toàn, tạo ra leak (lỗ hổng) trên bộ nhớ.

Leak bộ nhớ là vùng nhớ trên heap thực sự không được sử dụng nhưng hệ điều hành

nghĩ là nó đang sử dụng và sẽ không sử dụng vùng nhớ này để cấp phát cho các đối

tượng khác. Leak bộ nhớ thường do bạn cấp phát động bộ nhớ (sử dụng hàm new, ...)

mà không giải phóng nó (hàm delete,...). Bị leak bộ nhớ sẽ gây ra sự lãng phí tài

nguyên bộ nhớ, đặc biệt trên thiết bị giới hạn về tài nguyên như di động thì là cả một

vấn đề.

Ví dụ: void UnsafeFunctionL()

{

CExClass* test = CExClass::NewL(); //Hàm có thể leave test->FunctionMayLeaveL();

delete test;

}

Điều gì xảy ra khi hàm FunctionMayLeaveL() bị leave, lúc này hàm

UnsafeFunctionL() sẽ bị ngắt, stack sẽ bị xóa, biến test bị bị xóa nhưng vùng nhớ

cấp cho nó trên heap qua hàm CExClass::NewL() thì vẫn còn và lúc này không ai

quản lý nó cả, nó bị "mồ côi" trên heap. Vùng nhớ cấp phát này sẽ tồn tại mà không

được giải phóng tại ra một lỗ hổng trong bộ nhớ.

Vậy bây giờ ta phải làm sao đây để luôn đảm bảo không bị lỗ hổng trên bộ nhớ khi có

leave xảy ra? Symbian đã đưa ra khái niệm mới là Cleanup Stack. Cleanup stack là

một ngăn xếp có nhiệm vụ giải phóng các vùng nhớ cấp cho các đối tượng được đưa

vào chúng trước đó khi leave xảy ra.

Ví dụ: Dùng hàm trên với cleanup stack:

void SafeFunctionL()

{

CExClass* test = CExClass::NewL(); //Hàm có thể leave CleanupStack:: push(test);

test->FunctionMayLeaveL();

CleanupStack:: pop(test);

Page 25: Symbian Programing

delete test;

}

Lúc này nếu có leave xảy ra thì chúng ta vẫn không sợ bị lủng bộ nhớ vì cleanup stack

đã giải phóng vùng nhớ cho biến test giùm chúng ta rồi nhờ hàm:

CleanupStack::push(test).

Một số lưu ý: - Nếu leave không xảy ra thì chúng ta phải lấy đối tượng cần hủy ra khỏi cleanup

stack qua hàm CleanupStack::pop(test) (chúng ta có thể dùng nhiều cách pop khác

nhau, chi tiết các bạn xem qua lớp CleanupStack).

- Với những hàm kế thúc bằng LC, nghĩa là có thể leave và đã có push lên cleanup

stack rồi, nên sau khi gọi hàm này, bạn phải gọi hàm CleanupStack::pop() hoặc

CleanupStack::popAndDestroy() nếu không sẽ bị lỗi. Lỗi này tôi cũng đã nói trong

phần quy ước rồi, các bạn chú ý nhé, hay bị lỗi này lắm đó.

- Đối với các đối tượng kế thừa các lớp khác ngoài lớp C thì khi hủy cleanup stack

chỉ có thể hủy vùng nhớ mà không thể gọi destructor như đối với lớp C được nên

Sym bian đề xuất một số hàm push khác cho phù hợp: CleanupReleasePushL() để

chỉ giải phóng vùng nhớ (đối tượng lớp T), CleanupDeletePushL() để chỉ thực thi

destructor (đối tượng lớp M) hay CleanupClosrPushL() để giải phóng tài nguyên

cấp cho các đối tượng lớp R.

Leave và Cleanup stack là một cặp bài trùng tạo nên sự an toàn cho lập trình trên

Symbian. Đây là 2 khái niệm rất cơ bản, nếu không hiểu vè nó, trong khi lập trình có

thể bạn sẽ gặp lỗi mà không biết đường sửa hay có thể gặp vài lỗi rất ngớ ngẫn.

Khởi tạo hai pha (Two-phase construction) trong Symbian

Đến đây chắc bạn đã thấy là Symbian hỗ trợ quản lý bộ nhớ tốt như thế nào, đảm bảo

cả trong điều kiện lỗi vẫn không bị lủng bộ nhớ. Lý do khiến Symbian rất chú trọng

đến việc này là so với PC, điện thoại di động có bộ nhớ không lớn bằng hơn nữa các

ứng dụng trên điện thoại đôi khi phải chạy hàng tháng, thậm chí hàng năm (nếu ta

không tắt máy).

Từ bài cleanup stack, có người thắc mắc là có phải tất cả các lớp đều có hàm NewL()

và NewLC() để khởi tạo đối tượng không. Nhận thấy có một phần quan trọng đi liền

sau leave và cleanup stack là khởi tạo 2 pha (two-phase construction) nên tôi sẽ xin

nói về nó luôn.

1. Khởi tạo hai pha (Two-phase construction) Theo đúng cú pháp C++, một đối tượng mới sẽ được cài đặt như sau:

CExam* exam = new (Eleave) CExam();

Hệ thống sẽ làm gì với code trên: "Đầu tiên, một vùng nhớ sẽ được cấp trên heap cho

đối tượng lớp CExam nhớ hàm new, rồi sau đó constructor của lớp CExam sẽ được

gọi để hoàn tất việc khởi tạo đối tượng. Điều gì sẽ xảy ra nếu hàm constructor của

Page 26: Symbian Programing

lớp này bị leave, rõ ràng là bộ nhớ sẽ bị lủng do heap đã cấp một vùng cho đối tượng

foo rồi và như vậy vùng nhớ này sẽ bị "mồ côi" trên heap".

=> Lúc này ắt hẳn bạn sẽ nghĩ ngay đến cleanup stack, thế nhưng tiếc thay trong

trường hợp này lại không dùng được. Tai sao ư? Tại vì để làm được điều đó thì hàm

CleanupStack::push phải đặt trong lòng toán tử new, điều này có thể sao?!

Vì vậy Symbian đưa ra một luật là: "constructor không được phép leave". Nhưng đôi

khi trong phần khởi tạo của chúng ta lại có phần có thể leave thì sao, chẳng hạn như

cấp phát bộ nhớ hay tạo một session truy cập tài nguyên. Trong tình huống đó, khởi

tạo 2 pha (two-phase construction) sẽ giúp bạn:

- Pha 1: Phần constructor đơn giản, không leave. Phần này sẽ được gọi liền ngay sau

khi toán tử new được gọi.

- Pha 2: Một hàm khác sẽ đảm nhận việc hoàn tất khởi tạo, trên Symbian thường đặt

tên là ConstructL(), hàm này có thể leave.

CExam* exam = new (Eleave) CExam(); // Pha 1

CleanupStack::push(exam);

exam->ContructL(); // Pha 2

CleanupStack:: pop();

Và bây giờ thì ta đã yên tâm là bất cứ có gì xảy ra, bộ nhớ vẫn nguyên vẹn.

2. NewL() và NewLC() Nhưng cách trên bất tiện ở chỗ là khi khởi tạo 1 đối tượng lại phải gọi 2 pha với 4

hàm, vừa bất tiện vừa dễ quên. Do đó Symbian tiếp tục đưa ra một khái niệm nữa để

giúp cho lập trình viên chúng ta tránh được sự hay quên và dài dòng này. Trong lớp

CExam, chúng ta tạo thêm 2 hàm tĩnh (có từ khóa static đằng trước phần khai báo

thông thường) NewL() và NewLC() như sau:

CExam* CExam::NewLC()

{

CExam* me = new (Eleave) CExam(); // Pha 1

CleanupStack::push(me);

exam->ContructL(); //Pha 2

return me;

}

CExam* CExam::NewL()

{

CExam* me = CExam::NewLC();

CleanupStack:: pop (me);

return me;

}

Và lúc này việc khai báo đối tượng của bạn sẽ vừa dễ dàng lại đảm bảo:

CExam* exam = CExam::NewL();

Lưu ý: Ở trên các bạn thấy tôi luôn xài Eleave sau toán tử new. Nhờ nó mà nếu

không cấp phát được, leave sẽ xảy ra. Nếu không có nó rõ ràng sau hàm new bạn phải

kiểm tra xem có cấp phát thành công không, rất mất công lại làm code phức tạp thêm.

Page 27: Symbian Programing

CExam* exam = new CExam();

if (NULL != exam)

{

// Cấp phát thành công }

Tóm lại: Nếu trong hàm constructor mà không có gì để gây ra leave cả, thì các bạn

cứ xài như đã từng xài trước đây, nghĩa là dùng code như C++ vậy. Nếu trong hàm

constructor này mà có leave thì bạn mới phải cần đến two-phase construction.

Sử dụng chuỗi (Descriptor) trên Symbian

+ Tổng quan về chuỗi (Descriptor) trên Symbian

Trên Symbian, chuỗi được gọi là descriptor bởi chúng tự mô tả: một descriptor chứa

kích thước, kiểu chuỗi bên cạnh nội dung chuỗi trong vùng nhớ. Đây là điều mà chuỗi

trong C/C++ hay Java không có.

Descriptor được xây dựng theo hướng tối ưu hóa vùng nhớ cấp phát, điều rất cần trên

các môi trường bộ nhớ thấp như Symbian. Nhưng cũng chính vì điều này mà

descriptor làm đau đầu khá nhiều lập trình viên về việc sử dụng chúng.

Từ version 5.0 trở về trước, Symbian chưa hỗ trợ Unicode nên descriptor chỉ hỗ trợ

chuỗi với ký tự 8 bit, nhưng từ v5.1 trở về sau thì descriptor trên Symbian hỗ trợ cả 8

bit và 16 bit (Unicode). Một điểm đặc biệt nữa là descriptor không sử dụng ký tự đặc

biệt để kết thúc chuỗi như trên C/C++ hay Java, nên dữ liệu chúng chứa có thể là dữ

liệu nhị phân. Việc sử dụng chung descriptor cho lưu trữ ký tự và nhị phân rõ ràng sẽ

Page 28: Symbian Programing

làm nhỏ gọn lại Symbian và tiện lợi cho người dùng. Lưu ý là khi muốn lưu trữ nhị phân, bạn phải khai báo descriptor ở dạng 8 bit.

Các descriptor có hai dạng:

- Descriptor hằng (Descriptor có dữ liệu không thể thay đổi được)

- Descriptor động (Descriptor có dữ liệu có thể thay đổi được)

Hình vẽ sau cho cho ta thấy được kiến trúc của Descriptor trên Symbian:

* Descriptor hằng TDesC Tất cả các kiểu descriptor trên Symbian đều kế thừa TDesC (typedef của TDesC16,

xem e32std.h) và được định nghĩa trong e32des16.h (thư mục: epoc32\include). Bản

8 bit là TDesC8 (e32des8.h). Như đã giới thiệu: C kết thúc lớp báo hiệu đây là lớp

hằng, dữ liệu không đổi.

Trên vùng nhớ , một descriptor được lưu trữ như sau:

- 4 byte đầu lưu trữ chiều dài (thật ra chỉ 28 bit trong số 32 bit (4 byte) là lưu trữ

chiều dài chuỗi, do đó chuỗi tối đa mà ta có thể chứa trong descriptor là 2^28 byte,

256 MB, 4 bit cao còn lại chứa kích thước của đối tượng descriptor, đây là cơ sở để

xác định kiểu descriptor. Với 4 bit chúng ta có thể phân biệt 16 kiểu descriptor nhưng

trên Symbian chỉ có 5 loại).

- Phần tiếp theo sẽ lưu trữ dữ liệu descriptor hay con trỏ chỉ đến vùng lưu trữ thật sự.

Lấy chiều dài thông qua hàm Length(), trong khi truy cập dữ liệu thì nhở vào hàm

Ptr(). Đây là 2 hàm ảo quan trọng nhất, từ đây TDesC sẽ cài đặt tất cả các hàm liên

quan cho descriptor như truy cập dữ liệu, so sánh chuỗi, tìm kiếm, ...

Đây là lớp trừu tượng nên nó không thể khởi tạo, vì vậy khi sử dụng lớp này làm tham

số cho hàm bạn sử dụng cú pháp dạng const TDesC& để cung cấp các truy cập chỉ đọc tới dữ liệu của Descriptor.

* Descriptor "động" TDes "Động" ở đây mang nghĩa là dữ liệu chứa trong descriptor có thể thay đổi. Tất cả các

descriptor động đều kế thừa từ TDes. Về mặt lưu trữ, descriptor động giống như

descriptor hằng, chỉ có thêm thành phần chứa chiều dài tối đa của chuỗi dữ liệu. Hàm

MaxLength() sẽ trả về giá trị này.

TDes định nghĩa một loạt các phương thức phục vụ cho việc thay đổi dữ liệu như

thêm, chèn, hay định dạng dữ liệu,... Một đặc điểm đáng lưu ý là một khi đã khai báo

chiều dài tối đa thì không sao thay đổi được, do TDes và các lớp kế thừa từ nó đều

không có hàm phục vụ cho việc cấp thêm bộ nhớ nên khi thêm dữ liệu, bạn phải lưu ý

là dữ liệu thật sự lưu không bao giờ được vượt quá max length, nếu không bạn sẽ gặp

phải lỗi.

TDesC, TDes (TDes16, TDes8 - Hiện nay TDes luôn là TDes16). Đây là các lớp cơ

sở của tất cả các lớp descriptor khác, chúng chủ yếu cung cấp các hàm thao tác cho

các descriptor hằng cũng như động khác hơn là phục vụ cho mục đích lưu trữ dữ liệu

như các lớp dẫn xuất khác. Do đó, bạn sẽ thấy chúng chủ yếu ở vai trò làm tham số

hay kết quả trả về nhằm mục đích phục vụ cho lập trình tránh bị phụ thuộc loại

Page 29: Symbian Programing

descriptor cụ thể (đặc điểm độc đáo của lập trình hướng đối tượng). Một điểm nữa

củng cố cho điều trên là bạn không thể khai báo trực tiếp một đối tượng kiểu TDesC

hay [color=#BF0000]TDes[/color] được do constructor của chúng là hàm protected.

+ Một số Descriptor cụ thể

* Xâu dạng Literals (Literal descriptor): Đây là một loại descriptor hằng, gần giống với static char [] trên C. Chúng thường

được dùng dưới dạng các macro gồm 3 dạng _LIT, _L và _S (đây là 3 dạng trung

tính, thật sự là _LIT16, _L16, _S16, _LIT8, _L8, _S8 phục vụ chuỗi 16 và 8 bit), bạn

có thể tìm thấy các khai báo macro này ở e32def.h.

Literals cung cấp cách đơn giản để định nghĩa xâu trong chương trình. Chúng ta có

thể định nghĩa và sử dụng như sau:

_LIT(KMyName, "Helen");

TBuf<KMaxItemLength> myName;

myName.Append(KMaxItemLength);

Literals rất dễ thay đổi nếu bạn định nghĩa chúng ở đầu file .cpp, chúng chỉ đơn giản

như định nghĩa marco.

Cũng giống như ở trên, với khai báo _L, một vùng dữ liệu trên file chương trình được

dùng để chứa chuỗi khai báo, nhưng khác với ở trên, chúng không có tên, không có gì

để nắm giữ, điều khiển chúng.

myName.Append(_L("Helen"));

Trong trường hợp này, hệ thống sẽ tạo một pointer descriptor là TPtrC trên stack

(chúng ta sẽ nghiên cứu TPtr sau) tạm thời đảm nhận việc kiểm soát và xử lý chuỗi dữ

liệu này. . Ví dụ, một khi ứng dụng lỗi, để test xem có phải hàm này gây ra hay

không, trên UIQ chúng ta có thể làm theo cách sau: ngay sau hàm nghi ngờ, chúng ta

đặt hàm sau:

User::InfoPrint(_L("Pass"));

Nếu dòng chữ "Pass" hiện lên màn hình thì rõ ràng lỗi chắc chắn nằm sau hàm này.

Cách viết này dễ hơn rất nhiều so với:

_LIT(KPass, "Pass");

User::InfoPrint(KPass));

_S macro gần giống với _L, tuy nhiên nó không yêu cầu tạo đối tượng tạm TPtr mà

sẽ cho phép sử dụng chuỗi trực tiếp như trên C.

=> Hiện nay, Symbian đã đề xuất bỏ kiểu khai báo này do tốn thêm stack cho đối

tượng tạm TPtr và chi phí khởi tạo nó. Tuy nhiên nhờ ưu điểm là giảm code lại khỏi

phải đặt tên nên chúng vẫn thường được dùng với mục đích test. _LIT cần ít bộ nhớ

hơn nếu xâu được sử dụng nhiều hơn 1 lần và Symbian khuyến khích sử dụng _LIT

trong việc tạo các ứng dụng sử dụng hiệu quả vùng nhớ.

Page 30: Symbian Programing

* Buffer descriptor: Đây là descriptor mà chuỗi dữ liệu chứa trong đối tượng descriptor. Chúng được chia

làm 2 loại dữ trên vùng nhớ lưu trữ: stack và heap.

- Stack buffer descriptor: Chúng có thể là descriptor hằng hoặc động. Chúng kế

thừa từ TBufCBase và TBufBase gồm TBufC<n> và TBuf<n>. TBufC phục vụ cho

các descriptor hằng, còn TBuf cho descriptor động, n ở đây chính là khai báo cho

chiều dài tối đa của chuỗi. Chúng được so sánh với char [] trên C. Ví dụ:

Mã: _LIT(KHello, "Hello World!");

TBufC<12> aHelloBufC(KHello);

TBuf<15> aHelloBuf(KHello);

Lưu ý: Do kích thước stack cấp cho một ứng dụng là rất nhỏ nên chuỗi cấp trên stack

cũng chỉ nên cấp cho các chuỗi nhỏ, thường dưới 128 byte, nếu lớn hơn nên cấp trên

heap.

- Heap buffer descriptor: Loại descriptor này ra đời để phục vụ cho các descriptor

có kích thước lớn, không thể lưu trên stack được, và đặc biệt hữu dụng trong các

trường hợp không biết rõ kích thước tại thời điểm biên dịch. Nó được dùng chủ yếu

cho mục đích lưu trữ dữ liệu trong các thao tác xử lý file hay trên các kênh truyền

thông: hồng ngoại hay bluetooth. Đại diện cho descriptor này là HBufC (HBufC16

hay HBufC8), nhưng thường được sử dụng thông qua con trỏ, HBufC*. Bạn có thể

dùng hàm NewL() để tạo các đối tượng descriptor, lưu ý là sau khi dùng xong phải

hủy chúng đi vì chúng được cấp trên heap. Ví dụ:

Mã: _LIT(KHello, "Hello World!");

HBufC* iHelloBufC = HBufC::NewL(20);

*iHelloBufC = KHello; //Copy nội dung KHello vào iHellBufC

Kí tự ‘C’ xác định descriptor là hằng và không thể chỉnh sửa được. Nếu bạn cần

chỉnh sửa descriptor này bạn có thể sử dụng hàm Des(), hàm này khởi tạo một con trỏ

trỏ tới descriptor này, là con trỏ dạng TPtr và có thể chỉnh sửa được dữ liệu. Ví dụ:

Mã: _LIT(KMessage, "Hello");

HBufC* aMessage = HBufC8::NewL(KMaxItemLength);

aMessage->Des().Append(KMessage);

Để có thể thao tác với xâu có kích thước lớn hơn, bạn có thể sử dụng ReAllocL() để

mở rộng kích thước của Desciptor nhưng khi đó có thể xảy ra lỗi tràn hay gây ra một

panic.

Mã: aMessage = aMessage->ReAllocL(25);

Bình thường các descriptor cấp phát trên vùng heap có thể khởi tạo bằng New() hoặc

NewLC(). Nhưng nếu descriptor này đã tồn tại, thì có thể dùng các phương thức

Alloc(), AllocL(), AllocLC() để tạo descriptor mới.

Mã: TBuf<KMaxLength> temp;

temp.Append(_L("Hello Mum"));

HBufC* hPtr;

hPtr = temp.AllocL();

Page 31: Symbian Programing

* Pointer descriptor: Đây là con trỏ trỏ tới Descriptor khác. Chúng bao gồm 2 loại

hằng và động được so sánh với const char* và char*, được thể hiện qua 2 lớp TPtrC

và TPtr. Ví dụ:

Mã: _LIT(KHello, "Hello World!");

TPtrC aHelloBufC(KHello);

TPtr aHelloBuf(KHello);

- TPtrC là kiểu hằng, kí tự ‘C’ trong TPtrC là viết tắt của từ Constant, có nghĩa là

không thể thay đổi. Con trỏ này có hai tham số là độ dài và địa chỉ:

- Trong khi đó TPtr có thêm tham số xác định độ dài tối đa Descriptor cho phép

chỉnh sửa (Max length)

+ Các phương thức thao tác với Descriptor

* Các phương thức cho descriptor hằng Sau đây tôi xin giới thiệu một vài phương thức thông dụng sử dụng cho lớp TDesC

and TBufC. Các phương thức khác bạn có thể tham khảo thêm trong tài liệu SDK.

- Alloc(), AllocL() và AllocLC(): Tạo desciptor 16 bit trên vùng heap và chứa bản sao

của dữ liệu.

- Compare(), CompareC() và CompareF(): So sánh hai xâu và trả về giá trị một số

nguyên. Chú ý kí tự ‘C’ chỉ “collated comparisons” còn kí tự ‘F’ chỉ ‘folded

comparisons’. Giá trị trả về của phương thức so sánh:

0: Hai xâu bằng nhau.

Giá trị dương: Descriptor chính lớn hơn tham số.

Giá trị âm: Descriptor chính nhỏ hơn tham số.

Mã: TBufC<KMaxLength> descriptorOne;

descriptorOne = _L("One");

TBufC<KMaxLength> descriptorTwo;

Page 32: Symbian Programing

descriptorTwo = _L("Two");

TInt result;

result = descriptorOne.Compare(descriptorTwo);

Biến result có giá trị -5 nhưng hiếm khi ta quan tâm tới giá trị này mà ta chỉ quan tâm

tới dấu của giá trị trả về của hàm so sánh.

- Find(), FindC() và FindF(): Tìm kiếm xâu con. Giá trị trả về là một số nguyên xác

định offset tới thể hiện đầu tiên của xâu tìm được. Nếu không tìm thấy, giá trị KErrNotFound được trả về. Các hàm này luôn tìm từ vị trí bắt đầu của xâu, để tìm từ

một vị trí khác bạn sử dụng thêm các hàm Left(), Mid(), Right().

- Left(TInt aLength): Trả về một TPtrC tới phần tận cùng bên trái của descriptor.

- Right(TInt aLength): Trả về một TPtrC tới phần tận cùng bên phải của descriptor.

- Mid(TInt aPos): Trả về một TPtrC tới một vùng xác định của xâu, bắt đầu từ vị trí aPos và kết thúc ở cuối xâu.

- Mid(TInt aPos, TInt aLength): Trả về một TPtrC tới một vùng xác định của xâu, bắt

đầu từ vị trí aPos với độ dài xác định bởi aLength.

- Length(): Trả về số kí tự trong xâu.

- Size(): Trả về số byte của Descriptor.

- Locate(), LocateC() và LocateF(): Tương tự như phương thức Find() nhưng để tìm

kí tự đơn chứ không phải tìm một xâu. Vị trí kí tự đầu tiên chính là vị trí đầu của xâu.

Ví dụ sau trả về giá trị 1 trong biến result:

Mã TBufC<KMaxLength>descriptorOne;

descriptorOne = _L("One");

TChar aChar;

aChar = 'n';

result = descriptorOne.Locate(aChar);

- LocateReverse(): Hàm này tương tự như Locate() nhưng tìm từ vị trí cuối xâu. Nếu

không tìm thấy thì giá trị KErrNotFound được trả về.

+ Toán tử !=, <, >, <=, >=, == và []: Giúp đơn giản trong so sánh xâu. Các toán tử này

được định nghĩa trong TDesC. Trong TBufC đưa ra toán tử =, mặc dù đây là lớp

hằng.

Mã TBufC<5> descriptorOne;

descriptorOne = _L("One");

TBufC<5> descriptorTwo;

descriptorTwo = _L("Two");

if (descriptorOne <= descriptorTwo)

descriptorTwo = descriptorOne;

* Các phương thức thao tác với desciptor "động" Descriptor TBuf và TPtr đưa ra các phương thức giúp bạn có thể chỉnh sửa được dữ

liệu.

- Append(): Giúp chèn thêm một kí tự hay một descriptor.

Mã TBuf<KMaxLength> aDescriptor;

aDescriptor.Append(_L("Hello"));

Nếu độ dài của descriptor mới và dữ liệu hiện tại của aDescriptor mà lớn hơn

KMaxLength, ứng dụng sẽ sinh ra USER 11 PANIC.

- Capitalize(), UpperCase() và LowerCase(): Tên của hàm đã thể hiện rõ chức năng

của các hàm này.

Page 33: Symbian Programing

- Copy(): Hàm này copy từ descriptor nguồn tới descriptor đích, và thay thế hết các

dữ liệu đã tồn tại.

- Delete(): Xóa các vùng con xác định của xâu. Ví dụ sau khi thực hiện lệnh sau thì

aDescriptor chứa “Hello Peace”:

Mã TBuf<20> aDescriptor;

aDescriptor.Append(_L("Hello World Peace"));

TChar aChar = 'W';

TInt aPos = aDescriptor.Locate(aChar);

TInt aLength = 6;

aDescriptor.Delete(aPos, aLength);

- Fill(): Hàm này điền đầy descriptor bằng một kí tự nào đó hay là kí tự có mã 0.

- Format(): Sao chép dữ liệu đã được định dạng vào descriptor. Chi tiết xem thêm tài

liệu SDK.

Mã: aDescriptor.Format(_L("%S\t%S"), aDes1, aDes2);

- Num(TInt aNum): Chuyển số nguyên sang xâu và đưa vào descriptor. Nếu

descriptor đã có dữ liệu thì nó thay thế dữ liệu đã tồn tại.

Một số thao tác vẽ cơ bản với đồ họa trong Symbian

Mỗi vùng màn hình chính là đối tượng CCoeControl, được xem như control mà bạn

có thể vẽ nội dung bất kỳ lên vùng màn hình mà nó chiếm. Phương thức Draw() kế

thừa từ CCoeControl cho phép truy cập tới vùng màn hình được định nghĩa bởi

TRect. Tất cả các lớp kế thừa từ CCoeControl đều có hàm Draw(), và bạn chồng

hàm này để thực hiện các thao tác vẽ.

Một control cần một cửa sổ để vẽ, và vùng cửa sổ này được thiết lập trong hàm

ConstructL(). Và để sử dụng CCoeControl bạn cũng cần include tệp “coecontrol.h”

và thêm link “cone.lib”. Ví dụ sau tạo một lớp kế thừa từ CCoeControl và thực hiện

vẽ lên vùng màn hình của nó:

Mã: class CStartContainer : public CCoeControl

{

public:

CStartContainer();

CStartContainer();

private:

void ConstructL(const TRect& aRect);

// from CCoeControl

void Draw(const TRect& aRect) const;

};

Hàm ConstructL() cần truyền kích thước cửa sổ, control, vùng mà ứng dụng cần truy

cập. Bạn có thể sử dụng hàm ClientRect() để lấy kích thước vùng client của ứng

dụng, và hàm ApplicationRect() để lấy kích thước của vùng ứng dụng.

Page 34: Symbian Programing

Bạn truyền AppUi()->ApplicationRect() trong hàm ConstructL() để truy cập tới

toàn bộ vùng màn hình. Dĩ nhiên bạn có thể tùy biến vùng kích thước này:

Mã:

void CStartContainer::ConstructL(const TRect& aRect)

{

CreateWindowL();

SetRect(aRect);

ActivateL();

}

- Hàm CreateWindowL() để tạo cửa sổ control

- SetRect() thiết lập phạm vi cửa sổ tới kích thước TRect.

- Hàm ActivateL() bảo cho framework biết rằng nó có thể truy cập vào màn hình.

Để vẽ lên màn hình, một ngữ cảnh đồ họa (Graphics Context - GC) được lấy ra. Và

tất cả việc vẽ đều thực hiện trong ngữ cảnh đồ họa này, CWindowGc.

Mã void CStartContainer::Draw(const TRect& aRect) const

{

CWindowGc& gc = SystemGc();

gc.Clear(aRect);

...

}

- Hàm SystemGc() trả về ngữ cảnh đồ họa chuẩn cho biến gc. Và vùng control phải

được xóa trước khi bạn thực hiện thao tác vẽ trên nó.

- Hàm Draw(), nó là hằng chứ không phải là leave, vì thế bạn không thể tạo các phần

tử động trong hàm Draw() và bạn cũng không thể sửa trạng thái bất kỳ dữ liệu nào

trong hàm này. Sau khi bạn thay đổi trạng thái bạn muốn cập nhật lại vùng vẽ bạn nên

gọi hàm DrawNow(), hàm này sẽ tự động gọi hàm Draw() của chính nó.

Để thực hiện vẽ hình theo ý của bạn, bạn phải thiết lập các thông số bút vẽ trước khi

thực hiện vẽ. Dạng và kích thước của bút vẽ cũng có thể thay đổi và được sử dụng để

vẽ các hình. Đoạn mã sau thiết lập kiểu bút vẽ là dash và kích thước tới giá trị aSize:

Page 35: Symbian Programing

gc.SetPenStyle(CGraphicsContext::EDashedPen);

gc.SetPenSize(aSize);

Kiểu liệt kê TPenStyle bao gồm:

- ENullPen

- ESolidPen

- EDottedPen

- EDashedPen

- EDotDashPen

- EDotDotDashPen

Đoạn mã sau sử dụng để vẽ đường thẳng và hình chữ nhật:

Mã: gc.DrawLine(aPoint, bPoint);

gc.DrawRect(rect);

Bút vẽ sử dụng để vẽ các đường, còn chổi vẽ để tô các vùng. Kiểu liệt kê

TBrushStyle được sử dụng trong hàm SetBrushStyle. Màu của chổi vẽ được thiết

lập thông qua hàm SetBrushColor().

Các phương thức vẽ khác như DrawEllipse() và DrawPolygon(), chúng sử dụng chổi

vẽ để tô vùng và bút vẽ để vẽ đường biên.

Sử dụng font và vẽ chữ trên Symbian

+ Hiển thị chữ

Theo lý thuyết việc vẽ xâu văn bản lên màn hình là rất đẹp nhưng việc định dạng có

thể là một phiền toái.

Mã: _LIT(KExampleText, "Chocolate Cake"));

gc.DrawText(KExampleText, TPoint(80,40));

Tham số vị trí là tương đối với Control vì vậy TPoint(0,0) là góc trên bên trái vùng

màn hình của control. Vị trí này có thể khác nhau trên các thiết bị khác nhau vì vậy

bạn phải rất cẩn thận. Nhưng thật may mắn có một số hàm như hàm

CGraphicsContext::ECenter giúp can lề giữa đoạn văn bản. Một vài hàm khác giúp

bạn thay đổi font và màu của văn bản.

Để thay đổi màu chữ khi vẽ bạn sử dụng hàm SetPenColor():

gc.SetPenColor(KRgbRed);

Có một số màu được định nghĩa trước có kiểu TRgb:

KRgbBlack

KRgbDarkGray

KRgbDarkRed

KRgbDarkGreen

Page 36: Symbian Programing

KRgbDarkYellow

KRgbDarkBlue

KRgbDarkMagenta

KRgbDarkCyan

KRgbRed

KRgbGreen

KRgbYellow

KRgbBlue

KRgbMagenta

KRgbCyan

KRgbGray

KRgbWhite

Lớp TRgb cho phép bạn tạo màu theo ý mình:

- Hàm khởi tạo: Ví dụ như TRgb(0x00112387), TRgb(50, 50, 0)

- Hàm thay đổi màu: như SetRed() …

- Hàm thay đổi số lượng màu: như Gray16()

Để thay đổi font chữ bạn sử dụng đoạn mã:

const CFont* font = iEikonEnv->AnnotationFont();

gc.UseFont(font);

Có một số font được định nghĩa trước, bao gồm:

Để lấy font bình thường (mặc định) bạn sử dụng lệnh:

gc.UseFont(iCoeEnv->NormalFont());

Nhớ rằng một khi bạn hoàn thành việc sử dụng font, bạn phải gọi hàm:

gc.DiscardFont();

Việc bố trí các phần tử trên màn hình với các font khác nhau là công việc khá phức

tạp. Một lựa chọn đó là không sử dụng cách vẽ trực tiếp mà sử dụng lớp CRichText.

Lớp này giúp bạn dễ dàng định dạng chữ và chèn ảnh.

+ Lựa chọn font chữ trong Symbian OS

Để lựa chọn font chữ bạn làm các thao tác sau:

Page 37: Symbian Programing

- Khởi tạo đối tượng CFont

- Thiết lập các thông số cho font (Thông qua cấu trúc TFontSpec)

- Gán CFont tới font sẵn có gần nhất để cấu trúc TFontSpec phù hợp với màn hình

thiết bị - Thiết lập làm font hiện tại (Ngữ cảnh đồ hoạ sử dụng font này) để vẽ (Sử dụng hàm

UseFont)

- Vẽ text

- Loại bỏ font khỏi ngữ cảnh đồ hoạ

- Loại bỏ font bằng hàm CGraphicsDevice::ReleaseFont().

Sau đây là đoạn mã ví dụ về lựa chọn Font:

_LIT(KFontName, "Verdana");

CFont* iUseFont = NULL;

TFontSpec myFontSpec(KFontName, 18);

TFontStyle myFontStyle(EPostureUpright, EStrokeWeightNormal,

EPrintPosSubscript);

myFontSpec.iFontStyle = myFontStyle;

iCoeEnv->ScreenDevice()-

>GetNearestFontInPixels(iUseFont,myFontSpec);

iFbsGc->UseFont(iUseFont);

_LIT(KTextExample, "\x43h\xE0o m\x1EEBng \x62\x1EA1n th\x61m

\x64i\x1EC5n \x111\xE0n MyShop\x34Vn"); // Xâu "Chào mừng bạn tham diễn đàn MyShop4Vn" iFbsGc->DrawText(KTextExample, TPoint(5,80));

iFbsGc->DiscardFont();

iCoeEnv->ScreenDevice()->ReleaseFont(iUseFont);

Chú ý: - Để có thể sử dụng font Verdana và hiển thị được tiếng việt bạn phải copy hai tệp

verdana.ttf và FREETYPE.DLL vào thư mục c\system\fonts.

- Hàm UseFont khá chậm nên bạn nên dùng nó ngay trong hàm khởi tạo. Khi sử dụng

hàm này, thì phải dùng thêm hàm DiscardFont() để loại bỏ font khỏi ngữ cảnh đồ

hoạ. Nếu bạn sử dụng nhiều font vẽ cùng lúc thì tốt nhất bạn nên sử dụng hàm

UseFontNoDuplicate (iFbsGc->UseFontNoDuplicate((const CFbsBitGcFont *)

iUseFont);), khi sử dụng hàm này bạn ko cần sử dụng hàm DiscardFont nữa.

+ Tự động load và unload tệp font *.gdr

Nhiều khi ứng dụng của bạn sử dụng bộ font chữ riêng *.gdr do bạn tự tạo, khi đó mỗi

khi khởi động ứng dụng bạn tự động load font này và mỗi khi kết thúc ứng dụng của

bạn, bạn phải unload nó. Giả sử bạn có font chữ với tên là "My Font" và tên tệp font

là "myfont.gdr" và bạn để nó trong thư mục "c:\data".

Đầu tiên bạn phải khai báo các biến cần dùng (nên là biến thành viên của lớp AppUi):

_LIT(KFontName, "My Font");

_LIT(KFontFile, "c:\\data\\myfont.gdr");

...

TInt iFontID;

CFont* iUseFont;

Khi khởi động bạn load font này lên bằng đoạn mã:

Page 38: Symbian Programing

TFileName fntFilename(KFontFile);

TInt nRes = CEikonEnv::Static()->ScreenDevice()-

>AddFile(fntFilename, iFontID);

if (nRes==KErrNone)

{

// Load được font // Tạo biến CFont để sử dụng font này TFontSpec myFontSpec(KFontName, 12);

TFontStyle myFontStyle(EPostureUpright, EStrokeWeightNormal,

EPrintPosNormal);

myFontSpec.iFontStyle = myFontStyle;

iCoeEnv->ScreenDevice()-

>GetNearestFontInPixels(iUseFont,myFontSpec);

}

else

{

// Không load được tệp font // ...

}

Bây giờ bạn có thể sử dụng font chữ này vẽ bình thường. Khi kết thúc ứng dụng, bạn

phải unload font này khỏi hệ thống bằng đoạn mã:

if (iUseFont)

iCoeEnv->ScreenDevice()->ReleaseFont(iUseFont);

if (iFontID!=0)

CEikonEnv::Static()->ScreenDevice()->RemoveFile(iFontID);

* Chú ý: - Bạn có thể dùng tiện ích "Easy GDR Creator" để tạo font gdr.

- Bạn có thể dùng tiện ích "KVT Symbian Font Converter" để chuyển từ font *.ttf

sang *.gdr

- Các tiện ích này bạn tìm trên mạng, rất nhiều và rất dễ tìm

- Hiển thị bằng font *.gdr thực sự không được đẹp lắm

- Bạn có thể dùng đoạn mã trên để load và hiển thị font *.ttf. Tôi đã thử trên dòng

Symbian S60 3rd, chạy rất okie.

+ Liệt kê các font sẵn có trong hệ thống

Nhiều lúc bạn muốn xem hệ thống hiện tại đã có những font gì, hay bạn muốn xem

font của bạn đã thực sự được load vào hệ thống hày chưa. Như vậy bạn cần liệt kê

được các font sẵn có trong hệ thống. Đoạn mã sau giúp bạn làm điều này:

typedef TBuf<256> MyFontName;

TInt iFontNum = 0;

CArrayFix<MyFontName>* iArrFonts = NULL;

iFontNum = iCoeEnv->ScreenDevice()->NumTypefaces();

if (iFontNum>0)

iArrFonts = new(ELeave)CArrayFixFlat<MyFontName>(iFontNum);

if (iArrFonts)

{

MyFontName myFontName;

TTypefaceSupport myTypefaceSupport;

for(TInt i=0; i<iFontNum; i++)

{

iCoeEnv->ScreenDevice()-

>TypefaceSupport(myTypefaceSupport, i);

Page 39: Symbian Programing

myFontName = myTypefaceSupport.iTypeface.iName.Des();

iArrFonts->AppendL(myFontName);

}

}

// Sử dụng mảng iArrFonts ở đây // ...

// Xóa mảng cấp phát if (iArrFonts)

delete iArrFonts;

Toàn bộ font tìm được sẽ lưu vào mảng iArrFonts để tiện cho việc sử dụng. Sau khi

liệt kê bạn có thể hiển thị bằng cách vẽ lên màn hình hoặc hiển thị bằng hộp thoại

Information.

Xử lý phím nhấn

Có nhiều cách khác nhau để tương tác với các ứng dụng trên điện thoại di động. Hình

sau thể hiện một số cách mà người dùng có thể tương tác với điện thoại di động:

Phương thức vào thông dụng là thông qua các phím trên điện thoại, bao gồm ba vùng

phím:

- Keypad: Các phím số từ 0 đến 9, phím *, #

Page 40: Symbian Programing

- Soft keys

- Navigation key: Phím định hướng, bao gồm phím lên, xuống, trái, phải và phím OK

Ngoài ra người dùng có nhiều cách khác để tương tác với điện thoại. Vì điện thoại

được thiết kế với mục đích chính là đàm thoại, vì thế giọng nói là phương thức vào

chính. Gần đây các nhà phát triển quan tâm tới các ứng dụng khởi động bằng giọng

nói và chắc chắn các ứng dụng loại này sẽ trở thành thông dụng trong tương lai không

xa. Ngoài ra, sử dụng hồng ngoại cũng như Bluetooth cũng cho phép vào ra dữ liệu

với điện thoại. Ở đây chúng ta quan tâm tới phương thức vào thông dụng nhất, đó là

sử dụng phím.

Trong lớp CoeControl có cài đặt một phương thức ảo OfferKeyEventL() để điều

khiển sự kiện nhấn phím, nó được framework gọi mỗi khi sự kiện nhấn phím xảy ra.

Vì vậy để bắt sự kiện phím nhấn, bạn phải kế thừa từ lớp CoeControl và định nghĩa

phương thức OfferKeyEventL().

#include <coecntrl.h>

class CKeyPressContainer : public CCoeControl,

MCoeControlObserver

{

...

TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,

TEventCode aType);

...

}

Khi sự kiện phím xảy ra, phương thức OfferKeyEventL() của tất cả các điều khiển

trong stack được gọi. Khi phương thức này được gọi, nó có thể xử lý sự kiện hoặc bỏ

qua nó thông qua giá trị trả về của hàm này: Trả về TKeyResponse:

EKeyWasNotConsumed nếu sự kiện bỏ qua và trả về EKeyWasConsumed nếu sự

kiện được xử lý.

Khi sự kiện phím xảy ra, đầu tiên bạn phải kiểm tra xem đó là sự kiện phím nào: phím

nhấn (Key down), phím nhả (Key up) hay sự kiện nhấn phím (Key press). Nếu bạn

chỉ quan tâm tới sự kiện phím nhấn, bạn có thể sử dụng đoạn mã:

TKeyResponse CKeyPressContainer::OfferKeyEventL(const

TKeyEvent& aKeyEvent, TEventCode aType)

{

if (aType != EEventKey)

return EKeyWasNotConsumed;

else

{

if (aKeyEvent.iCode == '5')

{

...

return EKeyWasConsumed;

}

}

}

Tiếp theo bạn phải kiểm tra các tham số của sự kiện phím trả về thông qua tham số có

kiểu TKeyEvent, đây là cấu trúc gồm 4 trường:

- iCode (định nghĩa trong TKeyCode): Mã của phím nhấn trong sự kiện Key Press.

Page 41: Symbian Programing

- iModifiers (định nghĩa trong TEventModifier): Trạng thái phím sửa và thiết bị trỏ

- iScanCode (định nghĩa trong TStdScanCode): Mã scan của phím, sử dụng trong

các sự kiện Key Down và Key Up.

Bạn cũng có thể sinh ra một sự kiện phím bằng cách gán các trường trong cấu trúc

TKeyEvent, sau đó gọi hàm OfferKeyEventL() để giả sự kiện:

TKeyEvent myEvent;

myEvent.iCode = EEventKeyDown;

myEvent.iModifiers = EAllModifiers;

myEvent.iRepeats = 0;

myEvent.iScanCode = EAllModifiers;

OfferKeyEventL(myEvent, EEventKey);

Sự kiện cho Menu

Phương thức HandleCommandL() được sử dụng để điều khiển menu chọn và các

lệnh khác được định nghĩa trong tệp resource. Nó là hàm ảo định nghĩa trong

CEikAppUi (hoặc CAknAppUi trong Symbian S60 3rd) và được gọi bởi phương

thức ProcessCommandL() trong Framework. Nơi thường được sử dụng để cài đặt

phương thức này là trong lớp AppUi (kế thừa từ CEikAppUi hoặc CAknAppUi).

void CKeyPressAppUi::HandleCommandL(TInt aCommand)

{

switch (aCommand)

{

case EEikCmdExit:

{

Exit();

break;

}

case EAknSoftkeyBack:

{

ActivateLocalViewL(KMainViewId);

break;

}

case EStartGame:

{

iContainer->StartGame();

break;

}

}

}

Còn nhiều phần quan trọng khác tôi không thể nói hết ở đây, bạn xem thêm cuốn

"Wiley S60 Programming - A Tutorial Guide (Apr - 2007).pdf" mà tôi giới thiệu

ngay ở bài viết đầu tiên.

Một số lỗi liên quan đến lập trình và cài đặt trên Symbian

Page 42: Symbian Programing

Khi lập trình hay cài đặt phần mềm đôi khi bạn gặp những rắc rối, mà bạn không biết

tại sao. Sẽ mất thời gian để bạn phải tìm hiểu nguyên nhân, hay serch trên mạng để

tìm cách giải quyết. Khi lập trình và cài đặt các phần mềm trên Symbian tôi cũng gặp

nhiều rắc rối, xin đưa ra để nếu các bạn có gặp phải sẽ không phải mất nhiều thời gian

để giải quyết.

* Một vài chú ý khi lâp trình với Symbian OS

- Nếu bạn muốn sử dụng thư viện toán học math.h trong thư viện chuẩn thì bạn phải

thêm dòng

SYSTEMINCLUDE \epoc32\include \epoc32\include\libc trong tệp mmp (Chú ý

phải cập nhật lại tệp này trước khi build).

- Khi build GCCE, nếu báo lỗi "undefined reference to `atan2`", lỗi này là do bạn

sử dụng thư viện toán học nhưng lại chưa đưa lib “estlib.lib”. Nếu bạn không khai

báo thư viện này thì vẫn chạy được máy ảo nhưng build cho máy thật lại bị lỗi. Sửa

lỗi này đơn giản là bạn khai báo thêm thư viện “estlib.lib”.

- Trong Symbian S60 3rd, nếu bạn nhận được thông báo “*** missing separator.

Stop.” tại một dòng nào đó trong tệp *.GCCE thì lỗi này do bạn chưa cài “CSL Arm

Toolchain” hoặc đường dẫn khai báo tới chương trình này trong biến môi trường

PATH không đúng. Đường dẫn mặc định của chương trình này là “C:\Program

Files\CSL Arm Toolchain\bin”. Sau khi cài xong, bạn đóng Project và mở lại, dịch

Release là được.

- Khi bạn dịch trên Symbian S60 3rd mà gặp lỗi báo: “error PRJ0019: A tool

returned an error code from "Building help file"”. Thì lỗi này là do bạn cài Perl

phiên bản không đúng (chẳng hạn như ActivePerl-5.8.8), bạn remove phiên bản Perl

này và cài lại phiên bản ActivePerl-5.6.1

- Thiết lập bàn phím QWERTY cho máy ảo trên Symbian 9: Hiện nay các con

E61 hay E90 có hỗ trợ bàn phím Qwerty. Để tiện lợi cho việc test ứng dụng trên con

này, bạn có thể thiết lập bàn phím Qwerty cho máy ảo. Để thiết lập, rất đơn giản bạn

chỉ cần vào thư mục “\Symbian\9.1\S60_3rd\Epoc32\Data”, edit tệp “epoc.ini” rồi

thêm dòng “configuration epoc_352x416_qwerty.ini”, bạn save lại, rồi bật máy ảo

là okie.

- Khi dịch Project Symbian S60 1st sử dụng VC nếu báo lỗi “This project does not

support platform or program "VC6””, lỗi này là do bạn cài SDK cho S60 1st rồi

lại cài SDK cho S60 3rd. Để khắc phục lỗi này bạn remove SDK S60 1st và cài lại

nó, sau đó [b]Restart[/b] lại. Để không gặp lỗi này khi cài đặt tốt nhất là bạn cài đặt

SDK S60 3rd trước rồi sau đó mới cài đặt SDK S60 1st.

- Khi build xong bạn ấn Ctrl+F5 mà máy ảo không nên được là do đường dẫn tới file

“EpocWrapper.exe” (trên S60 3rd) hoặc "epoc.exe" (trên S60 1st) không đúng.

Trên S60 3rd, bạn vào Properties của Project, ở mục Debugging, thay đổi lại đường

dẫn chính xác trong trường Command. Còn trên S60 1st, bạn chỉ đến đúng tệp

"epoc.exe" là okie (chú ý debug và release thì bạn trỏ tương ứng nhé)

* Một số lỗi khi cài đặt phần mềm (đặc biệt trên Symbian S60

3rd)

- Certificate may not yet be valid , is expired or phone's date setting may be

incorrect: Lỗi này thường gặp khi bạn mới format máy khi gặp lỗi này các bạn chỉ cần chỉnh lại ngày giờ cho chính xác với thời điểm hiện tại.

- not support: Lỗi nó là phần mềm bạn cài ko phải là của s60v3 mà của s60v2 hay là

Page 43: Symbian Programing

phần mềm của của các loại symbian khác (uiq, s90..), nhưng cũng có trường hợp do

các files có tên quá dài chấm nhiều chấm quá nên máy ko hiểu và báo lỗi, nếu báo lỗi

này thì trước tiên các bạn thử đổi tên nó ngắn gọn lại nhé và cài thử lại xem có được

ko.

+ File Corupted: Là files đó đã bị lỗi bạn nên tải lại files khác.

+ error update: Symbian OS 9.1 ko cho bạn update vesion của soft đã CR, bạn nên

xóa bỏ soft trong máy và cài lại sẽ ok, muốn update phải là ứng dụng ko CR (đăng ký

= chìa khóa).

+ Certificate error contact the application supplier: Lỗi này báo là pm này chưa

được signsis (đăng ký).

+ Certificate exprired: Lỗi "chứng chỉ hết hạn" này xảy ra đối với 1 số dòng máy

mới & firmware mới, bạn có thể đổi ngày giở lui lại khoảng 1 vài tháng, nhưng cũng

có 1 số soft ko cài được -> chỉ có cách là đợi vesion mới của soft được CR mà cài.

Đối với dòng E (E65, E61 ....): thì bạn vào app manager -> software intall -> chọn

all la ok.