Từ 1 tới 2 trên tổng số 2 kết quả

Đề tài: Sử dụng tiếng Việt Unicode trong Visual C++ 6

  1. #1
    Ngày gia nhập
    01 2007
    Nơi ở
    Hải Phòng
    Bài viết
    210

    Mặc định Sử dụng tiếng Việt Unicode trong Visual C++ 6

    Bài này mình sưu tầm trên tạp chí PC World Vietnam

    Trước tiên, ta nói về thực trạng hỗ trợ Unicode của các công cụ phát triển trực quan Visual C++ 6.0 và 7.1 (.NET 2003) (bản 7.0 - .NET 2002 - hiện không còn được dùng phổ biến; nhưng về cơ bản, nó tương tự như bản 7.1). Visual C++ 6.0 không cho phép nhập Unicode ở cả trình soạn thảo tài nguyên (resource editor – dùng để tạo các thành phần giao diện ứng dụng) lẫn trình soạn thảo mã nguồn. Visual C++ 7.1 cho phép nhập Unicode trong mã nguồn. Đối với việc soạn thảo tài nguyên, Unicode được hỗ trợ nếu bạn dùng .NET framework; còn nếu bạn dùng Win32API hoặc MFC thì không. Tuy nhiên, việc biên dịch mã Unicode lại khác, sẽ được đề cập ở phần sau.

    Mã lệnh Unicode

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		A0504_UD_114.jpg
Lần xem:	23
Size:		21.7 KB
ID:		5029
    Các xâu Unicode (hay xâu kí tự rộng) được lưu như là mảng wchar_t, về bản chất là kiểu int16 (2 byte). Để trình biên dịch biết một xâu/kí tự là Unicode, ta phải thêm tiếp đầu ngữ L. Ví dụ, L“Thế Giới Vi Tính” hoặc L“T”. Có thể dùng macro _T hoặc TEXT để đảm bảo các xâu có thể được dịch phù hợp với thiết định của project. Xâu là Unicode nếu macro UNICODE/_UNICODE được định nghĩa, là xâu bình thường nếu không. Với Visual Studio .NET, hai macro UNICODE và _UNICODE được tự động tạo ra khi ta đặt Character Set của Project là Unicode.


    Giao diện ứng dụng được Việt hóa

    Các kiểu như LPCSTR, CHAR... đều có kiểu 16 bit tương ứng như LPCWSTR, WCHAR. Các kiểu LPCTSTR, TCHAR được dịch là kiểu 8 bit nếu UNICODE và _UNICODE không được định nghĩa và 16 bit nếu ngược lại. Do đó, trong những trường hợp chung, nên dùng các kiểu có thành tố T.

    Các hàm nhận hoặc trả về xâu thường có hai phiên bản 8 bit và 16 bit với các tiếp vị ngữ A hoặc W kiểu như GetWindowTextA và GetWindowTextW. Tên không có tiếp vị ngữ (GetWindowText) được dịch là một trong hai hàm theo cách tương tự như trên.

    Để nhập xâu Unicode trong Visual Studio.NET, bạn phải ghi lại mã nguồn theo encoding là “Unicode” hoặc “Unicode (UTF-8 with signature)”, (đừng nhầm với “without signature”) bằng Save As (hoặc Advanced Save Options). Tốt nhất là nên dùng encoding thứ hai. Còn với Visual Studio 6.0, bạn buộc phải nhập mã Unicode của các kí tự. Trình UnikeyNT 3.6 cung cấp “bảng mã” “Unicode C String” để bạn thực hiện việc này dễ dàng hơn. Lưu ý là cách này không áp dụng được trong soạn thảo tài nguyên. Nếu bạn viết “\x1EA1”, bộ dịch tài nguyên xem như xâu có ba kí tự, một có mã 0x1E và hai kí tự kia là “A” và “1”. Nói cách khác, nó chỉ chấp nhận cách viết này cho kí tự ANSI.

    Một lưu ý nhỏ là toàn bộ các font mà ta sử dụng trong chương trình cũng như font hệ điều hành dùng cho các thành phần giao diện (font cho title bar, menu, tooltip...) đều phải có các kí tự tiếng Việt Unicode. Tốt nhất là những font quen thuộc như Arial, Tahoma... Một số font mặc định của Windows không đáp ứng được yêu cầu này như MS Sans Serif, Trebuchet MS... Có lẽ bạn nên thông báo cho người dùng chương trình của mình biết điều này.

    Thiết định Project hỗ trợ Unicode

    Trong Visual Studio .NET: Đơn giản bạn chỉ cần đặt Character Set thành Unicode trong Project Properties/Configuration Properties/General.

    Trong Visual Studio 6.0, bạn tạo thêm macro UNICODE và _UNICODE, xoá macro _MBCS (multibyte character set) (vào Project Settings, chọn gốc project từ cây bên trái, vào tab C/C++, chọn Category là Preprocessor, gõ thêm các macro, cách nhau bằng dấu phẩy, xoá macro cũ). Nếu sử dụng MFC, bạn còn phải thêm điểm vào cho ứng dụng (vào Project Settings, Link, Output, nhập vào ô Entry Point “wWinMainCRTStartup”. Để ý chữ w đầu tiên).

    Nhớ là bạn phải đặt hỗ trợ cho tất cả các chế độ dịch cần thiết (Debug, Release... trong “Configuration” hoặc “Settings for”).

    Việt hóa mã nguồn C/C++

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		A0504_UD_116a.jpg
Lần xem:	247
Size:		15.6 KB
ID:		5030
    Đối với Visual C/C++ 7.1, ta gõ tiếng Việt Unicode như bình thường (ví dụ: TEXT(“Thế Giới Vi Tính”)). Chú ý chọn font cho trình soạn thảo để hiển thị được tiếng Việt Unicode (Vào Tools/Options, trong mục Environment/Fonts and Colors, chuyển mục “Show settings for” thành “Text Editor” và chọn lại Font). Sau đó, ghi lại theo một trong hai cách sau:

    Một common dialog Việt hóa


    – Vào mục File/Advanced Save Options để đổi “Encoding” thành “Unicode – Codepage 1200” hoặc “Unicode (UTF-8 with signature) – Codepage 65001”. Sau đó ghi lại tập tin. Chú ý là cần có “with signature” để trình biên dịch biết rằng tập tin được lưu dưới dạng Utf-8; nếu không (“without signature”), trình biên dịch sẽ hiểu nhầm là tập tin ASCII. “Signature” ở đây là kí hiệu báo Utf-8 được ghi vào đầu tập tin.

    – Chọn File/Save As. Giữ nguyên tên file, nhấn chuột vào mũi tên bên phải nút “Save”, chọn “Save With Encoding...” và chọn một trong hai encoding trên.
    Nói chung, bạn chỉ cần chỉnh Encoding một lần cho một tập tin. Nhưng đôi khi Visual Studio có thể bị lỗi. Trong trường hợp đó, IDE sẽ báo lỗi đại loại như “Some Unicode characters in this file will not be saved...”. Nếu vậy, bạn nên tiến hành thiết định encoding lại.

    Đối với Visual C/C++ 6.0, bạn sử dụng một bộ gõ hỗ trợ “Unicode C String” (chẳng hạn UniKeyNT 3.6, download miễn phí tại unikey.sf.net) và gõ bằng “bảng mã” này. Chẳng hạn với xâu “Thế Giới Vi Tính”, bạn thu được TEXT(“Th\x1EBF Gi\x1EDBi Vi Tính”). Nếu bạn đã có xâu tiếng Việt sẵn với một bảng mã khác (chẳng hạn nguyên bản Unicode hoặc ABC), bạn có thể dùng chức năng chuyển mã trong mục “Công cụ” của Unikey.

    Việt hóa tài nguyên

    Đối với quá trình Việt hóa tài nguyên, cần chú ý mấy điểm sau:

    – Trình soạn thảo tài nguyên không hỗ trợ Unicode (ở đây chúng ta không bàn luận về .NET framework). Cả trình soạn thảo tài nguyên lẫn trình biên dịch tài nguyên đều không hỗ trợ Unicode C String.

    – Trình biên dịch tài nguyên hỗ trợ Unicode – Codepage 1200. Đây là chìa khoá cho vấn đề của chúng ta.


    Message Box được Việt hoá

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		A0504_UD_116b.jpg
Lần xem:	12
Size:		8.4 KB
ID:		5031 Nếu ứng dụng của bạn hỗ trợ hai ngôn ngữ tiếng Anh và tiếng Việt, bạn nên thiết kế giao diện tiếng Anh trước. Nếu ứng dụng của bạn chỉ dùng tiếng Việt, bạn sử dụng “bảng mã” utf-8 để gõ. Với Unikey, bạn chọn “bảng mã” “Utf-8 Literal”. Chú ý là kí tự tiếng Việt sẽ được hiển thị không chính xác, và thường dài hơn kết quả thực. Ví dụ: thay vì gõ “Thế Giới Vi Tính”, bạn gõ “Thế Giá»›i Vi Tính”.

    Để hiểu vì sao “bảng mã” này lại được Resource Editor chấp nhận, ta phải hiểu bản chất của Utf-8. Utf-8 thực ra không phải là một bảng mã, mà là một cách lưu trữ các chuỗi trong bảng mã Unicode như một chuỗi byte. Có thể hiểu hình tượng như một cách chuyển đổi chuỗi 2 byte thành chuỗi 1 byte (là chuỗi được chấp nhận trong Resource Editor). Ưu điểm của Utf-8 là tương thích ngược với ASCII. Nghĩa là các chuỗi ASCII được giữ nguyên khi lưu trữ bằng Utf-8. Do vậy mà ta làm việc bình thường với các chuỗi không phải là tiếng Việt. Để biết thêm chi tiết, bạn có thể tham khảo bài báo “Mã Unicode tiếng Việt, hiện thực trong Windows và Linux” của TS. Nguyễn Văn Hiệp TGVT A 12/2001 (tr.68).

    Tiếp theo, bạn phải dùng một trình soạn thảo văn bản hỗ trợ Unicode để mở tập tài nguyên ra chỉnh sửa. Với Visual C++ 7.1, bạn mở Solution Explorer (Ctrl-Alt-L), nhấn phải chuột vào tập tài nguyên (trong thư mục Resource Files), chẳng hạn “resource.rc”, chọn “Open With”, chọn “Source Code (Text) Editor With Encoding”, chọn “Unicode (UTF-8 without signature) – Codepage 65001” (bây giờ lại là “without”, vì ta chưa hề ghi signature vào tập). Với Visual C++ 6.0, bạn có thể dùng Notepad của Windows2000/XP để mở với Encoding là Utf-8. Nhớ chọn lại font để tiếng Việt Unicode hiển thị được (Format/ Font trong Notepad). Bây giờ xem lại nội dung của tập tin, bạn sẽ thấy các dòng văn bản mà bạn gõ bằng Utf-8 trước đó đã được chuyển thành tiếng Việt.

    Ghi tập tài nguyên lại với một tên khác (Save As), chẳng hạn “ResourceVn.rc” bằng Encoding “Unicode – Codepage 1200” (Unicode trong Notepad).

    Bây giờ, bạn đã có hai phiên bản tài nguyên: một phiên bản soạn thảo được bằng Resource Editor, một phiên bản soạn thảo bằng tay sử dụng Unicode.

    Với phiên bản mới, vì Codepage đã bị đổi, nên bạn phải huỷ thông tin Codepage cũ (bằng dấu chú thích//) ở dòng:

    #pragma code_page(1252)

    thành

    //#pragma code_page(1252)

    Vì ngôn ngữ bây giờ không phải là tiếng Anh nữa, nên tốt nhất là bạn huỷ cả dòng

    LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

    Và thay bằng dòng

    LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL

    Và ghi lại.

    Bây giờ ta đã có một phiên bản Unicode hoàn chỉnh. Ta sẽ thay thế phiên bản cũ bằng phiên bản mới này. Tuy nhiên, ta sẽ tìm cách để vẫn giữ lại phiên bản cũ trong project, nhờ đó có thể tận dụng thao tác trực quan của Visual Studio và bộ sinh mã tự động. Chẳng hạn, khi ta muốn gắn kết sự kiện với hàm, gắn điều khiển với biến, tìm ID của điều khiển... ta sẽ dùng phiên bản nguyên thuỷ. Nhưng khi biên dịch, ta dùng phiên bản Unicode.

    Để làm điều đó, ta phải ngăn Visual Studio biên dịch tập “resource.rc”:

    – Với Visual Studio 7.1: Bạn mở Solution Explorer (Ctrl-Alt-L), mở folder Resource Files, nhấn phải chuột vào resource.rc, chọn Properties (hoặc chọn tập tin và nhấn Alt-Enter). Trong mục Configuration Properties/ General, đặt Excluded From Build thành Yes.

    – Với Visual Studio 6.0: Bạn mở File View (Alt-0, nhấn Ctrl-PageDown đến tab File View), mở folder “Source Files”, chọn Resource.rc. Mở Project Settings (Alt-F7). Trong tab General, chọn Exclude file from build.

    Nhớ là bạn phải làm việc này cho tất cả các chế độ dịch cần thiết. Bây giờ, ta chỉ việc thêm tập “ResourceVn.rc” vào project là xong.

    – Với Visual Studio 7.1: Sử dụng chức năng File/ Add Existing Item.

    – Với Visual Studio 6.0: Project/ Add To Project/ Files.

    Chú ý: nếu bạn viết chương trình với hai ngôn ngữ (tiếng Việt và tiếng Anh), bạn phải tạo ra các chế độ dịch tương ứng. Với các chế độ dịch cho tiếng Anh, bạn phải ngăn việc dịch ResourceVn.rc và yêu cầu dịch Resource.rc.

    Cuối cùng là dịch và chạy thử chương trình. Để đảm bảo quá trình dịch và liên kết không nhầm lẫn, bạn nên chọn chức năng Build/ Rebuild Solution (Rebuild All). Chú ý rằng với Visual C/C++ 6.0, sẽ có một chuỗi báo lỗi “Could not find the file” khá dài, nhưng quá trình dịch và liên kết vẫn cho kết quả tốt.

    Để bảo trì, cập nhật lại tập tài nguyên, ta sử dụng một trong hai cách:

    – Phục hồi lại tập “ResourceVn.rc” về dạng mà Visual Studio đọc được bằng cách làm ngược lại quá trình trên (xoá dòng LANGUAGE mới, bỏ chú thích ở hai dòng cũ, ghi lại dưới encoding “Unicode Utf-8 without signature”. Nếu dùng Notepad, việc save ngược phải thực hiện theo 2 bước: đầu tiên là save dưới encoding “Utf-8”, sau đó là mở ra dưới dạng ANSI và xoá 3 kí tự signature ở đầu tập). Sau đó tiến hành thay đổi trên tập này. Chú ý là ta có thể kéo thả hoặc copy – paste các phần tử từ tập “Resource.rc” vào tập “ResourceVn.rc”.

    – Copy (bằng trình soạn thảo văn bản) những thay đổi từ tập “Resource.rc” vào tập “ResourceVn.rc”.

    Việc sử dụng cách nào tốt hơn là tùy tình huống cụ thể. Tuy nhiên, cách thứ hai thường hiệu quả hơn.

    Nhược điểm của phương pháp này là nếu bạn sử dụng MFC, Việt hóa không có tác dụng đối với data của ComboBox. Vì data này bị chuyển thành dữ liệu nhị phân (ghi dưới dạng các chuỗi hex) trong tập tài nguyên. Do đó, bạn buộc phải dùng cách bổ sung thủ công nội dung của chúng bằng mã chương trình.

    Hộp thoại thông dụng (COMMON DIALOG)

    Ứng dụng trên Windows thường sử dụng các hộp thoại đã được xây dựng sẵn của Windows trong các công việc như chọn font, chọn màu... Để Việt hóa những hộp thoại này, ta sẽ thiết kế lại với các caption của điều khiển phù hợp. Giải pháp này không chỉ áp dụng cho trường hợp Việt hóa bằng Unicode, nó cũng có tác dụng nếu bạn sử dụng các bảng mã khác. Trước tiên, ta cần tìm thiết kế gốc của hộp thoại cần chuyển. Thiết kế này thường bao gồm một tập đuôi dlg (chẳng hạn color.dlg) và một (hoặc nhiều) tập header đi kèm. Để biết tên tập .dlg, bạn mở MSDN Library, tìm mục “Common Dialog Box Library” (theo index), sau đó chọn loại hộp thoại bạn cần (ví dụ: Color Dialog Box) và tìm (Ctrl-F) “.dlg”. Sau đó tìm tập này trong thư mục cài đặt Visual Studio, mở tập này (bằng một trình soạn thảo văn bản) để tìm những tập .h cần thiết. Copy toàn bộ các macro (#define) của các tập header vào tập resource.h, ghi lại. Bây giờ, bạn tạo một dialog mới trong trình soạn thảo tài nguyên. Sau đó, copy nội dung phần định nghĩa dialog trong tập .dlg vào thay thế phần định nghĩa do bạn tạo (lưu ý thay tên tài nguyên gốc bằng tên tài nguyên bạn đã tạo) trong tập rc. Ví dụ, với hộp thoại màu, bạn copy từ phần ChooseColor đến hết, sau đó thay ChooseColor bằng tên tài nguyên của bạn (chẳng hạn IDD_CHOOSECOLOR), xoá phần định nghĩa cũ. Và bạn đã có thiết kế gốc của hộp thoại với tên tài nguyên mới. Bạn có thể thay đổi nó, đặc biệt, sửa caption của nó và đổi font phù hợp.

    Đối với MFC, việc dùng các hộp thoại thông dụng thường thông qua các lớp dẫn xuất từ CCommonDialog. Nên để áp dụng mẫu hộp thoại này, ta phải đặt mẫu cho cấu trúc thành viên của thể hiện hộp thoại (đối với hộp chọn màu là biến m_cc có kiểu CHOOSECOLOR) trước khi gọi DoModal() của nó. Để đơn giản hoá quá trình, ta tạo một lớp dẫn xuất từ lớp hộp thoại nguyên thuỷ (trong ví dụ này là lớp CSpecColorDialog dẫn xuất từ lớp CColorDialog). Sau đó, trong cấu tử, ta thực hiện các chuẩn bị cần thiết. Nhờ đó, CSpecColorDialog ứng xử như CColorDialog.

    Visual C++ Code:
    1. CSpecColorDialog(COLORREF clrInit=0,DWORD dwFlags=0,CWnd *pParentWnd=0)
    2.     :CColorDialog(clrInit,dwFlags,pParentWnd)
    3. {
    4.     m_cc.Flags|=CC_ENABLETEMPLATE;
    5.     m_cc.lpTemplateName=MAKEINTRESOURCE(IDD_CHOOSECOLOR);
    6.     m_cc.hInstance=0;
    7. }

    Phép toán hoặc bit (|) tránh làm mất những cờ mà người dùng đã đặt. Mẫu hộp thoại IDD_CHOOSECOLOR được chỉ ra trong lpTemplateName. Vì mẫu này nằm trong cùng một thể hiện ứng dụng với nơi gọi hộp thoại nên hInstance có thể đặt bằng 0. Cách làm đối với các Common Dialog khác không có gì khác biệt.

    Do việc thay thế mẫu hộp thoại được Win32 Platform SDK hỗ trợ nên nếu bạn không sử dụng MFC, cách Việt hóa cũng tương tự. Bạn có thể viết một hàm VietChooseColor thay thế hàm ChooseColor. Trong đó, trước khi gọi hàm ChooseColor, bạn thực hiện việc đặt mẫu như trong cấu tử của CSpecColorDialog.

    Visual C++ Code:
    1. BOOL VietChooseColor(LPCHOOSECOLOR lpcc)
    2. {
    3.     lpcc->Flags|=CC_ENABLETEMPLATE;
    4.     lpcc->lpTemplateName=MAKEINTRESOURCE(IDD_CHOOSECOLOR);
    5.     lpcc->hInstance=0;
    6.     return ChooseColor(lpcc);
    7. }

    Bây giờ, VietChooseColor ứng xử hoàn toàn như ChooseColor, ngoại trừ nó có giao diện tiếng Việt.

    Message Box

    Việc hiển thị thông báo tiếng Việt rất đơn giản. Chỉ cần truyền vào các xâu Unicode tiếng Việt như là tham số cho hàm MessageBox(W). Nhưng để ứng dụng được Việt hóa hoàn thiện thì các nút bấm (Button) cũng phải dùng tiếng Việt. Để làm được điều này, ta buộc phải viết lại hàm MessageBox cho riêng mình, một cách thức cổ điển mà hầu như ứng dụng tiếng Việt nào cũng sử dụng. Tuy nhiên, ở đây tác giả cố gắng tạo một MessageBox linh động hơn: có thể tạo ra số nút bấm tuỳ ý. Nhờ vậy, ta có thể giả lập tất cả các loại MessageBox của Windows.

    Đầu tiên, tạo một mẫu hộp thoại chỉ gồm một điều khiển là Static Text, đặt tên tài nguyên cho nó để ta có thể tìm và xử lí. Sau đó, tạo một lớp gắn với mẫu (giả sử là CVMsgDlg). Toàn bộ quá trình tạo dialog thực sự chủ yếu nằm trong OnInitDialog. Ở đây, ta tạo icon, các nút bấm, đặt vị trí và kích thước phù hợp cho chúng. Quá trình này khá tốn công sức vì mang nhiều tính thủ công, có lẽ không cần thiết phải trình bày chi tiết ở đây. Điểm mấu chốt là tạo một mảng kích thước động các nút bấm CButton*buttons. Các nút được tạo động bằng phương thức CButton::Create. Ta có thể xử lí thông điệp WM_COMMAND mà các nút bấm gửi cho dialog thông qua hàm ảo CWnd::OnCommand. Ta cũng cần phải thay đổi cư xử của khung ứng dụng khi nút OK và Cancel được nhấn. Chỉ cần định nghĩa chồng hàm OnOk và OnCancel bằng những hàm rỗng. Cũng không thể quên việc huỷ bỏ các thành phần khi dialog kết thúc trong thông điệp WM_DESTROY.


    Hộp thoại được Việt hoá và hộp thoại khi thiết kế

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		A0504_UD_118a(1).jpg
Lần xem:	243
Size:		17.8 KB
ID:		5032
    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		A0504_UD_118b.jpg
Lần xem:	244
Size:		12.9 KB
ID:		5033

    Cuối cùng là viết hàm VietMessageBox dùng lớp này. Hàm này chỉ đơn giản là tách thông tin truyền vào và truyền hợp lí cho cấu tử của lớp. Sau đó, hàm trả về giá trị của dialog.DoModal(), là ID của nút được nhấn.

    Nếu không sử dụng MFC, vấn đề cơ bản là thay đổi trong lớp CVMsgDlg. Thay vì dùng các phương thức của các lớp, bạn phải dùng các hàm SDK; chẳng hạn thay CButton::Create bằng CreateWindow với lớp “BUTTON”. Tuy nhiên, sử dụng thư viện lớp thì đơn giản hơn.

    Trên đây, tôi đã chia sẻ với các bạn một cách Việt hóa Unicode cho chương trình VC++, chạy trong WindowsNT/2000/XP. Hi vọng có thể giúp các bạn phát triển những ứng dụng thuần Việt tốt và nhanh.

    Tác giả gửi kèm chương trình “EasyPress” (tải về ở website TGVT), xem như một ứng dụng thực tế áp dụng phương pháp đã trình bày. Đây là chương trình tùy biến bàn phím, khá hữu dụng, nhất là đối với bàn phím đa phương tiện. Chương trình về cơ bản đã được Việt hóa, dù chưa hoàn toàn (Common Dialog, Message Box).

    Hồ Tất Thành
    Đại học Quốc Gia Hà Nội
    pEnGwINUS.

  2. #2
    Ngày gia nhập
    07 2006
    Nơi ở
    Hanoi, Vietnam
    Bài viết
    2,750

    Post Sử dụng tiếng Việt Unicode trong Visual C++ 6.0

    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.

    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++:

    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).

    wchar_t Unicode_String[256];

    MultiByteToWideChar(CP_UTF8,0,String1,strlen(Strin g1), 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:

    MultiByteToWideChar(CP_UTF8,0,String1,strlen(Strin g1), 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, http://unikey.sourceforge.net).

    Visual C++ Code:
    1. void Convert_String(BYTE *string_in, wchar_t *string_out)
    2.  
    3. {
    4.     int i, scnt = strlen((char*)string_in);
    5.     wchar_t unicode;
    6.     i = 0;
    7.     while (i
    8.     {
    9.         if (0xc2<= string_in[I] && string_in[I] <= 0xe0 && 0x80<= string_in[i+1] && string_in[i+1] <= 0xbf)
    10.         {
    11.             // 2byte
    12.             unicode = (string_in[i++] & 0x3f)<<6;
    13.             unicode += (string_in[i++] & 0x3f);
    14.             *string_out= unicode;
    15.         }
    16.         else if (0xe0<= string_in[I] && string_in[I] <= 0xef &&
    17.             0x80<= string_in[i+1] && string_in[i+1] <= 0xbf &&
    18.             0x80<= string_in[i+2] && string_in[i+2] <= 0xbf)
    19.         {
    20.             // 3byte
    21.             unicode = (string_in[i++] & 0x0f)<<12;
    22.             unicode += ((string_in[i++] & 0x3f)<<6);
    23.             unicode += (string_in[i++] & 0x3f);
    24.             *string_out = unicode;
    25.         }
    26.         else
    27.         { // 1byte
    28.             *string_out = string_in[i++];
    29.         }
    30.  
    31.         string_out++;
    32.     }
    33.  
    34.     *string_out = 0; // ket thuc chuoi
    35. }

    Khi dùng bạn chỉ cần khai báo như sau:

    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];

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		A0502_UD_111a.jpg
Lần xem:	7
Size:		4.4 KB
ID:		5034

    Convert_String((BYTE*)String1,unicode_string);

    Sau đó dùng chuỗi unicode_string này để gắn cho các control:

    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.


    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!

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		A0502_UD_111b.jpg
Lần xem:	4
Size:		10.7 KB
ID:		5035
    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:

    Visual C++ Code:
    1. {
    2.     CPaintDC dc(this); // device context for painting
    3.  
    4.     // TODO: Add your message handler code here
    5.     CDC *d;
    6.     d=GetWindowDC();
    7.     CFont c;
    8.     CFont *l;
    9.  
    10.     SetWindowText(_T(''));
    11.     d->SetBkMode(TRANSPARENT);
    12.     c.CreatePointFont(110,_T('Tahoma'));// dùng font Tahoma, Size 11
    13.     l=d->SelectObject(&c);
    14.  
    15.     // Chương trình hiển thị Tiếng Việt Unicode
    16.     char *string1='ChỈ°Ỉ¡ng trnh hi'ƒn th'‹ Tiº¿ng Vi'‡t Unicode';
    17.     wchar_t titlebar_str[256];
    18.     Convert_String((BYTE*)string1,titlebar_str); //chuyển UTF-8 sang Unicode
    19.     d->SetTextColor(RGB(255,255,255));
    20.     d->TextOut(25,3,titlebar_str); //vẽ tiêu đề mới
    21.     d->SelectObject(l);
    22. }

    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.


    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		A0502_UD_111c.jpg
Lần xem:	4
Size:		6.3 KB
ID:		5036
    [I]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.

    Đoàn Đình Dân
    Email: admin[@]congdongcviet.com | CC to: info[@]congdongcviet.com
    Phone: 0972 89 7667 (Office: 04 6329 2380)
    Yahoo & Skype: dreaminess_world (Vui lòng chỉ rõ mục đích ngay khi liên hệ, cảm ơn!)

    Một người nào đó coi thường ý thức kỷ luật cũng có nghĩa là người đó đã coi thường tương lai số phận của chính bản thân người đó. Những người coi thường ý thức kỷ luật sẽ không bao giờ có được sự thành công trong sự nghiệp!

Các đề tài tương tự

  1. Hiển thị tiếng việt Unicode trong Dev-C như thế nào?
    Gửi bởi kitti trong diễn đàn Thắc mắc lập trình C/C++/C++0x
    Trả lời: 3
    Bài viết cuối: 12-05-2012, 04:09 PM
  2. Cách tạo và nhập nội dung file Unicode trong Visual C++ 2010?
    Gửi bởi nguoihocnghe trong diễn đàn Thắc mắc lập trình Visual C++
    Trả lời: 3
    Bài viết cuối: 24-03-2012, 10:29 PM
  3. Vấn đề về chuỗi tiếng việt unicode của CString trong MFC
    Gửi bởi silver_wolf trong diễn đàn Thắc mắc lập trình C/C++/C++0x
    Trả lời: 6
    Bài viết cuối: 01-06-2011, 08:21 AM
  4. Lỗi tiếng việt unicode trên MFC
    Gửi bởi silver_wolf trong diễn đàn Nhập môn lập trình C/C++
    Trả lời: 0
    Bài viết cuối: 27-05-2011, 07:36 AM
  5. Tiếng việt Unicode trong kết nối CSDL
    Gửi bởi Socket trong diễn đàn Thắc mắc lập trình Visual C++
    Trả lời: 16
    Bài viết cuối: 13-07-2010, 12:21 PM

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn