A Aldeia Numaboa ancestral ainda está disponível para visitação. É a versão mais antiga da Aldeia que eu não quis simplesmente descartar depois de mais de 10 milhões de pageviews. Como diz a Sirley, nossa cozinheira e filósofa de plantão: "Misericórdia, ai que dó!"

Se você tiver curiosidade, o endereço é numaboa.net.br.

Leia mais...

Informática Numaboa - Tutoriais e Programação

Usando recursos (masm)

Qua

14

Jan

2009


17:12

(2 votos, média 5.00 de 5) 


Nível Intermediário

Depois do tutorial Janelas somos felizes possuidores de uma classe que nos permite criar janelas com a nossa grife. A janela que produzimos no tutorial anterior estava peladinha da silva, onde muitos recursos que costumam acompanhar janelas estão faltando. Este tutorial tem justamente este propósito: discutir os RECURSOS. Como exemplo, vamos colocar um bitmap numa janela.

O que são recursos

Recursos são dados binários que um compilador de recursos ou o programador adicionam ao arquivo executável de um aplicativo. Recursos podem ser do tipo padrão ou do tipo definido. Os dados de um recurso padrão descrevem ícones, cursores, menus, caixas de diálogo, gráficos do tipo .bmp e .emf, fontes, tabelas de teclas de atalho, tabela de mensagens, tabela de strings ou versão. Um recurso definido pelo aplicativo, também chamado de recurso personalizado (custom resource), pode conter quaisquer dados requeridos por um aplicativo específico.

Os recursos são descritos em arquivos texto próprios, chamados arquivos de recurso, geralmente com a extensão .rc. Estes arquivos precisam ser compilados (no menu do MASM [Project / Compile Resource File]) e, depois de compilados, podem ser combinados com o arquivo de código fonte durante o estágio de link. O produto final é um arquivo executável que contém instruções e recursos.

Podemos usar qualquer editor de texto para escrever arquivos de recursos. O texto é composto por frases que descrevem a aparência e os atributos dos recursos desejados para um determinado programa. Os recursos possuem uma linguagem própria, a Resource Script Language. Conhecendo um mínimo desta linguagem é o suficiente para podermos trabalhar (o help do Resource Workshop da Borland é uma referência muito boa).

Existem editores de recursos que facilitam muito o trabalho por oferecerem uma plataforma de trabalho visual. Editores de recursos geralmente estão incluídos nos pacotes de compiladores como Visual C++, Borland C++, etc.

Você pode usar o excelente XN Resource Editor, o ResourceStudio da Symantec ou o Resource Compiler. Estes você encontra na seção de Downloads/Informática/Compiladores.

Criando um arquivo de recursos

Use o programa gráfico da sua preferência para criar um gráfico ou escolha um da sua preferência. Salve-o ou transfira-o para o diretório de trabalho deste tutorial. O arquivo de recursos deve ficar no mesmo diretório do arquivo com o código fonte. O gráfico que preparei para este tutorial recebeu o nome de "bits.bmp" e é o que se vê abaixo:

Bits

A diretiva para indicar um recurso bitmap é a seguinte:

IDentificador BITMAP [tipo de carregamento] [opção de memória] NomeDoArquivo
  • Identificador é o ID do recurso, que é um número. O ID será usado quando quisermos usar este recurso no programa (Obrigatório).
  • BITMAP é uma palavra chave para indicar o tipo de recurso (Obrigatório).
  • Tipo de carregamento é opcional. Indica se queremos que o bitmap seja previamente carregado (PRELOAD) ou apenas seja carregado quando solicitado (LOADONCALL). O default é LOADONCALL.
  • Opção de memória indica como o recurso deve ser carregado na memória. Pode ser descartável para livrar espaço de memória (DISCARDABLE), ficar fixo num endereço de memória (FIXED), ser modificado após o carregamento (IMPURE), pode ser deslocado na memória (MOVEABLE), precisa permanecer na memória (NONDISCARDABLE), não é modificado após o carregamento (PURE). O default é MOVEABLE e DISCARDABLE.
  • NomeDoArquivo é o nome do bitmap.

Podemos resumir nosso arquivo RSRC.RC numa linha que contenha apenas o ID, a palavra chave BITMAP e o nome do arquivo. O restante deixamos como default. Abra um editor de texto (pode ser o GUN do MASM que você encontra em [Tools / TheGUN Text Editor]) e digite a linha abaixo:

   760 BITMAP "bits.bmp"

Você pode usar qualquer número para o ID, contanto que não seja o mesmo usado por outro recurso. Salve o arquivo com o nome de "RSRC.RC" no mesmo diretório onde estará o código fonte do nosso programa teste. Por enquanto é só.


O programa teste

Vamos criar uma janela que conterá o bitmap do recurso, portanto podemos partir do modelo "Janelas" que criamos no tutorial anterior.

.386 .MODEL FLAT,STDCALL option casemap:none include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\user32.inc includelib \masm32\lib\kernel32.lib includelib \masm32\lib\user32.lib gerenteJanela proto :DWORD, :DWORD, :DWORD, :DWORD .DATA? mInstancia DWORD ? linhaComando DWORD ? .DATA NomeClasse db "JanelaNua",0 TituloJanela db "Janelinha NumaBoa",0 .CODE inicio: invoke GetModuleHandle, NULL mov mInstancia, eax invoke GetCommandLine mov linhaComando, eax invoke gerenteJanela, mInstancia, NULL, linhaComando, SW_SHOWDEFAULT invoke ExitProcess,0 gerenteJanela proc mInst:DWORD, mInstAnt:DWORD, linhaCmd:DWORD, Mostra:DWORD LOCAL ej:WNDCLASSEX LOCAL mJanela:HWND LOCAL malote:MSG mov ej.cbSize, SIZEOF WNDCLASSEX mov ej.style, CS_HREDRAW or CS_VREDRAW mov ej.lpfnWndProc, OFFSET gerenteMensagem mov ej.cbClsExtra, NULL mov ej.cbWndExtra, NULL push mInst pop ej.hInstance invoke LoadIcon, NULL, IDI_WINLOGO mov ej.hIcon, eax mov ej.hIconSm, eax invoke LoadCursor, NULL, IDC_ARROW mov ej.hCursor, eax mov ej.hbrBackground, COLOR_WINDOW+1 mov ej.lpszMenuName, NULL mov ej.lpszClassName, OFFSET NomeClasse invoke RegisterClassEx, ADDR ej invoke CreateWindowEx, NULL, ADDR NomeClasse, ADDR TituloJanela, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, mInst, NULL mov mJanela,eax invoke ShowWindow, mJanela, SW_SHOWNORMAL invoke UpdateWindow, mJanela .WHILE TRUE invoke GetMessage, ADDR malote, NULL, 0, 0 .BREAK .IF (eax < 1) invoke TranslateMessage, ADDR malote invoke DispatchMessage, ADDR malote .ENDW mov eax, malote.wParam ret gerenteJanela endp gerenteMensagem proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM .IF uMsg == WM_CREATE .ELSEIF uMsg == WM_SIZE .ELSEIF uMsg == WM_PAINT .ELSEIF uMsg == WM_COMMAND .ELSEIF uMsg == WM_CLOSE .ELSEIF uMsg==WM_DESTROY invoke PostQuitMessage, NULL xor eax,eax ret .ENDIF invoke DefWindowProc, hWnd, uMsg, wParam, lParam ret gerenteMensagem endp end inicio

Vamos mudar o título da janela para "NumaBoa com Recursos" só para identificá-la melhor:

.DATA NomeClasse db "JanelaNua",0 TituloJanela db "NumaBoa com Recursos",0

Como queremos que o gráfico seja mostrado assim que a janela aparecer na tela, precisamos gerenciar a mensagem WM_CREATE que é enviada ao gerenteMensagem assim que a janela é criada. Primeiramente vamos criar uma área dentro da janela principal onde o bitmap deve ser mostrado. Essa área especial nada mais é que um controle, ou seja, uma janela especial. Já sabemos que, para criar uma janela/controle, precisamos de uma classe registrada que servirá como modelo. No Windows existem classes predefinidas para controles: BUTTON, COMBOBOX, EDIT, LISTBOX, SCROLLBAR e STATIC. Usaremos a STATIC, por que não esperamos adicionar nenhuma funcionalidade ao nosso bitmap. A primeira provicência, então, é inicializar uma variável com o nome da classe na seção .DATA:

.DATA NomeClasse db "JanelaNua",0 TituloJanela db "Janelinha NumaBoa",0 ClasseAreaBMP db "STATIC",0

Criando a janela

Como vamos precisar da função CreateWindowEx, não custa dar uma recapitulada:

HWND CreateWindowEx(
    DWORD dwExStyle, // estilo especial de janela
    LPCTSTR lpClassName, // ponteiro para a classe registrada
    LPCTSTR lpWindowName, // pointeiro para o nome da janela: NULL
    DWORD dwStyle, // estilo da janela
    int x, // posição horizontal da janela
    int y, // posição vertical da janela
    int nWidth, // largura da janela
    int nHeight, // altura da janela
    HWND hWndParent, // manipulador da janela-mãe ou proprietário da janela
    HMENU hMenu, // manipulador do menu ou identificador da janela-filha
    HINSTANCE hInstance, // manipulador da instância do aplicativo
    LPVOID lpParam // ponteiro para dados de criação da janela
);
  • dwExStyle: não usaremos um estilo especial - NULL.
  • lpClassName: o nome da classe está na variável ClasseAreaBMP - seu endereço será ADDR ClasseAreaBMP.
  • lpWindowName: a janela não precisa de título - usaremos NULL.
  • dwStyle: a composição do estilo será "Estilo Janela (WS) Filha" + "Estilo Janela (WS) Visível" + "Controle Estático (SS) com Bitmap" que é indicado com WS_CHILD or WS_VISIBLE or SS_BITMAP.
  • x e y: a posição horizontal e vertical do canto superior esquerdo da janela do controle dentro da janela-mãe - indicamos ambos como 20 pixels.
  • nWidth e nHeight: a largura e a altura da janela em pixels - indicamos temporariamente como 10. O porque do temporário será explicado logo adiante (4.4. Preparando a pintura).
  • hWndParent: o manipulador da janela-mãe - no nosso exemplo é o parâmetro hWnd do procedimento gerenteMensagem.
  • hMenu: não existe menu no controle, portanto NULL.
  • hInstance: o manipulador do módulo, mInstancia.
  • lpParam: não há dados na criação da janela - NULL.

Tudo em riba para podermos incluir a chamada à função que criará o controle com a área que deve conter o bitmap:

gerenteMensagem proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM .IF uMsg == WM_CREATE invoke CreateWindowEx, NULL, ADDR ClasseAreaBMP, NULL, WS_CHILD or WS_VISIBLE or SS_BITMAP, 20, 20, 10, 10, hWnd, NULL, mInstancia, NULL ... .ELSEIF ...

A função CreateWindowEx retorna o valor do manipulador da janela em EAX. Precisaremos deste valor logo adiante, portanto, criaremos uma variável local e a inicializamos com o valor de retorno:

gerenteMensagem proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM LOCAL mAreaBMP: DWORD .IF uMsg == WM_CREATE invoke CreateWindowEx, NULL, ADDR AreaBitmap, NULL, WS_CHILD or WS_VISIBLE or SS_BITMAP, 20, 20, 10, 10, hWnd, NULL, mInstancia, NULL mov mAreaBMP, eax ... .ELSEIF ...

Nosso bitmap está nos recursos e tem o identificador 760. Agora precisamos obter um manipulador para o bitmap para que possamos acessá-lo. Usamos a função LoadBitmap:

HBITMAP LoadBitmap(
    HINSTANCE hInstance, // manipulador da instância do aplicativo
    LPCTSTR lpBitmapName // endereço do nome do recurso bitmap
);

Da mesma forma que acima, precisamos de uma variável local que receba o manipulador:

gerenteMensagem proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM LOCAL mAreaBMP: DWORD LOCAL mBMP: DWORD .IF uMsg == WM_CREATE invoke CreateWindowEx, NULL, ADDR AreaBitmap, NULL, WS_CHILD or WS_VISIBLE or SS_BITMAP, 20, 20, 10, 10, hWnd, NULL, mInstancia, NULL mov mAreaBMP, eax invoke LoadBitmap, mInstancia, 760 mov mBMP, eax ... .ELSEIF ...

O sistema possui um "pintor" de plantão que pode ser acionado sempre que necessário. Basta enviar uma mensagem com os dados necessários para que ele possa trabalhar. A função SendMessage envia a mensagem especificada para uma ou mais janelas. Esta função chama o gerente de mensagens do(s) destinatário(s) e não retorna enquanto o pedido não for integralmente realizado.

LRESULT SendMessage(
    HWND hWnd, // manipulador da janela destino
    UINT Msg, // mensagem a ser enviada
    WPARAM wParam, // primeiro parâmetro da mensagem
    LPARAM lParam // segundo parâmetro da mensagem
);
  • hWnd: nossa janela destino é a janela do controle com a área que foi preparada para receber o bitmap - mAreaBMP.
  • Msg: a mensagem é dirigida a um controle estático (STatic control Message), ou seja, do tipo STM_ alguma coisa. As mensagens que existem são STM_GETICON, STM_SETICON, STM_GETIMAGE e STM_SETIMAGE. Obviamente é da STM_SETIMAGE que estamos precisando.
  • wParam: o primeiro parâmetro de uma mensagem do tipo STM_SETIMAGE refere-se ao tipo de imagem e pode ser IMAGE_BITMAP, IMAGE_CURSOR, IMAGE_ENHMETAFILE e IMAGE_ICON. O tipo da nossa imagem é IMAGE_BITMAP.
  • lParam: o segundo parâmetro da mensagem STM_SETIMAGE refere-se ao manipulador da imagem. No nosso caso, mBMP.

Vamos enviar nossa mensagem com:

gerenteMensagem proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM LOCAL mAreaBMP: DWORD LOCAL mBMP: DWORD .IF uMsg == WM_CREATE invoke CreateWindowEx, NULL, ADDR AreaBitmap, NULL, WS_CHILD or WS_VISIBLE or SS_BITMAP, 20, 20, 10, 10, hWnd, NULL, mInstancia, NULL mov mAreaBMP, eax invoke LoadBitmap, mInstancia, 760 mov mBMP, eax invoke SendMessage, mAreaBMP, STM_SETIMAGE, IMAGE_BITMAP, mBMP .ELSEIF ...

Você ainda se lembra de que dimensionamos nosso controle para ter 10 x 10 pixels? Nosso gráfico tem 255 x 185 pixels. Vai faltar pixel para abrigar o gráfico inteiro - problema do "pintor" de plantão. Como enviamos as coordenadas da posição do controle estático, o "pintor" vai transferindo a sequência de pixels que ele encontrar nos recursos e "estica" o controle para fazer espaço para o gráfico. Tão simples assim... mas precisamos saber disso para que o gráfico não avance sobre outros controles desformatando nosso layout.


Finalmentes

Neste exemplo, o resultado final será este:

Resultado

Se você quiser fazer o download do texto, do código fonte e do executável deste tutorial, procure em Downloads / Tutoriais / Assembly Numaboa clicando no menu à direita.

Espero que tenham gostado e, como sempre

Grande abraço da vó Vicki vovo

mfx brokerинтернет магазин кухоньтоподин отзывотзывов сайтыmfx broker инвестицииmfx brokerполигон ооо

Informações adicionais