• Hello MLAers! We've re-enabled auto-approval for accounts. If you are still waiting on account approval, please check this thread for more information.

Is there a programming forum here for help using the Toolbox Manager and Quickdraw Manager?

I think it's using the Basilisk II emulator. It's totally feasible to build software under BasiliskII using a period IDE - I do that - but debuggers don't work very well.
For PowerPC, SheepShaver can build with Code Warrior Pro 4 but not debug. SheepShaver supports 7.5.3 and later.

I was able to get farther with debugging in DingusPPC but sometimes it would bus error so there still might be work to do there. DingusPPC supports 7.1.2 and later.

Is this an emulator? I'm writing a software that uses large chunks of RAM, and I'm glad to see your post, by the way, I would really like to have a real Mac, but such machines don't exist in my area.
An emulator makes it easier to test different Macs, RAM sizes, and OS's.
 
I think it's using the Basilisk II emulator. It's totally feasible to build software under BasiliskII using a period IDE - I do that - but debuggers don't work very well.
Hi, I would like to ask you a question, I am using NewPtr to request a 128K space and it fails, what should I do about it? Thanks.
 
For PowerPC, SheepShaver can build with Code Warrior Pro 4 but not debug. SheepShaver supports 7.5.3 and later.

I was able to get farther with debugging in DingusPPC but sometimes it would bus error so there still might be work to do there. DingusPPC supports 7.1.2 and later.


An emulator makes it easier to test different Macs, RAM sizes, and OS's.
Hi, do you know any details about NewPtr? I was hoping to request a very large space, about 128K, but it failed, how should I achieve this? Thank you.
 
Hi, I would like to ask you a question, I am using NewPtr to request a 128K space and it fails, what should I do about it? Thanks.

well, for starters, unless you have a very good reason you should be using NewHandle instead...

have you checked how much memory is allocated to your application? Don't forget in MacOS, the memory available to an application is manually set, the system does not manage it for you.
 
well, for starters, unless you have a very good reason you should be using NewHandle instead...

have you checked how much memory is allocated to your application? Don't forget in MacOS, the memory available to an application is manually set, the system does not manage it for you.
Sorry, I'm using Think C and I'm not sure how I should set the size of the allocated memory.

NewHandle also fails, which is a bit strange.

The reason I'm using 128K of RAM is that I have a homebrew emulator, but lack a way to import files, and I'm going to make that happen with this RAM.
 
Sorry, I'm using Think C and I'm not sure how I should set the size of the allocated memory.

In development, go to Project -> Project Type and set the Partition under that. Your production application, you'll want that in a SIZE resource. I'm not sure if THINK C generates one for you - it might.

NewHandle also fails, which is a bit strange.

I think the default partition size under at least the version of Think C I have is something like 300K, which would account for it.

The reason why you should use handles not pointers is to allow the memory manager to defragment your heap for you and move memory about. If you use NewPtr, you have a pointer and thus the block the memory manager hands to you can never move. If you have a handle, you have a pointer to another pointer, and that other pointer can be changed by the memory manager (look for the little "moves memory" icons in THINK Reference). The downside, of course, is that you have to be a bit careful about where you call things that can move memory.
 
In development, go to Project -> Project Type and set the Partition under that. Your production application, you'll want that in a SIZE resource. I'm not sure if THINK C generates one for you - it might.



I think the default partition size under at least the version of Think C I have is something like 300K, which would account for it.

The reason why you should use handles not pointers is to allow the memory manager to defragment your heap for you and move memory about. If you use NewPtr, you have a pointer and thus the block the memory manager hands to you can never move. If you have a handle, you have a pointer to another pointer, and that other pointer can be changed by the memory manager (look for the little "moves memory" icons in THINK Reference). The downside, of course, is that you have to be a bit careful about where you call things that can move memory.
Thank you, I'll give it a go, I know a toolkit routine called HLock prevents the memory manager from moving it, yes?
 
Thank you, I'll give it a go, I know a toolkit routine called HLock prevents the memory manager from moving it, yes?
If I can chip in? I'm more of a THINK C person (version 5), so I'm fairly familiar with it. There is one good reason to use NewPtr, when it's a fixed block of memory you know will never get deallocated. You allocate it at the beginning and then just leave it there. It's a bit faster and less error-prone to access and the garbage collector won't have to work around it.

A Handle, as I guess you know is a pointer to a pointer. That means that instead of e.g.

C:
typedef struct {
    char iName[256];
    int iAge, iZipCode;
}tMyInfo;

... later...
    
tMyInfo *gInfo;

gInfo=(tMyInfo *)NewPtr(sizeof(tMyInfo));
... later....
DrawString(gInfo->iName);

You'd end up doing:

C:
typedef struct {
    char iName[256];
    int iAge, iZipCode;
}tMyInfo;

... later...
    
tMyInfo **gInfo;

gInfo=(tMyInfo **)NewHandle(sizeof(tMyInfo));
... later....
HLock(gInfo); // lock the handle first.
DrawString((*gInfo)->iName);
HUnlock(gInfo); // unlock when finished

So everything gets a bit more complex then. If you use a QuickDraw routine on a handle, you'll need to lock it first, - lock it because many routines move memory, so you need to prevent that from happening. And if early Mac OS can't move memory it can generate out-of-memory errors just like for NewPtr. Also Locking and Unlocking isn't reference counted or some other garbage collection technique. Instead there's just a single global lock per handle. Also, you should allow handles to be purgeable when possible, so that Mac OS can free their memory. Also, it's common practice to HMoveHi(aHandle) when possible too, to make the garbage collector more efficient.

Lots of rules. But, I do actually like handles, they're a clever technique for coping with low-memory computers. They'd be a really good technique to apply to lots of IOT oriented MCUs which have a lot of the same kinds of constraints (on MCUs I tend to statically allocate so I can be sure that I don't get memory allocation failures).
 
If I can chip in? I'm more of a THINK C person (version 5), so I'm fairly familiar with it. There is one good reason to use NewPtr, when it's a fixed block of memory you know will never get deallocated. You allocate it at the beginning and then just leave it there. It's a bit faster and less error-prone to access and the garbage collector won't have to work around it.

A Handle, as I guess you know is a pointer to a pointer. That means that instead of e.g.

C:
typedef struct {
    char iName[256];
    int iAge, iZipCode;
}tMyInfo;

... later...
   
tMyInfo *gInfo;

gInfo=(tMyInfo *)NewPtr(sizeof(tMyInfo));
... later....
DrawString(gInfo->iName);

You'd end up doing:

C:
typedef struct {
    char iName[256];
    int iAge, iZipCode;
}tMyInfo;

... later...
   
tMyInfo **gInfo;

gInfo=(tMyInfo **)NewHandle(sizeof(tMyInfo));
... later....
HLock(gInfo); // lock the handle first.
DrawString((*gInfo)->iName);
HUnlock(gInfo); // unlock when finished

So everything gets a bit more complex then. If you use a QuickDraw routine on a handle, you'll need to lock it first, - lock it because many routines move memory, so you need to prevent that from happening. And if early Mac OS can't move memory it can generate out-of-memory errors just like for NewPtr. Also Locking and Unlocking isn't reference counted or some other garbage collection technique. Instead there's just a single global lock per handle. Also, you should allow handles to be purgeable when possible, so that Mac OS can free their memory. Also, it's common practice to HMoveHi(aHandle) when possible too, to make the garbage collector more efficient.

Lots of rules. But, I do actually like handles, they're a clever technique for coping with low-memory computers. They'd be a really good technique to apply to lots of IOT oriented MCUs which have a lot of the same kinds of constraints (on MCUs I tend to statically allocate so I can be sure that I don't get memory allocation failures).
Hi, I wrote just a small tool that implements the same functionality as ImportFl for minivmac, which I use because of the large amount of information linking NewPtr and malloc. Well, I set the Partition to 1024,it still doesn't work, what should I do to get 128K of space using NewPtr?
 
Hi, I have set the partition to 1024 but NewPtr and NewHandle both fail with the error message Insufficient Memory. My environment is SE with 4MB of RAM. in the end I was just hoping to get a 32KB space and it still fails.

Oh, and I've used MaxApplZone at the beginning of the programme.
 
Last edited:
Hi, I have set the partition to 1024 but NewPtr and NewHandle both fail with the error message Insufficient Memory. My environment is SE with 4MB of RAM. in the end I was just hoping to get a 32KB space and it still fails.

Oh, and I've used MaxApplZone at the beginning of the programme.
It should certainly be possible to allocate over 128kB. I'll look into it at my end!
 
As I said, I don't use THINK C, but this works under CWPro:

C:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <Memory.h>

#define K 1024

int main(void)
{
    Handle hdl;
    OSErr err;

    printf("hello world\n");
    hdl = NewHandle(128 * K);
    err = MemError();
    
    if (hdl == NULL) {
        printf("allocation failed:\n");
        switch(err) {
        case -108:
            printf("no room in heap"); break;
        case -109:
            printf("nil handle"); break;
        case -111:
            printf("illegal op on free block"); break;
        case -112:
            printf("illegal op on locked block"); break;
        case -117:
            printf("can't move a locked block"); break;
        default:
            printf("err: %h", err); break;
        }
        printf("\n");
    } else {
        printf("allocation successful\n");
        DisposeHandle(hdl);
    }
    
    return 0;
}

You might want to see if you can get this working before doing anything hairier.
 
Here's some Pascal for a memory init routine:
Code:
{$IFC TARGET_API_MAC_CARBON}

	PROCEDURE SetupMemory;
	BEGIN
		MoreMasterPointers( numAddMasters * 64 );
	END;

{$ELSEC}

	PROCEDURE SetupMemory;
	VAR
		myZone		:	THz;
		oldMoreMast	:	Integer;
	BEGIN
		stackSizeInK := stackSizeInK * 1024;
		SetApplLimit( Ptr( ORD4( GetApplLimit ) - stackSizeInK ) );		{ set top of the application heap }
		MaxApplZone;										{ grow the heap }

		myZone := ApplicationZone;

		oldMoreMast := myZone^.moreMast;
		myZone^.moreMast := myZone^.moreMast * numAddMasters;
		MoreMasters;											{ create all master pointers in single block }

		myZone^.moreMast := oldMoreMast;
	END;

{$ENDC}
Call this before InitGraf, etc.
Stack size depends on how much recursion your app does and how much stack space the local variables of the functions use up.
Masters depends on the maximum number of handles you'll have allocated at once.

I think the standard C libraries of Think C or CW Pro do the InitGraf and possibly memory stuff for you? You have to check the libraries to find out. CW Pro has source code for its libraries.
 
As I said, I don't use THINK C, but this works under CWPro:

C:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <Memory.h>

#define K 1024

int main(void)
{
    Handle hdl;
    OSErr err;

    printf("hello world\n");
    hdl = NewHandle(128 * K);
    err = MemError();
   
    if (hdl == NULL) {
        printf("allocation failed:\n");
        switch(err) {
        case -108:
            printf("no room in heap"); break;
        case -109:
            printf("nil handle"); break;
        case -111:
            printf("illegal op on free block"); break;
        case -112:
            printf("illegal op on locked block"); break;
        case -117:
            printf("can't move a locked block"); break;
        default:
            printf("err: %h", err); break;
        }
        printf("\n");
    } else {
        printf("allocation successful\n");
        DisposeHandle(hdl);
    }
   
    return 0;
}

You might want to see if you can get this working before doing anything hairier.
Maybe I should change my compiler. lol
 
Here's some Pascal for a memory init routine:
Code:
{$IFC TARGET_API_MAC_CARBON}

    PROCEDURE SetupMemory;
    BEGIN
        MoreMasterPointers( numAddMasters * 64 );
    END;

{$ELSEC}

    PROCEDURE SetupMemory;
    VAR
        myZone        :    THz;
        oldMoreMast    :    Integer;
    BEGIN
        stackSizeInK := stackSizeInK * 1024;
        SetApplLimit( Ptr( ORD4( GetApplLimit ) - stackSizeInK ) );        { set top of the application heap }
        MaxApplZone;                                        { grow the heap }

        myZone := ApplicationZone;

        oldMoreMast := myZone^.moreMast;
        myZone^.moreMast := myZone^.moreMast * numAddMasters;
        MoreMasters;                                            { create all master pointers in single block }

        myZone^.moreMast := oldMoreMast;
    END;

{$ENDC}
Call this before InitGraf, etc.
Stack size depends on how much recursion your app does and how much stack space the local variables of the functions use up.
Masters depends on the maximum number of handles you'll have allocated at once.

I think the standard C libraries of Think C or CW Pro do the InitGraf and possibly memory stuff for you? You have to check the libraries to find out. CW Pro has source code for its libraries.
There is no code other than some window initialisation, no recursion or anything else.

By the way, is there a compiler that supports the C99 standard on a classic Mac? Declaring variables at the beginning is very cumbersome.
 
Here's some Pascal for a memory init routine:
Code:
{$IFC TARGET_API_MAC_CARBON}

    PROCEDURE SetupMemory;
    BEGIN
        MoreMasterPointers( numAddMasters * 64 );
    END;

{$ELSEC}

    PROCEDURE SetupMemory;
    VAR
        myZone        :    THz;
        oldMoreMast    :    Integer;
    BEGIN
        stackSizeInK := stackSizeInK * 1024;
        SetApplLimit( Ptr( ORD4( GetApplLimit ) - stackSizeInK ) );        { set top of the application heap }
        MaxApplZone;                                        { grow the heap }

        myZone := ApplicationZone;

        oldMoreMast := myZone^.moreMast;
        myZone^.moreMast := myZone^.moreMast * numAddMasters;
        MoreMasters;                                            { create all master pointers in single block }

        myZone^.moreMast := oldMoreMast;
    END;

{$ENDC}
Call this before InitGraf, etc.
Stack size depends on how much recursion your app does and how much stack space the local variables of the functions use up.
Masters depends on the maximum number of handles you'll have allocated at once.

I think the standard C libraries of Think C or CW Pro do the InitGraf and possibly memory stuff for you? You have to check the libraries to find out. CW Pro has source code for its libraries.
Oh, you mean NewPtr should be called before InitGraf?
 
Back
Top