Messages From The Inside Mark Wherry takes a look at AES messages, and how to interface your programs with them. In modern Atari programming there is one area that is rapidly increasing in popularity, it seems that every week there are more and more protocols and messages for us to learn and use. However, what is even more frustrating is not being able to use the protocols, either because you're unsure, or the documentation is in (add an appropriate word of your choice here) German! In this article, and perhaps others to follow, I'll de-mystify the ancient art of the AES message. The first step to be taken is when you appl_init() your application. It is now really important that you store the integer that will be returned, as this will be the unique number that identifies your application in the AES. eg. int ap_id; /* Application Identifier */ ap_id=appl_init(); Before you want to send a message, you must first find out the identifier of the application you want to send the message to. This is really easy as there is a function to do just that; use appl_find with the name of the application, and the id will be returned. eg. int other_id; char *name; other_id=appl_find(name); It is important that the name is only 8 characters long, but if it is shorter, you will have to pad it with spaces. So for example, if you wanted to find the identifier for CAB, you would call appl_find like this: cab_id=appl_find("CAB "); If something goes wrong, the value -1 will be returned as the identifier. This means that the program is not loaded in the memory. The actual message is an array of eight shorts which has a standard length of 16 bytes, declared like this: short msg[8]; However, we now want to put something into the values but what do we do? Well, we need to know exactly how the message we want to send is structured. Although each message is different, there are a few conventions common to all messages: msg[0] is always the message type, eg. AC_OPEN. msg[1] always contains the application identifier of the program sending the message. msg[2] always defines the length of the message, not including the pre-defined 16 bytes. This is usually 0. So how do you put information into the message? Well numerical values are easy, but what about filenames or other uses involving an array of characters? Well they're easy too using the following code: When sending characters you need to do it like this: *(char**)&msg[x]=text_to_send; x is the pointer to which part of the array the pointer will be stored. In message definitions you will usually see something like this: msg[3]= \Pointer to the text msg[4]= / For this example, x would be three, but there would be no need for any direct definition for msg[4]. We could define the following function, to make using the above code even more easier: #define str2ptr(x,text) *(char**)&msg[x]=text So now we can define a message, we send it using the appl_write function, which is defined as: error=appl_write(ap_id,length,msg); ap_id is the value returned by appl_init, the identifier for your application, length is the length of the message you are sending, which will usually be 16 and, msg is the message itself. The error value will be returned as 0 if everything went OK, and as a non-zero value if there was a problem. So that's all there is to sending a message, and here's a function from my own GEM library to make life that bit easier! It's not exactly a mile- stone in coding, but it helps out a little. (PS. I'm using LC5) int SendMessage(char *apptosend, short sm0, short sm1, short sm2, short sm3, short sm4, short sm5, short sm6, short sm7) { short sm_msg[8]; int error; other_id=appl_find(apptosend); error=other_id; if(other_id>=0){ sm_msg[0]=sm0; sm_msg[1]=sm1; sm_msg[2]=sm2; sm_msg[3]=sm3; sm_msg[4]=sm4; sm_msg[5]=sm5; sm_msg[6]=sm6; sm_msg[7]=sm7; error=appl_write(other_id,16,sm_msg); } return error; } The obvious gap now is, how do we receive the messages? Well, you'll be glad to know that it's even easier than sending them. Simply use the evnt_mesag function which you may already be familiar with from window and accessory handling. Here is an example of how to handle messages: while(notfalse) { evnt_mesag(msg); switch(msg[0]) { case MESSAGE_TYPE_1: ...Your handling of the message goes here... break; case MESSAGE_TYPE_2: ...Your handling of the message goes here... break; } } To get numerical values out of the message is as easy as putting them in, what about extracting characters using pointers? When extracting characters from a received message, simply do this: text_to_retrieve=((char*)(((long)msg[x]<<16)|(((long)msg[x+1])&0xFFFF))) x is again the pointer to retrieve the text, so for the previous example, x would be 3, and obviously x+1 would be 4. We could define the following function, to make using the above code even more easier: #define ptr2str(x) ((char*)(((long)msg[x]<<16)|(((long)msg[x+1])&0xFFFF))) To round off our first expedition let's have a quick look at the popular VA_START message as an example. The VA_START message is defined and structured like this: #define VA_START 0x4711 msg[0]=VA_START msg[1]=ap_id msg[2]=0 msg[3]= \ Pointer to filename (must include full path) msg[4]= / msg[5]=0 msg[6]=0 msg[7]=0 An important point to make is that when send a path using '\', you must use two instead of one. So if you want to send "C:\HELLO\HELLO.IMG", you would actually send "C:\\HELLO\\HELLO.IMG". To send a VA_START message to CAB, you would: error_return=SendMessage("CAB ",VA_START,0,0, str2ptr(3,"C:\\HELLO\\HELLO.HTM"),0,0,0); To receive a VA_START message you would: evnt_mesag(msg); if(msg[0]==VA_START){ filename=ptr2str(3); printf("%s\n",filename); } I hope this will have helped you in some way, and stay tuned for more protocols to be covered soon. If you want to contact me for help, suggestions, chit-chat.... Please feel free! Mark Wherry, 4 Fernpark Close, Topsham Road, Exeter, Devon, EX2 6AW