PDA

View Full Version : یونیکد در VC



alpha
پنج شنبه 06 آذر 1382, 10:13 صبح
sghl
حتما می دونید که MFC پیش فرض یونیکد رو ساپورت نمی کنه ولی این امکان هست که یونیکد و به برنامه ای که VC نوشتین اضافه کنید . من همه مواردی رو که باید انجام بدم تو MSDN خوندم ولی اصلا نتونستم انجام بدم . کسی یک راهنمای کامل ولی قدم به قدم ( انگلیسی یا فارسی ) در این مورد سراغ نداره ؟

Inprise
پنج شنبه 06 آذر 1382, 10:45 صبح
از طرفی حس توضیح دادن مفصل نیست و از طرف دیگه سایتی که این مقاله توش هست ثبت نام میخاد برای دسترسی به مقالات لذا متنش رو هر چند طولانیه همینجا کپی میکنم راحتتر بخونی . موفق باشی





UNICODE Conversions in Visual C++

Introduction

If you live in Eastern Europe, Japan or the Middle East, and you write computer programs, you are probably familiar with UNICODE. If you are writing programs in Visual C++/MFC, then you probably have experienced some of the problems with trying to write code that runs under UNICODE and ASCII. This article should help clear up some of the confusion. The principles here will work for anyone using Visual C++ and/or MFC.

What is UNICODE ?
UNICODE is a popular solution that has evolved to solve the 256-character ASCII limit problem. The ASCII character set is limited to 256 characters, numbered 0-255. For most Latin-based languages, this is fine; one set of upper-case characters, one set of lower-case characters, and a smattering of special characters (like punctuation, currency, etc.).

However, many Asian and Eastern languages contain many more than 256 characters, sometimes thousands more. Since ASCII is limited to 256, there has been no simple way to write programs for languages with more than 255 characters.

UNICODE replaces the ASCII standard with a much larger range for mapping numeric codes to characters of many languages. It does this by doubling the bytes of the character in the program.

ASCII versus UNICODE
An ASCII character is stored in one byte of memory (one byte has a numeric range of 0-255). In order to create enough space to store larger character sets for many other languages, it was determined that the byte size for one character be increased to two bytes. This provides a numeric range of 0-65535, or 65534 characters.

Unfortunately, doubling the byte size also causes compatibility problems. Most programs that are written on the ASCII standard simply assume that a character is one byte. Many methods and functions in Windows programs take advantage of this. When these programs are compiled for UNICODE, they break.

Visual C++ Solutions
What does all this mean to you as a software developer ? If you are writing programs in Visual C++, it means you must now decide whether your program is to run internationally, or if it is to remain local to ASCII compliant markets.

There is some good news here. Visual C++ provides some built-in support for UNICODE. The AppWizard in VC++ allows the developer to decide whether or not to support UNICODE before generating the application framework. The Win32 SDK contains several data types that allow UNICODE compliance, and MFC provides macros that convert generic text to UNICODE data types. The developer only needs to change a few coding habits to write UNICODE-friendly applications.

The Character String
C programmers declare a character array with the char keyword :


char str[100];


Function prototypes are declared as :


void strcpy( char *out, char *in );


To adapt these declarations to two-byte per character UNICODE, use the following :


wchar_t str[100];


or


void wcscpy( wchar_t *out, wchar_t *in );


Microsoft also provides a way to write code that is preprocessor reliant. When you create a new project in Visual C++, and you decide that it should support another character set, AppWizard puts a pre-processor statement into one of the header files. This tells the compiler what character set you are intending to support. From there, you can use the Generic Data Types that are supplied with VC++, and the preprocessor will replace them with the correct data type depending on what character set you are supporting. This makes the code much easier to re-compile for other character sets.

To activate the UNICODE standard in Visual C++, select Build | Settings from the file menu (in Visual C++ 5, select Project | Settings). Select the C/C++ tab. Append the _UNICODE value to the "Preprocessor definitions" field.

In your code, you would use TCHAR wherever the keyword char would normally be used, and LPTSTR wherever char * would be used. String constants defined in quotes ("Hello, World") would be re-written using the TEXT macro :


TEXT("Hello, World")


Microsoft provides several data types, including generic types, that are compatible with both ASCII and UNICODE. All of these can be found in the Microsoft on-line documentation under Generic Data Types or Data Types.

The Code
Here are some examples using one of the code fragments from the Developing Professional Applications For Windows 95 and NT Using MFC book by Marshall Brain and Lance Lovette.

This is the "Hello, World" application using the ASCII character set :


//************************************************** **********
// From the book "Visual C++ 2: Developing Professional
// Applications for Windows 95 and NT with MFC"
//
// by Marshall Brain and Lance Lovette
// Published by Prentice Hall
//
// Copyright 1995, by Prentice Hall.
// This code implements a simple "Hello World!" program in MFC
//************************************************** **********

//hello.cpp

#include <afxwin.h>

// Declare the application class
class CHelloApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};

// Create an instance of the application class
CHelloApp HelloApp;

// Declare the main window class
class CHelloWindow : public CFrameWnd
{
CStatic* cs;
public:
CHelloWindow();
};

// The InitInstance function is called each
// time the application first executes.
BOOL CHelloApp::InitInstance()
{
m_pMainWnd = new CHelloWindow();
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}

// The constructor for the window class
CHelloWindow::CHelloWindow()
{
// Create the window itself
Create(NULL, "Hello World!", WS_OVERLAPPEDWINDOW,
CRect(0,0,200,200));

// Create a static label
cs = new CStatic();
cs->Create("hello world", WS_CHILD|WS_VISIBLE|SS_CENTER,
CRect(50,80,150,150), this);
}





The string constants must be changed to their UNICODE counterparts. In the following code fragment, the same string constants are passed into the TEXT macro. TEXT will tell the preprocessor to check and see what character standard is being used :




// The constructor for the window class
CHelloWindow::CHelloWindow()
{
// Create the window itself
Create(NULL, TEXT("Hello World!"), WS_OVERLAPPEDWINDOW,
CRect(0,0,200,200));

// Create a static label
cs = new CStatic();
cs->Create( TEXT("hello world!"), WS_CHILD|WS_VISIBLE|SS_CENTER,
CRect(50,80,150,150), this);
}


When the preprocessor encounters a generic data type, it checks the AFXWIN.H header file for the _UNICODE definition. The preprocessor will then insert the proper data type based on whether or not the UNICODE standard is defined.

The following is an example of one of the Win32 API generic data types from the Win32 System Services book by Marshall Brain :


//************************************************** ********
// From the book "Win32 System Services: The Heart of Windows NT"
// by Marshall Brain
// Published by Prentice Hall
//
// Copyright 1994, by Prentice Hall.
//
// This code sets the volume label for drive C.
//************************************************** ********

// drvsvl.cpp

#include <windows.h>
#include <iostream.h>

void main()
{
BOOL success;
char volumeName[MAX_PATH];

cout << "Enter new volume label for drive C: ";
cin >> volumeName;

success = SetVolumeLabel("c:\\", volumeName);
if (success)
cout << "success\n";
else
cout << "Error code: " << GetLastError() << endl;
}


The character array declared at the top of this fragment will be declared as a two byte character array using the TCHAR data type. The TEXT macro will again be used for the string constants :




void main()
{
BOOL success;

TCHAR volumeName[MAX_PATH];

cout << TEXT("Enter new volume label for drive C: ");
cin >> volumeName;

success = SetVolumeLabel(TEXT("c:\\" ), volumeName);
if (success)
cout << TEXT("success\n");
else
cout << TEXT("Error code: ") << GetLastError() << endl;
}




Generic Data Types in Visual C++

Visual C++ provides several MFC-specific data types for making applications tolerant to international character sets. These are defined generically, to make the application fully portable to UNICODE, ASCII, DBCS (double byte character sets) and MBCS (multi byte character sets). It is beyond the scope of this article to explain all of the differences between the character sets; MFC provides a transparent way of implementing them all. How these Generic Data Types are mapped depends on which character set variable is set for the Project : none (the default, which is automatically ASCII), MBCS, DBCS or UNICODE. Since this article is primarily about UNICODE, I have provided the mappings for ASCII and UNICODE character types in the table that follows :

Generic MFC Data Type Map to ASCII Map to UNICODE Notes :
_TCHAR char wchar_t _TCHAR is a macro that maps to the ASCII char data type if UNICODE is not set, and wchar_t when it is.
_T or _TEXT char constant strings wchar_t constant strings These are functionally identical macros. They are ignored (removed by the preprocessor) for ASCII; for UNICODE, these macros convert the string into the UNICODE equivalent.
LPTSTR char*, LPSTR(Win32) wchar_t* A portable-32 bit pointer to a character string. It maps to the character type that is set for the project, as explained above.
LPCTSTR const char*, LPCSTR(Win32) const wchar_t* A portable 32-bit pointer to a constant character string. It maps to the character type that is set for the project, as explained above.

By using the above Generic Data Types, the developer is able to ensure that ONE variable set when the project is created, and the use of these Generic Data Types in place of the byte-specific ones they replace, is all that is needed to compile an application that is friendly to both ASCII and UNICODE. However, it is important to note that the above Generic Types are Microsoft extensions; they are not ANSI compatible. For detailed descriptions of the Generic Data Types that Microsoft provides, read the Microsoft documentation Generic Data Types and Using Generic-Text Mappings in the Microsoft Help Files.

Some technical notes
To compile MFC programs for UNICODE, you must have access to the UNICODE versions of the MFC libraries. The library files are available through a custom installation of Visual C++.

It is important to note that not defining the UNICODE standard may not have a visible effect on your program. For example, the code above will build and execute without difficulty whether the _UNICODE variable is set in the build settings or not. The problems arise when the developer begins using Win32 API functions that have more than one implementation.

When the developer uses an API function that has a dual implementation (as any of the Win32 API functions that take a char or string as a parameter will), the compiler calls the correct function based on whether the _UNICODE variable is set. Without the _UNICODE being defined the standard, the compiler will call the ASCII declared version of the function; the preprocessor will strip out the "ignored" macros.

Conclusion
As we have shown, compiling applications for the UNICODE standard is not difficult. As a mental shift, UNICODE is unique in that the changes it requires are simple and intuitive. The extensions provided by Microsoft serve to make the choice of character set even more transparent. These simple changes help simplify the process of writing new applications, and changing old ones, for international markets.



:roll:

alpha
جمعه 07 آذر 1382, 11:02 صبح
آقا خیلی ممنون . البته باید اول بخونم بعد بگم که چطوریه . خدا کنه مشکل حل بشه . مرسی

alpha
دوشنبه 10 آذر 1382, 15:45 عصر
آقا این مشکل من رو حل نکرد . یه خواهش از کسانی که قبلا این کار رو انجام دادن دارم و اونم اینه که یک برنامه خیلی ساده ( مثلا گرفتن و نمایش یک متن و یا فقط نمایش یک متن فارسی یونیکدی ) رو بنویسن و اینجا بزارن . اینطوری من می تونم بفهمم اشکال کارم کجاست .
ممنون از همه

Inprise
دوشنبه 10 آذر 1382, 16:26 عصر
دو سوال :

1. نسخه ویندوزت ؟
2. از کدام نگارش ویژوال سی استفاده میکنی ؟

---


void CunicodetestDlg::OnBnClickedButton1()
{
m_Edit.SetWindowText(TEXT("سلام"));
// TODO: Add your control notification handler code here
‍}

من با این کد روی ویندوز اکس پی و وی سی هفت مشکلی ندارم .

alpha
شنبه 15 آذر 1382, 16:26 عصر
من ویندوزم ایکس پی هست و از ویژوال سی 6 یا دات نت استفاده می کنم . فزق نمی کنه شما یک نمونه کوچک بفرستید ممنونتون می شم .

Inprise
یک شنبه 16 آذر 1382, 10:54 صبح
حتما" اشکالی در مجموعهء سیستمت وجود داره . من بدون مشکل و با همون شرحی که داده شد و میبینی دارم کار میکنم :!:

alpha
یک شنبه 16 آذر 1382, 15:15 عصر
آقا این که نوشته های برنامه فارسی باشه این می شه . منظور من اینه که از یک ادیت باکس به صورت یونیکد بگیره و مثلا بریزه تو فایل یا نشون بده . این رو ببین می تونی بکنی ؟

Inprise
یک شنبه 16 آذر 1382, 16:32 عصر
void CunicodetestDlg::OnBnClickedButton1()
{
LPTSTR str=new TCHAR[m_Edit.GetWindowTextLength()];
m_Edit.GetWindowText(str , m_Edit.GetWindowTextLength());
MessageBox(_T(LPCTSTR(str)));
delete[] str;
// TODO: Add your control notification handler code here
}

این کد رو همین الان نوشتم و بدون مشکل یونیکد رو نمایش میده ! :roll:

alpha
سه شنبه 18 آذر 1382, 08:40 صبح
آقا من کلا این کد رو نوشتم ( کپی کردم ) ولی بازم مشکل حل نشد . خروجی رو به صورت علامت سوال نشون میده :( واسه همین می گم سورس رو برام بفرستید که من مقایسه کنم ببینم کجای کارم مشکل داره .

Inprise
سه شنبه 18 آذر 1382, 09:47 صبح
عجیبه . سورس برنامه دقیقا" همونیه که داری میبینی . یه پروژه MFC ایجاد کن و یک کلید و یک ادیت باکس روی فرم بگذار و به عنوان رویدادگردان کلیک روی فرم کد فوق رو بنویس . عکس زیر هم از نسخه اجرائیش روی سیستم حقیر :roll:

alpha
سه شنبه 18 آذر 1382, 13:35 عصر
بابا عجیبه . من هم که عین همین کار رو کردم . من چند ساله که برنامه نویس سی هستم و با ویژوال سی هم زیاد کار کردم ولی تو این یونیکدش موندم :( واسه همین می گم سورسشو برام بفرست ببینم اصلا تو سیستم من کار می کنه یا نه . اگر هم کار می کنم مقایسه بکنم .

Amin_Li
چهارشنبه 19 آذر 1382, 09:07 صبح
با سلام
من جواب یونیکد را در ویزوال سی پیدا کردم
خیلی ساده هست
همش تقصیر این برنامه نویسان بی عرضه میکروسافت هست چطور؟
وقتی شما یونیکد را تعریف میکنید
وقتی شما بصورت فارسی در resource می نویسید
ویزوال سی انرا بصورت علامت سوال ذخیره می کند.
خوب حالا چطوری حل میشه؟
راحته - دفعه بعد بهتون میگم:)

alpha
چهارشنبه 19 آذر 1382, 14:33 عصر
بابا خوشحالم کردی ولی آخرشو خراب کردی :(
دفعه بعد کی هست ؟