logo
Contato | Sobre...        
rebarba rebarba

Rodrigo Strauss :: Blog


Win32: Unicode e Ansi

Procurando a declaração da função MessageBox (um F12 sobre o nome da função resolve isso no Visual Studio), encontramos isso:


WINUSERAPI
int
WINAPI
MessageBoxA(
    __in_opt HWND hWnd,
    __in_opt LPCSTR lpText,
    __in_opt LPCSTR lpCaption,
    __in UINT uType);
WINUSERAPI
int
WINAPI
MessageBoxW(
    __in_opt HWND hWnd,
    __in_opt LPCWSTR lpText,
    __in_opt LPCWSTR lpCaption,
    __in UINT uType);
#ifdef UNICODE
#define MessageBox  MessageBoxW

#else
#define MessageBox  MessageBoxA
#endif // !UNICODE

Podemos notar que não existe função MessageBox, e sim um #define MessageBox, que aponta para a função com o sufixo A ou W. A letra A é adicionada no nome das funções que suportam caracteres ANSI, e a letra W nas funções que aceitam caracteres UNICODE (o W vem de “wide char”). Como estamos usando Windows NT, a função correta é a que tem W no final.

Os caracteres UNICODE ocupam 2 bytes, o que permite que um caractere UNICODE possa representar até 65536 letras ou símbolos diferentes (em oposição ao ANSI/ASCII, que suporta somente 255), o que permite conter confortavelmente todos os caracteres e símbolos de todas as línguas e dialetos existentes no nosso planeta. Isso acaba com aquela história de MODE CON CODEPAGE PREPARE (lembra?) para ficarmos mudando a página de caracteres dependendo do idioma escolhido. Para declarar strings UNICODE em C++ precisamos prefixá-la com um L (L"dessa forma";). Quando o Windows NT foi projetado (nos ido de 1989), foi feita a decisão pelo UNICODE, para facilitar a internacionalização do Windows e dos softwares que nele rodam. O mesmo não aconteceu com o Windows 95/98/Me, que herda muita coisa do Windows 3.1, baseado em ANSI.

Na hora de programar em Win32, o #define UNICODE é o que vai definir ser vamos usar ANSI ou Unicode. As duas versões funcionam no Windows NT, sendo que o MessageBoxA (assim como todas as APIs ANSI) converte as strings de entrada para UNICODE, chama a função MessageBoxW, e converte as strings de saída de UNICODE para ANSI. Você pode inclusive chamar diretamente uma ou outra versão, como no exemplo abaixo:


#include "stdafx.h"
 
int main()
{
	//
	// ANSI
	//
	MessageBoxA(NULL, "mensagem ANSI", "www.1bit.com.br", MB_OK | MB_ICONEXCLAMATION);

 
	//
	// UNICODE
	//
	MessageBoxW(NULL, L"mensagem UNICODE", L"www.1bit.com.br", MB_OK | MB_ICONQUESTION);
 
 
	//
	// TCHAR: a macro _T() automaticamente coloca o prefixo L caso
	// estejamos compilando com UNICODE. Dessa forma é possível compilar
	// o mesmo código para UNICODE ou ANSI. Apesar de estar entrando em
	// desuso hoje em dia, isso era importante na era dos Windows 9x.
	//
	MessageBox(NULL, _T("mensagem em TCHAR"), _T("www.1bit.com.br"), MB_OK | MB_ICONERROR);
}
   

Em 04/03/2008 22:22, por Rodrigo Strauss


  
 
 
Comentários
Moisés Simões | website | em 05/03/2008 | #
Excelente artigo ...

São conceitos simples que muitas vezes abstraímos ou sequer temos noção da existencia deles.

abs,
Thiago Falcão | website | em 06/03/2008 | #
Grande artigo, mostra com clareza (código da WIN API) a importância do UNICODE. Essencial para quem quer desenvolver software para vários idiomas.
Giuliano | website | em 05/05/2010 | #
Esse artigo me esclareceu uma dúvida que não conseguia resolver, o porque de usar o unicode em vez do ansi no prototype do método.
Muito bom
Andrew | em 14/03/2011 | #
Boa tarde.

Parabéns pelo seu blog, só uma pequena correção em seu texto:

"em oposição ao ANSI/ASCII, que suporta somente 255"

Na verdade, não são 255 e sim 256 (pois varia de 0 a 255).

Abraços
Rodrigo Strauss | website | em 14/03/2011 | #
Putz, não sei não. O ASCII zero conta como um caractere?
Andrew | website | em 04/04/2011 | #
Sim, conta sim.
rebarba rebarba
  ::::