TweetFollow Us on Twitter

4D Externals
Volume Number:4
Issue Number:11
Column Tag:Database Corner

4th Dimension® Externals

By Todd Carper, ACIUS, Inc., Cupertino, CA

[Todd Carper is a Technical Support Engineer for 4th Dimension® and handles all external procedure development. He has been there for one year.]

External Procedures in 4th Dimension®

4th Dimension is a powerful and sophisticated database for the Macintosh. It provides an excellent environment for developing custom databases and applications. 4th Dimension allows you to quickly generate screens, menus, buttons, scrollable areas, and procedures to create a true Macintosh interface without starting from scratch.

4th Dimension’s language enables you to avoid pages of code and hours of work by accessing the Macintosh ToolBox with high level commands. Though the language is very powerful it may not contain all the built-in commands to meet every need. For this reason 4th Dimension was designed as an open architecture database that can utilize your own commands. These commands are called “external procedures”, and this document will discuss the design and implementation of external procedures.

External procedures enable you to add unlimited functionality to a 4th Dimension database or application. For example, you can add sound, pop-up menus, picture buttons, mathematics, or telecommunications capabilities. External procedures are extensions to the 4th Dimension commands that you create like XCMDs for HyperCard. Once the procedure is installed, it is part of 4th Dimension and can be called just as you call built-in commands.

External procedures can be written in assembly language, or any higher level language that compiles to native 68000 code. It is very important that the code be stand-alone, in that it does not require additional modules to function properly. This article will use Pascal programs created with the Apple Macintosh Programmers Workshop (MPW) Pascal.

Calling the Externals

When 4th Dimension ‘calls’ the external procedure, it simply performs a direct link, Link A6, to the routine and executes the supplied code until the code ends, and by nature executes a return statement to the calling routine.

Because the supplied code is being called from within another application, you should not try to access any global variables, as those are stored off the A5 register and it’s contents may not be correct for your call. Therefore always declare your variables local. If you need the variables to be used as if they were global then define them within a procedure, and have all called procedures and functions defined within the procedure defining the ‘global’ variables.

The idea is to make all references relative. This is important because when the code is moved into 4th Dimension, the Code 0 segment is not used. (This is where the Jump table is located). Therefore if you have procedures you want to call, they should be declared as FORWARD and your top most procedure should be the one that ‘runs’ your program.

Following is an example external procedure. This procedure will receive a number, multiply the number by 2, and return the result. Because the variable is declared as a var in the procedure parameter list, the result can be returned to 4th Dimension.

Program Ext_Doubler;
VarDumInt:Integer;

procedure Doubler(var TheInt:Integer);
begin
 TheInt:=TheInt*2;
end;  {Doubler}

Begin
 Doubler(DumInt); {Used for compile only}
End.    {Main Block}

Following is an example utilizing multiple procedures which doesn’t take any parameters. It simply assigns the string ‘Hello there’ to the global variable Global2. It then beeps once for each character in the string. The variables Global1 and Global2, appear to be global type variables because the procedures which use them are within the scope of the procedure which defines both the variables and the procedure using the variables.

The main block calls the procedure Caller, (this call i4th Dimensionns only.) Caller then calls the procedure to be executed, HaveGlobals. HaveGlobals was declared as FORWARD so that Caller would know that it exists. HaveGlobals defines the variables to be used by the procedures defined in it’s scope. HaveGlobals assigns the string to Global2. It then calls First to assign the length of Global1 to Global2. Then Second is called to have the system beep Global1 times.

Program TestProg;

Uses Memtypes, QuickDraw, OSIntf;

procedure HaveGlobals; FORWARD;
{so Caller knows about the procedure}

procedure Caller;
begin
 HaveGlobals;
end;

procedure HaveGlobals;
var
 Global1:Integer;
 Global2:str255;

 procedure First;
 begin
 Global1:=Length(Global2);
 end; {First}

 procedure Second;
 var Count:Integer;
 begin
 For Count:=1 to Global1 do Sysbeep(2);
 end; {Second}

begin {HaveGlobals}
 Global2:=’Hello there’;
 First;
 Second;
end; {HaveGlobals}

Begin {Main Block}
 Caller;
End. {program}

Creation of External procedures

Be sure that if your external compiles to more than 1 code segment, or if one of the linked modules is placed in it’s own segment, that you join the segments into 1 complete segment. This is important if your application uses the SANE library.

You can compile to an application and then use the 4D External Mover™ to transfer the code segment and to specify the parameters. You can also compile directly to a Proc.Ext type file and specify the parameter list. Then you can use the 4D External Mover to copy the already set-up external to the proper Proc.Ext file. There will also be an item in the list, (if viewed in the 4D External Mover), with the name %A5Init. This item may be deleted from the list as it is not needed by the external.

Here is an example of a MPW linker spec to join the SANE code segment with the Main code segment and the method of installing directly into a Proc.Ext type file.

link -w -p MyProg.p.o 
 “{Libraries}”Interface.o 
 “{Libraries}”Runtime.o 
 “{PLibraries}”Paslib.o 
 “{PLibraries}”SANELib.o 
 -rt ‘4DEX=15000’  #Specify resource ID.
 # Joins segment Main and the Sane libraries into
 # one. *
 -sg “Main2=Main,SANELib “
 # Change segment name. **
 -sn ‘Main2’=’MyProg(&S;&R)’ 
 # Specify the creator and type.
 -c “4DMX” -t “PEXT”
 -o MyProg

* Note: for this external procedure, the Sane libraries are needed, therefore, they must exist in the same segment as the main code. If your code does not require the Sane libraries then this command is not necessary. Be sure to note the case used in “SANELib ” and the space which is between ‘b’ and the quote mark.

** The segment name was changed from Main2 to MyProg, the additional parameters, in parens, specify the types of the parameters being passed from 4th Dimension. In this example, (&S;&R), specifies that a String and a Real are to be passed. String first, Real second. Each parameter is preceded by an ampersand, ‘&’. A semicolon is used to separate each parameter.

The parameter types are as follows:

I Integer

L LongInt

R Real

S String

T Text

D Date

P Picture

Following are the Pascal type definitions for Date and Text fields.

Date    type
 Date4D = record
 day:integer;
 month:integer;
 year:integer;
 end;

Text    type
 TERec4D = record
 length:integer;
 text:CharsHandle;
 end;

With the release of the 128k ROMs, the restriction of code segments being less than 32k has gone away. Because of this, your external procedure may be very large. There is one important note however; you cannot perform a branch to an address which is farther than 32k from where you are branching from. The linker will catch this and you will have to put in a ‘stepping stone’ procedure. All these procedures do is call the procedure you wanted to call originally. They are located between the calling procedure and the procedure to be called and are used as stepping stones to get to the proper procedure.

In this example, we want to call Proc4 from Proc1. Proc1 and Proc3 are very large; such that the distance from the call to Proc3 and the location of Proc3 is greater than 32k when compiled. To accomplish the call we need to insert a ‘stepping stone’ procedure after Proc1 called Step. Proc1 calls the procedure Step. Step then calls Proc3. In this way, the distance between calls is less than 32k.

Program Ext_StepStone;

Uses Memtypes;

Var
 {Variable definitions}

procedure Proc2; Forward;
procedure Proc3; Forward;
procedure Step; Forward;

procedure Proc1;
var
 MyVar:str255;
begin
 MyVar:=’Hello’;
 {Now we call Step to get to Proc3}
 Step;
   {Lot’s of Code}
end;    {Proc1}

procedure Step;
begin
 {This routine just calls Proc3}
 Proc3;
end;    {Step}

procedure Proc2;
begin
   {Lot’s of code}
end;    {Proc2}

procedure Proc3;
begin
 {Here’s the code we want to use}
   {Some more code}
end;    {Proc3}

Begin {Main Block}
 Proc1;
End.  {Main Block}

Handles and External procedures

Whenever storing a data structure, be sure that you are accessing it via a Handle and that you lock the Handle if you want to ensure that it is there when you return.

Be sure to Dispose of all Handles that you have created when you have finished with them. If you leave unused handles in memory, you could run out of memory at a later point in the program.

Using Pictures in Externals

When passing Picture variables, to and from external procedures, be sure to include room for the additional 6 bytes needed by 4th Dimension to store the (Horizontal, Vertical) origin of the picture used when it is displayed in an On-Background field, (4 bytes), and the mode in which the picture is to be displayed, (2 bytes). For most pictures this means using SetHandleSize to increase the allocated space:

 SetHandleSize(Handle(MyPic),      
 GetHandleSize(Handle(MyPic))+6)

* Remember, Pictures can now be greater than 32k in size. Therefore the PicSize element of the PicHandle record, may not be valid. You should always call GetHandleSize to learn the size of the Picture.

When using externals it is sometimes necessary to save a complex data structure or just a handle of a type unknown to 4th Dimension. To store types of handle other than PicHandle, you can simply use Type Coercion to change the handle to type PicHandle and then pass the handle back to 4th Dimension in the form of a picture. Do not attempt to display the ‘picture’ as strange things will definitely happen.

Here is an example of storing SND’s in a 4th Dimension picture field. This example reads an SND resource from a file and returns to 4th Dimension a picture variable containing the SND. You can then store the picture (SND) and replay it at a later time using PlayPict, (the routine PlayPict follows this one). SoundToPict takes 3 parameters, SoundToPict(Parm1;Parm2;Parm3). Parm1 is the name of the file on disk containing the SND. Parm2 is the name of the SND to be retrieved. Parm3 returns a picture variable containing the SND. For information about the Resource Manager, see Inside Macintosh.

Program Ext_SoundToPict;

Uses MemTypes, QuickDraw, OSIntf,
 ToolIntf, PackIntf, Sound;

Var
 DFile, DSound:str255;
 DPict:PicHandle;

procedure SoundToPict(
 var TheFile, SoundName:str255;
 var MyPict:PicHandle);

type
 FFSynthHandle = ^FFSynthPtr;

var
 MySound:FFSynthHandle;
 TheRes:integer;
 MyPtr:Ptr;
 MyFFPtr:FFSynthPtr;

begin
 MyPict:=Nil;
 TheRes:=OpenResFile(TheFile);
 MySound:=FFSynthHandle(GetNamedResource
 (‘Snd ‘,SoundName));  {Locate SND}
 {Test if the sound was found and read}
 if MySound<>Nil then
 begin
 Hlock(Handle(MySound));
 {Copy the Pointer}
 MyPtr:=Ptr(MySound^);
 {Type coerce the new Ptr}
 MyFFPtr:=FFSynthPtr(MyPtr);
 {Set the playback mode and ratio}
 MyFFPtr^.mode:=FFMode;
 MyFFPtr^.count:=FixRatio(1,1);
 MyFFPtr^.wavebytes[0]:=0;
 {Type coerce the handle to type}
 {PicHandle}
 MyPict:=Pichandle(MySound);
 {Lock the picture so we don’t lose it}
 HLock(Handle(MyPict));
 {Coerce and Copy the pointer}
 MyPict^:=PicPtr(MyPtr);
 {Unlock the Handles before leaving}
 HUnlock(Handle(MySound));
 Hunlock(Handle(MyPict));
 {Now Detach the Resource since we}
 {have another handle to it.}
 DetachResource(Handle(MySound));
 end; {if mysound<>Nil}
 CloseResFile(TheRes);
end;    {SoundToPict}

Begin
 SoundToPict(DFile, DSound, DPict);
End.    {Main Block}

This routine is used to play the SND that was stored in a 4th Dimension picture field. It takes a 4th Dimension picture variable and converts the ‘picture’ to a sound. The sound is then played with StartSound. If the passed picture variable does not contain information generated by SoundToPict, you will get unexpected results. For information about the Sound Driver, see Inside Macintosh.

Program Ext_PlayPict;

Uses MemTypes, QuickDraw, OSIntf,
 ToolIntf, PackIntf, Sound;

Var
 DPict:PicHandle;
 DFile, DSound:integer;

procedure PlayPict(
 var Numer, Denom:integer;
 var MyPict:PicHandle);

type
 FFSynthHandle=^FFSynthPtr;

var
 MySound:FFSynthHandle;
 MyPtr:Ptr;
 MyFFPtr:FFSynthPtr;

begin
 {make sure that we recieved something}
 if MyPict<>Nil then
 begin
 {Coerce the handle}
 MySound:=FFSynthHandle(MyPict);
 {Lock the sound so we don’t lose it}
 HLock(Handle(MySound));
 {Copy the pointer}
 MyPtr:=Ptr(MySound^);
 {Type Coerce the pointer}
 MyFFPtr:=FFSynthPtr(MyPtr);
 {Set the playback mode}
 MyFFPtr^.mode:=FFMode;
 {Set the playback count to the}
 {parameters passed.}
 MyFFPtr^.count:=FixRatio(Numer, Denom);
 MyFFPtr^.wavebytes[0]:=0;
 {Play the sound}
 StartSound(MyPtr,
 GetHandleSize(Handle(MySound)),
 POINTER(-1));
 {Unlock the sound so it can be}
 {disposed}
 HUnLock(Handle(MySound));
 end;   {if MyPict<>Nil}
end;    {PlayPict}

Begin
 PlayPict(DFile, DSound, DPict);
End.    {Main Block}

The Grafport and External procedures

If you change the current Grafport or it’s settings, you must restore the Grafport to it’s original status before returning to 4th Dimension. For example, if you were to call an external procedure that changed the current Grafport to an off-screen port, perform some drawing operations, and use CopyBits to copy the image to the original Grafport, you must restore the Grafport to it’s original location before you leave the external procedure. You cannot access QuickDraw globals, therefore you must do the following to track the current GrafPort:

{Get the current GrafPort, DO NOT use  ThePort}
GetPort(OrgPort);
{Set to the new port}
SetPort(MyPort);
.
.
.
{Set the port back to it’s original status}
SetPort(OrgPort);

Changing the Mac environment

It is sometimes necessary to modify the settings of certain Mac items, such as the Serial Port buffer size. By default the buffer size is 64 bytes. Many applications that use the serial ports for communication need to have the buffer much larger. The buffer size can be modified while in 4th Dimension but you must remember to re-assign the buffer to it’s original location before exiting 4th Dimension or else the new buffer might be cleared by another system operation and there would be an erroneous pointer to buffer space.

Here is an example of how to modify the serial port buffers. This routine creates a new buffer the size of NbOfBytes for serial port access. SetSerialBuf takes 3 parameters, SetSerialBuf(Device;BufHandle;BufSize). Where Device contains the value 0 or 1 to specify Printer or Modem, respectively. BufHandle will return the address of the generated buffer. (Do not change this variable after the call, as it is needed to find and dispose of the buffer later.) BufSize specifies the size of the buffer in bytes, to be created. BufSize will return the size of the buffer actually created. The minimum buffer size is 1024 bytes. The maximum buffer size is 32000 bytes. In the case of an error, BufSize will return a negative number specifying the Macintosh Error Code. For an explanation of Macintosh Error Codes and information about the Device Manager, see Inside Macintosh.

Program Ext_SetSerBuf;

Uses  MemTypes,QuickDraw,OSIntf,ToolIntf,
 Packintf;
{$D+}
{$R-} 
Var
 BufHandle:Handle;
 PrinterOrModem,NbOfBytes:Integer;

procedure SetSerBuf(
 var PrinterOrModem:Integer;
 var BufHandle:Handle;
 var NbOfBytes:Integer);

var Error,RefNum:Integer;

begin
 {default buffersize of 1024 bytes}
 if NbOfBytes<1 then NbOfBytes:=1024;
 {max buffer size is 32000}
 if NbOfBytes>32000 then
 NbOfBytes:=32000;
 {generate space for the new buffer}
 BufHandle:=NewHandle(Ord4(NbOfBytes));
 {Test for Handle allocation error}
 Error:=MemError;
 if Error=NoErr then
 begin
 {Move Handle out of the way to avoid}
 {fragmentation.}
 MoveHHI(BufHandle);
 {Lock that puppy down}
 HLock(BufHandle);
 {Set Reference Number accordingly.}
 {0 is Printer, 1 is Modem}
 if PrinterOrModem=0 then
 RefNum:=-8 {Printer}
 else
 RefNum:=-6;{Modem}
 {Reassign the serial port buffer} Error:=SerSetBuf(RefNum,Ptr(BufHandle^)
   ,Ord(GetHandleSize(BufHandle)));
 {Test for errors from reassignment}
 if Error<>NoErr then
 begin
 {If errors then beep and undo what we}
 {have done.}
 SysBeep(10);
 {Assign the error code to NbOfBytes}
 {so that it is returned}
 NbOfBytes:=Error;
 {Unlock and dispose of buffer}
 HUnLock(BufHandle);  DisposHandle(BufHandle);  BufHandle:=Nil;
 end;   {if Error<>NoErr}
 end    {if Error=NoErr, TRUE}
 else
 begin
 {there was a memory allocation error}
 SysBeep(10);
 NbOfBytes:=Error;
 end;   {if Error=NoErr, FALSE}
end;    {SetSerBuf}

Begin
 SetSerBuf(PrinterOrModem,BufHandle,
 NbOfBytes);
End. {Main Block}

This routine disposes of the buffer created by SetSerialBuf and reassigns the serial port back to it’s default buffer. ClearSerBuf takes two parameters, SetSerBuf(Device; BufHandle). Device specifies the printer or modem port and should be the same value that was used when SetSerBuf was called. BufHandle contains the address to the buffer generated by SetSerBuf.

Program Ext_ClearSerBuf;

Uses
 MemTypes,QuickDraw,OSIntf,ToolIntf,
 PackIntf;
{$D+}
{$R-}
var
 BufHandle:Handle;
 PrinterOrModem,NbOfBytes:Integer;

procedure ClearSerBuf(
 var PrinterOrModem:Integer;
 var BufHandle:Handle);

var Error,RefNum:Integer;

begin
 {test for validity of passed Handle}
 if BufHandle<>Nil then
 begin
 {set RefNum according to the port}
 if PrinterOrModem=0 then
 RefNum:=-8
 else
 RefNum:=-6;
 {Disable usage of our buffer}
 Error:=SerSetBuf(RefNum,Ptr(BufHandle^)
 ,0);
 {Test for errors}
 if Error=NoErr then
 begin
 {Unlock and Dispose of the Handle}
 HUnLock(BufHandle);      DisposHandle(BufHandle);
 BufHandle:=Nil;
 end  {if Error=NoErr, TRUE}
 else
 {Problem encountered}
 SysBeep(10);  {if Error=NoErr, FALSE}
 end    {if BufHandle<>Nil, TRUE}
 else
 {Non-Valid Handle was passed}
 SysBeep(10);
 {if BufHandle<>Nil, FALSE}
end;    {ClearSerBuf}

Begin
 ClearSerBuf(PrinterOrModem,BufHandle);
End.  {Main Block}

External Areas

External Areas provide a way for an external procedure to take complete control of an area on a 4th Dimension input layout. You could, for example, allow the user to draw shapes using QuickDraw, implement a full-function word processor, or display a picture format that is not supported by 4th Dimension such as TIFF.

You need at least two external procedures to operate an external area. One of the external procedures will control the activity in the external area. One or more external procedures will be used to exchange information with the external area procedure. When the 4th Dimension input layout is opened, the external area procedure will be called and should create a data structure in memory. This data structure will be used by other external procedures to ‘talk’ with the external area. In this way your 4th Dimension procedure can know what is happening in the external area and it can provide the external area procedure with information about other user operations.

You define an external area on a 4th Dimension layout by drawing a variable field and specifying it as an External Area. The variable name will be used to store the address of the data structure defined in your external area. You enter the name of the external area procedure in the format box in the variable definition dialog. (The box may be labeled as ‘Not Used’.) The size of the variable box on the layout will determine the size and location of the rectangle which your external area procedure can control.

Procedures that are to be used as external area procedures must be defined as follows:

procedure MyExtArea(
 var AreaEvent:EventRecord;
 var AreaRect:Rect;
 var AreaName:str255;
 var AreaHndl:MyDataHndl);

EventRecord, Rect, and str255 are defined in Inside Macintosh.

AreaEvent is used to inform your external area of Macintosh events.

AreaRect contains the current location of your external area on the screen.

AreaName contains the name of the 4th Dimension variable on the layout which defines the external area.

AreaHndl contains is a handle to your data structure defined as type MyDataHndl. AreaHndl is used to exchange information between your 4th Dimension procedure and your external area procedure.

You can test for the following events via the EventRecord.what parameter:

InitEvt 16

DeInitEvt 17

CursorEvt 18

SelectReq 20

ActivNote 21

DeActivNote 22

NotUsed 23

NotUsed 24

ScrollEvt 25

DrawReq 26

UpdateEvt predefined in the Toolbox

MouseDown predefined in the Toolbox

Event 16 is informing you that your routine has been called for the first time and you should create any data structures required by your external area. (Define AreaHndl.)

Event 17 is informing you that your routine is about to be removed and you should clean-up and dispose of any data structures you created. (Dispose of AreaHndl.)

Event 18 is informing you that the cursor is over the area defined for your external area.

Event 20 is a request for you to accept all keyboard events. If you return the value 101 in the message element, you will receive all subsequent keyboard events until the user clicks on another item in the input layout.

Event 21 is sent only if you requested to be selectable when you received event 20. The receipt of event 21 means that your area has been selected and you should prepare to receive keyboard events.

Event 22 is sent only if you requested to be selectable when you received event 20. The receipt of event 22 means that your area has been deselected and you should not continue testing for keyboard events.

Event 25 is informing you that the window is being scrolled. This is so you can update the rectangle coordinates you are using. DO NOT update the screen when this event has been received. You will receive an UpdateEvt if the screen needs to be updated.

Event 26 is a request for you to display your picture in the 4th Dimension Layout Editor in place of the 1’s and 0’s displayed by 4th Dimension. If you return the value 102 in the message element, 4th Dimension will not draw the area occupied by the defined variable associated with the external area procedure. If you accept responsibility for drawing the area, then you must draw a picture or nothing will be displayed.

You do not directly pass parameters to an external area procedure, rather you access the data structure defined as type MyDataHndl and place information in the data structure for the external area to recognize and act upon.

For example, the following external area procedure detects a mouse down event within an external area. When a mouse down is detected in the external area, a 1 will be stored in the data structure pointed to by AreaHndl. This external area procedure is useful for defining invisible buttons on a 4th Dimension input layout.

Program Ext_AreaButton;

Uses MemTypes, QuickDraw, OSIntf,
 ToolIntf, PackIntf;

Const
 InitEvt=16;
 DeInitEvt=17;

Type
 {This is the definition of the data}
 {structure I want to use.  All I want}
 {to know is if the Mouse was clicked}
 {in the external area.  0 if NO,}
 {1 if YES.}
 MyData = record
   Status:Integer;
 end;
 MyDataPtr = ^ MyData;
 MyDataHndl = ^MyDataPtr;

Var
 AreaEv:EventRecord;
 AreaRec:Rect;
 AreaNam:str255;
 AreaHnd:MyDataHndl;

procedure AreaButton(
 var AreaEvent:EventRecord;
 var AreaRect:Rect;
 var AreaName:str255;
 var AreaHndl:MyDataHndl);

var tPoint:Point;{Tracks the mouse location.}

begin
 Case AreaEvent.What of
 InitEvt:
 begin
 {Create a new handle for our}
 {structure.}
 AreaHndl:=MyDataHndl(NewHandle(
 sizeof(MyData)));
 {Initialize the setting to 0. Not}
 {clicked.}
 AreaHndl^^.Status:=0;
 end; {InitEvt}
 MouseDown:
 begin
 {Wait for mouse up so we know they}
 {completed the click within our}
 {area and didn’t drag out of the}
 {area before releasing.}
 While StillDown do begin end;
 {Is the mouse in our area?}
 GetMouse(tPoint);
 {AreaRect is our rect so test if the}
 {point is in our area.}
 if(PtInRect(tPoint, AreaRect)) then
 {They clicked in our area so}
 {Status=1.  Clicked}
 AreaHndl^^.Status:=1;
 end; {MouseDown}
 DeInitEvt:
 begin  {Get rid of our handle}
 DisposHandle(Handle(AreaHndl));
 end; {DeInitEvt}
 end; {Case AreaEvent.What}
end;  {AreaButton}

Begin
 AreaButton(AreaEv, AreaRec, AreaNam,
 AreaHnd);
End.    {Main Block}

The external area procedure above will track whether a mouse down has occurred in the external area. Now we need to check it’s status from our 4th Dimension procedure. We check the status by calling another external procedure which accesses the data structure we created and returns the current setting of AreaHndl^^.Status. Once we’ve tested the variable, we set AreaHndl^^.Status back to 0, (not clicked), so we can test for the next mouse down.

We check the current setting with the following external procedure:

Program Ext_GetButton;

Uses MemTypes, QuickDraw, OSIntf,
 ToolIntf, PackIntf;

Type
 MyData = record
 Status:Integer;
 end;
 MyDataPtr = ^ MyData;
 MyDataHndl = ^MyDataPtr;

Var
 Areahnd:MyDataHndl;
 Result:Integer;

procedure GetButton(
 var AreaHndl:MyDataHndl;
 var Result:Integer);

begin
 {Result returns Status}
 Result:=AreaHndl^^.Status;
 {Set Status to Not Clicked}
 AreaHndl^^.Status:=0;
end;    {GetButton}

Begin
 GetButton(AreaHnd, Result);
End.

From 4th Dimension we would call this procedure as GetButton(MyButton;Clicked). Where MyButton is the name of the 4th Dimension variable defining the space for the external area. (Remember, the variable name contains the address of the data structure in memory.) Clicked is a 4th Dimension global variable which will return the current setting of AreaHndl^^.Status.

When writing and installing external areas it is important to note that once you have assigned the external area to a variable in the layout editor, the External is called by the layout editor. Therefore, it is important that your routine be ready to be called immediately.

4D External Mover

There are 3 resource types used for 4th Dimension externals plus any additional resources required by your external procedure. They are 4DEX, 4DTE, and 4BND.

4DEX contains the code for your external procedure. Each procedure must have only one 4DEX resource. Therefore, if your procedure compiles to more than one code segment, you must use linker commands to join the code segments.

4DTE contains the comments about the external procedure. The information in 4DTE resources, appear in the comments field in 4D External Mover, for the associated 4DEX code.

4BND contains the bundling information needed by 4D External Mover to properly copy your external routines and bundled resources to other files. Bundling ensures that when you use the 4D External Mover to transfer an external to another file, that you get all necessary resources which have been bundled with that external procedure.

When 4D External Mover copies external procedures and any associated resources, specified in the bundle, it checks the global resource id’s of resources currently in the file. If the resource id of the external you want to install is already in use, then 4D External Mover will change the global id of the resource being copied. If the id changes, 4D External Mover will also update the bundle information for that external procedure. Because the resource id may change when the resource is later copied, it is important to not access needed resources directly via the global resource id, unless you are sure the id is correct. Following is example code for obtaining the global id of resources which may have moved. This code is from the 4th Dimension Utilities and Developers Notes.

{The CurProcResid function is assembly}
{code which returns the 4BND resource}
{number.}

function CurProcResid:Integer;
INLINE $3EAD, $DE4E;

function GetResNum(T:ResType; Localid:Integer):Integer; FORWARD;
.
. Your code here
.

{Pass GetResNum the resource type and}
{the local id and it will return the}
{global id.}

function GetResNum;

type
 ResEntry = record
 Typ:ResType;
 LocalNum, GlobalNum:Integer;
 end;
 ResTab = record
 nbEntry:Integer;
 Tab:array[1..1] of ResEntry;
 end;
 ResTabPtr = ^ResTab;
 ResTabHandle = ^ResTabPtr;

var
 i:Integer;
 r:ResTabHandle;
 Done:Boolean;

begin
 GetResNum:=0;
 Done:=False;
 i:=1;
 {Get the pointer to 4BND resource}
 r:=POINTER(GetResource(‘4BND’,
 CurProcResId));
 {make sure we found the resource}
 if r<> Nil then
 begin
 {Cycle thru all the entries in the}
 {4BND resource}
 while((i<=r^^.nbEntry) and
 (Not(Done))) do
 begin
 {loop until we find the one with}
 {the localID and the type we want}
 with r^^.Tab[i] do
 begin
 {check for a match}
 if (t=Typ) and
 (LocalNum=LocalId) then
 begin
 {we found it, so return the}
 {GlobalID to the calling routine}
 GetResNum:=GlobalNum;
 Done:=True;
 end; {if}
 end; {with}
 i:=i+1;{increment our entry counter}
 end;   {while}
 end;   {if r<>Nil}
end;    {GetResNum}

4th Dimension and external procedures can significantly improve your programming efficiency. 4th Dimension can fulfill most of your program development and data management needs. External procedures can supplement 4th Dimension by providing an open architecture and greater flexibility. This document provided the information you need to create and install external procedures to 4th Dimension. I hope this will help you to create externals to make your 4th Dimension databases and applications insanely great.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Smultron 10.0.2 - Easy-to-use, powerful...
Smultron 10 is an elegant and powerful text editor that is easy to use. You can use Smultron 10 to create or edit any text document. Everything from a web page, a note or a script to any single piece... Read more
Capto 1.2.5 - $29.99
Capto (was Voila) is an easy-to-use app that takes capturing, recording, video and image editing to the next level. With an intelligent file manager and quick sharing options, Capto is perfect for... Read more
Cocktail 11.0.1 - General maintenance an...
Cocktail is a general purpose utility for macOS that lets you clean, repair and optimize your Mac. It is a powerful digital toolset that helps hundreds of thousands of Mac users around the world get... Read more
Sketch 47.1 - Design app for UX/UI for i...
Sketch is an innovative and fresh look at vector drawing. Its intentionally minimalist design is based upon a drawing space of unlimited size and layers, free of palettes, panels, menus, windows, and... Read more
Slack 2.8.2 - Collaborative communicatio...
Slack is a collaborative communication app that simplifies real-time messaging, archiving, and search for modern working teams. Version 2.8.2: A small release containing nothing but another Electron... Read more
Path Finder 7.6.1 - Powerful, award-winn...
Path Finder makes you a master of file management. Take full control over your file system. Save your time: compare and synchronize folders, view hidden files, use Dual Pane and full keyboard... Read more
Sketch 47.1 - Design app for UX/UI for i...
Sketch is an innovative and fresh look at vector drawing. Its intentionally minimalist design is based upon a drawing space of unlimited size and layers, free of palettes, panels, menus, windows, and... Read more
Cocktail 11.0.1 - General maintenance an...
Cocktail is a general purpose utility for macOS that lets you clean, repair and optimize your Mac. It is a powerful digital toolset that helps hundreds of thousands of Mac users around the world get... Read more
Path Finder 7.6.1 - Powerful, award-winn...
Path Finder makes you a master of file management. Take full control over your file system. Save your time: compare and synchronize folders, view hidden files, use Dual Pane and full keyboard... Read more
Slack 2.8.2 - Collaborative communicatio...
Slack is a collaborative communication app that simplifies real-time messaging, archiving, and search for modern working teams. Version 2.8.2: A small release containing nothing but another Electron... Read more

Dune! guide - how to toe the line and ge...
Publisher Voodoo is at it again with an all new high score chaser -- Dune! In this fast-paced arcade game, you have to propel yourself along sand dunes, gaining enough momentum to jump above the line to score points, while making sure you have... | Read more »
The best deals on the App Store this wee...
Happy Tuesday, dear readers. Your favorite part of the week as officially arrived. It's time to take a look at the best deals in games. Things are admittedly a bit sparse, but there are a few diamonds in the rough to see you through if you're... | Read more »
Be the last person standing in Legacy of...
Yoozoo Games’ popular action MMO Legacy of Discord is getting a huge new update to celebrate its first anniversary. Perhaps the biggest change is the addition of an exciting survival mode titled Last Guardian. This new survival mode will pit you... | Read more »
Home Street guide - how to make friends...
From the creators of Food Street comes Home Street, a new simulation game that tasks you with building a social network and designing a beautiful home. It's a bit like The Sims, but you won't have to worry about the daily chores involved (feeding,... | Read more »
Color Ballz guide - how to bounce to the...
Color Ballz is an addictive new arcade title from Ketchapp Studios. It takes old school mechanics from games like Brickles and puts a fun twist on it. Your job? To catch balls with a paddle and send them back into a chute to be carried back to... | Read more »
Q&A: A-33 Studio explains why Combat...
When it comes to mobile FPS, it’s often tricky to get the fundamentals right on a platform lacking a physical controller, large display and hefty RAM. With Combat Squad: Project Wednesday, A-33 Studio bravely took on the challenge of making a... | Read more »
Taichi Panda 3: Dragon Hunter guide - ti...
Taichi Panda 3: Dragon Hunter launched this week to players all over the world. It's a beautiful mobile MMORPG that blends elements of Eastern and Western fantasy. It reminds us of a mix between World of Warcraft and Jade Empire. MMO's can have a... | Read more »
The best new games we played this week -...
Phew. It has been a week, but now it's time to relax, put your feet up, and enjoy some brand new mobile games. It was a bit of slow week, but there's still plenty of new titles to add to your collection. Here are four of our favorites. [Read... | Read more »
Yoink - Improved Drag and Drop (Product...
Yoink - Improved Drag and Drop 1.0 Device: iOS Universal Category: Productivity Price: $2.99, Version: 1.0 (iTunes) Description: Yoink for iPad and iPhone lets you easily and quickly store items you drag, copy or share, for later use... | Read more »
Cottage Garden (Games)
Cottage Garden 1.11 Device: iOS Universal Category: Games Price: $4.99, Version: 1.11 (iTunes) Description: | Read more »

Price Scanner via MacPrices.net

13″ MacBook Pros on sale for up to $120 off M...
B&H Photo has 2017 13″ MacBook Pros in stock today and on sale for up to $120 off MSRP, each including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Space Gray MacBook... Read more
15″ MacBook Pros on sale for up to $200 off M...
B&H Photo has 15″ MacBook Pros on sale for up to $200 off MSRP. Shipping is free, and B&H charges sales tax in NY & NJ only: – 15″ 2.8GHz MacBook Pro Space Gray (MPTR2LL/A): $2249, $150... Read more
Roundup of Apple Certified Refurbished iMacs,...
Apple has a full line of Certified Refurbished 2017 21″ and 27″ iMacs available starting at $1019 and ranging up to $350 off original MSRP. Apple’s one-year warranty is standard, and shipping is free... Read more
Sale! 27″ 3.8GHz 5K iMac for $2098, save $201...
Amazon has the 27″ 3.8GHz 5K iMac (MNED2LL/A) on sale today for $2098 including free shipping. Their price is $201 off MSRP, and it’s the lowest price available for this model (Apple’s $1949... Read more
Sale! 10″ Apple WiFi iPad Pros for up to $100...
B&H Photo has 10.5″ WiFi iPad Pros in stock today and on sale for $50-$100 off MSRP. Each iPad includes free shipping, and B&H charges sales tax in NY & NJ only: – 10.5″ 64GB iPad Pro: $... Read more
Apple iMacs on sale for up to $130 off MSRP w...
B&H Photo has 21-inch and 27-inch iMacs in stock and on sale for up to $130 off MSRP including free shipping. B&H charges sales tax in NY & NJ only: – 27″ 3.8GHz iMac (MNED2LL/A): $2179 $... Read more
2017 3.5GHz 6-Core Mac Pro on sale for $2799,...
B&H Photo has the 2017 3.5GHz 6-Core Mac Pro (MD878LL/A) on sale today for $2799 including free shipping plus NY & NJ sales tax only . Their price is $200 off MSRP. Read more
12″ 1.2GHz Space Gray MacBook on sale for $11...
Amazon has the 2017 12″ 1.2GHz Space Gray Retina MacBook on sale for $100 off MSRP. Shipping is free: 12″ 1.2GHz Space Gray MacBook: $1199.99 $100 off MSRP Read more
Bare Bones Software Releases macOS High Sierr...
Bare Bones Software has announced the release and immediate availability of BBEdit 12.0, a significant upgrade to its professional strength text and code editor. BBEdit 12 introduces a new foundation... Read more
Yale Announces Availability of Apple HomeKit-...
Yale Locks & Hardware has announced that Apple HomeKit support for its Assure Lock family is available this month. The new Yale iM1 Network Module, which provides support for the Apple Home app... Read more

Jobs Board

Fraud Analyst, *Apple* Advertising Platform...
Job Summary Apple Ad Platforms has an opportunity to redefine advertising on mobile devices. Apple reaches hundreds of millions of iPhone, iPod touch, and iPad Read more
*Apple* Information Security - Security Data...
Job Summary This role is responsible for helping to strengthen Apple 's information security posture through the identification and curation of security event data. Read more
Lead *Apple* Solution Consultant - Apple In...
…develop a team of diverse partner employees focusing on excellence to deliver the Apple story. Even when you're not present, you will maintain a consistent influence Read more
watchOS Frameworks Engineering Manager, *App...
Job Summary Join the team that is shaping the future of software development for Apple Watch! Apple is looking for an exceptional software engineering leader to Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.