Arquivo da categoria ‘C/C++’

Qt – Signals e Slots – C++ – Linux

Publicado: 1 de outubro de 2014 em C/C++

Signals e slots são usados ​​para comunicação entre objetos, este é um recurso exclusivo do Qt e é uma das principais diferenças entre o Qt e outros frameworks. Um Signal (sinal) é emitido quando ocorre um evento em particular e um Slot é uma função que é chamada em resposta a um sinal, outros toolkits utilizam um call-back e uma função para executar este procedimento.

Existe dois modos de criar Signals/Slots, o primeiro é utilizando os recursos do Qt Design conectando os Widgets simplesmente arrastando um componente dentro do outro e escolhendo suas respectivas ações para os sinais e o Slot, deste modo nenhum código C++ será gerado e a conexão estará declarada dentro do arquivo .ui do formulário a outra maneira é por código fonte, declarando os sinais e os slots em suas respectivas classes.

Signals e Slots: http://qt-project.org/doc/qt-4.8/signalsandslots.html

Criando Sinais e Slots em Design Time

Vamos criar primeiramente os sinais e slots em Design Time para que você aprenda mais sobre a IDE visual do Qt Creator, visto que sempre criaremos sinais e slots em todos os programas daqui para frente:

1 – Crie uma nova aplicação de Widgets no Qt Creator e arraste para a tela um componente Label, um componente Horizontal Slider e um componente Progress Bar, mude a propriedade de texto do rotulo como desejar e alinhe os componentes Slider e Pogress Bar através da barra de ferramentas na opção Lay Out Vertically. Quando você alinha os componentes você pode perceber que eles estão de um novo componente chamado VerticallyLayout, este novo componente é responsável pelo alinhamento e você pode aumenta-lo ou diminui-lo e todos os widgets dentro dele serão afetados.

Widgets - Alinhamento

Widgets – Alinhamento

2 – Na barra de ferramentas clique no segundo botão chamado Edit Signals/Slot e em seguida arraste o Slider para dentro do Progress Bar, uma nova janela aparecera para que você escolha as propriedades de cada widget. Para o Slider escolha o sinal ValueChanged(int) e para a barra de progresso escolha o slot chamado setValue(int), em seguida clique em OK.

Editando Signals/Slot

Editando Signal/Slot

3 – Agora vamos analisar o resultado da nossa edição, você pode ver que no formulário os componentes estão conectados entre si por sinais e por slots. Isto significa que o Horizontal Slider declarou um sinal com o conteúdo de mudança de valor e o Progress Bar declarou um slot para sua propriedade valor, sendo assim tanto o sinal quanto o slot são valores inteiros e toda vez que o Slider sofrer uma mudança de valor o sinal enviará o valor para o slot que por sua vez mudara a propriedade de valor da barra de progresso, sincronizando os dois valores, veja a imagem abaixo para entender o Signal e Slot criados logo abaixo do formulário:

Signal e Slots

Signal e Slots

4 – Rode o programa e mova o Slider como desejar:

Programa - Eventos - Slider e Progress Bar

Programa – Eventos – Slider e Progress Bar

Exemplo:

Neste exemplo criamos um Signal e um Slot em Design Time para conectarmos dois componentes, visto que quando utilizamos o Design Time nenhum código C++ é necessário, o sinal e o slot criados residem dentro do código XML do formulário dentro da tag connections como você pode ver no código abaixo.

XML

Este código é gerado automaticamente e não precisa ser utilizado:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>438</width>
    <height>332</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Desenvolvimento Aberto</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QLabel" name="label">
    <property name="geometry">
     <rect>
      <x>6</x>
      <y>20</y>
      <width>431</width>
      <height>20</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <weight>75</weight>
      <bold>true</bold>
     </font>
    </property>
    <property name="layoutDirection">
     <enum>Qt::RightToLeft</enum>
    </property>
    <property name="text">
     <string>Signals e Slots</string>
    </property>
    <property name="alignment">
     <set>Qt::AlignCenter</set>
    </property>
   </widget>
   <widget class="QWidget" name="layoutWidget">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>120</y>
      <width>381</width>
      <height>62</height>
     </rect>
    </property>
    <layout class="QVBoxLayout" name="verticalLayout">
     <item>
      <widget class="QSlider" name="horizontalSlider">
       <property name="orientation">
        <enum>Qt::Horizontal</enum>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QProgressBar" name="progressBar">
       <property name="value">
        <number>24</number>
       </property>
      </widget>
     </item>
    </layout>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>438</width>
     <height>25</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections>
  <connection>
   <sender>horizontalSlider</sender>
   <signal>valueChanged(int)</signal>
   <receiver>progressBar</receiver>
   <slot>setValue(int)</slot>
   <hints>
    <hint type="sourcelabel">
     <x>207</x>
     <y>173</y>
    </hint>
    <hint type="destinationlabel">
     <x>207</x>
     <y>203</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

 

 

Anúncios

O sistema operacional livre mais famoso e o favorito dos desenvolvedores está disponível para desktops, servidores, tabletssmartphones e com ele uma gama de novas possibilidades para se desenvolver aplicativos poderosos que cruzam os mais diferentes dispositivos.

Munidos dos recursos de modelos do Ubuntu, divididos entre Apps, no qual o desenvolvedor pode escrever uma variedade de aplicações utilizando QML, HTML5 e Cordova e dos Scopes utilizando visões dedicadas que organizam, buscam e mostram uma variedades de tipos e conteúdos na internet ou no dispositivo local, fazem do Ubuntu SDK um conjunto completo de ferramentas de alto nível para criar aplicações elegantes e funcionais que também proporcionam ao desenvolvedor força extra para manipular processos mais complicados, utilizando o poder do C++ que é a linguagem de programação escolhida para fechar com chave de ouro o Kit de desenvolvimento do Ubuntu

Ubuntu Phone: http://www.ubuntu.com/phone

E para aqueles que adoram provar que o Linux é sempre melhor que o Windows, podem se deliciar com as possibilidades da IDE gráfica do QTCreator que faz parte do Kit de desenvolvimento do Ubuntu e com seus recursos modernos tanto de design como de edição, e se adicionada a programação C++ visual para Linux com Qt (Signals e Slots) constata-se que é muito mais eficaz e rápida do que a do Windows (Message Map) pois não utiliza a arquitetura de mensagens de loops, fazendo o Visual Studio da Microsoft parecer o editor de textos Microsoft Word. E se compararmos as funcionalidades e produtividade da IDE visual para C++ do QT com a IDE visual para C++ do MFC (que por sinal é quase a mesma do .NET) você poderá ver que há vários recursos sobre layouts e manipulação de componentes que o Visual Studio não possui, além da diferença de código, o MFC gera um código automático muito maior para a mesma aplicação, contudo ainda é possível portar seus aplicativos MFC para a plataforma Linux.

Qt-Project: http://qt-project.org/

Sobre MFC e Linux: https://www.novell.com/coolsolutions/feature/11244.html

Instalando o Ubuntu SDK

O Ubuntu SDK permite que você desenvolva software para a ultima versão de sua plataforma, para isto precisamos garantir que os pacotes do seu sistema operacional estejam atualizados.

sudo apt-get update && sudo apt-get dist-upgrade
sudo add-apt-repository ppa:ubuntu-sdk-team/ppa
sudo apt-get update && sudo apt-get install ubuntu-sdk

Se estiver utilizando o Ubuntu em uma maquina virtual, a atualização de pacotes podem requerer que você reinstale os adicionais para convidados para obter a resolução widescreen da tela, veja como efetuar este procedimento em nosso post de como instalar o Ubuntu em uma maquina virtual. Outras informações sobre o Ubuntu SDK:

Ubuntu Developer: http://developer.ubuntu.com/

Configurando o Ubuntu SDK e Criando uma Aplicação

1- Após a instalação abra o Ubuntu SDK na barra de ferramentas ou abra o QTCreator. Qualquer uma das opções mostrará a janela de boas vindas do Ubuntu SDK, clique em Next:

Bem-Vindo

Bem-Vindo

2 – Na janela Build Targets, você pode criar a plataforma em que deseja compilar seus aplicativos e também escolher a versão do framework para desenvolvimento, elas são AMD64, ARMhf e i386, crie um novo kit AMD64 para garantir que todos os pacotes sejam baixados e aguarde, este procedimento pode levar algum tempo:

Criando Kit da plataforma (pode demorar)

Criando Kit da plataforma (pode demorar)

3 – Após criar o kit clique em Next para pular a criação de um emulador de dispositivos já que vamos utilizar um projeto desktop e clique em Finish para abrir o QtCreator:

Ubuntu SDK - QTCreator

Ubuntu SDK – QTCreator

4 – Com a IDE aberta clique no menu File e escolha novo projeto, na janela de modelos de projetos, em projetos escolha Applications e selecione a opção Qt Widget Application e clique em Choose:

Tipos de Projetos

Tipos de Projetos

5 – Na janela de propriedades do projeto em Name escolha MinhaApp, em Create in escolha um diretório de sua preferencia e clique em Next:

Propriedades do Projeto

Propriedades do Projeto

6 – Na janela Kit Selection escolha Desktop e clique em Next:

Kit de compilação

Kit de compilação

7 – Na janela Class Information podemos mudar os nomes de arquivos para a classe do projeto, neste primeiro momento apenas clique em Next:

Informações da Classe

Informações da Classe

8 – Na janela Project Management podemos escolher um controlador de versões para o projeto, por enquanto clique em Finish:

Gerenciamento do Projeto

Gerenciamento do Projeto

9 – Pronto você já pode ver o código fonte C++ na sua IDE, na janela Projects expanda o node Form e dê um duplo clique em mainwindow.ui para ir para o modo de design do formulário. Utilize a paleta de widgets para arrastar os componentes para o Form, arraste 4 Labels, 3 LineEdits e um PushButton, utilize a barra de ferramentas para alinhar os componentes no formulário e altere suas propriedades na janela de propriedades no canto inferior direito da tela:

Form - Design

Form – Design

10 – Após terminar o design do formulário, para criar o evento de clique do botão, selecione o componente PushButton, clique com botão direito do mouse e escolha a opção Go to Slot e na janela seguinte escolha o método Clicked() e clique OK:

Slot - Evento de Clique

Slot – Evento de Clique

11 – Você foi direcionado para o código fonte no método de clique do botão, preencha o método com o código encontrado logo abaixo e clique em RUN na barra de ferramentas do lado inferior esquerdo da IDE (seta verde):

Código Fonte - C++

Código Fonte – C++

12 – Pronto, você já criou seu primeiro programa utilizando os recursos básicos dos Widgets Qt utilizando o Kit de desenvolvimento do Ubuntu:

Ubuntu SDK - C++ - Programa

Ubuntu SDK – C++ – Programa

Agora você pode seguir os outros posts sobre como desenvolver aplicativos para o sistema operacional Ubuntu neste site.

Exemplo:

Neste exemplo criamos um aplicativo básico C++ utilizando os Widgets Qt.

C++

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    ui->lineEdit->setText("Desenvolvimento Aberto");
    ui->lineEdit_2->setText("Ubuntu - SDK - C++");
    ui->lineEdit_3->setText("QtCreator 3.1.1 - Qt 5.2.1");
}

Uma Sequence é um objeto de banco de dados encontrado nos bancos de dados Oracle e IBM DB2, que permite a geração automática de valores, tais como números de identificação. Sequências são ideais para a tarefa de gerar valores de chaves únicas. Os aplicativos podem usar sequências para evitar possíveis problemas de simultaneidade e de desempenho resultantes de valores de coluna. A vantagem que tem sobre as  sequências de números criados fora do banco de dados é que o servidor de banco de dados mantém o registro dos números gerados e nenhum tipo de acidente no banco de dados causará números duplicados.

Sequence & Identity - C++

Sequence & Identity – C++

Identity é encontrado no banco de dados Micosoft SQL Server e é muito similar ao Sequence e possui o mesmo objetivo que é de criar números sequenciais, porem não é um objeto do banco de dados e sim uma propriedade de uma coluna pertencente a uma tabela. Quando você insere um valor em uma tabela que possui uma propriedade Identity você deve excluir o campo referente a esta coluna da clausula SQL, sendo assim o MSSQL Server é o único banco de dados que permite que a quantidade de colunas na linha Values da instrução Insert seja diferente da quantidade de colunas na tabela do banco de dados.

sequence-3-sql-server

MSSQL – Identity – Propriedades

Para saber mais detalhes sobre os recursos dos objetos Sequences ou da propriedade Identity recomendamos que você utilize os links oficiais de cada banco de dados:

Oracle: Sequence
IBM DB2: Sequence
MSSQL Server: Identity

Algo extremamente útil sobre Sequence ou Identity

Utilizar um objeto ou uma propriedade auto incremento é o método correto para criar IDs automáticos no banco de dados, nunca utilize uma Trigger para executar este procedimento, pois deste modo você esta reduzindo sensivelmente a performance do banco de dados, visto que você precisa de acessos e objetos extras para executar a mesma função.

Para valores de Sequence ou Identity que são utilizados fora do banco de dados, por exemplo, números de sequência usados ​​para identificadores externos (números de cheques bancários ou outros), se o banco de dados é recuperado para um ponto no tempo antes de uma falha, então isso poderia causar a geração de valores duplicados para algumas sequências. Para evitar possíveis valores duplicados, bancos de dados que usam valores de sequência fora do banco de dados não deve ser recuperado para um ponto anterior no tempo.

Visual Studio

Para efetuar as conexões com os diferentes bancos de dados você precisa primeiro configurar os drivers ODBC necessários no sistema operacional, depois você pode criar um design com 3 componentes RadioButton, um componente Button e um componente CListControl,  você encontra um walkthrough de como configurar os drivers ODBC na categoria SQL e C++ deste site, use a figura abaixo para referencia do design:

Visual Studio - Design - cpp

Visual Studio – Design – MFC Dialog Based

 

Exemplo:

Neste exemplo utilizamos uma Sequence para os bancos de dados Oracle e IBM DB2 e uma propriedade Identity para o banco de dados MSSQL para criar identificadores automáticos para a coluna chave de uma tabela.

SQL

Oracle

-- Cria sequencia
CREATE SEQUENCE Sequencia_seq
 START WITH     1
 INCREMENT BY   1
 NOCACHE
 NOCYCLE;

-- Cria tabela
CREATE TABLE SEQUENCIA (
   Identificador   NUMBER(10),
   Nome            VARCHAR(30),
   Sobrenome       VARCHAR(70),
   Cargo           VARCHAR(30),
   Salario         Decimal(9,2));

 -- Testa sequencia
insert into SEQUENCIA VALUES (Sequencia_seq.NEXTVAL ,'Teste','Teste Sobrenome','Programador',2234.56);

-- verifica resultado
SELECT * FROM SEQUENCIA

IBM DB2

-- Cria Sequencia
CREATE SEQUENCE Sequencia_seq
 START WITH     1
 INCREMENT BY   1
 NOCACHE
 NOCYCLE;

-- Cria tabela
CREATE TABLE SEQUENCIA (
   Identificador   INTEGER,
   Nome            VARCHAR(30),
   Sobrenome       VARCHAR(70),
   Cargo           VARCHAR(30),
   Salario         Decimal(9,2));

 -- Testa Sequencia
insert into SEQUENCIA VALUES (Sequencia_seq.NEXTVAL ,'Teste','Teste Sobrenome','Programador',2234.56);

-- Verifica resultado
Select * from SEQUENCIA;

MSSQL

-- Cria tabela / Identity
CREATE TABLE SEQUENCIA(
	Identificador int IDENTITY(1,1) NOT NULL,
	Nome          nvarchar(30) NULL,
	Sobrenome     nvarchar(70) NULL,
	Cargo         nvarchar(30) NULL,
	Salario       decimal(9, 2) NULL);

-- Testa identação
insert into SEQUENCIA VALUES ('Teste','Teste Sobrenome','Programador',2234.56);

-- Verifica tabela
select * from SEQUENCIA;

C++

Classe – Definição – arquivo .h

// Classe gerada automaticamente
// AcessocppDlg.h : header file
//

#pragma once

// Inclui classe de banco de dados MFC
#include "afxdb.h"
#include "afxcmn.h"
#include "afxwin.h"


class CAcessocppDlg : public CDialogEx
{

public:
	CAcessocppDlg(CWnd* pParent = NULL);	// standard constructor

	enum { IDD = IDD_ACESSOCPP_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support
	
protected:
	HICON m_hIcon;

	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	
	// Cria métodos e objetos da classe
	CDatabase db;
	CString bancodedados;
	void conectarDB(CString dns, CString usuario, CString senha);
		
	afx_msg void OnBnHotItemChangeRadio1(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnHotItemChangeRadio2(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnHotItemChangeRadio3(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnClickedButton1();
	
	CListCtrl m_tabela;
	
};

Classe – Implementação – arquivo .cpp

// Código gerado automaticamente
// AcessocppDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Acessocpp.h"
#include "AcessocppDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);   

protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


CAcessocppDlg::CAcessocppDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CAcessocppDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CAcessocppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST2, m_tabela);
}

BEGIN_MESSAGE_MAP(CAcessocppDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO1, &CAcessocppDlg::OnBnHotItemChangeRadio1)
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO2, &CAcessocppDlg::OnBnHotItemChangeRadio2)
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO3, &CAcessocppDlg::OnBnHotItemChangeRadio3)
	ON_BN_CLICKED(IDC_BUTTON1, &CAcessocppDlg::OnBnClickedButton1)
END_MESSAGE_MAP()


BOOL CAcessocppDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	SetIcon(m_hIcon, TRUE);			
	SetIcon(m_hIcon, FALSE);		

	// Desenvolvimento Aberto
	// Inicializa dialogo

	// Define variavel padrão para o banco de dados
	bancodedados = "oracle";

	// Cria o modelo de exibição de dados
	m_tabela.SetView(LV_VIEW_DETAILS);
	m_tabela.SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);

	return TRUE;  
}

void CAcessocppDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

void CAcessocppDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); 

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

HCURSOR CAcessocppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

// **************************
// * Desenvolvimento Aberto *
// **************************
// Nosso código começa aqui

// Seleciona banco de dados Oracle
void CAcessocppDlg::OnBnHotItemChangeRadio1(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);
	
	bancodedados = "oracle";
	*pResult = 0;
}

// Seleciona banco de dados IBM DB2
void CAcessocppDlg::OnBnHotItemChangeRadio2(NMHDR *pNMHDR, LRESULT *pResult)
{	
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "db2";
	*pResult = 0;
}

// Seleciona banco de dados MSSQL
void CAcessocppDlg::OnBnHotItemChangeRadio3(NMHDR *pNMHDR, LRESULT *pResult)
{	
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "mssql";
	*pResult = 0;
}

// Evento de clique do botão
void CAcessocppDlg::OnBnClickedButton1()
{
	// campo de dado da tabela
	CString m_campo;

	// Abre conexão
	if (bancodedados == "oracle")
	{
		conectarDB(L"OracleXE", L"user", L"p@55w0rd");
	}

	if (bancodedados == "db2")
	{
		conectarDB(L"IBMDB2", L"user", L"p@55w0rd");
	}

	if (bancodedados == "mssql")
	{
		conectarDB(L"MSSQLSERVER", L"user", L"p@55w0rd");
	}

	// Cria um set de dados
	CRecordset  dados(&db);
	CString insereSql;


	// DB2 e Oracle utilizam sequence
	// SQL Server utiliza o Identity
	// Como é um objeto atrelado ao campo
	// Necessita ser suprimido da clausula SQL
	if (bancodedados != "mssql") 
	{

		insereSql = L"insert into SEQUENCIA VALUES (Sequencia_seq.NEXTVAL ,\'Teste\',\'Teste Sobrenome\',\'Programador\',2234.56)";

	}
	else
	{
		insereSql = L"insert into SEQUENCIA VALUES (\'Teste\',\'Teste Sobrenome\',\'Programador\',2234.56)";

	}
	
	// Executa instrução SQL
	db.ExecuteSQL(insereSql);
		
	// Declara instrução SQL
	CString sql = L"SELECT * FROM SEQUENCIA ORDER BY 1 DESC";

	// Abre set de dados
	dados.Open(CRecordset::forwardOnly, sql);

	// Cria item
	LVITEM lvItem;

	// cria estrutura para inserir o item
	typedef struct _LVITEM 
	{
		UINT mask;
		int iItem;
		int iSubItem;
		UINT state;
		UINT stateMask;
		LPTSTR pszText;
		int cchTextMax;
		int iImage;
		LPARAM lParam;
        #if (_WIN32_IE >= 0x0300)
		  int iIndent;
        #endif
	 } LVITEM, FAR *LPLVITEM;

	// Define variaveis de itens
	int InsertItem(const LVITEM* pItem);
	int nItem;

	// Converte CString para LPTSTR atraves de um TCHAR
	TCHAR sz[1024];
		
	// Verifica colunas
	short nFields = dados.GetODBCFieldCount();
	int colunas = m_tabela.GetHeaderCtrl()->GetItemCount();
	
	// Verifica colunas
	if (colunas == 0)
	{
		// Lê metadata da tabela
		CODBCFieldInfo field;
		for (UINT i = 0; i < nFields; i ++)
		{
			dados.GetODBCFieldInfo(i, field);
			m_tabela.InsertColumn(i, field.m_strName, LVCFMT_LEFT, 100);
		}

	}

	// Deleta itens do controle de lista
	m_tabela.DeleteAllItems();
	
	// Recupera dados da tabela
	while (!dados.IsEOF())
	{
		for (short index = 0; index < nFields; index++)
		{
			dados.GetFieldValue(index, m_campo);
			
			// Retorna linha do banco de dados
			if (index == 0)
			{
				// Insere linha
				lvItem.mask = LVIF_TEXT;
				lvItem.iItem = 0;
				lvItem.iSubItem = 0;
				lvItem.pszText = lstrcpy(sz, m_campo);
				nItem = m_tabela.InsertItem(&lvItem);
			}

			// Retorna colunas da linha
			m_tabela.SetItemText(nItem, index, lstrcpy(sz, m_campo));
					
		}
		// Move o cursor para a proxima linha
		dados.MoveNext();
	}

	// Fecha o set de dados e a conexão
	dados.Close();
	db.Close();
	 
}

void CAcessocppDlg::conectarDB(CString dns, CString usuario, CString senha)
{
	// Cria string de conexão ODBC
	CString conexao;
	
	// Cria string de conexão
	conexao = L"DSN=" + dns + L";UID=" + usuario + L";PWD=" + senha;

	// Abre conexão
	db.OpenEx(conexao, 0);	
}

Instalando o Eclipse Luna – C++ – Linux

Publicado: 21 de setembro de 2014 em C/C++

O Eclipse é sem duvida um dos mais famosos ambiente de desenvolvimento integrado (IDE) para Java, mas a IDE Eclipse suporta também as linguagens de programação C/C++ PHP. Você pode facilmente combinar o suporte ao idioma e outras características utilizando qualquer um dos pacotes padrões, você pode também utilizar inúmeras extensões permitindo a personalização praticamente ilimitada da IDE Eclipse.

Entretanto a IDE Eclipse é um ambiente profissional e sua versão para C++, pode não ser tão amigável para os iniciantes assim como outras IDEs disponíveis para a linguagem. Para instalar o Eclipse no Linux você precisa descompactar o arquivo baixado corretamente, pois uma descompactação sem os parâmetros necessários podem bloquear a exibição do menu principal da IDE no Ubuntu (experimente baixar e descompactar com o gerenciador de arquivos pela GUI), a linha de comando correta para descompactação é como a do exemplo abaixo:


tar xzvf eclipse-cpp-luna-R-linux-gtk-x86_64.tar.gz

Download Eclipse: https://www.eclipse.org/ide/

C/C++ e o Eclipse

A IDE Eclipse pode ser facilmente instalada no Linux, pois o sistema operacional já comtempla um compilador C/C++, chamado GNU GCC Compiler (GCC ++). Utilizar o C/C++ no sistema operacional Linux é relativamente fácil, a única diferença inicial no qual você precisa saber é que um código fonte C/C++ para Linux precisa ser construído (Build) antes de ser compilado. A construção do seu aplicativo C/C++ também pode ser limpa (Clean) ou seja você pode excluir toda a construção do aplicativo (Build) e criar uma nova construção quando for necessário. Outro ponto importante que você precisa saber são os diretórios onde o Linux utiliza seus includes, caso precise adicionar uma nova biblioteca de arquivos Headers, os diretórios são: /usr/include.

O Eclipse não executará o build e clean automaticamente para você, é preciso fazer tudo manualmente, você precisa ter cuidado ao utilizar as configurações do Eclipse ou você pode inutiliza-lo criando erros na construção ou compilação dos seu aplicativos, mas não preocupe você pode restaurar as configurações efetuando uma limpeza, utilizando as opções Build All ou Clean All na opção Build Configuration no menu de contexto do seu projeto (botão direito no nome do projeto) ou pode construir e limpar o seu projeto usando a opção Build Project ou Clean Project.

Instalando o Eclipse

1 – Após efetuar o download e descompactação dos arquivos, clique no executável Eclipse (requer Java), caso ainda não tenha instalado o Java:

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java7-installer
Eclipse - Bem-vindo

Eclipse – Bem-vindo

2 – Feche a janela Welcome e no menu File clique em New e escolha C++ Project, na janela subsequente em Project Name, preencha com Hello, e na opção Toolchains escolha Linux GCC:

Novo Projeto

Novo Projeto

3 – Na janela Project Explorer, clique em cima do seu projeto com o botão direito e escolha New e em seguida escolha Source File. Em Source File preencha com hello.cpp:

Source File

Source File

4 – Copie e cole o código abaixo no seu arquivo vazio, clique com o botão direito do mouse em seu projeto e escolha a opção Build Project:

Build

Build

5  – Após a construção do seu projeto ser efetuada com sucesso, você pode perceber que o Eclipse criou uma nova pasta na sua arvore do projeto chamada Binaries, ela contem o seu arquivo executável que terá o nome do seu projeto. Agora você pode compilar o seu projeto clicando em Run na barra de ferramentas (seta verde):

Console

Console

Pronto! Seu programa foi compilado com sucesso e exibido em uma janela de console do Eclipse. Agora você esta apto a utilizar os projetos C/C++ para console encontrados na categoria C++, exceto os projetos visuais utilizando as classes MFC que são exclusivos para Windows, os projetos visuais para C++ de outras plataformas ainda serão publicados.

Como aprender C++ neste site?

Após instalar o Code blocks ou Eclipse, no menu categorias clique em C/C++ e vá para o primeiro post, cada post contem uma teoria e um código fonte, siga os em ordem decrescente ou seja do ultimo para o mais recente, o post mais antigo contem as primeiras lições e como usar a IDE, continue acompanhando o site para se atualizar e aprender mais sobre C++.

Exemplo:

Este é um programa básico conhecido como Hello Word.

C++

/*
 * hello.cpp
 *
 *  Created on: 21/09/2014
 *      Author: Desenvolvimento Aberto
 */

#include <iostream>

using namespace std;

int main()
{
    cout << "Hello world!" << endl;
    return 0;
}

Instalando o Code Blocks – C/C++ – Linux

Publicado: 21 de setembro de 2014 em C/C++

Code::Blocks é um software livre e de código aberto, multi-plataforma para as linguagens C, C ++, e Fortran. É uma IDE construída para atender as mais exigentes necessidades de seus usuários. Ela é projetada para ser muito extensível e totalmente configurável, uma IDE com todos os recursos que você precisa, com uma aparência consistente e um look and feel que facilita sua operação em várias plataformas. Construído em torno de um framework de plug-ins, o Code::Blocks pode ser estendido facilmente através de um novo plug-in. Qualquer tipo de funcionalidade pode ser adicionada pela instalação/codificação de um plug-in.

Code::Blocks: http://www.codeblocks.org/

C/C++ e o Code::Blocks

A IDE Code::Blocks pode ser facilmente instalada no Linux, pois o sistema operacional já comtempla um compilador C/C++, chamado GNU GCC Compiler. Utilizar o C/C++ no sistema operacional Linux é relativamente fácil, a única diferença inicial no qual você precisa saber é que um código fonte C/C++ para Linux precisa ser construído (Build) antes de ser compilado, mas não se preocupe o Code::Blocks irá lhe avisar quando a construção for necessária. A construção do seu aplicativo C/C++ também pode ser limpa (Clean) ou seja você pode excluir toda a construção do aplicativo (Build) e criar uma nova construção quando for necessário.

Outro ponto importante que você precisa saber são os diretórios onde o Linux utiliza seus includes, caso precise adicionar uma nova biblioteca de arquivos Headers, os diretórios são: /usr/include.

Instalando o Code::Blocks

1 – Você pode instalar o C::B de um modo bem simples, basta utilizar a instrução abaixo em uma janela do terminal, após a instalação abra a IDE, digitando seu nome (codeblocks), e na janela de boas vindas clique em novo projeto:


sudo apt-get install codeblocks libwxgtk2.8-dev

Welcome - Novo Projeto

Welcome – Novo Projeto

2- Em Category, escolha a opção Console e clique em GO:

Projeto para o Console

Projeto para o Console

3 – Na janela Console Application escolha C++ para sua aplicação e clique em Next:

C++ Application

C++ Application

4 – Escolha um titulo e um local para salvar seu projeto e clique em Next:

Titulo e Diretório

Titulo e Diretório

5 –  Escolha o compilador C/C++ de sua preferencia ou utilize o padrão e clique em Finish:

Compilador

Compilador

6 – Um código de um programa Hello Word será automaticamente criado para você, altere como desejar ou clique em Run. A IDE irá lhe perguntar se deseja construir o seu projeto, clique em Yes:

Construindo - Project Build

Construindo – Project Build

7 – Pronto! Seu programa foi compilado com sucesso e exibido em uma janela de console do Xterm.

Console

Console

Agora você esta apto a utilizar os projetos C/C++ para console encontrados na categoria C++, exceto os projetos visuais utilizando as classes MFC que são exclusivos para Windows, os projetos visuais para C++ de outras plataformas ainda serão publicados.

Como aprender C++ neste site?

Após instalar o Code blocks ou Eclipse, no menu categorias clique em C/C++ e vá para o primeiro post, cada post contem uma teoria e um código fonte, siga os em ordem decrescente ou seja do ultimo para o mais recente, o post mais antigo contem as primeiras lições e como usar a IDE, continue acompanhando o site para se atualizar e aprender mais sobre C++.

 

Uma View ou visão em português, é uma tabela virtual. A View não possui um armazenamento de dados permanente associado a ela, mas é baseada em outra tabela ou tabelas. Existem vários tipos de visões, elas podem variar suas funcionalidades de banco de dados para banco de dados, as Views mais comum são do tipo padrão, particionada ou materializada.

A visão fornece uma forma alternativa de olhar os dados em uma ou mais tabelas. A vista é uma especificação chamada de uma tabela de resultados. Conceitualmente, a criação de um ponto de vista é como o uso de binóculos. Você pode olhar através de binóculos para ver uma paisagem inteira ou olhar para uma imagem específica dentro da paisagem, como uma árvore. Da mesma forma, você pode criar uma visão que combina dados de diferentes tabelas de base ou criar uma visão limitada de uma tabela que omite dados. Na verdade, estes são os motivos mais comuns para usar um ponto de vista. Combinando informações de tabelas de base simplifica a obtenção de dados para o usuário final, e limitar os dados que um usuário pode ver é útil para fins de segurança.

Devido aos vários tipos diferentes de Views e suas respectivas diferenças de funcionalidades entre os bancos de dados Oracle, IBM DB2 e MSSQL é recomendado que você utilize os links oficiais para referencia:

Oracle: Create View
IBM DB2: Create View
Microsoft SQL Server: Create View

View - C++

View – C++

Algo Extremamente Útil Sobre Views

As Views são essenciais para uma boa performance de um sistema que manipula dados, elas são uteis de muitas maneiras diferentes, todos os sistemas de grande porte utilizam tipos de View.

As Views acrescentam performance a aplicação, podem conter constraints e índices, podem criar visões baseadas em formato XML, podem ser utilizadas para fins de segurança, podem ser criadas a partir de tabelas particionadas alocadas em vários servidores diferentes e retornar uma visão única, são fundamentais na criação de complexos relatórios, modelo de dados para exportação e até no manuseio de cadastros.

As Views possuem um recurso muito útil quando unidas ao evento INSTEAD OF de uma Trigger, na verdade este tipo de evento foi desenvolvido especialmente para a utilização em conjunto com uma View (exceto para banco de dados MSSQL que permite o uso em tabelas comuns). A utilização do evento “ao invés de” em uma View permite que o desenvolvedor ganhe a maior performance possível na distribuição de dados baseados em uma única visão para varias tabelas físicas contidas em locais diferentes.

Isto acontece porque, por exemplo, um formulário de cadastramento complexo geralmente é composto de varias tabelas interligadas pelo seu identificador, a combinação ViewTrigger permite que você retorne em uma única pesquisa todo o cadastro utilizando um único acesso. Quando disparado um evento para criar um cadastro novo ou modificar um cadastro existente em cima de uma View, automaticamente uma Trigger “ao invés de inserir” ou “ao invés de alterar” pode distribuir todos os dados alimentados pelo usuário em cada tabela especifica, tendo em seu beneficio, que todo o processo esta sendo efetuado dentro do motor do banco de dados.

Visual Studio

Você encontra um walkthrough de como instalar os bancos de dados, seus drivers e a configuração da IDE Visual Studio na categoria SQL e C++, use a imagem abaixo para referencia de como criar design utilizando, 1 GroupBox, 8 StaticTexts, 7 EditControls e 5 Buttons:

Visual C++ - Design

Visual C++ – Design

Exemplo:

Neste exemplo utilizamos o conceito básico de uma View em conjunto com o evento INSTEAD OF de uma Trigger, no programa abaixo o método de inserção esta completo, fica como exercício criar o método INSTEAD OF UPDATE e INSTEAD OF DELETE.

Você encontra uma visão contendo duas tabelas relacionadas, a tabela Funcionários e Desconto, e a partir de uma trigger utilizamos o evento “ao invés de inserir” para distribuir os dados para suas respectivas tabelas. Na aplicação C++ o campo porcentagem possui cor diferente pois se encontra em outra tabela, você pode utilizar este exemplo básico para criar cadastros mais complexos.

* Para referencia sobre as triggers utilize nosso post C++ com o tópico Triggers.

** Você encontra este mesmo programa utilizando SQL direto na aplicação, clicando aqui.

SQL

Oracle

-- Cria tabela de funcionarios
create table Funcionarios(
  ID_Funcionario  NUMBER(5),
  Nome            VARCHAR2(30),
  Sobrenome       VARCHAR2(70),
  Cargo           VARCHAR2(30),
  Salario         NUMBER(9,2));

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO NUMBER,
  PORCENTAGEM NUMBER(9,2));

-- Cria View (Visão) do Cadastro de funcionarios
Create or Replace View CadFuncionario as
Select
  A.ID_FUNCIONARIO, A.NOME, A.SOBRENOME,
  A.CARGO, A.SALARIO, B.PORCENTAGEM
  from FUNCIONARIOS A, DESCONTO B
Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

-- Cria Trigger Ao inves de inserir sobre a View
create or replace TRIGGER CADFUNC_INSERT
   INSTEAD OF INSERT ON CadFuncionario
   FOR EACH ROW 

   BEGIN
    -- Insere dados na tabela de Funcionario
    Insert into FUNCIONARIOS values (
     :new.ID_FUNCIONARIO,
     :new.NOME,
     :new.SOBRENOME,
     :new.CARGO,
     :new.SALARIO);

     -- Insere dados na tabela de Desconto
     Insert into DESCONTO values (
     :new.ID_FUNCIONARIO,
     :new.PORCENTAGEM);  

   END CADFUNC_INSERT;

IBM DB2

-- Desenvolvimento Aberto --
-- Atente-se para o terminador de instruções
-- o IBM DATA STUDIO não consegue utilizar
-- Begin... END com scripts sql
-- Mude o terminador para o caractere @
-- para mudar clique com o botão direito do mouse aqui!!!

-- Cria tabela de funcionarios
create table Funcionarios (
    ID_Funcionario  INTEGER,
    Nome            VARCHAR(30),
    Sobrenome       VARCHAR(70),
    Cargo           VARCHAR(30),
    Salario         NUMERIC(9,2))@

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INTEGER,
  PORCENTAGEM DECIMAL(9,2))@

-- Cria View (Visão) do Cadastro de funcionarios
Create or Replace View CadFuncionario as
Select
  A.ID_FUNCIONARIO, A.NOME, A.SOBRENOME,
  A.CARGO, A.SALARIO, B.PORCENTAGEM
  from FUNCIONARIOS A, DESCONTO B
Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO@

-- Cria Trigger Ao inves de inserir sobre a View
create or replace TRIGGER CADFUNC_INSERT
   INSTEAD OF INSERT ON CadFuncionario
   REFERENCING NEW AS N
      FOR EACH ROW 

  T1:  BEGIN
    -- Insere dados na tabela de Funcionario
    Insert into FUNCIONARIOS values (
     N.ID_FUNCIONARIO,
     N.NOME,
     N.SOBRENOME,
     N.CARGO,
     N.SALARIO);

     -- Insere dados na tabela de Desconto
     Insert into DESCONTO values (
     N.ID_FUNCIONARIO,
     N.PORCENTAGEM);  

   END T1

MSSQL Server

-- Cria tabela de funcionarios
create table Funcionarios (
   ID_Funcionario  Int,
   Nome            VARCHAR(30),
   Sobrenome       VARCHAR(70),
   Cargo           VARCHAR(30),
   Salario         Decimal(9,2));

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INT,
  PORCENTAGEM DECIMAL(9,2));

-- Cria View (Visão) do Cadastro de funcionarios
Create View CadFuncionario as
Select
  A.ID_FUNCIONARIO, A.NOME, A.SOBRENOME,
  A.CARGO, A.SALARIO, B.PORCENTAGEM
  from FUNCIONARIOS A, DESCONTO B
Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

-- Cria Trigger Ao inves de inserir sobre a View
create Trigger CADFUNC_INSERT
    ON CadFuncionario INSTEAD OF INSERT as

   BEGIN
    -- Insere dados na tabela de Funcionario
    Insert into FUNCIONARIOS
	Select
       ID_FUNCIONARIO,
       NOME,
       SOBRENOME,
       CARGO,
       SALARIO
	from inserted;

     -- Insere dados na tabela de Desconto
     Insert into DESCONTO
	 Select
       ID_FUNCIONARIO,
      PORCENTAGEM
     from inserted

   END;

C++

Classe – Arquivo .h


// CamposcppDlg.h : header file
//

#pragma once

// Inclui classe de banco de dados MFC
#include "afxdb.h"
#include "afxwin.h"

// CCamposcppDlg dialog
class CCamposcppDlg : public CDialogEx
{

public:
	CCamposcppDlg(CWnd* pParent = NULL);	// standard constructor

// Dialog Data
	enum { IDD = IDD_CAMPOSCPP_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support

// Implementation
protected:
	HICON m_hIcon;

	// Generated message map functions
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:

	// Cria métodos e objetos da classe
	CDatabase db;

	// Esta variavel define o banco de dados
	// oracle = Oracle Database
	// db2 = IBM DB2
	// mssql = MSSQL Server
	CString m_db = L"oracle";

	// Conecta ao banco de dados
	void conectarDB(CString banco);

	// Variaveis Edits
	CEdit m_pesquisa;
	CEdit m_codigo;
	CEdit m_pnome;
	CEdit m_snome;
	CEdit m_cargo;
	CEdit m_salario;
	CEdit m_porcentagem;

	// Variaveis Botões
	CButton m_apagar;
	CButton m_novo;

	// Eventos
	afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
	afx_msg void OnBnClickedButton1();
	afx_msg void OnBnClickedButton2();
	afx_msg void OnBnClickedButton3();
	afx_msg void OnBnClickedButton4();
	afx_msg void OnBnClickedButton5();
	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);

};

Classe – Arquivo .cpp


// CamposcppDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Camposcpp.h"
#include "CamposcppDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CCamposcppDlg::CCamposcppDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CCamposcppDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CCamposcppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT6, m_pesquisa);
	DDX_Control(pDX, IDC_EDIT1, m_codigo);
	DDX_Control(pDX, IDC_EDIT2, m_pnome);
	DDX_Control(pDX, IDC_EDIT3, m_snome);
	DDX_Control(pDX, IDC_EDIT4, m_cargo);
	DDX_Control(pDX, IDC_EDIT5, m_salario);
	DDX_Control(pDX, IDC_BUTTON5, m_apagar);
	DDX_Control(pDX, IDC_BUTTON2, m_novo);
	DDX_Control(pDX, IDC_EDIT7, m_porcentagem);
}

BEGIN_MESSAGE_MAP(CCamposcppDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, &CCamposcppDlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CCamposcppDlg::OnBnClickedButton2)

ON_WM_SHOWWINDOW()
ON_BN_CLICKED(IDC_BUTTON3, &CCamposcppDlg::OnBnClickedButton3)
ON_BN_CLICKED(IDC_BUTTON4, &CCamposcppDlg::OnBnClickedButton4)
ON_BN_CLICKED(IDC_BUTTON5, &CCamposcppDlg::OnBnClickedButton5)
ON_WM_CTLCOLOR()
END_MESSAGE_MAP()

BOOL CCamposcppDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	SetIcon(m_hIcon, TRUE);
	SetIcon(m_hIcon, FALSE);
	return TRUE;
}

void CCamposcppDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); 

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

HCURSOR CCamposcppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

// ************************         Desenvolvimento Aberto
// Nosso código começa aqui

void CCamposcppDlg::conectarDB(CString banco)
{
	// Cria string de conexão
	CString dns, usuario, senha;

	// Define banco de dados
	if (banco == "oracle")
	{
		dns = L"OracleXE";
		usuario = L"daberto";
		senha = L"p@55w0rd";
	}

	if (banco == "db2")
	{
		dns = L"IBMDB2";
		usuario = L"db2admin";
		senha = L"p@55w0rd";
	}

	if (banco == "mssql")
	{
		dns = L"MSSQLSERVER";
		usuario = L"devaberto";
		senha = L"p@55w0rd";
	}

	// Cria string de conexão ODBC
	CString conexao;

	// Cria string de conexão
	conexao = L"DSN=" + dns + L";UID=" + usuario + L";PWD=" + senha;

	// Abre conexão
	db.OpenEx(conexao, 0);
}

void CCamposcppDlg::OnBnClickedButton1()
{
	// Define variaveis
	CString codigo;
	CString m_campo;

	// Referincia objeto statico
	CWnd * p_rotulo;

	// Associa objeto statico
	p_rotulo = GetDlgItem(IDC_Rotulo);
	p_rotulo->SetWindowTextW(L"Database - Cadastro Funcionários - " + m_db);

	// Conecta ao banco de dados
	conectarDB(m_db);

	// Cria um set de dados
	CRecordset  dados(&db);

	// Cria pesquisa
	m_pesquisa.GetWindowTextW(codigo);

	dados.Open(CRecordset::forwardOnly,
		L"Select * From CadFuncionario Where  ID_FUNCIONARIO = " + codigo);

	// Retorna dados por nome de campo e os exibe
	// Oracle e o DB2 transformam os nomes de campos para maiusculo,
	// basta efetuar um select na tabela de cada banco e você verá
	// O MSSQL não faz esta mudança sendo assim você precisa mudar os campos
	// do banco de dados MSSQL para que fique compativel com o ORACLE e DB2 ou
	// encontrará um erro ao tentar utilizar a tabela que criamos anteriormente.

	dados.GetFieldValue(L"ID_FUNCIONARIO", m_campo);
	m_codigo.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"NOME", m_campo);
	m_pnome.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"SOBRENOME", m_campo);
	m_snome.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"CARGO", m_campo);
	m_cargo.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"SALARIO", m_campo);
	m_salario.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"PORCENTAGEM", m_campo);
	m_porcentagem.SetWindowTextW(m_campo);

	// Fecha o set de dados e a conexão
	dados.Close();
	db.Close();

}

void CCamposcppDlg::OnBnClickedButton2()
{
	// Limpa componentes
	m_codigo.SetWindowTextW(NULL);
	m_pnome.SetWindowTextW(NULL);
	m_snome.SetWindowTextW(NULL);
	m_cargo.SetWindowTextW(NULL);
	m_salario.SetWindowTextW(NULL);
	m_porcentagem.SetWindowTextW(NULL);

	// Define foco
	CEdit* pesquisa;
	pesquisa = (CEdit*)GetDlgItem(IDC_EDIT1);
	GotoDlgCtrl(pesquisa);

}

void CCamposcppDlg::OnShowWindow(BOOL bShow, UINT nStatus)
{
	CDialogEx::OnShowWindow(bShow, nStatus);

	// Define foco inicial
	CEdit* pesquisa;
	pesquisa = (CEdit*)GetDlgItem(IDC_EDIT6);
	GotoDlgCtrl(pesquisa);
}

// Cria método de menssagem
int menssagem(bool correto, LPCWSTR texto)
{
	LPCWSTR msg;

	if (correto)
	{
		msg = texto;
	}
	else
	{
		msg = texto;
	}

	// Cria nova caixa de menssagens
	int msgboxID = MessageBox(
		NULL,
		msg,
		(LPCWSTR)L"Conexão",
		MB_ICONWARNING | MB_OK | MB_DEFBUTTON2
		);

	switch (msgboxID)
	{
	case IDOK:

		break;
	}

	return msgboxID;
}

// Clique do botão inserir
void CCamposcppDlg::OnBnClickedButton3()
{
	// Define variaveis para componentes
	CString codigo;
	CString pnome;
	CString snome;
	CString cargo;
	CString salario;
	CString porcentagem;

	// conecta ao banco de dados
	conectarDB(m_db);

	// Recupara texto dos componentes
	m_codigo.GetWindowTextW(codigo);
	m_pnome.GetWindowTextW(pnome);
	m_snome.GetWindowTextW(snome);
	m_cargo.GetWindowTextW(cargo);
	m_salario.GetWindowTextW(salario);
	m_porcentagem.GetWindowTextW(porcentagem);

	// Troca ponto decimal para o banco de dados
	int i = salario.Replace(L",", L".");

	// Cria instrução SQL
	CString sql = L"Insert into  CadFuncionario  values ( " +  codigo + ", " +
		"'" + pnome + "', " +
		"'" + snome + "', " +
		"'" + cargo + "', " +
		      salario  + ", " +
		      porcentagem + ")";

	// Executa SQL
	try
	{
		db.ExecuteSQL(sql);
		menssagem(true, L"Dados inseridos com sucesso!");
		db.Close();
	}
	catch (CDBException* pe)
	{
		menssagem(false, L"Erro ao inserir dados.");
		db.Close();
	}	

}

// botão Updata
void CCamposcppDlg::OnBnClickedButton4()
{
	// TODO: Criar Trigger INSTEAD OF UPDATE
}

void CCamposcppDlg::OnBnClickedButton5()
{
	// TODO: Criar Trigger INSTEAD OF DELETE
}

HBRUSH CCamposcppDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);

	// Seleciona controle no dialogo e muda sua cor
	if (pWnd->GetDlgCtrlID() == IDC_Porcentagem)
	{
		// RGB - Vermelho
		pDC->SetTextColor(RGB(255, 0, 0));
		pDC->SetBkMode(TRANSPARENT);
	}

	return hbr;
}

Uma Function em um banco de dados é muito similar a uma função em uma linguagem de programação comum, podendo até mesmo ser criada com uma linguagem de programação como Java, para os bancos de dados Oracle e IBM DB2 ou uma rotina CLR para o banco de dados MSSQL, entretanto possuem varias diferenças entre os diferentes bancos de dados.

Uma Function padrão pode ser do tipo Escalar que normalmente retorna um valor ou pode ser do tipo Tabela, que retorna uma tabela, porem dependendo do banco de dados utilizado, podem existir vários outros tipos de retornos ou também de funções, por este motivo é recomendado que você acesse os links oficiais a seguir para saber mais detalhes sobre as funções:

Oracle: Create Function

IBM DB2: Create Function

Microsoft SQL ServerCreate Function

O programa abaixo é muito similar ao programa anterior que cria uma trigger, porem o calculo do campo SLIQUIDO é efetuado através de uma função do mesmo nome, na query que retorna o set de dados para a grade, você pode notar que esta função possui uma sintaxe muito semelhante as funções ou métodos do qual você já está acostumado, exceto pelo banco de dados MSSQL que necessita que o proprietário da função seja declarado antes do nome da função.

Function - C++

Function – C++

Visual Studio

Para efetuar as conexões com os diferentes bancos de dados você precisa primeiro configurar os drivers ODBC necessários no sistema operacional, depois você pode criar um design com 3 componentes RadioButton, 2 componentes Static Texts, 2 componentes Text Control, um componente Button e um componente CListControl,  você encontra um walkthrough de como configurar os drivers ODBC na categoria SQL e C++ deste site, use a figura abaixo para referencia do design:

Visual C++ - Design Time

Visual C++ – Design Time

Exemplo:

Neste exemplo utilizamos uma simples função escalar para efetuar um calculo e retornar um valor, utilize o script abaixo para criar os objetos necessários para cada banco de dados ou o banco de dados da sua preferencia.

SQL

Oracle

create table Funcionarios(
  ID_Funcionario  NUMBER(5),
  Nome            VARCHAR2(30),
  Sobrenome       VARCHAR2(70),
  Cargo           VARCHAR2(30),
  Salario         NUMBER(9,2));

-- Cria Funcionarios
Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO NUMBER,
  PORCENTAGEM NUMBER(9,2));

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO NUMBER,
  DATA_LANC  DATE,
  VDESCONTO NUMBER(9,2));

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto;
delete from salario;

-- Cria trigger na tabela Desconto
create or replace TRIGGER DESCONTO_INSERT
   BEFORE INSERT ON DESCONTO
   FOR EACH ROW

   -- Declara variáveis
   DECLARE pID NUMBER;
           pSalario NUMBER(9,2);
           pPorcentagem NUMBER(9,2);
   BEGIN   

    -- Alimenta variáveis com os valores a serem inseridos
    pID := :new.ID_FUNCIONARIO;
    pPorcentagem := :new.PORCENTAGEM;

    -- Seleciona Salario do funcionario corrente
    Select SALARIO INTO pSalario FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             pID,
             SYSDATE,
             (pSalario * pPorcentagem)/100);

   END DESCONTO_INSERT;

-- Cria Função
Create or replace function
    sLiquido(sal IN NUMBER, vdesc IN NUMBER)
    RETURN NUMBER IS resultado NUMBER (9,2);
  BEGIN
    resultado := sal - vdesc;
    return (resultado);
  END;

DB2

create table Funcionarios (
    ID_Funcionario  INTEGER,
    Nome            VARCHAR(30),
    Sobrenome       VARCHAR(70),
    Cargo           VARCHAR(30),
    Salario         NUMERIC(9,2))@

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56)@
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71)@
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21)@

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INTEGER,
  PORCENTAGEM DECIMAL(9,2))@

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INTEGER,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2))@

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto@
delete from salario@

-- Cria trigger na tabela Desconto
create TRIGGER DESCONTO_INSERT
   BEFORE INSERT ON DESCONTO
   REFERENCING NEW AS N
   FOR EACH ROW

 P1:  BEGIN

   -- Declara variáveis
   DECLARE pID NUMBER;
   DECLARE pSalario DECIMAL(9,2);
   DECLARE pPorcentagem DECIMAL(9,2);

    -- Alimenta variáveis com os valores a serem inseridos
    SET pID = N.ID_FUNCIONARIO;
    SET pPorcentagem = N.PORCENTAGEM;

    -- Seleciona Salario do funcionario corrente
    Select SALARIO INTO pSalario FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             pID,
             SYSDATE,
             (pSalario * pPorcentagem)/100);

   END P1

-- Cria Função
CREATE FUNCTION sLiquido (sal Decimal, vdesc Decimal)
	RETURNS  DECIMAL (9,2)
	NO EXTERNAL ACTION

F1: BEGIN ATOMIC

	DECLARE resultado DECIMAL(9,2);
	SET resultado = sal - vdesc;
	RETURN resultado;  	

END

MSSQL

create table Funcionarios (
   ID_Funcionario  Int,
   Nome            VARCHAR(30),
   Sobrenome       VARCHAR(70),
   Cargo           VARCHAR(30),
   Salario         Decimal(9,2));

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INT,
  PORCENTAGEM DECIMAL(9,2));

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INT,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2));

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto;
delete from salario;

-- Cria trigger na tabela Desconto
create TRIGGER DESCONTO_INSERT ON
  DESCONTO AFTER INSERT AS      

   BEGIN
   -- Declara variáveis
   DECLARE @pID Int,
           @pSalario DECIMAL(9,2),
           @pPorcentagem DECIMAL(9,2); 

    -- Alimenta variáveis com os valores a serem inseridos
	Select @pID = ID_FUNCIONARIO,
	       @pPorcentagem = PORCENTAGEM
    from inserted;

    -- Seleciona Salario do funcionario corrente
    Select  @pSalario = SALARIO FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = @pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             @pID,
             GETDATE(),
             (@pSalario * @pPorcentagem)/100);

   END;

-- Cria função
Create function sLiquido(@sal decimal, @vdesc decimal)
Returns decimal(9,2) as
Begin
  return(@sal-@vdesc);
end

C++

Classe – Arquivo .h

// Classe gerada automaticamente
// AcessocppDlg.h : header file
//

#pragma once

// Inclui classe de banco de dados MFC
#include "afxdb.h"
#include "afxcmn.h"
#include "afxwin.h"

class CAcessocppDlg : public CDialogEx
{

public:
	CAcessocppDlg(CWnd* pParent = NULL);	// standard constructor

	enum { IDD = IDD_ACESSOCPP_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support

protected:
	HICON m_hIcon;

	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:

	// Cria métodos e objetos da classe
	CDatabase db;
	CString bancodedados;
	void conectarDB(CString dns, CString usuario, CString senha);

	afx_msg void OnBnHotItemChangeRadio1(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnHotItemChangeRadio2(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnHotItemChangeRadio3(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnClickedButton1();
	CListCtrl m_tabela;
	CEdit m_funcionario;
	CEdit m_porcentagem;
};

Classe – Arquivo .cpp

// Código gerado automaticamente
// AcessocppDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Acessocpp.h"
#include "AcessocppDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);   

protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

CAcessocppDlg::CAcessocppDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CAcessocppDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CAcessocppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST2, m_tabela);
	DDX_Control(pDX, IDC_EDIT1, m_funcionario);
	DDX_Control(pDX, IDC_EDIT2, m_porcentagem);
}

BEGIN_MESSAGE_MAP(CAcessocppDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO1, &CAcessocppDlg::OnBnHotItemChangeRadio1)
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO2, &CAcessocppDlg::OnBnHotItemChangeRadio2)
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO3, &CAcessocppDlg::OnBnHotItemChangeRadio3)
	ON_BN_CLICKED(IDC_BUTTON1, &CAcessocppDlg::OnBnClickedButton1)
END_MESSAGE_MAP()

BOOL CAcessocppDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	SetIcon(m_hIcon, TRUE);
	SetIcon(m_hIcon, FALSE);		

	// Desenvolvimento Aberto
	// Inicializa dialogo

	// Define variavel padrão para o banco de dados
	bancodedados = "oracle";

	// Cria o modelo de exibição de dados
	m_tabela.SetView(LV_VIEW_DETAILS);
	m_tabela.SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);

	return TRUE;
}

void CAcessocppDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

void CAcessocppDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); 

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

HCURSOR CAcessocppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

// **************************
// * Desenvolvimento Aberto *
// **************************
// Nosso código começa aqui

// Seleciona banco de dados Oracle
void CAcessocppDlg::OnBnHotItemChangeRadio1(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "oracle";
	*pResult = 0;
}

// Seleciona banco de dados IBM DB2
void CAcessocppDlg::OnBnHotItemChangeRadio2(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "db2";
	*pResult = 0;
}

// Seleciona banco de dados MSSQL
void CAcessocppDlg::OnBnHotItemChangeRadio3(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "mssql";
	*pResult = 0;
}

// Evento de clique do botão
void CAcessocppDlg::OnBnClickedButton1()
{
	// campo de dado da tabela
	CString m_campo;

	// Abre conexão
	if (bancodedados == "oracle")
	{
		conectarDB(L"OracleXE", L"daberto", L"p@55w0rd");
	}

	if (bancodedados == "db2")
	{
		conectarDB(L"IBMDB2", L"db2admin", L"p@55w0rd");
	}

	if (bancodedados == "mssql")
	{
		conectarDB(L"MSSQLSERVER", L"devaberto", L"p@55w0rd");
	}

	// Cria um set de dados
	CRecordset  dados(&db);

	// Cria variáveis de entrada
	CString m_func;
	CString m_porc;

	// Recupera valor de entrada
	m_funcionario.GetWindowTextW(m_func);
	m_porcentagem.GetWindowTextW(m_porc);

	// Cria instrução SQL para disparar a trigger
	CString sqltrigger = L"insert into DESCONTO VALUES (" + m_func + ", " + m_porc + ")";

	// Executa instrução SQL
    db.ExecuteSQL(sqltrigger);

	// Cria proprietario do banco de dados
	CString owner = L"dbo.";

	// SQL Server requer o proprietario para que a função seja executada
	if (bancodedados != "mssql") owner = "";

	// Verfica banco de dados e passa script SQL
	CString sql = CString("Select A.ID_FUNCIONARIO, A.NOME, A.CARGO, ")
				+ CString(" A.SALARIO, B.PORCENTAGEM,C.VDESCONTO, ")
				+ CString("C.DATA_LANC,  ") + owner
				// Executa função SLIQUIDO - retorna o calculo do salario liquido.
				+ CString("SLIQUIDO(A.SALARIO, C.VDESCONTO) AS SLIQUIDO ")
				+ CString("from FUNCIONARIOS A, DESCONTO B, SALARIO C Where ")
				+ CString("A.ID_FUNCIONARIO = B.ID_FUNCIONARIO  AND ")
				+ CString("A.ID_FUNCIONARIO = C.ID_FUNCIONARIO ")
				+ CString("Order by 1 desc");

	// Abre set de dados
	dados.Open(CRecordset::forwardOnly, sql);

	// Cria item
	LVITEM lvItem;

	// cria estrutura para inserir o item
	typedef struct _LVITEM
	{
		UINT mask;
		int iItem;
		int iSubItem;
		UINT state;
		UINT stateMask;
		LPTSTR pszText;
		int cchTextMax;
		int iImage;
		LPARAM lParam;
        #if (_WIN32_IE >= 0x0300)
		  int iIndent;
        #endif
	 } LVITEM, FAR *LPLVITEM;

	// Define variaveis de itens
	int InsertItem(const LVITEM* pItem);
	int nItem;

	// Converte CString para LPTSTR atraves de um TCHAR
	TCHAR sz[1024];

	// Verifica colunas
	short nFields = dados.GetODBCFieldCount();
	int colunas = m_tabela.GetHeaderCtrl()->GetItemCount();

	// Verifica colunas
	if (colunas == 0)
	{
		// Lê metadata da tabela
		CODBCFieldInfo field;
		for (UINT i = 0; i < nFields; i ++)
		{
			dados.GetODBCFieldInfo(i, field);
			m_tabela.InsertColumn(i, field.m_strName, LVCFMT_LEFT, 100);
		}

	}

	// Deleta itens do controle de lista
	m_tabela.DeleteAllItems();

	// Recupera dados da tabela
	while (!dados.IsEOF())
	{
		for (short index = 0; index < nFields; index++)
		{
			dados.GetFieldValue(index, m_campo);

			// Retorna linha do banco de dados
			if (index == 0)
			{
				// Insere linha
				lvItem.mask = LVIF_TEXT;
				lvItem.iItem = 0;
				lvItem.iSubItem = 0;
				lvItem.pszText = lstrcpy(sz, m_campo);
				nItem = m_tabela.InsertItem(&lvItem);
			}

			// Retorna colunas da linha
			m_tabela.SetItemText(nItem, index, lstrcpy(sz, m_campo));

		}
		// Move o cursor para a proxima linha
		dados.MoveNext();
	}

	// Fecha o set de dados e a conexão
	dados.Close();
	db.Close();

}

void CAcessocppDlg::conectarDB(CString dns, CString usuario, CString senha)
{
	// Cria string de conexão ODBC
	CString conexao;

	// Cria string de conexão
	conexao = L"DSN=" + dns + L";UID=" + usuario + L";PWD=" + senha;

	// Abre conexão
	db.OpenEx(conexao, 0);
}

Uma Trigger ou gatilho é um tipo especial de procedimento armazenado (Stored Procedure) que executa automaticamente quando um evento ocorre no servidor de banco de dados. Gatilhos DML executam quando um usuário tenta modificar dados através de uma linguagem de manipulação de dados (DML). Eventos DML são INSERT, UPDATE, ou DELETE em uma tabela ou exibição. Esses gatilhos disparam quando qualquer evento válido é acionado, independentemente de haver ou não linhas da tabela afetadas.

As Triggers possuem muitas diferenças de sintaxe e funcionalidades de um banco de dados para outro, por exemplo Trigger que dispara o evento INSTEAD OF INSERT (ao invés de inserir) no banco de dados Oracle só pode ser declarada sobre uma VIEW enquanto em MSSQL Server pode ser declarada em uma tabela comum, o evento BEFORE INSERT (antes de inserir) existe nos bancos de dados Oracle e IBM DB2, mas não existe no MSSQL. Por este motivo é recomendado que você procure os links oficiais para saber mais detalhes sobre as Triggers.

Triggers - C++

Triggers – C++

Algo extremamente útil que você deve saber sobre Triggers

As Triggers foram regulamentadas na revisão da língua SQL em 1999 e passou a ser padrão em banco de dados relacionais, no entanto alguns bancos de dados vem atualizando estes recursos regularmente, por exemplo o Oracle utiliza Triggers que disparam por esquema (Schema-level triggers) desde a sua versão 9i, enquanto o MSSQL suporta trigger do tipo DDL, ou logon trigger apenas desde a versão 2008.

Muitos sistemas de grande porte como SAP e vários outros não utilizam triggers, principalmente sistemas que no qual rodam em diversos bancos de dados, estas são consideradas verdadeiras armadilhas por muitos DBAs, podem ser facilmente esquecidas na hora de alterações e se tornarem invalidas (Oracle), gerando assim muitos erros caso não haja uma boa politica de desenvolvimento e qualidade (testes unitários e integrados) antes de colocar as rotinas do sistema em produção. Mesmo as IDEs de estudios SQL já mudaram varias vezes a localização do node de triggers ao longo de suas versões para tentar facilitar a manutenção das mesmas, aqui veremos como exemplo a IDE do IBM Data Studio que possui um wizard especifico para triggers.

As Triggers também devem ser desenvolvidas com cuidado sempre seguindo as melhores praticas, pois o desenvolvimento SQL é muito abrangentes e cheio de recursos, então é fácil extrapolar e criar triggers contendo cursores, stored procedures, rollbacks, acessos repetitivos, outras triggers, lembre-se da lei de Murphy, tudo que não pode ser escrito em uma trigger, será e isto reduz sensivelmente a performance de um sistema, sem contar com a complexidade do desenvolvimento, transformado seu desenvolvimento SQL em verdadeiros planos da ACME, lembre-se do coite que tentava incessantemente capturar o papa-léguas.

Cuidado com as Triggers

Cuidado com as Triggers

Nunca use Triggers para criar campos auto incremento para os códigos (ID), os bancos de dados possuem recursos específicos para este trabalho, o uso de triggers somente criará acessos e UPDATES desnecessários no banco de dados, além de reduzir a performance, imagine importar 10.000 linhas utilizando um Insert…Select, à partir de uma outra tabela ou arquivos externos, você efetuara um Select e um Update para cada registro se utilizar triggers, enquanto os bancos de dados contam com seus campos auto incremento que já nos permitem utilizar dados em massa e inserir as 10.000 linhas em um único acesso.

As Triggers também são um alto risco a segurança, é possível escalar privilégios e se tornar proprietário do banco de dados e do servidor SQL caso você insira um código mal intencionado em uma Trigger, exemplo: suponha que o usuário Jõao da Silva tenha diretos de Administrador do banco de dados,  se um desenvolvedor mal intencionado criar uma trigger DDL sobre o evento DELETE de uma tabela qualquer utilizando por exemplo a instrução: GRANT CONTROL SERVER TO BadUser; Quando o usuário João da Silva executar o procedimento que dispara a trigger o Grant será delegado ao usuário mal intencionado e os direitos aplicados a ele, enquanto ele mesmo não teria acesso para delegar tal direito, deste modo possibilitando que o desenvolvedor mal intencionado tome conta do servidor SQL, podendo fazer o que bem entender com os dados.

Security: http://msdn.microsoft.com/pt-br/library/ms191134.aspx

Visual Studio

Para efetuar as conexões com os diferentes bancos de dados você precisa primeiro configurar os drivers ODBC necessários no sistema operacional, depois você pode criar um design com 3 componentes RadioButton, 2 componentes Static Texts, 2 componentes Text Control, um componente Button e um componente CListControl,  você encontra um walkthrough de como configurar os drivers ODBC na categoria SQL e C++ deste site, use a figura abaixo para referencia do design:

C++ - Design Time

C++ – Design Time

IBM Data Studio

O IBM Data Studio possui uma funcionalidade especifica para criar triggers (Wizard), assim como possui para Stored Procedures e Function no qual necessitam de executar um Deploy antes de ser executada. Portanto você não poderá criar a Trigger utilizando a configuração Default do editor SQL comum, para isto você precisa mudar a configuração do terminador de instrução de ponto e virgula (;) para arroba(@), basta clicar com o botão direito do mouse e escolher a opção: Configurar Terminador de Instrução. Utilize a figura abaixo para referencia:

IBM Data Studio - Configuração

IBM Data Studio – Configuração

Exemplo:

Neste exemplo criamos uma funcionalidade similar do nosso exemplo anterior (Cursor), utilizando a mesma modelagem de dados, porem para executar este procedimento as tabelas DESCONTO e SALARIO devem estar vazias, o usuário entrará com o código do funcionário e a porcentagem do desconto e a trigger sobre a tabela DESCONTO se encarregara de criar o lançamento na tabela de SALARIO.

SQL

Oracle

create table Funcionarios(
  ID_Funcionario  NUMBER(5),
  Nome            VARCHAR2(30),
  Sobrenome       VARCHAR2(70),
  Cargo           VARCHAR2(30),
  Salario         NUMBER(9,2));

-- Cria Funcionarios
Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO NUMBER,
  PORCENTAGEM NUMBER(9,2));

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO NUMBER,
  DATA_LANC  DATE,
  VDESCONTO NUMBER(9,2));

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto;
delete from salario;

-- Cria trigger na tabela Desconto
create or replace TRIGGER DESCONTO_INSERT
   BEFORE INSERT ON DESCONTO
   FOR EACH ROW

   -- Declara variáveis
   DECLARE pID NUMBER;
           pSalario NUMBER(9,2);
           pPorcentagem NUMBER(9,2);
   BEGIN   

    -- Alimenta variáveis com os valores a serem inseridos
    pID := :new.ID_FUNCIONARIO;
    pPorcentagem := :new.PORCENTAGEM;

    -- Seleciona Salario do funcionario corrente
    Select SALARIO INTO pSalario FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             pID,
             SYSDATE,
             (pSalario * pPorcentagem)/100);

   END DESCONTO_INSERT;

DB2

create table Funcionarios (
    ID_Funcionario  INTEGER,
    Nome            VARCHAR(30),
    Sobrenome       VARCHAR(70),
    Cargo           VARCHAR(30),
    Salario         NUMERIC(9,2))@

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56)@
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71)@
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21)@

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INTEGER,
  PORCENTAGEM DECIMAL(9,2))@

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INTEGER,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2))@

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto@
delete from salario@

-- Cria trigger na tabela Desconto
create TRIGGER DESCONTO_INSERT
   BEFORE INSERT ON DESCONTO
   REFERENCING NEW AS N
   FOR EACH ROW

 P1:  BEGIN

   -- Declara variáveis
   DECLARE pID NUMBER;
   DECLARE pSalario DECIMAL(9,2);
   DECLARE pPorcentagem DECIMAL(9,2);

    -- Alimenta variáveis com os valores a serem inseridos
    SET pID = N.ID_FUNCIONARIO;
    SET pPorcentagem = N.PORCENTAGEM;

    -- Seleciona Salario do funcionario corrente
    Select SALARIO INTO pSalario FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             pID,
             SYSDATE,
             (pSalario * pPorcentagem)/100);

   END P1

MSSQL

create table Funcionarios (
   ID_Funcionario  Int,
   Nome            VARCHAR(30),
   Sobrenome       VARCHAR(70),
   Cargo           VARCHAR(30),
   Salario         Decimal(9,2));

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INT,
  PORCENTAGEM DECIMAL(9,2));

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INT,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2));

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto;
delete from salario;

-- Cria trigger na tabela Desconto
create TRIGGER DESCONTO_INSERT ON
  DESCONTO AFTER INSERT AS      

   BEGIN
   -- Declara variáveis
   DECLARE @pID Int,
           @pSalario DECIMAL(9,2),
           @pPorcentagem DECIMAL(9,2); 

    -- Alimenta variáveis com os valores a serem inseridos
	Select @pID = ID_FUNCIONARIO,
	       @pPorcentagem = PORCENTAGEM
    from inserted;

    -- Seleciona Salario do funcionario corrente
    Select  @pSalario = SALARIO FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = @pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             @pID,
             GETDATE(),
             (@pSalario * @pPorcentagem)/100);

   END;

C++

Classe – AcessocppDlg.h

// Classe gerada automaticamente
// AcessocppDlg.h : header file
//

#pragma once

// Inclui classe de banco de dados MFC
#include "afxdb.h"
#include "afxcmn.h"
#include "afxwin.h"

class CAcessocppDlg : public CDialogEx
{

public:
	CAcessocppDlg(CWnd* pParent = NULL);	// standard constructor

	enum { IDD = IDD_ACESSOCPP_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support

protected:
	HICON m_hIcon;

	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:

	// Cria métodos e objetos da classe
	CDatabase db;
	CString bancodedados;
	void conectarDB(CString dns, CString usuario, CString senha);

	afx_msg void OnBnHotItemChangeRadio1(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnHotItemChangeRadio2(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnHotItemChangeRadio3(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnClickedButton1();
	CListCtrl m_tabela;
	CEdit m_funcionario;
	CEdit m_porcentagem;
};

Classe – AcessocppDlg.cpp

// Código gerado automaticamente
// AcessocppDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Acessocpp.h"
#include "AcessocppDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);   

protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

CAcessocppDlg::CAcessocppDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CAcessocppDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CAcessocppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST2, m_tabela);
	DDX_Control(pDX, IDC_EDIT1, m_funcionario);
	DDX_Control(pDX, IDC_EDIT2, m_porcentagem);
}

BEGIN_MESSAGE_MAP(CAcessocppDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO1, &CAcessocppDlg::OnBnHotItemChangeRadio1)
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO2, &CAcessocppDlg::OnBnHotItemChangeRadio2)
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO3, &CAcessocppDlg::OnBnHotItemChangeRadio3)
	ON_BN_CLICKED(IDC_BUTTON1, &CAcessocppDlg::OnBnClickedButton1)
END_MESSAGE_MAP()

BOOL CAcessocppDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	SetIcon(m_hIcon, TRUE);
	SetIcon(m_hIcon, FALSE);		

	// Desenvolvimento Aberto
	// Inicializa dialogo

	// Define variavel padrão para o banco de dados
	bancodedados = "oracle";

	// Cria o modelo de exibição de dados
	m_tabela.SetView(LV_VIEW_DETAILS);
	m_tabela.SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);

	return TRUE;
}

void CAcessocppDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

void CAcessocppDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); 

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

HCURSOR CAcessocppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

// **************************
// * Desenvolvimento Aberto *
// **************************
// Nosso código começa aqui

// Seleciona banco de dados Oracle
void CAcessocppDlg::OnBnHotItemChangeRadio1(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "oracle";
	*pResult = 0;
}

// Seleciona banco de dados IBM DB2
void CAcessocppDlg::OnBnHotItemChangeRadio2(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "db2";
	*pResult = 0;
}

// Seleciona banco de dados MSSQL
void CAcessocppDlg::OnBnHotItemChangeRadio3(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "mssql";
	*pResult = 0;
}

// Evento de clique do botão
void CAcessocppDlg::OnBnClickedButton1()
{
	// campo de dado da tabela
	CString m_campo;

	// Abre conexão
	if (bancodedados == "oracle")
	{
		conectarDB(L"OracleXE", L"daberto", L"p@55w0rd");
	}

	if (bancodedados == "db2")
	{
		conectarDB(L"IBMDB2", L"db2admin", L"p@55w0rd");
	}

	if (bancodedados == "mssql")
	{
		conectarDB(L"MSSQLSERVER", L"devaberto", L"p@55w0rd");
	}

	// Cria um set de dados
	CRecordset  dados(&db);

	// Cria variáveis de entrada
	CString m_func;
	CString m_porc;

	// Recupera valor de entrada
	m_funcionario.GetWindowTextW(m_func);
	m_porcentagem.GetWindowTextW(m_porc);

	// Cria instrução SQL para disparar a trigger
	CString sqltrigger = L"insert into DESCONTO VALUES (" + m_func + ", " + m_porc + ")";

	// Executa instrução SQL
    db.ExecuteSQL(sqltrigger);

	CString sql = L"Select A.ID_FUNCIONARIO, A.NOME, A.CARGO, A.SALARIO, B.PORCENTAGEM, C.VDESCONTO, C.DATA_LANC, A.SALARIO - C.VDESCONTO AS SLIQUIDO from FUNCIONARIOS A, DESCONTO B, SALARIO C Where A.ID_FUNCIONARIO = B.ID_FUNCIONARIO  AND A.ID_FUNCIONARIO = C.ID_FUNCIONARIO";

	dados.Open(CRecordset::forwardOnly, sql);

	// Cria item
	LVITEM lvItem;

	// cria estrutura para inserir o item
	typedef struct _LVITEM
	{
		UINT mask;
		int iItem;
		int iSubItem;
		UINT state;
		UINT stateMask;
		LPTSTR pszText;
		int cchTextMax;
		int iImage;
		LPARAM lParam;
        #if (_WIN32_IE >= 0x0300)
		  int iIndent;
        #endif
	 } LVITEM, FAR *LPLVITEM;

	// Define variaveis de itens
	int InsertItem(const LVITEM* pItem);
	int nItem;

	// Converte CString para LPTSTR atraves de um TCHAR
	TCHAR sz[1024];

	// Verifica colunas
	short nFields = dados.GetODBCFieldCount();
	int colunas = m_tabela.GetHeaderCtrl()->GetItemCount();

	// Verifica colunas
	if (colunas == 0)
	{
		// Lê metadata da tabela
		CODBCFieldInfo field;
		for (UINT i = 0; i < nFields; i ++)
		{
			dados.GetODBCFieldInfo(i, field);
			m_tabela.InsertColumn(i, field.m_strName, LVCFMT_LEFT, 100);
		}

	}

	// Deleta itens do controle de lista
	m_tabela.DeleteAllItems();

	// Recupera dados da tabela
	while (!dados.IsEOF())
	{
		for (short index = 0; index < nFields; index++)
		{
			dados.GetFieldValue(index, m_campo);

			// Retorna linha do banco de dados
			if (index == 0)
			{
				// Insere linha
				lvItem.mask = LVIF_TEXT;
				lvItem.iItem = 0;
				lvItem.iSubItem = 0;
				lvItem.pszText = lstrcpy(sz, m_campo);
				nItem = m_tabela.InsertItem(&lvItem);
			}

			// Retorna colunas da linha
			m_tabela.SetItemText(nItem, index, lstrcpy(sz, m_campo));

		}
		// Move o cursor para a proxima linha
		dados.MoveNext();
	}

	// Fecha o set de dados e a conexão
	dados.Close();
	db.Close();

}

void CAcessocppDlg::conectarDB(CString dns, CString usuario, CString senha)
{
	// Cria string de conexão ODBC
	CString conexao;

	// Cria string de conexão
	conexao = L"DSN=" + dns + L";UID=" + usuario + L";PWD=" + senha;

	// Abre conexão
	db.OpenEx(conexao, 0);
}

A linguagem de banco de dados SQL permite que você retorne um resultado de dados completo de uma única vez, mas as vezes precisamos manipular este resultado em tempo de execução, uma linha de cada vez, deste modo podemos utilizar um recurso chamado Cursor para realizar este procedimento.

Basicamente todos os bancos de dados possuem este recurso, entretanto cada um deles possui também suas peculiaridades e funcionalidades diferenciadas, mas no geral funcionam da seguinte maneira: a instrução DECLARE CURSOR define os atributos de um cursor do servidor SQL, como o seu comportamento de rolagem e a consulta usada para construir o conjunto de resultados no qual o cursor funciona. A instrução OPEN popula o conjunto de resultados e FETCH retorna uma linha do conjunto de resultados. A instrução CLOSE libera o conjunto de resultados atual associado ao cursor. A declaração DEALLOCATE libera os recursos usados ​​pelo cursor.

Cursor - C++

Cursor – C++

Preparando o Banco de dados

Utilizaremos uma modelagem básica contendo três tabelas básicas sem chave primaria, sem chave estrangeira, permitido assim que nosso exemplo possua dados duplicados,  basicamente utilizaremos apenas a logica relacional para brincar com os dados utilizando uma Stored procedure contendo um cursor.

Relacionamentos

A tabela de FUNCIONARIOS contem dados de cadastro e o salario de cada funcionário, a tabela DESCONTO possui os valores de porcentagens de desconto para cada funcionário, e a tabela SALARIO contem os lançamentos de salários e deve ser alimentada mês a mês para cada funcionário.  Utilize os Scripts abaixo para criar as tabelas e os dados iniciais.

Visual Studio

Para efetuar as conexões com os diferentes bancos de dados você precisa primeiro configurar os drivers ODBC necessários no sistema operacional, depois você pode criar um design com 3 componentes RadioButton, um componente Button e um componente CListControl,  você encontra um walkthrough de como configurar os drivers ODBC na categoria SQL e C++ deste site, use a figura abaixo para referencia do design:

Visual Studio - DesignTime - Cpp

Visual Studio – Design Time – Cpp

 

Algo Extremamente Útil  Sobre Cursores

Cursores são mais rápidos do que os looping efetuados dentro da linguagem de programação de sua preferencia, funcionam basicamente da mesma maneira, porem residem no motor do banco de dados dentro de uma Stored Procedure.

Os Cursores utilizam memoria e também necessitam de um laço para rolar registro a registro do resultado de dados e manipula-lo, é de extrema importância que você utilize cursores somente quando necessário. Caso queira que seu programa tenha uma ótima performance, antes de optar por um cursor é necessário saber que os motores dos bancos de dados são projetados para manipular dados em massa, manipulação de dados registro a registro deve ser utilizada somente quando não houver possibilidade de usar instruções SQL, para ilustrar esta explicação vamos escrever um script SQL que executa o mesmo procedimento do cursor utilizando apenas um acesso ao banco de dados, você encontra este script logo após o código C++.

Exemplo:

Neste exemplo criamos um cursor que reside dentro de uma Stored Procedure, calcula o desconto do salario dos funcionários e insere os valores líquidos em uma tabela de lançamento, após efetuar o procedimento que seria mensal, uma query exibe o relatório em uma grade de dados.

Cursor

O cursor seleciona dados da tabela de FUNCIONARIOS e da tabela de DESCONTO, através de um looping, alimenta os dados relevantes dentro de variáveis e insere os lançamentos na tabela de SALARIO efetuando o calculo do desconto.

SQL

Oracle

create table Funcionarios
(     

    ID_Funcionario  NUMBER(5),
    Nome            VARCHAR2(30),
    Sobrenome       VARCHAR2(70),
    Cargo           VARCHAR2(30),
    Salario         NUMBER(9,2)

);

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO NUMBER,
  PORCENTAGEM NUMBER(9,2));

-- Insere porcentagem por  funcionario
Insert Into DESCONTO Values (1, 5 );
Insert Into DESCONTO Values (2, 8 );

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO NUMBER,
  DATA_LANC  DATE,
  VDESCONTO NUMBER(9,2));

-- Lista lançamentos por funcionario
select * from salario;

-- Desenvolvimento Aberto - Cursor explicito
create or replace Procedure CalculoDesconto  is
-- Declara cursor
Cursor calculo is
  Select A.ID_FUNCIONARIO, A.SALARIO, B.PORCENTAGEM
  from FUNCIONARIOS A, DESCONTO B
  Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

  -- Declara variáveis
  pID NUMBER;
  pSalario NUMBER(9,2);
  pPorcentagem NUMBER(9,2);

  -- Abre cursor
  begin
    open calculo;
      -- Cria laço
      loop
        -- Alimenta variáveis
        fetch calculo into pID, pSalario, pPorcentagem;
        EXIT WHEN calculo%NOTFOUND;

        -- Insere valores da tabela
        Insert into SALARIO
        values  (
                 pID,
                 SYSDATE,
                 (pSalario * pPorcentagem)/100);

      end loop;
    -- Fecha cursor
    close calculo;  

  end;

DB2

create table Funcionarios
(     

    ID_Funcionario  INTEGER,
    Nome            VARCHAR(30),
    Sobrenome       VARCHAR(70),
    Cargo           VARCHAR(30),
    Salario         NUMERIC(9,2)

);

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INTEGER,
  PORCENTAGEM DECIMAL(9,2));

-- Insere porcentagem por  funcionario
Insert Into DESCONTO Values (1, 5 );
Insert Into DESCONTO Values (2, 8 );

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INTEGER,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2));

-- Lista lançamentos por funcionario
select * from desconto;

-- Desencolcimento Aberto - Cursor explicito
CREATE PROCEDURE calculodesconto ()
	DYNAMIC RESULT SETS 1	

P1: BEGIN

	-- Declara variáveis
	 DECLARE pID INTEGER;
	 DECLARE pSalario DECIMAL(9,2);
	 DECLARE pPorcentagem DECIMAL(9,2);
	 DECLARE eof SMALLINT DEFAULT 0;

	-- Declara cursor
	DECLARE calculo CURSOR WITH RETURN for
	Select A.ID_FUNCIONARIO, A.SALARIO, B.PORCENTAGEM
    from FUNCIONARIOS A, DESCONTO B
    Where
    A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

   -- Declara handler para final de arquivo
   DECLARE CONTINUE HANDLER FOR NOT FOUND SET eof = 1;

	-- Abre cursor
	OPEN calculo;

	-- Cria label e executa looping
	fim:
	LOOP
	  -- Alimenta valores nas variáveis
	  FETCH calculo into pID, pSalario, pPorcentagem;
	  	  IF eof <> 0 THEN LEAVE fim;
	      END IF;	  

	      -- Insere dados na tabela
	      Insert into SALARIO values (
	        pID,
	        Current date,
	        (pSalario * pPorcentagem)/100);

	END LOOP fim;
	CLOSE calculo;
END P1

Mssql

create table Funcionarios
(     

    ID_Funcionario  Int,
    Nome            VARCHAR(30),
    Sobrenome       VARCHAR(70),
    Cargo           VARCHAR(30),
    Salario         Decimal(9,2)

);

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INT,
  PORCENTAGEM DECIMAL(9,2));

-- Insere porcentagem por  funcionario
Insert Into DESCONTO Values (1, 5 );
Insert Into DESCONTO Values (2, 8 );

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INT,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2));

-- Lista lançamentos por funcionario
select * from salario;

-- Desenvolvimento Aberto - cursor explicito
Create Procedure CALCULODESCONTO
AS
BEGIN
-- Declara Variáveis
DECLARE @pID INT,
        @pSalario DECIMAL(9,2),
		@pPorcentagem DECIMAL(9,2);

-- Declara cursor
DECLARE calculo CURSOR FOR
   Select A.ID_FUNCIONARIO, A.SALARIO, B.PORCENTAGEM
   from FUNCIONARIOS A,   DESCONTO B
   Where
   A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

   -- Abre cursor
   Open calculo;

   -- Alimenta -
   FETCH NEXT FROM calculo INTO @pID, @pSalario, @pPorcentagem;

   While @@FETCH_STATUS = 0
   BEGIN
      Insert into SALARIO values (
	        @pID,
	        GETDATE(),
	        (@pSalario * @pPorcentagem)/100);

      FETCH NEXT FROM calculo INTO @pID, @pSalario, @pPorcentagem;
   END

   -- Fecha conteudo do cursor
   Close calculo;
   -- Desaloca cursor da memória
   Deallocate calculo;
END

C++
Classe: CAcessocpp

Arquivo .h

// Classe gerada automaticamente
// AcessocppDlg.h : header file
//

#pragma once

// Inclui classe de banco de dados MFC
#include "afxdb.h"
#include "afxcmn.h"

class CAcessocppDlg : public CDialogEx
{

public:
	CAcessocppDlg(CWnd* pParent = NULL);	// standard constructor

	enum { IDD = IDD_ACESSOCPP_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support

protected:
	HICON m_hIcon;

	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:

	// Cria métodos e objetos da classe
	CDatabase db;
	CString bancodedados;
	void conectarDB(CString dns, CString usuario, CString senha);

	afx_msg void OnBnHotItemChangeRadio1(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnHotItemChangeRadio2(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnHotItemChangeRadio3(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnClickedButton1();
	CListCtrl m_tabela;
};

Arquivo .cpp

// Código gerado automaticamente
// AcessocppDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Acessocpp.h"
#include "AcessocppDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);   

protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

CAcessocppDlg::CAcessocppDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CAcessocppDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CAcessocppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST2, m_tabela);
}

BEGIN_MESSAGE_MAP(CAcessocppDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO1, &CAcessocppDlg::OnBnHotItemChangeRadio1)
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO2, &CAcessocppDlg::OnBnHotItemChangeRadio2)
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO3, &CAcessocppDlg::OnBnHotItemChangeRadio3)
	ON_BN_CLICKED(IDC_BUTTON1, &CAcessocppDlg::OnBnClickedButton1)
END_MESSAGE_MAP()

BOOL CAcessocppDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	SetIcon(m_hIcon, TRUE);
	SetIcon(m_hIcon, FALSE);		

	// Desenvolvimento Aberto
	// Inicializa dialogo

	// Define variavel padrão para o banco de dados
	bancodedados = "oracle";

	// Cria o modelo de exibição de dados
	m_tabela.SetView(LV_VIEW_DETAILS);
	m_tabela.SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);

	return TRUE;
}

void CAcessocppDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

void CAcessocppDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); 

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

HCURSOR CAcessocppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

// **************************
// * Desenvolvimento Aberto *
// **************************
// Nosso código começa aqui

// Seleciona banco de dados Oracle
void CAcessocppDlg::OnBnHotItemChangeRadio1(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "oracle";
	*pResult = 0;
}

// Seleciona banco de dados IBM DB2
void CAcessocppDlg::OnBnHotItemChangeRadio2(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "db2";
	*pResult = 0;
}

// Seleciona banco de dados MSSQL
void CAcessocppDlg::OnBnHotItemChangeRadio3(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "mssql";
	*pResult = 0;
}

// Evento de clique do botão
void CAcessocppDlg::OnBnClickedButton1()
{
	// campo de dado da tabela
	CString m_campo;

	// Abre conexão - ODBC - (DNS,user,pass)
	if (bancodedados == "oracle")
	{
		conectarDB(L"OracleXE", L"user", L"p@55w0rd");
	}

	if (bancodedados == "db2")
	{
		conectarDB(L"IBMDB2", L"user", L"p@55w0rd");
	}

	if (bancodedados == "mssql")
	{
		conectarDB(L"MSSQLSERVER", L"user", L"p@55w0rd");
	}

	// Cria um set de dados
	CRecordset  dados(&db);

	if (bancodedados == "mssql")
	{
		db.ExecuteSQL(_T("EXEC CALCULODESCONTO"));
	}
	else
	{
		db.ExecuteSQL(_T("CALL CALCULODESCONTO();"));
	}

	CString sql = L"Select A.ID_FUNCIONARIO, A.NOME, A.CARGO, A.SALARIO, B.PORCENTAGEM, C.VDESCONTO, C.DATA_LANC, A.SALARIO - C.VDESCONTO AS SLIQUIDO from FUNCIONARIOS A, DESCONTO B, SALARIO C Where A.ID_FUNCIONARIO = B.ID_FUNCIONARIO  AND A.ID_FUNCIONARIO = C.ID_FUNCIONARIO";

	dados.Open(CRecordset::forwardOnly, sql);

	// Cria item
	LVITEM lvItem;

	// cria estrutura para inserir o item
	typedef struct _LVITEM
	{
		UINT mask;
		int iItem;
		int iSubItem;
		UINT state;
		UINT stateMask;
		LPTSTR pszText;
		int cchTextMax;
		int iImage;
		LPARAM lParam;
        #if (_WIN32_IE >= 0x0300)
		  int iIndent;
        #endif
	 } LVITEM, FAR *LPLVITEM;

	// Define variaveis de itens
	int InsertItem(const LVITEM* pItem);
	int nItem;

	// Converte CString para LPTSTR atraves de um TCHAR
	TCHAR sz[1024];

	// Verifica colunas
	short nFields = dados.GetODBCFieldCount();
	int colunas = m_tabela.GetHeaderCtrl()->GetItemCount();

	// Verifica colunas
	if (colunas == 0)
	{
		// Lê metadata da tabela
		CODBCFieldInfo field;
		for (UINT i = 0; i < nFields; i ++)
		{
			dados.GetODBCFieldInfo(i, field);
			m_tabela.InsertColumn(i, field.m_strName, LVCFMT_LEFT, 100);
		}

	}

	// Deleta itens do controle de lista
	m_tabela.DeleteAllItems();

	// Recupera dados da tabela
	while (!dados.IsEOF())
	{
		for (short index = 0; index < nFields; index++)
		{
			dados.GetFieldValue(index, m_campo);

			// Retorna linha do banco de dados
			if (index == 0)
			{
				// Insere linha
				lvItem.mask = LVIF_TEXT;
				lvItem.iItem = 0;
				lvItem.iSubItem = 0;
				lvItem.pszText = lstrcpy(sz, m_campo);
				nItem = m_tabela.InsertItem(&lvItem);
			}

			// Retorna colunas da linha
			m_tabela.SetItemText(nItem, index, lstrcpy(sz, m_campo));

		}
		// Move o cursor para a proxima linha
		dados.MoveNext();
	}

	// Fecha o set de dados e a conexão
	dados.Close();
	db.Close();

}

void CAcessocppDlg::conectarDB(CString dns, CString usuario, CString senha)
{
	// Cria string de conexão ODBC
	CString conexao;

	// Cria string de conexão
	conexao = L"DSN=" + dns + L";UID=" + usuario + L";PWD=" + senha;

	// Abre conexão
	db.OpenEx(conexao, 0);
}

SQL – A instrução a seguir, substitui o cursor em um único acesso. (Oracle)

-- Este script SQL efetua o mesmo procedimento do cursor
-- utilizando apenas um acesso ao banco de dados.
-- é importante projetar seu acesso a dados para obter alta performance
-- você deve utilizar cursores apenas quando realmente for necessário.
--
-- Para os outros bancos substitua o campo SYSDATE
-- Para DB2 use Current date
-- Para MSSQL use GETDATE() 

Insert into SALARIO
Select A.ID_FUNCIONARIO,SYSDATE, ((A.SALARIO * B.PORCENTAGEM)/100)
  from FUNCIONARIOS A, DESCONTO B
  Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

 

 

Na linguagem de programação C++ um desenvolvedor pode utilizar as classes de fundação da Microsoft chamadas de MFC para desenvolver programas capazes de executar instruções SQL diretas utilizando a classe CDatabase ao invés de utilizar um DataSource.

A maioria dos comandos para manipular uma fonte de dados são emitidos através de um objeto CRecordSet que suporta os comandos para a seleção de dados, inserir novos registros, excluir registros e edição de registros. No entanto, nem todas as funcionalidades do ODBC são suportadas diretamente pelas classes de banco de dados, então as vezes, você precisa fazer uma chamada SQL direta com a instrução ExecuteSQL.

CDatabase::ExecuteSQL

Chame este membro da função quando você precisar executar um comando SQL diretamente.

C++ - MFC - CDatabase

C++ – MFC – CDatabase

 

Visual Studio

Para criar um programa que executa as quatro operações básicas de um banco de dados em uma aplicação C++ MFC Dialog Based, siga os seguintes passos:

1 – Crie um novo projeto C++ e disponha os componentes como na imagem abaixo:

Design Time

Design Time

3 – Use o Class Wizard para introduzir a mensagem WM_SHOWWINDOW, e crie as variáveis e os eventos adequados para cada componente, para isto você pode se basear no método DoDataExchange e BEGIN_MESSAGE_MAP encontrados no código abaixo:

Class Wizard

Class Wizard

Exemplo:

Este programa executa as quatro operações básicas em diferentes bancos de dados, atente-se para o padrão de campos do Microsoft SQL Server, que por default utilizando a classe CDatabase o torna case-sensitive.

C++

Arquivo .h


// CamposcppDlg.h : header file
//

#pragma once

// Inclui classe de banco de dados MFC
#include "afxdb.h"
#include "afxwin.h"

// CCamposcppDlg dialog
class CCamposcppDlg : public CDialogEx
{

public:
	CCamposcppDlg(CWnd* pParent = NULL);	// standard constructor

// Dialog Data
	enum { IDD = IDD_CAMPOSCPP_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support

// Implementation
protected:
	HICON m_hIcon;

	// Generated message map functions
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:

	// Cria métodos e objetos da classe
	CDatabase db;

	// Esta variavel define o banco de dados
	// oracle = Oracle Database
	// db2 = IBM DB2
	// mssql = MSSQL Server
	CString m_db = L"oracle";

	// Conecta ao banco de dados
	void conectarDB(CString banco);

	afx_msg void OnBnClickedButton1();
	CEdit m_pesquisa;
	CEdit m_codigo;
	CEdit m_pnome;
	CEdit m_snome;
	CEdit m_cargo;
	CEdit m_salario;
	afx_msg void OnBnClickedButton2();
	afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
	afx_msg void OnBnClickedButton3();
	afx_msg void OnBnClickedButton4();
	afx_msg void OnBnClickedButton5();
	CButton m_apagar;
	CButton m_novo;
};

Arquivo .cpp


// CamposcppDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Camposcpp.h"
#include "CamposcppDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CCamposcppDlg::CCamposcppDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CCamposcppDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CCamposcppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT6, m_pesquisa);
	DDX_Control(pDX, IDC_EDIT1, m_codigo);
	DDX_Control(pDX, IDC_EDIT2, m_pnome);
	DDX_Control(pDX, IDC_EDIT3, m_snome);
	DDX_Control(pDX, IDC_EDIT4, m_cargo);
	DDX_Control(pDX, IDC_EDIT5, m_salario);
	DDX_Control(pDX, IDC_BUTTON5, m_apagar);
	DDX_Control(pDX, IDC_BUTTON2, m_novo);
}

BEGIN_MESSAGE_MAP(CCamposcppDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, &CCamposcppDlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CCamposcppDlg::OnBnClickedButton2)

ON_WM_SHOWWINDOW()
ON_BN_CLICKED(IDC_BUTTON3, &CCamposcppDlg::OnBnClickedButton3)
ON_BN_CLICKED(IDC_BUTTON4, &CCamposcppDlg::OnBnClickedButton4)
ON_BN_CLICKED(IDC_BUTTON5, &CCamposcppDlg::OnBnClickedButton5)
END_MESSAGE_MAP()

BOOL CCamposcppDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	SetIcon(m_hIcon, TRUE);
	SetIcon(m_hIcon, FALSE);
	return TRUE;
}

void CCamposcppDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); 

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

HCURSOR CCamposcppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

// ************************         Desenvolvimento Aberto
// Nosso código começa aqui

void CCamposcppDlg::conectarDB(CString banco)
{
	// Cria string de conexão
	CString dns, usuario, senha;

	// Define banco de dados
	if (banco == "oracle")
	{
		dns = L"OracleXE";
		usuario = L"daberto";
		senha = L"p@55w0rd";
	}

	if (banco == "db2")
	{
		dns = L"IBMDB2";
		usuario = L"db2admin";
		senha = L"p@55w0rd";
	}

	if (banco == "mssql")
	{
		dns = L"MSSQLSERVER";
		usuario = L"devaberto";
		senha = L"p@55w0rd";
	}

	// Cria string de conexão ODBC
	CString conexao;

	// Cria string de conexão
	conexao = L"DSN=" + dns + L";UID=" + usuario + L";PWD=" + senha;

	// Abre conexão
	db.OpenEx(conexao, 0);
}

void CCamposcppDlg::OnBnClickedButton1()
{
	// Define variaveis
	CString codigo;
	CString m_campo;

	// Referincia objeto statico
	CWnd * p_rotulo;

	// Associa objeto statico
	p_rotulo = GetDlgItem(IDC_Rotulo);
	p_rotulo->SetWindowTextW(L"Database - Fields - " + m_db);

	// Conecta ao banco de dados
	conectarDB(m_db);

	// Cria um set de dados
	CRecordset  dados(&db);

	// Cria pesquisa
	m_pesquisa.GetWindowTextW(codigo);

	dados.Open(CRecordset::forwardOnly,
		L"Select * From FUNCIONARIOS Where  ID_FUNCIONARIO = " + codigo);

	// Retorna dados por nome de campo e os exibe
	// Oracle e o DB2 transformam os nomes de campos para maiusculo,
	// basta efetuar um select na tabela de cada banco e você verá
	// O MSSQL não faz esta mudança sendo assim você precisa mudar os campos
	// do banco de dados MSSQL para que fique compativel com o ORACLE e DB2 ou
	// encontrará um erro ao tentar utilizar a tabela que criamos anteriormente.
	dados.GetFieldValue(L"ID_FUNCIONARIO", m_campo);
	m_codigo.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"NOME", m_campo);
	m_pnome.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"SOBRENOME", m_campo);
	m_snome.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"CARGO", m_campo);
	m_cargo.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"SALARIO", m_campo);
	m_salario.SetWindowTextW(m_campo);

	// Fecha o set de dados e a conexão
	dados.Close();
	db.Close();

}

void CCamposcppDlg::OnBnClickedButton2()
{
	// Limpa componentes
	m_codigo.SetWindowTextW(NULL);
	m_pnome.SetWindowTextW(NULL);
	m_snome.SetWindowTextW(NULL);
	m_cargo.SetWindowTextW(NULL);
	m_salario.SetWindowTextW(NULL);

	// Define foco
	CEdit* pesquisa;
	pesquisa = (CEdit*)GetDlgItem(IDC_EDIT1);
	GotoDlgCtrl(pesquisa);

}

void CCamposcppDlg::OnShowWindow(BOOL bShow, UINT nStatus)
{
	CDialogEx::OnShowWindow(bShow, nStatus);

	// Define foco inicial
	CEdit* pesquisa;
	pesquisa = (CEdit*)GetDlgItem(IDC_EDIT6);
	GotoDlgCtrl(pesquisa);
}

// Cria método de menssagem
int menssagem(bool correto, LPCWSTR texto)
{
	LPCWSTR msg;

	if (correto)
	{
		msg = texto;
	}
	else
	{
		msg = texto;
	}

	// Cria nova caixa de menssagens
	int msgboxID = MessageBox(
		NULL,
		msg,
		(LPCWSTR)L"Conexão",
		MB_ICONWARNING | MB_OK | MB_DEFBUTTON2
		);

	switch (msgboxID)
	{
	case IDOK:

		break;
	}

	return msgboxID;
}

// Clique do botão inserir
void CCamposcppDlg::OnBnClickedButton3()
{
	// Define variaveis para componentes
	CString codigo;
	CString pnome;
	CString snome;
	CString cargo;
	CString salario;

	// conecta ao banco de dados
	conectarDB(m_db);

	// Recupara texto dos componentes
	m_codigo.GetWindowTextW(codigo);
	m_pnome.GetWindowTextW(pnome);
	m_snome.GetWindowTextW(snome);
	m_cargo.GetWindowTextW(cargo);
	m_salario.GetWindowTextW(salario);

	// Troca ponto decimal para o banco de dados
	int i = salario.Replace(L",", L".");

	// Cria instrução SQL
	CString sql = L"Insert into FUNCIONARIOS values ( " +  codigo + ", " +
		"'" + pnome + "', " +
		"'" + snome + "', " +
		"'" + cargo + "', " +
		salario + ")";

	// Executa SQL
	try
	{
		db.ExecuteSQL(sql);
		menssagem(true, L"Dados inseridos com sucesso!");
		db.Close();
	}
	catch (CDBException* pe)
	{
		menssagem(false, L"Erro ao inserir dados.");
		db.Close();
	}	

}

// botão Updata
void CCamposcppDlg::OnBnClickedButton4()
{
	CString codigo;
	CString pnome;
	CString snome;
	CString cargo;
	CString salario;
	CString troca;

	conectarDB(m_db);

	m_codigo.GetWindowTextW(codigo);
	m_pnome.GetWindowTextW(pnome);
	m_snome.GetWindowTextW(snome);
	m_cargo.GetWindowTextW(cargo);
	m_salario.GetWindowTextW(salario);

	int i = salario.Replace(L",", L".");

	CString sql = L"Update FUNCIONARIOS set ID_FUNCIONARIO =  " + codigo + ", " +
		"NOME = '" + pnome + "', " +
		"SOBRENOME  = '" + snome + "', " +
		"CARGO = '" + cargo + "', " +
		"SALARIO = " + salario + " " +
		"Where ID_FUNCIONARIO = " + codigo;

	try
	{
		db.ExecuteSQL(sql);
		menssagem(true, L"Dados alterados com sucesso!");
		db.Close();
	}
	catch (CDBException* pe)
	{
		menssagem(false, (LPWSTR)pe);
		db.Close();
	}
}

void CCamposcppDlg::OnBnClickedButton5()
{
	CString codigo;
	conectarDB(m_db);

	m_codigo.GetWindowTextW(codigo);

	CString sql = L"Delete From FUNCIONARIOS Where ID_FUNCIONARIO =  " + codigo;

	try
	{
		db.ExecuteSQL(sql);

		// Executa clique do botão novo
		// crie variavel m_novo
		SendMessage(WM_COMMAND, MAKEWPARAM(IDC_BUTTON2, BN_CLICKED), (LPARAM)m_novo.m_hWnd);

		menssagem(true, L"Dados apagados com sucesso!");
		db.Close();
	}
	catch (CDBException* pe)
	{
		menssagem(false, L"Erro ao apagar dados.");
		db.Close();
	}
}