win32编程(二) UNICODE

 一 编码的历史

单字节编码

 2.1.1 ASCII  0-127 7位表示
 2.1.2 ASCII扩展码 0-255 8位表示
   代码页:通过代码页来切换对应的


多字节编码

 2.1.3 双字节字符集 DBCS
   使用一个或两个字节表示字符.
     
      "A中B国"
          12 1 2 
          A: 0x41 中:0x8051
          B: 0x42 国:0x8253
          
1    2    3    4    5     6
0x41 0x80 0x51 0x42 0x82  0x53   
A    中        B     国


这样既包含多字节又包含单字节的成为多字节编码


宽字节编码

 2.1.4 Unicode
    全部使用2个字节表示字符
"A 中 B 国"
           2  2 2 2 
          A: 0x0041 中:0x8051
          B: 0x0042 国:0x8253
          1  2  3   4    5   6   7   8
         41 00  51  80   42  00  53  82
        
       内存/硬盘等资源占用变大.
       对编程支持度.



二  C语言和编码

    1 单字节的字符和字符串

      char cText = 'A';
      char * pszText = "ABCD";
      

    2 宽字节的字符

      wchar_t cText = 'A'
      wchar_t * pszText = L"ABCD";
      

    3 相关函数

      单字字符的函数,对应有多.宽字节的函数.
       strlen wcslen mbslen
       printf wprintf
       

    4 TCHAR 

   为了程序中可以方便的支持的Unicode和多字节字符等,所以使用TCHAR来定义字符和字符串.
  根据_UNICODE宏开关,会将TCHAR编译成不同字符类型.
#ifndef _UNICODE
  typedef char TCHAR
#define __T(x) x
#else
typedef wchar_t TCHAR
#define __T(x)  L##x
#endif


使用时,要增加TCHAR.H头文件支持,使用
 _UNICODE 宏开关进行编译
  
CL window.c  /D_UNICODE
 
#define _UNICODE
#include "tchar.h"
 
定义方式:
  TCAHR * pszText = __T("ABCDEF"); 


代码使用:使用UNICODE宏开关,通知
  编译器选择编译的代码.

#ifndef _UNICODE
int nLen = strlen( pszText );
#else
int nLen = wcslen( pszText );
#endif




2.5 Unicode的控制台打印

			BOOL WriteConsole(
  			HANDLE hConsoleOutput, //控制台输出流的句柄 
  			CONST VOID *lpBuffer,//输出的字符串的指针
  		 DWORD nNumberOfCharsToWrite,//输出的字符串的长度
    LPDWORD lpNumberOfCharsWritten,
              // 返回已输出字符的数量
     LPVOID lpReserved ); // 保留值



代码实例:

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <tchar.h> //TCHAR


void ascii()
{
	for(int i=0;i<255;i++)
	{
		printf("%c ",i);
	}
	printf("\n");

	//因为现在是中文字符集 而中文是双字节的 所以 128以后的都变成问号了   
}

void codePage(int nCodePage)
{
	/*
	BOOL SetConsoleCP(
	UINT wCodePageID   // code page to set
	);

    437 美国  936 中国
	*/

	SetConsoleOutputCP(nCodePage);
	for(int i=0;i<255;i++)
	{
		printf("%c ",i);
	}
	printf("\n");

}


void c_char()
{
	char *pszText = "hello world";
	int nLen = strlen(pszText);
	printf("%d,%s\n",nLen,pszText);
}

void c_wchar()
{
	SetConsoleOutputCP(936); 
	wchar_t cText = 'A';  //char 可以指直接转换为wchar_t
	
	// wchar_t *pszText = "ABCD"; 错误 无法从const char[5] 转换成wchar_t *
	wchar_t *pszText = L"ABCD"; //L告诉编译器 字符串是双字节字符串
	int nLen = wcslen(pszText); // 这里是4 和以前一样 表示有4个双字节

	//printf("%s\n",pszText); //发现只打印了A 因为A的aci是41 变成双字节后 在小端模式内存中是 41 00  所以按单字节打印时只显示A了  查看内存方法 调试-窗口-内存
	wprintf(L"%d,%s\n",nLen,pszText);// 格式化输出之前要写个L
	
	//宽字节字符串
	wchar_t *pszChs = L"我是程序员";
	nLen = wcslen(pszChs);
	wprintf(L"%d,%s\n",nLen,pszChs); //5 ????  printf 对unicode的支持不高 所以汉字打印不出来

	//多字节字符串
	char * ptr = "我是程序员";
	nLen = strlen(ptr);
	printf("%d,%s\n",nLen,ptr); //10 我是程序员


}


void tchar()
{	
	TCHAR *pszText = __T("我是程序员"); // __T 根据是否是unicode在前面加L
#ifndef _UNICODE
	int len = strlen(pszText);
#else
	int len = wcslen(pszText);
#endif
	printf("%d\n",len);
}


void printUnicode(wchar_t *pszStr)
{
	//如何打印UNICODE WINDOWS API
	/*
	BOOL WriteConsole(
	HANDLE hConsoleOutput, // handle to a console screen buffer
	CONST VOID *lpBuffer,  // pointer to buffer to write from 
	DWORD nNumberOfCharsToWrite, // number of characters to write
	LPDWORD lpNumberOfCharsWritten, // pointer to number of characters written
	LPVOID lpReserved      // reserved
	);
	*/
	HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE); //得到console的句柄
	int nLen = wcslen(pszStr);
	WriteConsole(hout,pszStr,nLen,NULL,NULL);


	/*
	//将所有的unicode打印出来
	wchar_t szText[2] = {0};
	for(BYTE nHigh=0;nHigh<0xFF;nHigh++)
	{
		for(BYTE nLow=0;nLow<0xFF;nLow++)
		{
			szText[0] = MAKEWORD(nLow,nHigh); //宏 MAKEWORD 构成一个字
			WriteConsole(hout,szText,wcslen(szText),NULL,NULL);
		}
	}
	*/
}





int _tmain(int argc, _TCHAR* argv[])
{
	 
	printf("hello world\n");
	c_char();
	ascii();
	printf("----------------------\n");
	codePage(437);
	 c_wchar();
	 tchar();


	printUnicode(L"我是程序员\n");

	system("pause");
	return 0;
}









三  Win32程序与编码

1 Win32 API的定义

 每个API对多字节字符和UNICODE分别有
 不同的版本.
  MessageBox 
      MessageBoxA  多字节字符  
     MessageBoxW  UNICODE字符
 

2 字符的定义,使用TEXT, 由Winnt.h提供定义

#ifdef  UNICODE                     
#define __TEXT(quote) L##quote      
#else   /* UNICODE */               
#define __TEXT(quote) quote         
#endif /* UNICODE */  

TCHAR * pszText = TEXT( "ABCD" );              


3 字符转换

宽字节到多字节

      int WideCharToMultiByte(
 UINT CodePage, //代码页 CP_ACP ascii码
 DWORD dwFlags, //转换方式  0
 LPCWSTR lpWideCharStr, //需要被转换WCHAR地址
 int cchWideChar, //需要被转换WCHAR的长度  
 LPSTR lpMultiByteStr,//用于存放转换后的结果BUFF
 int cchMultiByte, //BUFF的长度 
 LPCSTR lpDefaultChar,//使用的缺省字符串的地址   NULL
 LPBOOL lpUsedDefaultChar //缺省字符串被使用的标识 0
);

多字节到宽字节

int MultiByteToWideChar(
 UINT CodePage,// 代码页
 DWORD dwFlags,// 转换方式
 LPCSTR lpMultiByteStr, // 需要被转换CHAR地址
 int cchMultiByte,//需要被转换CHAR的长度
 LPWSTR lpWideCharStr,//用于存放转换后的结果BUFF
 int cchWideChar );//BUFF的长度

使用方法:
  
1 将要转换的字符串,传递给函数(cchWideChar 或者 cchMultiByte = 0),从 返回值中获取转换后字符串的元素个数。
2 分配字符串空间
3 再次调用函数,并将分配的空间传递给函数,获取结果.

4 例子

void MyMessageBox()
{
	MessageBox(NULL,TEXT("helloWide"),TEXT("宽的"),MB_OK);
}

void Multi2Wide()
{
	CHAR * pszText = "MultiByte";
	//先测算一次长度
	int nLen = MultiByteToWideChar(CP_ACP,0,pszText,strlen(pszText),NULL,0);
	// 拿到长度后分配空间
	wchar_t *pwszText = (wchar_t *)malloc((nLen+1)*sizeof(wchar_t)); //多一个wchar空间来存放\0\0
	memset(pwszText,0,(nLen+1)*sizeof(wchar_t));
	//再进行转换
	MultiByteToWideChar(CP_ACP,0,pszText,strlen(pszText),pwszText,nLen);

	MessageBoxW(NULL,pwszText,TEXT("Multi2Wide"),MB_OK);

	free(pwszText);
};

void Wide2Multi()
{
	WCHAR *pwszText = TEXT("Widebyte");
	int nLen = WideCharToMultiByte(CP_ACP,0,pwszText,wcslen(pwszText),NULL,0,NULL,0);
	char *pszText = (char*)malloc((nLen+1)*sizeof(char));
	memset(pszText,0,(nLen+1)*sizeof(char));
	WideCharToMultiByte(CP_ACP,0,pwszText,wcslen(pwszText),pszText,nLen,NULL,0);
	MessageBoxA(NULL,pszText,"Wide2Multi",MB_OK);



};






你可能感兴趣的:(win32编程(二) UNICODE)