How to Create ToonTalk Extensions

For very advanced users only:

Programmers in languages like C or Pascal can define new extensions to ToonTalk. A ToonTalk user thinks of an extension is a faraway place that cannot be visited. But a user can obtain a bird which will "fly" there. The bird can even bring along other birds who can fly back with things made by the extension. Extensions can make any capability of the underlying operating system (e.g. Windows) available to users inside of ToonTalk. Examples include files, window management, Internet access, producing music or 3D graphics, and much more. If you do make a ToonTalk extension, please contribute it to the larger ToonTalk community by sending it to support@toontalk.com.

Extensions are implemented as Microsoft Windows DLLs (dynamic link libraries). The library needs only to export one procedure. The procedure's type should be:

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);

If a bird connected to an extension is given a box then the receiver associated with that bird is called with the following arguments:

HANDLE handle.

A handle associated with the bird. Will be NULL unless the bird was created by an extension. Used, for example, by the file extension to hold the file handle.

void **data_in

data_in is an array of pointers. To be interpreted relative to types described below.

char *types_in

A null-terminated string describing the ToonTalk types of the box received by the bird. L is for a long integer from a ToonTalk number pad. S is for a string for a ToonTalk text pad. H is for a handle of a bird to an extension. Square brackets ([]) enclose the elements of a box. A minus sign (-) indicates an empty hole of a box. B indicates a normal bird. ? is for all other ToonTalk objects. For L, S, B, - and ? there is a corresponding data item in the data argument described above. The elements of a box inside a box occur in place in data_in. A handle (H) needs 3 data items: the receiver procedure, the associated handle, and a string that labels the handle.

char *label

A null-terminated string labeling this bird. Typically can be seen on the T-shirt of the bird.

char *country_code

A null-terminated 2 letter string indicating the country code of this version of ToonTalk. Examples include "US", "UK", "SE", "DE", and "BR". This argument is provided in case the extension wants Marty to speak or to put up a dialog box in a language sensitive manner.

void ***data_out

This is an array of pointers -- one for each bird in the box given to the extension bird. This enables an extension to specify what items should be given to birds that it receives. Each element of data_out should be set to another array of pointers whose length and elements are consistent with the corresponding elements in types_out (described below). Note that storage allocated for the values of types_out should be allocated in Windows global heap. (E.g. using GlobalAlloc.)

char **types_out

This is an array of pointers -- one for each bird in the box given to the extension bird. To specify what a bird should receive set the corresponding element (its occurrence while scanning from left to right) to a globally allocated null-terminated string that describes the types in exactly the same manner as types_in. For each element in types_out, a ToonTalk item is created using the data in data_out.

char **to_say

Should be set to a null-terminated globally allocated string if the extension wishes Marty to say something.

BOOL *ok_to_speak

This should be set to non-zero if, when Marty is to speak the to_say string, he should use a text-to-speech engine. If not set, then Marty will use talk balloons.

HINSTANCE string_library

This is a handle on the currently loaded ToonTalk string resource DLL. It should be ignored unless the writer of the extension has access to ToonTalk's string table.

Returns.

The receiver procedure should return non-zero if the data_out and types_out variables were set.

Remarks.

If types_in is NULL then the procedure is being called so that Marty can describe what this bird does. If types_in is "H", then the last bird associated with handle is being destroyed. Here is an opportunity to clean up (e.g. close file handles).

 

The DEF file for the DLL should contain the line:

EXPORTS receive@1

The DLL should be named "TT" followed by the extension name. If a DLL is to be used by the 16-bit version of ToonTalk it should be named "T16" followed by the extension name. Simply placing the DLL file in the ToonTalk directory installs it.

Sample code.

Here is an example definition of a file extension defined in C++ (though with only minor differences could have been defined in C).

 

// Copyright (c) 1992,1998. Ken Kahn, Animated Programs, All rights reserved.

// You may copy and modify this file so long as you keep this copyright notice.

#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); // Can't use library's local storage

    memcpy(destination,source,length);

    destination[length] = '\0'; // terminate the string

    return(destination);

  • };

     

    // This receiver procedure is associated with opened files

    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) {

    };

     

    // Here is the exported procedure for opening file handles

    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) { // asking for help
  • // Set *to_say to help 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) { // received a box with "Create File", followed by the file name, followed by a bird

  • creation = CREATE_NEW;

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

  • } else if (stricmp(selector,"Open") == 0) { // received a box with "Open", followed by the file name, followed by a bird

  • creation = OPEN_EXISTING;

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

  • } else {

  • // set *to_say to describe problem

    return(FALSE);

  • };

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

    if (file == INVALID_HANDLE_VALUE) {

  • // set *to_say to describe problem

    return(FALSE);

  • };

    // give the bird in the third hole a box with a new bird which is associated with the file handle

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

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

    out[0][0] = (void *) file_receive; // behavior defined above

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

    out[0][2] = copy_string(name,0); // use the file name as a label

    return(TRUE);

  • } else if (strcmp(types,"H") == 0) { // destroyed

  • return(FALSE);
  • };

    // Set *to_say to give help

    return(FALSE);

  • };

    home | search | buy | manual | news | faq | support | press | contact us