Hiện nay, các môi trường lập trình như Java của Sun và .NET của
Microsoft đều hỗ trợ Unicode đầy đủ cho nên việc xây dựng ứng dụng có
hiển thị tiếng Việt là rất dễ dàng. Tuy nhiên, bạn sẽ gặp khó khăn
trong môi trường VC++ 6.0 vì Unicode chỉ được hỗ trợ một nửa! Tức là
chỉ cung cấp các hàm xử lý Unicode bên dưới nhưng không hiển thị được
Unicode, bạn cũng không thể nhập trực tiếp chuỗi Unicode để đặt tên cho
các control trong chương trình. Cách giải quyết vấn đề này như sau: Sử
dụng các chuỗi CHAR và gán cho chúng nội dung theo bảng mã UTF8 (hoặc
bảng mã TCVN, VNI...), sau đó trong thân chương trình dùng các hàm của
Windows (hoặc hàm của chính bạn tự viết) để chuyển các chuỗi này thành
chuỗi Unicode, và dùng các chuỗi Unicode để gán cho các control. Các
hướng dẫn trong bài viết này chỉ áp dụng đúng đối với ứng dụng viết để
chạy trên nền Windows NT/2000/XP, còn đối với Windows 9x bạn phải dùng
thư viện MSLU - Microsoft Layer for Unicode (tham khảo bài 'Thư viện
Unicode trên Windows 9x' - TGVT A 5/2003, t.92).
Xây dựng ứng dụng
Đầu tiên, để có thể xây dựng ứng dụng Unicode trong VC++ bạn phải cài
bổ sung thư viện Unicode trong VC (có sẵn trong đĩa cài đặt), nếu không
có thư viện này bạn sẽ bị báo lỗi 'Link Error: can't find mfc42ud.lib'
khi biên dịch trong chế độ _UNICODE. Bạn chạy lại file Setup.exe trong
đĩa cài đặt, chọn chế độ Add/Remove, chọn Microsoft Visual C++ 6.0 rồi
nhấn Change Option->VC++ MFC and Template Libraries->MS
Foundation Class Libraries, đánh dấu thêm 2 mục: Static Libraries for
Unicode và Shared Libraries for Unicode, sau đó nhấn OK.
Tiếp theo, bạn cần thêm một số thông số biên dịch cho mỗi project. Chọn menu Project->Settings (Alt+F7), tìm đến các thẻ sau:
• Thẻ C/C++: thêm _UNICODE vào cuối dòng lệnh.
Vd: WIN32,_DEBUG,_WINDOWS,
_AFXDLL,_MBCS,_UNICODE
• Thẻ Link: chọn Output trong mục Category, thêm vào 'wWinMainCRTStartup' (không có dấu nháy) trong phần Entry-point symbol.
Nhấn OK để đóng hộp thoại lại.
Trong thân của chương trình, bạn khai báo một chuỗi sau: CHAR *String1
rồi dùng chương trình gõ tiếng Việt (Unikey, VietKey) nhập nội dung
tiếng việt theo bảng mã UTF-8.
Vd: nội dung tiếng Việt là 'Chương trình hiển thị tiếng Việt Unicode', bạn gõ như sau trong VC++:
Code:
Mã:
char *String1 = 'ChỈ°Ỉ¡ng trnh hi'ƒn th'‹ tiº¿ng vi'‡t Unicode';Chuỗi nhập vào theo mã UTF-8, vì vậy bây giờ chúng ta sẽ dùng hàm của
Windows để chuyển chuỗi này thành chuỗi Unicode. Bạn có thể dùng hàm
MultiByteToWideChar() (tham khảo MSDN).
Code:
Mã:
wchar_t Unicode_String[256];
MultiByteToWideChar(CP_UTF8,0,String1,strlen(String1), Unicode_String,strlen(String1));Tuy nhiên, việc sử dụng hàm này khá phức tạp và có một số khó khăn khi
phải xác định chiều dài chuỗi Unicode được tạo ra từ chuỗi UTF-8, cụ
thể là hàm trên sẽ vẫn cho kết quả chuyển ra Unicode đúng, nhưng độ dài
chuỗi 'String2' sẽ không đúng và kéo theo một số ký tự thừa phía sau.
Nguyên nhân là theo bảng mã UTF-8, các ký tự sẽ được mã hoá với độ dài
không giống nhau, có ký tự chỉ cần một byte nhưng có ký tự lại chiếm
đến 2-3 byte hoặc hơn. Ví dụ, khi bạn gõ chữ 'A' - 0xC2 theo UTF8 thì
hiện ra ngay chữ 'A' - 1 ký tự, còn nếu bạn gõ 'ẻ' - 0x1EBB thì sẽ hiện
ra 'º'' - 3 ký tự. Do đó, khi chuyển sang Unicode độ dài chuỗi Unicode
và UTF-8 có sự chênh lệch.
Có thể khắc phục điều này bằng phương pháp thủ công là tính chiều dài
chuỗi tiếng Việt rồi gắn trực tiếp vào hàm. Chẳng hạn, độ dài chuỗi
String1 trong ví dụ trên là 41, hàm trên được viết lại như sau:
Code:
Mã:
MultiByteToWideChar(CP_UTF8,0,String1,strlen(String1), Unicode_String,41);
Unicode_String [41]=0; // ket thuc chuoi
Một cách giải quyết khác là bạn tự viết hàm chuyển đổi, cách này tuy
hơi phức tạp nhưng bù lại bạn có thể nhập nội dung theo bảng mã bất kỳ.
Ở đây, tôi xin giới thiệu một hàm chuyển từ UTF-8 sang Unicode (bạn có
thể tham khảo thêm các hàm chuyển các bảng mã khác sang Unicode trong
mã nguồn của chương trình Unikey,
[You must be registered and logged in to see this link.]).
Code:
Mã:
void Convert_String(BYTE *string_in, wchar_t *string_out)
{
int i, scnt = strlen((char*)string_in);
wchar_t unicode;
i = 0;
while (i {
if (0xc2<= string_in[i] && string_in[i] <= 0xe0 &&
0x80<= string_in[i+1] && string_in[i+1] <= 0xbf)
{
// 2byte
unicode = (string_in[i++] & 0x3f)<<6;
unicode += (string_in[i++] & 0x3f);
*string_out= unicode;
}
else
if (0xe0<= string_in[i] && string_in[i] <= 0xef &&
0x80<= string_in[i+1] && string_in[i+1] <= 0xbf &&
0x80<= string_in[i+2] && string_in[i+2] <= 0xbf)
{
// 3byte
unicode = (string_in[i++] & 0x0f)<<12;
unicode += ((string_in[i++] & 0x3f)<<6);
unicode += (string_in[i++] & 0x3f);
*string_out = unicode;
}
else
{ // 1byte
*string_out = string_in[i++];
}
string_out++;
}
*string_out = 0; // ket thuc chuoi
}
Khi dùng bạn chỉ cần khai báo như sau:
Code:
Mã:
char *String1 = 'ChỈ°Ỉ¡ng trnh hi'ƒn th'‹ tiº¿ng vi'‡t Unicode';
// chương trình hiển thị tiếng Việt Unicode
wchar_t unicode_string[256];
Convert_String((BYTE*)String1,unicode_string);
Sau đó dùng chuỗi unicode_string này để gắn cho các control:
Code:
Mã:
SetDlgItemText(IDC_STATIC_TEXT,unicode_string);
SetWindowText(unicode_string);
Vì khuôn khổ của bài báo có hạn nên tôi sẽ không trình bày chi tiết ở
đây, mã nguồn mẫu có thể tải về tại website của TGVT - PC World VN.
Hình ảnh
Các vấn đề cần lưu ý
Khi chạy chương trình có thể bạn sẽ gặp trường hợp khi hiển thị được
tiếng Việt khi không! Chạy ở máy cài WinXP thì hiện tiếng Việt rất tốt,
nhưng khi đem qua chạy ở máy cài Windows 2000 thì lại không hiện dấu
hoàn chỉnh, titlebar (thanh tiêu đề) hiển thị được tiếng Việt nhưng các
control thì lại không hoặc ngược lại!
Hình ảnh
Nguyên nhân là do Windows không sử dụng các font Unicode cho các cửa
sổ. Để khắc phục, bạn vào Control Panel->Display
Properties->Appearance->Advanced->Item, chọn lần lượt từng
Item rồi chỉnh lại font chữ là Arial hoặc Tahoma... Tuy nhiên cách này
chỉ làm cho chương trình hiển thị đúng tiếng Việt trên máy của mình,
còn khi đem sang máy khác lại có thể gặp lỗi tương tự. Cách giải quyết
triệt để là quy định luôn font mặc định dùng cho chương trình của mình.
Trong VC++, bạn nhấn phải chuột vào Dialog cần quy định, chọn
Properties->Font, chọn tên font là Arial hoặc Tahoma hoặc một font
Unicode khác.
Lưu ý, font chữ này chỉ tác động đến các control trên Dialog, không ảnh
hưởng đến titlebar. Việc hiển thị tiếng Việt trên titlebar vẫn còn phụ
thuộc vào quy định dùng font trong Windows.
Tôi xin mách bạn một mẹo nhỏ để có thể hiển thị được tiếng Việt trên
titlebar, mà không cần thay đổi font mặc định. Cách này có một chút bất
tiện là khi chuyển qua lại giữa các chương trình, titlebar sẽ có thể
biến mất trong một khoảng thời gian ngắn.
Bạn tìm đến hàm ::OnPaint() và thay nội dung hàm này bằng nội dung mới như sau:
Code:
Mã:
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
CDC *d;
d=GetWindowDC();
CFont c;
CFont *l;
SetWindowText(_T(''));
d->SetBkMode(TRANSPARENT);
c.CreatePointFont(110,_T('Tahoma'));// dùng font Tahoma, Size 11
l=d->SelectObject(&c);
// Chương trình hiển thị Tiếng Việt Unicode
char *string1='ChỈ°Ỉ¡ng trnh hi'ƒn th'‹ Tiº¿ng Vi'‡t Unicode';
wchar_t titlebar_str[256];
Convert_String((BYTE*)string1,titlebar_str); //chuyển UTF-8 sang Unicode
d->SetTextColor(RGB(255,255,255));
d->TextOut(25,3,titlebar_str); //vẽ tiêu đề mới
d->SelectObject(l);
}Một vấn đề nữa có thể bạn cũng gặp phải, đó là khi mang sang máy khác
chương trình của bạn không chạy được. Máy báo lỗi 'không thể tìm thấy
tập tin MFC42UD.DLL'. Nguyên nhân là do Windows chưa được cài bổ sung
bộ thư viện Unicode cho VC++ (đã nhắc đến trong phần trên), nên thiếu
các file DLL cần thiết. Làm sao bây giờ? Chẳng lẽ mỗi lần mang chương
trình đi chạy ở máy khác lại mang theo bộ thư viện Unicode để cài thêm!
Để khắc phục điều này, khi biên dịch bạn chọn chế độ 'Use MFC in a
Static Library' để VC gộp luôn cả thư viện Unicode vào trong chương
trình.
Trong VC++, nhấn Alt+F7, chọn thẻ General, ở mục Microsoft Foundation
Classes bạn chọn 'Use MFC in a Static Library', nhấn OK và biên dịch
lại, bạn sẽ có chương trình chạy không phụ thuộc vào việc có cài thư
viện Unicode hay chưa.
Hình ảnh
Bạn nghĩ tất cả đã xong? Chưa đâu..., bạn nhìn thử lại kích thước file
exe của chương trình xem! Kích thước phình to thêm đến gần 2MB! Đó là
do VC gộp thêm các hàm xử lý Unicode vào trong chương trình của bạn, và
một nguyên nhân nữa là bạn đã chọn biên dịch theo chế độ Debug! Trong
chế độ này, file exe còn chứa thêm các thông tin để kiểm soát lỗi xảy
ra nên kích thước mới lớn như vậy. Để giảm bớt kích thước, bạn hãy
chuyển sang biên dịch ở chế độ Release. Trong VC, nhấn Alt+F7, trong
cột bên trái, mục Setting For bạn chọn 'WIN32 Release', tiếp theo là
cấu hình giống như phần trên đã trình bày, thêm các thông số _UNICODE
và wWinMainCRTStartup, cuối cùng nhấn OK để lưu lại.
Khi cần biên dịch ra file exe, bạn chọn menu Build->Batch Build, bỏ đánh dấu mục WIN 32 Debug, sau đó nhấn Rebuild All.
Bây giờ, kích thước file exe giảm 10 lần, chỉ tăng thêm khoảng 200KB so với kích thước ban đầu.
Hy vọng một chút kinh nghiệm riêng sẽ giúp ích cho bạn khi lập trình sử
dụng Unicode trong Visual C++. Rất mong nhận được các ý kiến đóng góp.