Arquivo da categoria ‘Coding’

Windows Unicode Strings

Publicado: 28/10/2009 em Coding

Uma das variáveis mais complicadas do desenvolvimento de aplicações em código nativo C/C++ é a quantidade de tipos diferentes para representar Strings.
Basicamente, uma string é uma cadeia de caracteres que pode inicialmente ser representada como

char myString[100] = “Minha string”;

Uma cadeia de “char”, caracteres de 8-bit ANSI

Para o alfabeto americano, 8-bit é suficiente para representar cada caracter, porém outros alfabetos como o Kanji precisam de mais informação para representar alguns caracteres e é aí que nasce o Unicode e os diversos UTFs.

Eis que temos então os caracteres ANSI representados por 1 byte e os conhecidos UTF-8, UTF-16 e UTF-32.

O UTF-8 codifica alguns caracteres utilizando 1 byte, alguns caracteres usando 2, 3 ou 4 bytes. (Loucura não?)
O UTF-16 codifica todos os caracteres utilizando 2 bytes.
O UTF-32 codifica os caracteres utilizando 4 bytes.

O UTF-8 é bastante interessante, porém ele é menos eficiente que o UTF-16 caso existam muitos caracteres que necessitam de 2 bytes ou mais.

As linguagens C/C++ suportam caracteres Unicode e as APIs do Windows também suportam. Existe o tipo wchar_t que é utilizando em C++ para representar caracteres Unicode e é aí que começa a bagunça.

Diversas aplicações mesclam funcões que manipulam caracteres ANSI e UNICODE, o que causa além de um trabalho maior para o desenvolvedor ficar convertendo entre diversos tipos, uma perda de performance e aumento no consumo de memória.

A partir do Windows Vista, a API do Windows utiliza Unicode para tudo, porém as funções da API sempre possuem duas versões, uma versão que ANSI e uma Unicode e dependendo da definição da macro UNICODE, que é definida automaticamente pelo Visual C++.

O tipo TCHAR é um bom exemplo, vejam a declaração simplificada

#ifdef UNICODE
typedef WCHAR TCHAR, *PTCHAR, PTSTR;
#else
typedef CHAR TCHAR, *PTCHAR, PTSTR;
#endif

Se no momento da compilação a macro UNICODE estiver definida o tipo TCHAR representará o WCHAR senão representará o tipo CHAR.
E isto serve para o consumo das funções do Windows que possuem duas versões, por exemplo a função CreateWindowEx:

Versão Unicode (WIDE)
HWND WINAPI CreateWindowExW(…)

Versão ANSI
HWND WINAPI CreateWindowExA(…)

O consumo de versão da função CreateWindowEx é resolvido no momento da compilação devido à esta declaração:

#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#else
#define CreateWindowEx CreateWindowExA
#endif

Use somente strings UNICODE!

É importante ter consciência de todos estes detalhes para que ao construir uma aplicação minimize a utilização de caracteres não Unicode.
No Windows, as funções com o sufixo “A” que é a versão Ansi, simplesmente convertem a string passada para a função para uma string Unicode e executam a versão Unicode da função.
Ao término da execução da função Unicode, a função Ansi que a invocou, converte o resultado para uma string Ansi e retorna para a aplicação. Ou seja, ocorre uma sobrecarga de processamento apenas pelas conversões entre tipos.
Strings Ansi proporcionam uma falsa economia de memória, que se perde e pode ter efeito contrário ao passar pela camada de “tradução” da API do Windows.

Outro ponto importante que deve ser levado em consideração para migrar totalmente para strings Unicode é interoperabilidade com aplicações COM e .Net, que também são baseados em Unicode.

Não se preocupe .Net é Unicode!

O .Net framework que possui a classe System.String que simplifica muito a manipulação deste tipo de dado e é Unicode por padrão.
Para o programador .Net (C#/VB/F#/etc) a questão das string é transparente, pois não é necessário manipular ou se preocupar com isto.
Porém toda esta facilidade tem um pequeno porém, toda string no .Net é imutável, ou seja, as manipulações de string com o tipo string padrão do .Net sempre cria cópias das strings e elas são destruídas pelo Gargage Collector. Por isto é preciso ter cuidado e não exagerar nas strings para não desperdiçar a vantagem de trabalhar com o Unicode por padrão.

Para mais informações acesse:

The Unicode Consortium
www.unicode.org

Unicode and Character Sets
http://msdn.microsoft.com/en-us/library/dd374083(VS.85).aspx

Unicode in Visual C++ 2
http://msdn.microsoft.com/en-us/library/cc194799.aspx

How to: Convert between varios string types
http://msdn.microsoft.com/en-us/library/ms235631(VS.80).aspx

Divirtam-se!

[]’s

beginner_developer_center
A “Start Page” do Visual Studio 2010 exibe um item muito interessante, o “Create your first program”. Este item aponta para o portal para programadores iniciantes dentro do MSDN.
A versão mais atual do portal está em Inglês, mas existe a versão em Português também.

O conteúdo é bem dividido e linear, vale a pena começar a estudar programação por esta caminho. Um ponto muito importante é que o conteúdo é baseado em vídeos, o que torna o aprendizado muito mais dinâmico.

Recomendo a visita ao “Windows Track”, que ensina desde o início como é o Windows como plataforma e os recursos que podem ser incorporados às suas aplicações passando pela plataforma .Net etc.

E para quem quer se aventurar nas versões Express do Visual Studio, também existem vídeos sobre cada uma das versões, com um grande diferencial: Quem narra os vídeos é UMA program manager, o que deixa o vídeo extremamente agradável.

image

Fácil aprender a utilizar o Visual C++ agora não? Não é apenas C++, tem vídeos para todas as versões das ferramentas express.

beginner_cpp_beginners_guide

E falando em C++, também está disponível no Developer Center um livro de C++ para iniciantes que ensina os conceitos básicos da linguagem, muito bom.
São 12 capítulos descrevendo desde os fundamentos da linguagem, tipos de dados até templates e tratamento de exceções.
http://msdn.microsoft.com/en-us/beginner/cc305129.aspx 

Para quem está começando ou quem quer dar uma polida nos conhecimentos sobre os fundamentos de desenvolvimento vale a pena uma visita ao portal e encaminhar para os amigos que estão começando.

Beginner Developer Learning Center
http://msdn.microsoft.com/en-us/beginner/default.aspx

Divirtam-se!!

[]’s

Skills de um programador

Publicado: 21/01/2009 em Coding

Olá pessoal como vão? Faz tempo que não consigo parar para escrever um post no blog, muito código para fazer aqui na empresa 😀
Em meio à tanto código tenho notado o quanto a atividade de programador de computadores é constituída por uma série de conceitos que absorvemos com o tempo e nos torna cada vez mais um bom programador.
Pensando nisso, resolvi fazer uma lista de conceitos que um bom programador deve conhecer para que ele consiga resolver os mais diversos problemas de maneira eficiente. Esta lista não está completa, aguardo sugestões para aumentá-la, eu mesmo vou adicionar assim que indentificar/lembrar de novos pontos importantes. Vou enumerar, mas neste caso a ordem dos fatores não altera o produto.

gates-centerfold

1 – Documentação
Conhecer a documentação da plataforma que utiliza é essencial para que o programador consiga resolver os problemas.
Se a plataforma fornece uma boa documentação e você sabe como utilizá-la adequadamente, provavelmente você não precisará de tantos livros para aprofundar seu conhecimento nas bibliotecas e recursos que você não domina.
Entender o modelo e sugerir melhorias na documentção pode ajudar em momentos cruciais onde o projeto está no limite do prazo e você tem problemas “desconhecidos” para resolver.

2 – Padrões de projeto/arquitetura/etc
Conhecer padrões de codificação e distribuição de componentes desenvolvidos por outras pessoas/empresas ajuda  a tomar decisões mais eficientes de como resolver os problemas. Como economizar determinado recurso, como resolver problemas críticos como sincronização etc, manter um equilíbrio entre flexibilidade, portabilidade e especificidade de um código.
Estas decisões influenciam diretamente no resultado final, e é bom ver como as pessoas resolvem as coisas por aí, pois muitas vezes alguém já se deparou com um problema semelhante e pode-se aprender com as decisões anteriormente tomadas.

3 – Regular Expressions
Validações de dados, busca e manipulação de texto sempre são muito úteis. Regular Expressions são uma forma muito interessante de resolver estes problemas. É um padrão e pode ser utilizado em qualquer plataforma. O que não vale é fazer algoritmos de validação de dados gigantes e utilizar como desculpa que não conhece Regular Expressions e vai demorar para aprender, é só se esforçar um pouco, você só tem a ganhar, pois elas trabalham MUITO por você.

4- Arquivos
Em algum momento você precisa manipular um arquivo. Seja gravar um arquivo de texto no disco, carregar uma figura em memória, ler um arquivo XML ou criar seu próprio formato de arquivo binário. Fazemos isto à todo momento e é um recurso que pode ser muito útil, mais do que pensamos.
vale a pena entender como sua plataforma trabalha com arquivos de texto e binários e extrair o potencial da persistência de dados.

5 – Banco de Dados/SQL
Se as Regular Expressions trabalham muito por você, os bancos de dados praticamente são seus pais. Podemos reclamar, muitos não gostar, mas todos usamos bancos de dados em algum momento. É importante conhecer o modelo de dados que eles utilizam para otimizar o acesso aos dados de maneira a não afetar o resltado final do programa, pois como os bancos podem ajudar, eles também podem ser grandes inimigos da performance quando não são bem utilizados.

6 – Rede
Diferentemente de alguns anos atrás hoje o mundo, inclusive o Brasil está amplamente conectado. O trabalho caminha junto com a conectividade e informações que chegam pela rede, porém fazer bom uso deste recurso fabuloso é trabalhoso. O programador deve ter em mente como a rede funciona e como ela pode ajudar a resolver os seus problemas. O conceito de cloud computing que está na moda é uma grande utilização da rede para resolver problemas. Como usar? O que da pra fazer? Pode afetar a resposta do meu software? (sim) Como otimizar para não interferir na experiência do usuário? Enviar e receber bytes? hmmm bastante coisa e é muito interessante!

7 – Processamento paralelo/threads
Cada vez mais temos hardware com suporte à processamento paralelo, mas fazmos uso dele? Até hoje, muito pouco. Como fazer um processamento paralelo? Como resolver as tarefas de maneira mais eficiente utilizando este recurso? Como funcionam as threads? Essencial ter um bom conhecimento sobre estes assuntos, tendo em vista que é tendência e que os softwares estão cada vez mais sofsticados, precisando efetuar mais tarefas e responder mais rápido ao usuário, que cada vez está mais exigente.

8 – Orientação à Objetos
A OO ajuda a organizar o sistema de uma maneira muito interessante além de uma série de recursos que proporcionam o reaproveitamento de código e uma elegância ao software. Hoje é essencial, tendo em vista que temos as linguagens mais populares tirando proveito total dos recursos de OO, e para tirar proveito das linguagens baseadas em OO é necessário um bom entendimento de como funciona e como pode ajudar ao desenvolver.

A lista já está grande, continuamos outro dia 😉
Gostaria da contribuição de vocês com outros ítens top of mind para um programador.

Divirtam-se!

[]’s

Olá pessoal!!!

Ultimamente ando vendo muitas soluções de problemas baseadas em utilização do FileSystem, principalmente utilizando-se arquivos de texto para comunica aplicações que não tem infraestrutura necessária para uma comunicação elegante entre seus componentes.

Uma coisa que eu vejo é também o desconhecimento de alguns recursos que podem tornar esta tarefa( que já não é a mais elegante possível para trocar informação entre aplicações) mais elegante eheheh

Um bom exemplo disto é verificar quando arquivos são criados em um determinado diretório e assim importar suas informações e utilizá-las no sistema.

Uma prática comum é utilizar um Timer e de tempos em tempos varrer o diretório procurando por novos arquivos…

Minha sugestão para melhorar este trabalho é monitorar o sistema de arquivos utilizando as APIs disponibilizadas pelo sistema operacional, no nosso caso o Windows com sua API Win32 ou o .Net Framework.

.Net Way

No .Net temos a classe FileSystemWatcher que fornece um mecanismo muito elegante baseado em eventos para que saibamos quando alterações acontecem tanto em arquivos quanto em diretórios.

Vejam abaixo o exemplo citado na documentação, ele apresenta um objeto que monitora uma pasta e dispara eventos para alterações nos arquivos .txt. Notem que os eventos podem ser filtrados pelos atributos conhecidos de arquivos e pastas no windows com os NotifyFilters

public class Watcher
{

    public static void Main()
    {
    Run();

    }

    [PermissionSet(SecurityAction.Demand, Name="FullTrust")]
    public static void Run()
    {
        string[] args = System.Environment.GetCommandLineArgs();

        // If a directory is not specified, exit program.
        if(args.Length != 2)
        {
            // Display the proper way to call the program.
            Console.WriteLine("Usage: Watcher.exe (directory)");
            return;
        }

        // Create a new FileSystemWatcher and set its properties.
        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Path = args[1];
        /* Watch for changes in LastAccess and LastWrite times, and
           the renaming of files or directories. */
        watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
           | NotifyFilters.FileName | NotifyFilters.DirectoryName;
        // Only watch text files.
        watcher.Filter = "*.txt";

        // Add event handlers.
        watcher.Changed += new FileSystemEventHandler(OnChanged);
        watcher.Created += new FileSystemEventHandler(OnChanged);
        watcher.Deleted += new FileSystemEventHandler(OnChanged);
        watcher.Renamed += new RenamedEventHandler(OnRenamed);

        // Begin watching.
        watcher.EnableRaisingEvents = true;

        // Wait for the user to quit the program.
        Console.WriteLine("Press ‘q’ to quit the sample.");
        while(Console.Read()!=’q’);
    }

    // Define the event handlers.
    private static void OnChanged(object source, FileSystemEventArgs e)
    {
        // Specify what is done when a file is changed, created, or deleted.
       Console.WriteLine("File: " +  e.FullPath + " " + e.ChangeType);
    }

    private static void OnRenamed(object source, RenamedEventArgs e)
    {
        // Specify what is done when a file is renamed.
        Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
    }
}

O trabalho fica muito bom não?

 

C++ Win32 Way

Se precisarmos utilizar código nativo podemos utilizar a função ReadDirectoryChangesW, que permite que obtenhamos informações sobre alterações no diretório em questão. Esta função é utilizada pelo FileSystemWatcher.
Vejam um exemplo de projeto no CodeProject http://www.codeproject.com/KB/files/directorychangewatcher.aspx

Também existe a função FindFirstNotification que permite que monitoremos os arquivos de maneira elegante utilizando a API Win32.

Abaixo um exemplo retirado do msdn http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspx

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>

void RefreshDirectory(LPTSTR);
void RefreshTree(LPTSTR);
void WatchDirectory(LPTSTR);

void _tmain(int argc, TCHAR *argv[])
{
    if(argc != 2)
    {
        _tprintf(TEXT("Usage: %s <dir>n"), argv[0]);
        return;
    }

    WatchDirectory(argv[1]);
}

void WatchDirectory(LPTSTR lpDir)
{
   DWORD dwWaitStatus;
   HANDLE dwChangeHandles[2];
   TCHAR lpDrive[4];
   TCHAR lpFile[_MAX_FNAME];
   TCHAR lpExt[_MAX_EXT];

   _tsplitpath_s(lpDir, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);

   lpDrive[2] = (TCHAR)’\’;
   lpDrive[3] = (TCHAR)”;
// Watch the directory for file creation and deletion. 
   dwChangeHandles[0] = FindFirstChangeNotification(
      lpDir,                          // directory to watch
      FALSE,                          // do not watch subtree
      FILE_NOTIFY_CHANGE_FILE_NAME);  // watch file name changes
   if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
   {
     printf("n ERROR: FindFirstChangeNotification function failed.n");
     ExitProcess(GetLastError());
   }
// Watch the subtree for directory creation and deletion. 
   dwChangeHandles[1] = FindFirstChangeNotification(
      lpDrive,                       // directory to watch
      TRUE,                          // watch the subtree
      FILE_NOTIFY_CHANGE_DIR_NAME);  // watch dir name changes
   if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
   {
     printf("n ERROR: FindFirstChangeNotification function failed.n");
     ExitProcess(GetLastError());
   }

// Make a final validation check on our handles.
   if ((dwChangeHandles[0] == NULL) || (dwChangeHandles[1] == NULL))
   {
     printf("n ERROR: Unexpected NULL from FindFirstChangeNotification.n");
     ExitProcess(GetLastError());
   }

// Change notification is set. Now wait on both notification
// handles and refresh accordingly. 
   while (TRUE)
   {
   // Wait for notification.
      printf("nWaiting for notification…n");

      dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,
         FALSE, INFINITE);
      switch (dwWaitStatus)
      {
         case WAIT_OBJECT_0:
         // A file was created, renamed, or deleted in the directory.
         // Refresh this directory and restart the notification.
             RefreshDirectory(lpDir);
             if ( FindNextChangeNotification(dwChangeHandles[0]) == FALSE )
             {
               printf("n ERROR: FindNextChangeNotification function failed.n");
               ExitProcess(GetLastError());
             }
             break;
         case WAIT_OBJECT_0 + 1:
         // A directory was created, renamed, or deleted.
         // Refresh the tree and restart the notification.
             RefreshTree(lpDrive);
             if (FindNextChangeNotification(dwChangeHandles[1]) == FALSE )
             {
               printf("n ERROR: FindNextChangeNotification function failed.n");
               ExitProcess(GetLastError());
             }
             break;
         case WAIT_TIMEOUT:

         // A time-out occurred. This would happen if some value other
         // than INFINITE is used in the Wait call and no changes occur.
         // In a single-threaded environment, you might not want an
         // INFINITE wait.
            printf("nNo changes in the time-out period.n");
            break;

         default:
            printf("n ERROR: Unhandled dwWaitStatus.n");
            ExitProcess(GetLastError());
            break;
      }
   }
}

void RefreshDirectory(LPTSTR lpDir)
{
   // This is where you might place code to refresh your
   // directory listing, but not the subtree because it
   // would not be necessary.

   _tprintf(TEXT("Directory (%s) changed.n"), lpDir);
}

void RefreshTree(LPTSTR lpDrive)
{
   // This is where you might place code to refresh your
   // directory listing, including the subtree.

   _tprintf(TEXT("Directory tree (%s) changed.n"), lpDrive);
}

Percebem como podemos realmente monitorar um sistema de arquivos de maneira elegante?

Espero que ajude no trabalho, principalmente em situações onde te obrigarem a fazer a comunicação entre sistemas através de arquivos de texto, o que não é muito legal 😀 eheheh

Divirtam-se