[comp.sys.mac.hypercard] XCMD's cannot set global variables.

willcox@urbana.mcd.mot.com (David A Willcox) (05/25/90)

In article <3707@darkstar.ucsc.edu> sirkm@ssyx.ucsc.edu (Greg Anderson) writes:

>I believe that the book "XCMD's for HyperCard" by Gary Bond mentions that
>XCMDs cannot create global variables.  His solution, if I recall, is to
>create a new button (from within the XCMD), give it a script that references
>the global variable & then do a callback to it.

Am I missing something?  I don't have any documentation available here
at work, but I could swear that there are a pair of callbacks called
something like GetGlobal() and SetGlobal() that let you get and set
globals from an XCMD.  I've used them, and they work.  It's the only
way I know of to keep some memory around between invocations of an
XCMD.  (Allocate a handle, convert its address to something ASCII,
store it in a global.)

David A. Willcox
Motorola MCD - Urbana		UUCP: ...!uiucuxc!udc!willcox
1101 E. University Ave.		INET: willcox@urbana.mcd.mot.com
Urbana, IL 61801		FONE: 217-384-8534

sirkm@ssyx.ucsc.edu (Greg Anderson) (05/28/90)

In article <1266@urbana.mcd.mot.com> willcox@urbana.mcd.mot.com (David A Willcox) writes:
>In article <3707@darkstar.ucsc.edu> I write:
>>I believe that the book "XCMD's for HyperCard" by Gary Bond mentions that
>>XCMDs cannot create global variables.
>
>Am I missing something?  I don't have any documentation available here
>at work, but I could swear that there are a pair of callbacks called
>something like GetGlobal() and SetGlobal() that let you get and set
>globals from an XCMD.  I've used them, and they work.

Yes, GetGlobal and SetGlobal exist and work fine, but in my experience,
strange things happen if the global variables do not exist before the
XCMD tries to Get or Set them.  (Strange things == the next XCMD that
gets the variable finds it empty.)

The best solution is to declare "Global foo" in some script that is always
executed before the XCMD is invoked.
  ___\    /___               Greg Anderson              ___\    /___ 
  \   \  /   /         Social Sciences Computing        \   \  /   /
   \  /\/\  /    University of California, Santa Cruz    \  /\/\  /
    \/    \/              sirkm@ssyx.ucsc.edu             \/    \/

willcox@urbana.mcd.mot.com (David A Willcox) (05/31/90)

>>In article <3707@darkstar.ucsc.edu> I write:
>>>I believe that the book "XCMD's for HyperCard" by Gary Bond mentions that
>>>XCMDs cannot create global variables.
>>
>>Am I missing something?  I don't have any documentation available here
>>at work, but I could swear that there are a pair of callbacks called
>>something like GetGlobal() and SetGlobal() that let you get and set
>>globals from an XCMD.  I've used them, and they work.

>Yes, GetGlobal and SetGlobal exist and work fine, but in my experience,
>strange things happen if the global variables do not exist before the
>XCMD tries to Get or Set them.  (Strange things == the next XCMD that
>gets the variable finds it empty.)

>The best solution is to declare "Global foo" in some script that is always
>executed before the XCMD is invoked.

I couldn't believe this since I've used SetGlobal() and GetGlobal() in
XCMDs without "global foo" in any script.  I went home and tried it, and
found that you are absolutely wrong - the "global foo" is not required. 
Source for my very simple minded example in Think C 3.?  is below. 

BUT THEN...  As a last step in checking this out, I tried my example
on the old klunker machine at work, and found that it didn't work -
the "global foo" was necessary in the script.  The difference appears
to be that the MAC at work still has HC version 1.0.1, while I have
version 1.2.something.

My conclusion - If you have a "modern" version of HyperCard, then you
can create globals from within an XCMD/XFCN; the "global" in your
script is not necessary.  If you have an old version of HyperCard, the
"global" is necessary.  Sounds to me like a bug that has been fixed.

David A. Willcox		"Just say 'NO' to universal drug testing"
Motorola MCD - Urbana		UUCP: ...!uiucuxc!udc!willcox
1101 E. University Ave.		INET: willcox@urbana.mcd.mot.com
Urbana, IL 61801		FONE: 217-384-8534

Sample XCMD:

/*
 * Invoke this as "GetSetGlobal arg".  It remembers arg, and
 * returns the previous value of arg.
 */

#include <MacTypes.h>
#include <HyperXCmd.h>
#include <SetUpA4.h>

#define nil 0L

#define GLOB_NAME "\pDummyGlobal"

pascal void main (XCmdBlock *);

Handle CopyHand(h)
Handle *h;
{
    long len;
    Handle ret;
    
    len = strlen (*h) + 1;
    ret = NewHandle (len);
    strcpy (*ret, *h);	/* yeah, I should lock them ... */
    return (ret);
}

pascal void main (paramPtr)
XCmdBlock *paramPtr;
{
    RememberA0();
    SetUpA4();
    
    paramPtr->returnValue = GetGlobal (paramPtr, (StringPtr)GLOB_NAME);
    SetGlobal (paramPtr, (StringPtr)GLOB_NAME, CopyHand (paramPtr->params[0]));

    RestoreA4();
}

johner@portia.Stanford.EDU (John Lynch) (06/03/90)

In article <1269@urbana.mcd.mot.com> willcox@urbana.mcd.mot.com (David A Willcox) writes:

>My conclusion - If you have a "modern" version of HyperCard, then you
>can create globals from within an XCMD/XFCN; the "global" in your
>script is not necessary.  If you have an old version of HyperCard, the
>"global" is necessary.  Sounds to me like a bug that has been fixed.
>
Just a note: You need to declare them in Supercard also. At least, you
do if you are going to access them explicitly from Supertalk. In other
words, if you create a dummy global just to use from your XCMD, like
XXX_My_Global, then only acces it from an XCMD, you are fine, i.e. you get
the necessary storage and the XCMD can find it. But if you explicilty use it
in Supertalk when it was created from an XCMD, it usually can't find it
the first time. In fact, if you acces it within a callback from the XCMD,
you often crash. Whoops. Point is, if using Supercard, declare globals you
expect to set from an XCMD.

John Lynch
Trilogy Development Group