Controles ActiveX MFC: tópicos avançados
Este artigo aborda tópicos avançados relacionados ao desenvolvimento de controles ActiveX. Estão incluídos:
Importante
O ActiveX é uma tecnologia herdada que não deve ser usada para novo desenvolvimento. Para mais informações sobre tecnologias modernas que substituem o ActiveX, confira Controles do ActiveX.
Usar classes de banco de dados em controles ActiveX
Como as classes de controle ActiveX fazem parte da biblioteca de classes, você pode aplicar os mesmos procedimentos e regras para usar classes de banco de dados em um aplicativo MFC padrão para desenvolver controles ActiveX que usem as classes de banco de dados MFC.
Para obter uma visão geral das classes de banco de dados MFC, consulte Classes de banco de dados MFC (DAO e ODBC). O artigo apresenta as classes ODBC e DAO do MFC e direciona você para mais detalhes sobre elas.
Observação
O DAO tem suporte por meio do Office 2013. O DAO 3.6 é a versão final e é considerado obsoleto. O ambiente e os assistentes do Visual C++ não dão suporte a DAO (embora as classes DAO estejam incluídas e você ainda possa usá-las). A Microsoft recomenda que você use modelos OLE DB ou ODBC e MFC para novos projetos. Use DAO apenas na manutenção de aplicativos existentes.
Implementar uma propriedade parametrizada
Uma propriedade parametrizada (às vezes chamada de matriz de propriedades) é um método para expor uma coleção homogênea de valores como uma única propriedade do controle. Por exemplo, você pode usar uma propriedade parametrizada para expor uma matriz ou um dicionário como uma propriedade. No Visual Basic, essa propriedade é acessada usando notação de matriz:
x = o.Array(2, 3) ' gets element of 2D array
o.Array(2, 3) = 7 ' sets element of 2D array
Use o Assistente para Adicionar Propriedade para implementar uma propriedade parametrizada. O Assistente para Adicionar Propriedade implementa a propriedade adicionando um par de funções Get/Set que permitem que o usuário de controle acesse a propriedade usando a notação acima ou da forma padrão.
Semelhante a métodos e propriedades, as propriedades parametrizadas também têm um limite para o número de parâmetros permitidos. No caso de propriedades parametrizadas, o limite é de 15 parâmetros (com um parâmetro reservado para armazenar o valor da propriedade).
O procedimento a seguir adiciona uma propriedade parametrizada, chamada Array, que pode ser acessada como uma matriz bidimensional de inteiros.
Para adicionar uma propriedade parametrizada usando o Assistente para Adicionar Propriedade
Carregue o projeto do controle.
No Modo de Exibição de Classe, expanda o nó de biblioteca do controle.
Clique com o botão direito do mouse no nó de interface do controle (o segundo nó do nó da biblioteca) para abrir o menu de atalho.
No menu de atalho, clique em Adicionar e, em seguida, em Adicionar Propriedade.
Na caixa Nome da propriedade, digite
Array
.Na caixa Tipo de propriedade, selecione
short
.Para o Tipo de Implementação, clique em Métodos Get/Set.
Nas caixas Função Get e Função Set, digite nomes exclusivos para suas funções Get e Set ou aceite os nomes padrão.
Adicione um parâmetro chamado linha (tipo short), usando os controles Nome do Parâmetro e Tipo do Parâmetro.
Adicione um segundo parâmetro chamado coluna (tipo short).
Clique em Concluir.
Alterações feitas pelo Assistente para Adicionar Propriedade
Quando você adiciona uma propriedade personalizada, o Assistente para Adicionar Propriedade faz alterações nos arquivos de cabeçalho da classe de controle (.H) e de implementação (.CPP).
As linhas a seguir são adicionadas ao arquivo .H da classe de controle:
SHORT GetArray(SHORT row, SHORT column);
void SetArray(SHORT row, SHORT column, SHORT newVal);
Esse código declara duas funções chamadas GetArray
e SetArray
que permitem que o usuário solicite uma linha e uma coluna específicas ao acessar a propriedade.
Além disso, o Assistente para Adicionar Propriedade adiciona as seguintes linhas ao mapa de expedição de controle, localizado no arquivo (.CPP) de implementação da classe de controle:
DISP_PROPERTY_PARAM_ID(CMyAxUICtrl, "Array", dispidArray, GetArray, SetArray, VT_I2, VTS_I2 VTS_I2)
Por fim, as implementações das funções GetArray
e SetArray
são adicionadas ao final do arquivo .CPP. Na maioria dos casos, você modificará a função Get para retornar o valor da propriedade. A função Set geralmente conterá o código que deve ser executado antes ou depois das alterações da propriedade.
Para que essa propriedade seja útil, você pode declarar uma variável de membro de matriz bidimensional na classe de controle, de tipo short
, para armazenar valores para a propriedade parametrizada. Em seguida, você pode modificar a função Get para retornar o valor armazenado na linha e coluna adequadas, conforme indicado pelos parâmetros, e modificar a função Set para atualizar o valor referenciado pelos parâmetros de linha e coluna.
Manipular erros no controle ActiveX
Se ocorrerem condições de erro no controle, talvez seja necessário relatar o erro ao contêiner de controle. Há dois métodos para relatar erros, dependendo da situação em que o erro ocorrer. Se o erro ocorrer dentro da função Get ou Set de uma propriedade ou dentro da implementação de um método de Automação OLE, o controle deverá chamar COleControl::ThrowError, que sinaliza ao usuário de controle que ocorreu um erro. Se o erro ocorrer em qualquer outro momento, o controle deverá chamar COleControl::FireError, que dispara um evento de erro de estoque.
Para indicar o tipo de erro que ocorreu, o controle deve passar um código de erro para ThrowError
ou FireError
. Um código de erro é um código de status OLE, e tem um valor de 32 bits. Quando possível, escolha um código de erro no conjunto padrão de códigos definidos no arquivo de cabeçalho OLECTL.H. A tabela a seguir resume esses códigos.
Códigos de erro de controle ActiveX
Erro | Descrição |
---|---|
CTL_E_ILLEGALFUNCTIONCALL | Chamada de função ilegal |
CTL_E_OVERFLOW | Estouro |
CTL_E_OUTOFMEMORY | Memória insuficiente |
CTL_E_DIVISIONBYZERO | Divisão por zero |
CTL_E_OUTOFSTRINGSPACE | Espaço insuficiente na cadeia de caracteres |
CTL_E_OUTOFSTACKSPACE | Espaço em pilha insuficiente |
CTL_E_BADFILENAMEORNUMBER | Nome ou número de arquivo inválido |
CTL_E_FILENOTFOUND | Arquivo não encontrado |
CTL_E_BADFILEMODE | Modo de arquivo inválido |
CTL_E_FILEALREADYOPEN | Arquivo já aberto |
CTL_E_DEVICEIOERROR | Erro de E/S do dispositivo |
CTL_E_FILEALREADYEXISTS | O arquivo já existe |
CTL_E_BADRECORDLENGTH | Comprimento de registro inválido |
CTL_E_DISKFULL | Disco cheio |
CTL_E_BADRECORDNUMBER | Número de registro inválido |
CTL_E_BADFILENAME | Nome de arquivo inválido |
CTL_E_TOOMANYFILES | Muitos arquivos |
CTL_E_DEVICEUNAVAILABLE | Dispositivo não disponível |
CTL_E_PERMISSIONDENIED | Permissão negada |
CTL_E_DISKNOTREADY | O disco não está pronto |
CTL_E_PATHFILEACCESSERROR | Erro de acesso a caminho/arquivo |
CTL_E_PATHNOTFOUND | demarcador não localizado |
CTL_E_INVALIDPATTERNSTRING | Cadeia de caracteres de padrão inválida |
CTL_E_INVALIDUSEOFNULL | Uso inválido de NULL |
CTL_E_INVALIDFILEFORMAT | Formato de arquivo inválido |
CTL_E_INVALIDPROPERTYVALUE | Valor da propriedade inválido |
CTL_E_INVALIDPROPERTYARRAYINDEX | Índice da matriz de propriedade inválido |
CTL_E_SETNOTSUPPORTEDATRUNTIME | Não há suporte para Set em tempo de execução |
CTL_E_SETNOTSUPPORTED | Não há suporte para Set (propriedade somente leitura) |
CTL_E_NEEDPROPERTYARRAYINDEX | Índice da matriz de propriedade necessário |
CTL_E_SETNOTPERMITTED | Definição não permitida |
CTL_E_GETNOTSUPPORTEDATRUNTIME | Não há suporte para Get em tempo de execução |
CTL_E_GETNOTSUPPORTED | Não há suporte para Get (propriedade somente gravação) |
CTL_E_PROPERTYNOTFOUND | Propriedade não localizada |
CTL_E_INVALIDCLIPBOARDFORMAT | Formato da área de transferência inválido |
CTL_E_INVALIDPICTURE | Imagem inválida |
CTL_E_PRINTERERROR | Erro de impressora |
CTL_E_CANTSAVEFILETOTEMP | Não é possível salvar o arquivo no diretório TEMP |
CTL_E_SEARCHTEXTNOTFOUND | Texto de pesquisa não encontrado |
CTL_E_REPLACEMENTSTOOLONG | Substituições muito longas |
Se necessário, use a macro CUSTOM_CTL_SCODE para definir um código de erro personalizado para uma condição que não seja abrangida por um dos códigos padrão. O parâmetro para essa macro deve ser um inteiro entre 1000 e 32767, inclusive. Por exemplo:
#define MYCTL_E_SPECIALERROR CUSTOM_CTL_SCODE(1000)
Se você estiver criando um controle ActiveX para substituir um controle VBX existente, defina seus códigos de erro de controle ActiveX com os mesmos valores numéricos usados pelo controle VBX para garantir que os códigos de erro sejam compatíveis.
Manipular chaves especiais no controle
Em alguns casos, talvez você queira lidar com determinadas combinações de tecla de forma especial; por exemplo, inserir uma nova linha quando a tecla ENTER for pressionada em um controle de caixa de texto de várias linhas ou mover entre um grupo de controles de edição quando uma ID de tecla direcional for pressionada.
Se a classe base do controle ActiveX for COleControl
, você poderá substituir CWnd::PreTranslateMessage para manipular mensagens antes que o contêiner as processe. Ao usar essa técnica, sempre retorne TRUE se você manipular a mensagem em sua substituição de PreTranslateMessage
.
O exemplo de código a seguir demonstra uma possível maneira de lidar com as mensagens relacionadas às teclas direcionais.
BOOL CMyAxUICtrl::PreTranslateMessage(MSG* pMsg)
{
BOOL bHandleNow = FALSE;
switch (pMsg->message)
{
case WM_KEYDOWN:
switch (pMsg->wParam)
{
case VK_UP:
case VK_DOWN:
case VK_LEFT:
case VK_RIGHT:
bHandleNow = TRUE;
break;
}
if (bHandleNow)
{
OnKeyDown((UINT)pMsg->wParam, LOWORD(pMsg->lParam), HIWORD(pMsg->lParam));
}
break;
}
return bHandleNow;
}
Para obter mais informações sobre como lidar com interfaces de teclado para um controle ActiveX, consulte a documentação do SDK do ActiveX.
Acessar controles de caixa de diálogo que são invisíveis em tempo de execução
Você pode criar controles de caixa de diálogo que não têm interface do usuário e são invisíveis em tempo de execução. Se você adicionar um controle ActiveX invisível em tempo de execução a uma caixa de diálogo e usar CWnd::GetDlgItem para acessar o controle, o controle não funcionará corretamente. Em vez disso, você deve usar uma das seguintes técnicas para obter um objeto que representa o controle:
Usando o Assistente para Adicionar Variável de Membro, selecione Variável de Controle e selecione a ID do controle. Insira um nome de variável de membro e selecione a classe wrapper do controle como o Tipo de Controle.
-ou-
Declare uma variável local e uma subclasse como o item da caixa de diálogo. Insira o código que se assemelha ao seguinte (
CMyCtrl
é a classe wrapper, IDC_MYCTRL1 é a ID do controle):CCirc myCirc; myCirc.SubclassDlgItem(IDC_CIRCCTRL2, this); // ... use myCirc ... myCirc.UnsubclassWindow();