Arquivo da categoria ‘C#’

Mais uma palestra realizada - SENAC Itu/SP

Carlos Mattos - Palestra Visual Studio 2008 - SENAC Itu-SPPalestra Visual Studio 2008 - SENAC Itu/SPPalestra Visual Studio 2008 - SENAC Itu/SPPalestra Visual Studio 2008 - SENAC Itu/SP
Na última quarta-feira, realizei mais uma palestra no SENAC. Desta vez, na unidade de Itu-SP. O tema apresentado foi Produtividade com Visual Studio 2008. Conversamos sobre os novos recursos do VS2008 que aumentam a produtivade do desenvolvedor, facilitam a comunicação da equipe, e permitem o gerenciamento eficiente do Ciclo de Vida da Aplicação (ALM). Apesar do pequeno número de pessoas presentes, todos estavam bastante interessados e o feedback foi muito positivo. Para aqueles que solicitaram, aqui está o arquivo da apresentação.

Listando Tabelas e Colunas utilizando LINQ-to-SQL

Recuperar nomes de tabelas e colunas a partir da estrutura do banco de dados é sempre útil no processo de desenvolvimento. Existem diversas técnicas utilizando diferentes tecnologias para isto. Este post mostra como obter uma lista com os nomes das tabelas e seus respectivos campos utilizando o LINQ-to-SQL. O exemplo foi implementado com 1 formulário contendo 1 botão e 1 controle ListBox. Essa construção é possível porque o LINQ-to-SQL mantém o mapeamento da estrutura do banco de dados armazenado no objeto DataContext. Veja abaixo a interface em tempo de execução mostrando a lista das tabelas e colunas:


 

ListandoTabelasColunasLINQ

Agora veja o código necessário para construir esta lista (é bem simples):

 

using
System.Data;
using
System.Drawing;
using
System.Linq;
using
System.Text;
using
System.Windows.Forms;
using
System.Data.Linq;
 

namespace
Testes
{

   public partial class Form1 : Form

   {

  

      DBTeste db = new DBTeste();

 

      public Form1()

      {

         InitializeComponent();

      }

 

      private void Button1_Click(object sender, EventArgs e)

      {

         var DBEstrutura = db.Mapping;

 

         foreach (var Tabela in DBEstrutura.GetTables())

         {

            listBox1.Items.Add(Tabela.TableName);

 

            foreach (var Coluna in Tabela.RowType.DataMembers)

               listBox1.Items.Add(” -” + Coluna.MappedName);

         }

      }

   }

}

Criptografando dados com C# e MD5

O exemplo abaixo demonstra como criptografar dados utilizando C# e o algorítmo MD5. O Namespace System.Security.Cryptography oferece os recursos necessários para esta implementação.


 

using
System.Security.Cryptography;
 


 

public static string GetMD5Hash(string input)

{

   MD5 md5Hasher = MD5.Create();

 

   byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));

  

   StringBuilder sBuilder = new StringBuilder();

  

   for (int i = 0; i < data.Length; i++)

   {

      sBuilder.Append(data[i].ToString(“x2″));

   }

   return sBuilder.ToString();

}

Abrindo Formulários Dinamicamente C# (Windows Forms)

Introdução


Uma tarefa comum no desenvolvimento de soluções Windows Forms é a necessidade de instanciar formulários com base no nome da classe, ou seja, como o desenvolvedor pode abrir um formulário dinamicamente (programaticamente) passando o nome deste formulário (classe) como string. Isto é muito comum quando há necessidade de criarmos menus populados dinamicamente a partir de uma base de dados.

 

Problema

Apesar de representar uma necessidade comum em aplicações Windows Forms, ainda há muitas dúvidas entre os desenvolvedores de como implementar corretamente um procedimento para instanciar um formulário dinamicamente. Faltam exemplos sobre esse tipo prática e os que estão disponíveis na Web não são facilmente encontrados e na maioria das vezes são apresentados em outro idioma.

 

Solução

Uma construção simples com o método CreateInstance do objeto Activator permite implementar esta funcionalidade. Veja o código abaixo:

 

public static void OpenForm(string Namespace_FormName, bool System_Modal)

{

   Type t = Type.GetType(Namespace_FormName);

  

   if (t != null)

   {

      System.Windows.Forms.Form f = (System.Windows.Forms.Form)Activator.CreateInstance(t);

 

      if (System_Modal)

         f.ShowDialog();

      else

         f.Show();

   }

}

 

Instanciando um formulário implementado em outro assembly

Com uma construção semelhante, é possível iniciar um formulário implementado eu outro assembly. Basta modificar o código acima para incluir informações sobre o assembly externo. O exemplo abaixo mostra como iniciar um formulário (MDIChild) contido em outro assembly e centralizá-lo no MDI:

 

private
void OpenChildFormFromExternalAssembly(
   string Full_Namespace_Class,

   string Root_Namespace,

   string Assembly_Version,

   string Assembly_Culture,

   string Assembly_PublicKeyToken,

   bool System_Modal)

{

   Type t = Type.GetType(Full_Namespace_Class + “,” + Root_Namespace

      + “, Version=” + Assembly_Version

      + “, Culture=” + Assembly_Culture

      + “, PublicKeyToken=” + Assembly_PublicKeyToken);

 

   if (t != null)

   {

      System.Windows.Forms.Form f = (System.Windows.Forms.Form)Activator.CreateInstance(t);

 

      f.MdiParent = this;

 

      int TopMargin = 0;

      int LeftMargin = 0;

 

      LeftMargin = ((this.Width - f.Width) / 2) + this.Left;

      TopMargin = ((this.Height - f.Height) / 2) + this.Top - 50;

 

      f.StartPosition = FormStartPosition.Manual;

      f.Top = TopMargin;

      f.Left = LeftMargin;

 

      if (System_Modal)

         f.ShowDialog();

      else

         f.Show();

   }

}

 

 

As linhas abaixo demonstram como invocar o procedimento acima passando os parâmetros necessários:

 

OpenChildFormFromExternalAssembly(

   “EIS.Presentation.frmTipoEis”, // Namespace completo

   “EIS”, // Root Namespace

   “1.0.0.0″, // Assembly Version (AssemblyInfo.cs)

   “neutral”, // Cultura (Default=neutral)

   “null”, // PublicKeyToken (Default=null)

   false

);

Ocultando o diálogo “Generating Previews” do Método System.Drawing.Printing.Print()

Muitas aplicações .NET utilizam o Namespace System.Drawing.Printing para criar documentos de impressão (PrintDocument) e enviá-los para impressora ou para janela de PrintPreview.

Um cenário comum é encontrado em aplicações WindowsForms. Imagine um ponto de venda que utiliza uma aplicação WindowsForms para impressão de cupons, comandas entre outros jobs. Considere que o operador desta aplicação utiliza o teclado para executar todos os comandos e entradas de dados (o uso do mouse é minimizado). Em cenários como este, é comum que a tecla [ENTER] seja pressionada repetidas vezes para completar um processo de entrada de um novo pedido por exemplo.

Tive um cenário semelhante implementado no módulo de caixa de um restaurante, o volume de comandas entregues pelos garçons ao caixa é grande e o procedimento do caixa para inserir os pedidos no sistema é rápido e agilizado pelo uso do teclado. Ao final do processe de inserir uma nova comanda, o sistema verifica os itens inseridos e envia um job para diferentes impressoras dependendo dos itens, por exemplo, os itens “pratos quentes” são impressos na cozinha, enquanto as bebidas são enviadas para a impressora do bar para que o pedido seja atendido.

O problema é que com o tempo, o usuário do caixa, tende a digitar as entradas cada vez mais rápido. Isso faz com que a tecla [ENTER] seja pressionada repetidas vezes, algumas para avançar para o próximo campo e outras para acionar os botões de comando. Contudo, é comum que o usuário pressione esta tecla pelo menos 1 vez mais além do necessário. Se isso ocorre quando a janela de diálogo “Generating Previews” está sendo exibida, o job de impressão é cancelado.



Imagine a situação, você está na mesa, solicitou um prato, o garçon emitiu a comanda, entregou ao caixa, o caixa registrou o pedido, mas, sem perceber, pressionou a tecla [ENTER] mais uma vez cancelando o envio da impressão para a cozinha. Seu prato demora, você reclama para o garçon, ele reclama para o caixa, o caixa culpa a cozinha e no final de tudo a cupla recai sobre o sistema que devia ter previsto este cenário e utilizado uma implementação diferente.

A solução: A solução é simples, porém os exemplos de impressão na documentação do MSDN não aborda nenhum cenário semelhante. Basicamente o que você precisa é mudar o PrintController do seu objeto PrintDocument. Por padrão, o PrintController é um objeto do tipo PrintControllerWithStatusDialog, assim toda vez que o método Print() é invocado, o PrintControllerWithStatusDialog exibe a janela Generating Previews. Basta substituí-lo pelo objeto StandardPrintController que a janela não será mais exibida. A sintaxe correta para esta construção é:

pd.PrintController = new StandardPrintController();
pd.Print();

Simples assim!

Acessando o PostgreSQL com Visual C#.NET

Conectividade para bancos de dados no Microsoft.NET
O Microsoft.NET CLR (Common Language Runtime) oferece várias opções de conexão para os mais diversos bancos de dados. Este artigo dedica-se a apresentar uma forma simples de utilização do ODBC Data Provider para conectar-se à um banco de dados PostgreSQL usando o Visual C#.NET (ou outra linguagem portada para o Microsoft.NET Framework.

ODBC Driver para PostgreSQL
O primeiro passo é verificar se você já possui o driver ODBC para PostgreSQL. Você pode verificar a existência deste driver através da janela ODBC Data Source Administrator (Figura 1) que pode ser acessada através do Painel de Controle à Ferramentas Administrativas à Data Sources (ODBC).

ODBC
Figura 1: ODBC Data Sources

É importante esclarecer que para obter os drivers atualizados e para versões específicas do PostgreSQL o desenvolvedor deverá acessar o website http://gborg.postgresql.org/project/psqlodbc/genpage.php?downloads. O arquivo que acompanha este artigo é compatível com a versão 7.03.02.00 e foi utilizado apenas para ilustrar os procedimentos apresentados.

Instalando o driver ODBC para PostgreSQL
Execute o arquivo [psqlodbc.msi] e siga os passos do assitente apresentado na Figura 2. O assistente para instalação do psqlODBC é bastante simples e a instalação é rápida.

Assistente para instalação do driver ODBC para PostgreSQL
Figura 2: O Assistente para instalação do driver ODBC para PostgreSQL.

Após concluir este procedimento, você precisará criar o arquivo DSN de usuário. Para isto, abra novamente a janela ODBC Data Source Administrator, selecione a guia User DSN e clique no botão [Add…], será exibida a janela Create New Datasource (Figura 3), selecione o driver PostgreSQL desejado e clique no botão [Finish].

ODBC PostgreSQL
Figura 3: Janela Create New Data Source

Após clicar no botão [Finish] o sistema exibirá outro diálogo, a janela PostgreSQL ODBC Driver Setup (Figura 4). Nesta janela o desenvolvedor deverá informar os dados básicos para conexão com seu banco de dados e uma descrição que será utilizada para referirmos à fonte de dados no código da aplicação. Configurações mais avançadas podem ser definidas através do botão [Datasource].

A Janela PostegreSQL ODBC Driver Setup
Figura 4: A janela PostgreSQL ODBC Driver Setup

Neste ponto, o desenvolvedor já poderá escrever aplicações com o Visual C#.NET (ou qualquer outra linguagem portada para o Microsoft.NET Framework) para acessar suas bases PostgreSQL. O ODBC.NET Provider que acompanha o Visual Studio.NET oferece um conjunto de classes como OdbcConnection, OdbcCommand e OdbcDataReader; que provêem as funcionalidades necessárias para você comunicar-se com seu servidor PostgreSQL e administrar suas bases de dados. Um bom conhecimento sobre os objetos do ADO.NET será fundamental para que o desenvolvedor possa implementar suas aplicações.

Implementando o código da aplicação Para ilustar este exemplo, será necessário a criação de uma tabela que será acessada pela nossa aplicação. O script necessário para criação desta tabela e alimentação de alguns registros iniciais é apresentado na Listagem 1.

CREATE TABLE TesteCSharp
(
ID serial,
Texto text,
Acessado timestamp
);

INSERT INTO TesteCSharp(Texto, Acessado) VALUES('Exemplo 1', now());
INSERT INTO TesteCSharp(Texto, Acessado) VALUES('Exemplo 2', now());
INSERT INTO TesteCSharp(Texto, Acessado) VALUES('Exemplo 3', now());
INSERT INTO TesteCSharp(Texto, Acessado) VALUES('Exemplo 4', now());
INSERT INTO TesteCSharp(Texto, Acessado) VALUES('Exemplo 5', now());

Listagem 1: A tabela TesteCSharp

Abaixo, você encontrará a Listagem 2 que apresenta a classe PostgreSQL_Sample implementada com Visual C#.NET que demonstra como estabelecer uma conexão com seu servidor PostgreSQL. Observe o código.

using System;
using System.Data;
using Microsoft.Data.Odbc;

class PostgreSQL_Sample
{

[STAThread]
static void Main(string[] args)
{

// string de conexão
string cnString = "DSN=dsnPostgreSQL;UID=cmattos;PWD=***;";

// cria o objeto OdbcConnection
OdbcConnection cnPostgreSQL = new OdbcConnection(cnString);

// O código a seguir demonstra como capturer e reporter uma ODBC exception.
// Para manter a simplicidade, este será o único tratamento de Exception neste exemplo.

try
{
cnPostgreSQL.Open();
}
catch (OdbcException ex)
{
Console.WriteLine (ex.Message + "\n\n" + "StackTrace: \n\n" + ex.StackTrace);
// Pausa para o usuário ler a mensagem
Console.WriteLine("\n Pressione qualquer tecla para continuar...");
Console.Read();
return;
}

// Cria o objeto DataSet
DataSet ds = new DataSet();
OdbcDataAdapter da = new OdbcDataAdapter();
OdbcCommandBuilder cb = new OdbcCommandBuilder(da);
da.SelectCommand = new OdbcCommand("SELECT ID, Texto, Acessado FROM TesteCSharp", cnPostgreSQL);
da.Fill(ds);

// Exibe o número de registros da tabela
Console.WriteLine("A Tabela [TesteCSharp] contém {0} registros.\n", ds.Tables[0].Rows.Count);

// Exibe os nomes das colunas da tabela
Console.WriteLine("Colunas\n=======\n");

foreach(DataColumn dc in ds.Tables[0].Columns)
{
Console.WriteLine("{0} ({1})", dc.ColumnName, dc.DataType);
Console.WriteLine("\n");
}

cnPostgreSQL.close();
}

Listagem 2: A classe PostgreSQL_Sample .NET Data Provider for PostgreSQL

Um informação muito importante para o desenvolvedor é que já encontra-se em desenvolvimento o .NET Data Provider for PostgreSQL. Informações detalhadas sobre o Npgsql (como foi batizado) podem ser obtidas no endereço http://gborg.postgresql.org/project/npgsql/projdisplay.php, contudo, o site informa que ainda não há uma versão estável pronta para distribuição. O desenvolvedor que utiliza o PostgreSQL deve ficar atento para a liberação desta ferramenta.

PostgreSQLDirect.NET Data Provider
Outra alternativa, para os desenvolvedores que estão dispostos a desembolsar alguns dólares, é o PostgreSQLDirect.NET Data Provider fornecido pela empresa CoreLab Software Development. Este componente oferece vários recursos para o acesso e administração de bases de dados PostgreSQL (ver Figura 5). A CoreLab também oferece Data Providers customizados para bases de dados SQL Server, Oracle, MySQL e DB2. Visite o website da empresa em http://www.crlab.com/ para obter maiores informações sobre os produtos. Informações mais detalhadas sobre o PostgreSQLDirect.NET Data Provider podem ser encontradas no endereço http://www.crlab.com/pgsqlnet/.

ToolBox PostgreSQL
Figura 5: Ferramentas do PostgreSQL Direct.NET

Mais informações sobre o PostgreSQL podem ser obtidas através do website http://www.postgresql.org/.

Consumindo funções do Microsoft Win32 API com C#

Introdução

Periodicamente recebo e-mails de desenvolvedores pedindo ajuda para implementar funções do Microsoft Win32 em suas aplicações. Nos idos do Visual Basic 6.0, a procura por funções de API era ainda maior. Isso mudou porque o .NET Framework, desde sua versão 1.0, implementou diversas funções que antes só conseguíamos utilizar através da API Microsoft Win32. O Microsoft Win32 expõe diversas funções através de um conjunto de bibliotecas. As bibliotecas mais utilizadas e suas finalidades são apresentadas na Tabela 1.

Biblioteca Descrição
Gdi32.dll Graphics Device Interface (GDI). Esta biblioteca implementa funções para dispositivos de saída, gráficos e gerenciamento de fontes.
Kernel32.dll Funções de baixo nível, como gerenciamento de memória e manipulação de recursos e dispositivos do sistema.
User32.dll Funções de gerenciamento do Windows como tratamento de mensagens, timers, menus, etc.

Tabela 1: Bibliotecas do Microsoft Win32

Microsoft Win32 API e o .NET Framework
Muitos desenvolvedores perguntam: “Por que temos que codificar funções que já estão implementadas no Windows? Por que o .NET Framework não provê essas funcionalidades?”. Na verdade uma boa parte das funções do Win32, foi portada para o .NET, mas o conjunto completo dessas funções é muito grande, e muitas funções foram deixadas de fora. A Microsoft disponibilizou um documento que estabelece o mapeamento das funções do Win32 com as classes do .NET, esse documento está disponível na seguinte URL: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/win32map.asp.

Platform Invoke (P/Invoke)
Platform Invocation Services (PInvoke) permite que uma aplicação, implementada com código gerenciado (Manage Code), possa fazer chamadas para funções encapsuladas em bibliotecas (DLL ) implementadas com código não-gerenciado (Unmanage Code). Através do P/Invoke, com o uso correto de alguns atributos e parâmetros, podemos invocar qualquer função do Microsoft Win32 ou de outra biblioteca. O fragmento de código abaixo apresenta uma chamada para a função externa CascadeWindows, armazenada na biblioteca User32.dll.

[DllImport("user32.dll")]
static extern ushort CascadeWindows(IntPtr hwndParent, uint wHow, IntPtr lpRect, uint cKids, IntPtr [] lpKids);

Observe que o atributo contendo a declaração DllImport(“biblioteca.dll”) deve preceder a declaração do método ou função que deve ser obrigatoriamente definido como static extern.

Não perca tempo, Seja produtivo!
É muito importante que o desenvolvedor utilize funções externas somente quando necessário. Sugiro uma boa pesquisa nas classes do .NET Framework antes de optar pela API do Win32. Não perca seu tempo tentando implementar uma função de API quando ela já está disponível no .NET Framework.

Unmanage Code vs. Segurança
Outro ponto a ser considerado quando se planeja utilizar funções de código não-gerenciado, refere-se à segurança. Você deve certificar-se de que o usuário da sua aplicação ou o seu componente possui os privilégios necessários para executar código não-gerenciado.

Exemplos Práticos
Neste artigo, vou apresentar quatro funções do Microsoft Win32. Estas funções não foram portadas para o .NET Framework e sua aplicabilidade prática é relativamente simples. A Tabela 2 apresenta as funções que serão utilizadas no aplicativo de exemplo.

Função Biblioteca Descrição
SetLocalTime Kernel32.dll Esta função permite que você altere a data e hora do Windows.
Beep Kernel32.dll Esta função emite um Beep sonoro que pode ter sua freqüência e duração definidas programaticamente.
MessageBeep User32.dll Esta função executa os sons associados aos tipos de mensagem do Windows (Exclamação, Pergunta, Erro, etc).
GetDiskFreeSpace Kernel32.dll Esta função permite obter informações específicas sobre uma unidade de disco (setores, clusters, espaço total e espaço livre). Existe uma função bastante próxima desta chamada GetDiskFreeSpaceEx que retorna apenas o espaço livre de uma unidade de disco, porém esta função já foi incorporada ao .NET Framework através do Namespace System.IO.

Tabela 2: Funções do Win32 utilizadas no exemplo.

Referência ao Namespace
Para utilizarmos funções externas, como as funções do Microsoft Win32, precisamos estabelecer uma referência ao Namespace System.Runtime.InteropServices. A linha de código abaixo apresenta a referência necessária.

using System.Runtime.InteropServices;

Alterando Data e Hora do Sistema com a função SetLocalTime
O Quadro 1 apresenta o código necessário para implementar a função SetLocalTime. Esta função é disponibilizada através da biblioteca kernel32.dll. Observe que a declaração do método externo é acompanhada do atributo DllImport(“kernel32.dll”). Para esta função o desenvolvedor precisa criar a estrutura SystemTime. Note que esta estrutura também possui um atributo chamado StructLayout. Este atributo controla o layout de um objeto quando é passado para o ambiente não-gerenciado, o parâmetro LayoutKind é representado por uma Enumeração. Os membros desta Enumeração são apresentados na Tabela 3.

\

Membro Descrição
Auto O runtime escolhe automaticamente o layout apropriado para os objetos quando são expostos. Contudo este método não deve ser utilizado para expor objetos ao ambiente não-gerenciado, isso geraria uma Exception.
Explicit A posição precisa de cada membro do objeto em ambiente não-gerenciado deve ser explicitamente especificada através da propriedade FieldOffsetAttribute.
Sequential Os membros do objeto são apresentados sequencialmente, na mesma ordem que serão expostos ao ambiente não-gerenciado.

Tabela 3: A Enumeração LayoutKind.

#region SetLocalTime Function

[DllImport("kernel32.dll")]
public static extern bool SetLocalTime(ref SystemTime sysTime);

public static void SetNewDateTime(DateTime dt)
{
SystemTime sysTime = new SystemTime();
sysTime.wYear = (ushort)dt.Year;
sysTime.wMonth = (ushort)dt.Month;
sysTime.wDay = (ushort)dt.Day;
sysTime.wHour = (ushort)dt.Hour;
sysTime.wMinute = (ushort)dt.Minute;
sysTime.wSecond = (ushort)dt.Second;
sysTime.wMiliseconds = (ushort)dt.Millisecond;

SetLocalTime(ref sysTime);
}

[StructLayout(LayoutKind.Sequential)]
public struct SystemTime
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMiliseconds;
}

private void cmdSetLocalTime_Click(object sender, EventArgs e)
{

DateTime myDate = new DateTime(dtpDate.Value.Year,
dtpDate.Value.Month,
dtpDate.Value.Day,
dtpTime.Value.Hour,
dtpTime.Value.Minute,
dtpTime.Value.Second);

SetNewDateTime(myDate);
}

private void frmSetLocalTime_Load(object sender, EventArgs e)
{
dtpDate.Value = System.DateTime.Today;
dtpTime.Value = System.DateTime.Now;
}

private void tmrLocal_Tick(object sender, EventArgs e)
{
lblDateTime.Text = DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToLongTimeString();
}

#endregion
Quadro 1: Implementando a função SetLocalTime

Emitindo Beep Sonoros no C#
Esta função é bastante simples e útil em algumas situações. Com a função Beep exposta pela biblioteca kernel32.dll, você pode emitir um aviso sonoro, controlando sua freqüência e duração. Semelhante à função Beep encontrada no Visual Basic. O Quadro 2 apresenta o código necessário para sua implementação.

#region Beep Function

[DllImport("kernel32.dll")]
public static extern bool Beep(int frequency, int duration);

private void cmdBeep_Click(object sender, EventArgs e)
{
Beep((int)upFrequency.Value, (int)upDuration.Value);
}

public enum BeepType
{
SimpleBeep = -1,
IconAsterisk = 0x00000040,
IconExclamation = 0x00000030,
IconHand = 0x00000010,
IconQuestion = 0x00000020,

Ok = 0x00000000,
}

#endregion
Quadro 2: A função Beep

Sons do Windows com a função MessageBeep
Semelhante ao exemplo anterior, a função MessageBeep, exposta pela bilbioteca user32.dll, emite avisos sonoros de acordo com o tipo de mensagem que você quer exibir. Os mesmos tipos que são definidos quando você codifica uma Caixa de Mensagem. Você pode executar um aviso sonoro simples, um aviso de exclamação ou de interrogação, e assim por diante. Os sons acionados por esta função são os mesmos configurados pelo usuário nas propriedades de som do Painel de Controle. Desta forma, se não houver som configurado para interrogação, por exemplo, a função não será executada. Observe o código desta implementação no Quadro 3.

#region MessageBeep Function

[DllImport("user32.dll")]
public static extern bool MessageBeep(BeepType beepType);

private void cmdMessageBeep_Click(object sender, EventArgs e)
{

switch (cboBeepType.Text)
{
case "Ok":
MessageBeep(BeepType.Ok);
break;
case "SimpleBeep":
MessageBeep(BeepType.SimpleBeep);
break;
case "IconAsterisk":
MessageBeep(BeepType.IconAsterisk);
break;
case "IconExclamation":
MessageBeep(BeepType.IconExclamation);
break;
case "IconQuestion":
MessageBeep(BeepType.IconQuestion);
break;
case "IconHand":
MessageBeep(BeepType.IconHand);
break;
default:
MessageBeep(BeepType.Ok);
break;
}
}

#endregion
Quadro 3: A função MessageBeep

Verificando o Espaço em Disco com a função GetDiskFreeSpace
Esta função, exposta pela biblioteca kernel32.dll, permite ao desenvolvedor verificar o espaço total e espaço livre de uma unidade de disco. As informações fornecidas por esta função incluem: Número de Setores por Cluster, Número de Bytes por Setor, Número de Clusters Livres e o Número Total de Clusters. Agora, se você quer saber apenas o espaço livre em uma unidade de disco, você pode utilizar a classe System.Io.DriveInfo do .NET Framework 2.0 para obter essa informação. Essa classe provê a mesma funcionalidade exposta pela função semelhante chamada GetDiskFreeSpaceEx do Win32. O Quadro 4 apresenta o código para implementação desta função.

#region GetDiskFreeSpace Function

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool GetDiskFreeSpace(string lpRootPathName,

out uint lpSectorsPerCluster,
out uint lpBytesPerSector,
out uint lpNumberOfFreeClusters,
out uint lpTotalNumberOfClusters);

private void cmdGetDiskFreeSpace_Click(object sender, EventArgs e)
{
uint SectorsPerCluster;
uint BytesPerSector;
uint NumberOfFreeClusters;
uint TotalNumberOfClusters;

GetDiskFreeSpace("C:\\", out SectorsPerCluster, out BytesPerSector,
out NumberOfFreeClusters, out TotalNumberOfClusters);

txtSectorsPerCluster.Text = SectorsPerCluster.ToString();
txtBytesPerSector.Text = BytesPerSector.ToString();
txtNumberOfFreeClusters.Text = NumberOfFreeClusters.ToString();
txtTotalNumberOfClusters.Text = TotalNumberOfClusters.ToString();

long Bytes = (long)NumberOfFreeClusters * SectorsPerCluster * BytesPerSector;
txtFreeSpaceInBytes.Text = Bytes.ToString();

decimal KiloBytes = (decimal)Bytes / 1024;
txtFreeSpaceInKilobytes.Text = KiloBytes.ToString();

decimal MegaBytes = (decimal)KiloBytes / 1024;
txtFreeSpaceInMegabytes.Text = MegaBytes.ToString();

decimal GigaBytes = (decimal)MegaBytes / 1024;
txtFreeSpaceInGigabytes.Text = GigaBytes.ToString();
}
#endregion

Quadro 4: A função GetDiskFreeSpace

Conclusão
Neste artigo você conheceu um pouco mais sobre o Microsoft Win32 e aprendeu como utilizar suas funções através do Microsoft Visual C# e o P/Invoke. Visite os links de referência. Consulte as classes do .NET Framework antes de recorrer ao uso de funções externas, não tente re-inventar a roda! Boa programação!

C# 3.0 - Auto Implemented Properties

Introdução
Frequentemente os métodos de acesso às propriedades de uma classe (get/set) têm uma implementação trivial, seguindo um modelo simples, onde o acessor get é responsável por retornar o valor armazenado num campo privado da classe e o acessor set tem o propósito de atribuir um novo valor ao campo.

O novo recurso Auto Implemented Properties, disponível no C# 3.0, oferece uma sintaxe mais concisa para implementar esse modelo, onde o compilador C# gera automaticamente os campos privados. O exemplo a seguir o ajudará a entender esse novo recurso e seu impacto no dia-a-dia do programador.

Utilizando a versão beta do Visual Studio 2008 (se você ainda não baixou, acesse o link http://msdn2.microsoft.com/en-us/vstudio/aa700831.aspx) crie um novo projeto utilizando o template Console Application, atribua o nome desejado para a Solução, eu utilizarei o nome CSNewFeatures.

Na janela Solution Explorer, abra o arquivo Program.cs, e adicione uma nova classe chamada Movie, como demonstra o código abaixo:

namespace CSNewFeatures
{
public class Movie
{
}

class Program
{
static void Main(string[] args)
{
}
}
}

Na nova classe Movie, adicione duas propriedades (Título e Gênero). E modifique o método ToString() da seguinte forma:

public class Movie
{
public string Titulo { get; set; }
public string Genero { get; set; }

public override string ToString()
{
return Titulo + "\t" + Genero;
}
}

Modifique o método Main da classe Program para criarmos uma nova instância da classe Movie, veja o código:

static void Main(string[] args)
{
Movie m = new Movie();
m.Titulo = "Em busca da felicidade";
m.Genero = "Drama";

Console.WriteLine(m);
Console.ReadLine();
}

Execute a aplicação (CTRL+F5) para visualizar o resultado. Pressione qualquer tecla para finalizar a aplicação console e retornar para o ambiente de desenvolvimento do Visual Studio 2008.

Este modelo de construção requer que a propriedade tenha os dois métodos de acesso (get/set). Contudo, podemos atribuir modificadores de acesso para uma construção mais elaborada. Por exemplo, considere que você queira acrescentar uma propriedade (Codigo) que seja somente leitura (ReadOnly), para isto bastaria acrescentar o modificador private junto ao acessor set. Veja o código abaixo:

public class Movie
{
public int Codigo { get; private set; }
public string Titulo { get; set; }
public string Genero { get; set; }

public override string ToString()
{
return Codigo + "\t" + Titulo + "\t" + Genero;
}
}

Neste caso, a propriedade código seria implementada somente para leitura. Desta forma, temos que realizar duas modificações, a primeira será acrescentarmos um construtor na classe Movie. Este construtor terá um argumento do tipo inteiro que será atribuído à nova propriedade Código quando uma nova instância da classe for criada. Confira o código a seguir:

public class Movie
{
public string Codigo { get; private set; }
public string Titulo { get; set; }
public string Genero { get; set; }

public Movie(int iCodigo)
{
Codigo = iCodigo;
}

public override string ToString()
{
return Codigo + "\t" + Titulo + "\t" + Genero;
}
}

A segunda modificação será feita no método Main da classe Program para instanciarmos corretamente a classe Movie:

static void Main(string[] args)
{
Movie m = new Movie(1);
m.Titulo = "Em busca da felicidade";
m.Genero = "Drama";

Console.WriteLine(m);
Console.ReadLine();
}

Execute novamente a aplicação para observar o resultado.

Conclusão
O novo recurso Auto Implemented Properties do C# 3.0 reduz a quantidade de código necessária para implementarmos as propriedades das nossas classes e torna o código mais claro. Com esta melhoria, os desenvolvedores ganharão produtividade significante para executar uma tarefa que é tão comum em todas as aplicações.