Como criar extensões do ToonTalk

Somente para usuários muito avançados:

Os programadores da linguagem C ou Pascal podem definir novas extensões para o ToonTalk. Um usuário do ToonTalk pensa que uma extensão é um lugar distante, impossível de se visitar. Mas um usuário pode obter um pombo que irá "voando" até lá. O pombo pode até mesmo acompanhar outros pombos, que podem retornar com coisas feitas por uma extensão. As extensões podem realizar qualquer recurso do sistema operacional básico (por exemplo, o Windows) disponível para os usuários dentro do ToonTalk. Os exemplos incluem arquivos, gerenciamento de janelas, acesso à Internet, produção de músicas ou imagens 3D e muito mais. Se você for criar uma extensão do ToonTalk, por favor, compartilhe-a com a imensa comunidade ToonTalk enviando-a para support@toontalk.com.

As extensões são implementadas como DLLs (dynamic link libraries) do Microsoft Windows. A biblioteca precisa apenas exportar um procedimento. O procedimento precisa ser do tipo:

BOOL __declspec(dllexport) receive(HANDLE handle, void **data_in, char *types_in, char *label, char *country_code, void ***data_out, char **types_out, char **to_say, BOOL *ok_to_speak, HINSTANCE string_library);

Se um pombo conectado a uma extensão for presenteado com uma caixa, então o destinatário associado ao pombo é chamado com os seguintes argumentos:

HANDLE handle.

Um handle associado ao pombo. Será NULL a menos que o pombo tenha sido criado por uma extensão. Usado, por exemplo, por uma extensão do arquivo para controlar o handle do arquivo.

void **data_in

data_in é um arranjo de ponteiros. Para ser interpretado conforme os tipos descritos abaixo.

char *types_in

Uma string terminada em null descrevendo os tipos de caixa do ToonTalk recebidas pelo pombo. L é para um inteiro longo a partir de um número pad do ToonTalk. S é para uma string para um texto pad do ToonTalk. H é para um handle de um pombo para uma extensão. Colchetes ([]) agrupam os elementos de uma caixa. Um sinal de subtração (-) indica um buraco vazio de uma caixa. B indica um pombo normal.? é para todos os outros objetos do ToonTalk. Para L, S, B, - e ? há um item de dado correspondente no argumento de dado descrito acima. Os elementos de uma caixa dentro de outra caixa ocorrem no lugar de data_in. Um handle (H) requer 3 itens de dados: o procedimento recebedor, o handle associado e uma string que identifica o handle.

char *label

Uma string terminada em null identificando seu pombo. Pode ser vista normalmente na camiseta do pombo.

char *country_code

Uma string de letras terminada em 2 indicando o código do país da sua versão do ToonTalk. Por exemplo, "US", "UK", "SE", "DE" e "BR". Este argumento é fornecido no caso de a extensão exigir que o Márcio fale ou coloque uma caixa de diálogo de modo sensível à linguagem.

void ***data_out

Este é um arranjo de ponteiros – uma para cada pombo na caixa dada ao pombo de extensão. Isto permite que uma extensão especifique quais itens precisam ser dados aos pombos que as recebem. Cada elemento de data_out precisa ser definido para outro arranjo de ponteiros, cujo tamanho e elementos são consistentes com os elementos correspondentes em types_out (descrito abaixo). Note que o armazenamento alocado para os valores de types_out precisam ser alocados na heap global do Windows. (Por exemplo, usando GlobalAlloc.)

char **types_out

Este é um arranjo de ponteiros – uma para cada pombo na caixa dada ao pombo de extensão. Para especificar o que um pombo precisa receber, configure o elemento correspondente (sua ocorrência enquanto faz a leitura da esquerda para a direita) para uma string terminada em null alocada globalmente que descreve os tipos exatamente da mesma maneira que types_in. Para cada elemento em types_out, um item do ToonTalk é criado utilizando-se os dados em data_out.

char **to_say

Deve ser configurado para uma string terminada em null alocada globalmente se a extensão quiser que Márcio diga algo.

BOOL *ok_to_speak

Este deve ser configurado como não-zero se, quando Márcio for falar a string to_say, ele precisar usar um mecanismo de text-to-speech. Caso não configure, Márcio usará os balões de diálogo.

HINSTANCE string_library

Este é um handle da string de recurso de DLL carregada atualmente no ToonTalk. Deve ser ignorado a menos que o gravador da extensão tenha acesso à tabela de strings do ToonTalk.

Returns.

O procedimento recebedor precisa retornar não-zero, caso as variáveis data_out e types_out tenham sido configuradas.

Remarks.

Se types_in for NULL, o procedimento é chamado para que Márcio possa descrever o que esse pombo faz. Se types_in for "H", então o último pombo associado ao handle será destruído. Aqui está uma oportunidade para limpar (por exemplo, fechar o arquivo de handles).

O arquivo DEF para a DLL precisa conter a seguinte linha:

EXPORTS receive@1

A DLL deve ser nomeada como "TT" seguida pelo nome de extensão. Se a DLL vai ser usada pela versão 16-bit do ToonTalk, ela deve ser nomeada "T16" seguida pela extensão do nome. Basta incluir o arquivo de DLL no diretório do ToonTalk para instalá-la.

Código de exemplo.

Veja a seguir uma definição de exemplo de uma extensão de arquivo escrita em C++ (embora fique um pouco diferente, ele também pode ser definido em C).

// Copyright (c) 1992,1998. Ken Kahn, Animated Programs, Todos os direitos reservados.

// Você pode copiar e modificar este arquivo desde que mantenha este termo de copyright.

#include <windows.h>

extern "C" int __declspec(dllexport) WEP (int nParam);

extern "C" BOOL __declspec(dllexport) receive(HANDLE handle, void **data, char *types, void ***out, char **out_types, char **to_say, HINSTANCE string_library);

int FAR PASCAL LibMain (HANDLE , WORD , WORD , LPSTR ) {

  • return 1 ;
  • }

    int __declspec(dllexport) WEP (int) {

  • return 1 ;
  • }

    char *copy_string(char *source, int length) {

  • if (source == NULL) return(NULL);

    if (length <= 0) length = strlen(source);

    char *destination = (char *) GlobalAlloc(0,length+1); // Não pode usar armazenamento local da biblioteca

    memcpy(destination,source,length);

    destination[length] = '\0'; // finaliza a string

    return(destination);

  • };

    // Este procedimento de recebimento está associado a arquivos abertos

    BOOL file_receive(HANDLE handle, void **data, char *types, char *label, char *country_code,

    void ***out, char **out_types, char **to_say, BOOL *ok_to_speak, HINSTANCE string_library) {

    • if (types == NULL) { // quer ajuda
    • *to_say = copy_string("This is a file handle.",0); // poderia oferecer uma ajuda melhor

      return(TRUE);

    • };

      if (strcmp(types,"[SLB]") == 0) {

    • if (stricmp((char *) data[0],"Read") == 0) { // a caixa contém "Read", um número, seguido por um pombo
    • long number_of_bytes_to_read = (long) data[1];

      DWORD number_of_bytes_read;

      char *buffer = (char *) GlobalAlloc(0,number_of_bytes_to_read+1);

      if(!ReadFile(handle,buffer,number_ of_bytes_to_read&number_of_bytes_read,NULL)){

    • // configure *to_say para descrever o erro.
    • };

      // dê ao pombo no terceiro buraco da caixa uma string contendo os caracteres que acabaram de ser lidos

      out_types[0] = copy_string("S",1);

      out[0] = (void * *) GlobalAlloc(0,sizeof(void*));

      buffer[number_of_bytes_read] = '\0'; // finaliza a string

      out[0][0] = (void *) buffer;

      return(TRUE);

    • } else if (stricmp((char *) data[0],"Read Bytes") == 0) {

    • long number_of_bytes_to_read = (long) data[1];

      DWORD number_of_bytes_read;

      char *buffer = (char *) GlobalAlloc(0,number_of_bytes_to_read+1);

      if (!ReadFile(handle,buffer,number_of_bytes_to_ read,&number_of_bytes_read,NULL)){

    • // configure *to_say para descrever o erro.
    • };

      // dê ao pombo uma caixa na qual para cada caractere lido há um inteiro cujo valor é o código ASCII do caractere

      out_types[0] = (char *) GlobalAlloc(0,number_of_bytes_read+3); // 3 extras para [] e finalizador

      out[0] = (void * *) GlobalAlloc(0,sizeof(void*)*number_of_bytes_read);

      int out_type_index = 0;

      out_types[0][out_type_index++] = '[';

      for (DWORD i = 0; i < number_of_bytes_read; i++) {

    • out_types[0][out_type_index++] = 'L';
      out[0][i] = (void *) buffer[i];
    • };

      out_types[0][out_type_index++] = ']';

      out_types[0][out_type_index++] = '\0'; // finaliza a string

      return(TRUE);

    • };

    • } else if (strcmp(types,"[SSB]") == 0) {

    • if (stricmp((char *) data[0],"Write") == 0) { // a caixa é Write, seguida por um text pad, seguido por um pombo
    • char *buffer = (char *) data[1];

      long number_of_bytes_to_write = strlen(buffer);

      DWORD number_of_bytes_written;

      if (WriteFile(handle,buffer,number_of_bytes_to_write, &number_of_bytes_written,NULL)){

    • out_types[0] = copy_string("L",1);
      out[0] = (void * *) GlobalAlloc(0,sizeof(void*));

      out[0][0] = (void *) number_of_bytes_written;

      return(TRUE);

    • } else {

    • // configure *to_say para descrever o erro
      return(FALSE);
    • };

    • };

    • } else if (strncmp(types,"[S[",3) == 0) { // procurando por [S[LL...LL]B] onde S são Write Bytes

    • if (stricmp((char *) data[0],"Write Bytes") == 0) {
    • int index = 3; // já verificados 3 caracteres do tipo
      while (types[index] != '\0') {< /DT>< /DT>
    • if (types[index] == ']') { // Tudo OK por enquanto
    • if (types[index+1] == 'B' && types[index+2] == ']') { // tudo bem
    • index -= 3; // o índice agora é do tamanho da caixa de números
      unsigned char *buffer = new unsigned char[index];< /DT >< /DT >< /DT >

      for (int i = 0; i < index; i++) {

    • buffer[i] = (unsigned char) data[i+1];
    • };

      DWORD number_of_bytes_written;

      if (WriteFile(handle,buffer,index, &number_of_bytes_written,NULL)){

    • // dê ao pombo um número que exibe quantos foram escritos

      out_types[0] = copy_string("L",1);

      out[0] = (void * *) GlobalAlloc(0,sizeof(void*));

      out[0][0] = (void *) number_of_bytes_written;

      return(TRUE);

    • } else {

    • // configure *to_say para descrever o erro
      return(FALSE);
    • };

    • } else break; // falha

    • } else if (types[index] == 'L') {

    • index++;
    • } else { // ruim

    • break; // falha no código que deveria configurar *to_say
    • };

    • };

    • };

    • } else if (strcmp(types,"H") == 0) { // isto significa que o último pombo associado a este handle foi destruído

    • if (!CloseHandle(handle)) {
    • // Configure *to_say para descrever o problema
    • };

      return(FALSE);

    • };

      // Configure *to_say para oferecer ajuda sobre como utilizar esta extensão

      return(FALSE);

    };

    // Aqui está o procedimento exportado para abrir handles de arquivo

    BOOL __declspec(dllexport) receive(HANDLE handle, void **data, char *types, char *label, char *country_code,

    void ***out, char **out_types, char **to_say, BOOL *ok_to_speak, HINSTANCE string_library) {

  • if (types == NULL) { // solicitando ajuda
  • // Configure *to_say para auxiliar a string

    return(TRUE);

  • };

    if (strcmp(types,"[SSB]") == 0) {

  • char *selector = (char *) data[0];

    DWORD creation;

    char *device_control_string = NULL;

    char name[MAX_PATH];

    if (stricmp(selector,"Create File") == 0) { // recebeu uma caixa com "Create File", seguida pelo nome do arquivo, seguido por um pombo

  • creation = CREATE_NEW;

    strcpy(name,(char *) data[1]);

  • } else if (stricmp(selector,"Open") == 0) { // recebeu uma caixa com "Open", seguido pelo nome do arquivo, seguido por um pombo

  • creation = OPEN_EXISTING;
    strcpy(name,(char *) data[1]);
  • } else {

  • // configure *to_say para descrever o problema
    return(FALSE);
  • };

    HANDLE file= CreateFile(name,GENERIC_READ|GENERIC_WRITE,0,NULL,creation FILE_ATTRIBUTE_NORMAL,NULL);

    if (file == INVALID_HANDLE_VALUE) {

  • // configure *to_say para descrever o problema return(FALSE);
  • };

    // dê ao pombo no terceiro buraco uma caixa com um novo pombo que está associado ao handle de arquivo

    out_types[0] = copy_string("[H]",3);

    out[0] = (void * *) GlobalAlloc(0,3*sizeof(void*));

    out[0][0] = (void *) file_receive; // comportamento definido acima

    out[0][1] = (void *) file; // handle d arquivo

    out[0][2] = copy_string(name,0); // use o nome do arquivo como um rótulo

    return(TRUE);

  • } else if (strcmp(types,"H") == 0) { // destruído

  • return(FALSE);
  • };

    // Configure *to_say para dar ajuda

    return(FALSE);


  • início busca compra manual novidades dúvidas suporte download imprensa contato