[FR] [IT]
  [INFO] [ACQUIRE] [MAP] [RESOURCES]


PORTING YOUR OLD CODE TO CARBON

On ‘Classic’ Systems, Carbon is really just a library, called CarbonLib and produced by Apple, that modernizes and extends the Macintosh Toolbox that we’ve come to know and love. Provided that the CarbonLib extension is present in your, or your users’, System Folder, your applications will run natively on all systems from 8.5 up to the latest version of the Classic Mac OS [9.2.2 as I write]. In Mac OS X, Carbon applications run natively.

Running PPC or 68K applications compiled with previous releases of FutureBASIC in Mac OS X invokes the Classic environment (installed along with OS X) so that non native applications can run in this compatibility box.

Release 6 allows you to get rid of this compatibility layer when running your compiled applications. But please, keep in mind that the whole FB^3 IDE is not yet carbonized. So, the Editor, Compiler and Program Generator run in Classic mode under OS X. Meanwhile, your Carbon application will run just the same as any other regular Mac OS X application.

That said, programming for Carbon is also a whole new ballgame. To lever the advantages of the modern Mac OS X system, various aspects of the Toolbox have been changed. Thus, if your program relies heavily on the Toolbox, you will have to take this into account.

As a matter of fact, you should not expect a program containing thousands of lines of code to execute flawlessly just selecting the Run menu item. You can dream, but don't bet the house on it and to prevent this dream becoming a nightmare, just keep on reading.

Below is a list of things you'll need to check to see if your code needs updating...


Release:
Paris, 02/25/2002

[return to top]

Low memory globals

We’ve got used to reading and writing certain values in system-wide global space by merely peeking or poking those values at addresses referred to by system constants.

For example, we could retrieve the current height in pixels of the menubar with the following statement:

hght% = PEEK WORD (_mBarHeight)

or more usually we wrote the following shorthand:

hght% = {_mBarHeight}

This is a direct violation of the protected memory that Mac OS X brings to your machine and as such, that kind of statement is prone to crash your application as soon as it is executed. Fortunately, the Compiler will throw you a warning if you are attempting to compile a program for Carbon that contains obsolete constants.

The solution is quite simple: for most of those global values, Apple now provides specific functions. It’s just a matter of using them. Following the above example, you should use now the Toolbox function called GetMBarHeight. That’s all there is to it.

hght% = FN GetMBarHeight

For the moment, you will have to search the Apple documentation for all the functions available to access those global values. Volunteers are assembling a list to be published soon.


[return to top]

Opaque structures

In a general manner, everything owned by the system is now protected. This holds true for many things that have become well known, and well used, by Mac programmers. More specifically, very common structures such as windows, menus, controls, etc. have gone ‘opaque’ in Carbon. The terminology* says it all: the programmer must not assume anything regarding the internal organization of those structures. Consequently, old programming techniques dealing with them are guaranteed to fail:

  • Accessing values using offsets (usually done through pseudo-records);

  • Reading/writing fields in true records.

    Both techniques presuppose a specific internal layout of the structures involved, so they are good for a crash in Carbon.

    Again, Apple has provided a solution: “getter” and “setter” accessor functions have been made available for us to call. So, part of your conversion job will be to find out which relevant function to use as a replacement in your code.

    Example:

    Formerly, to retrieve the menu title of a given menu we could have:

  • used the predefined constant _menuData as an offset to get the Pascal string located in a menuHandle, like the following for instance:

    title$ = PSTR$([menuHandle] + _menuData)

  • or, possibly defined a MenuInfo record declared in the Apple headers like so:

    BEGIN RECORD MenuInfo
      DIM menuID      AS SHORT
      DIM menuWidth   AS SHORT
      DIM menuHeight  AS SHORT
      DIM menuProc    AS HANDLE
      DIM enableFlags AS LONG
      DIM menuData    AS STR255
    END RECORD

    Later on, after having declared our menuHandle as a handle pointing to a MenuInfo structure (DIM menuHandle AS HANDLE TO MenuInfo) we could have written the following:

    title$ = menuHandle..menuData

    The above techniques still work in PPC and 68K, but not in Carbon, where you will have to use the GetMenuTitle Toolbox accessor function instead:

    dummy& = FN GetMenuTitle(menuRef,title$)

    Note a couple of interesting things here:

    Apart from the fact that no such a function existed before Carbon, the menuRef can be obtained via the regular GetMenuHandle function also used to return a menuHandle in PPC & 68K. Secondly, this function has added functionality in that it returns both the menu title in the title$ parameter and a pointer to the title string as a result. This allows you to pass the result as a parameter to another function.

    Similarly, statements such as menuHandle..menuWidth% should be replaced with FN GetMenuWidth(menuHandle), and so on...

    * As a side note, you will notice that those structures are defined in the Universal Apple header files as generic pointers or generic handles. Usually, their name ends up with the ref suffix. For instance, we are used to working with controlhandles which are handles pointing to a ControlRecord (^^ControlRecord). In Carbon, we must now deal with ControlRefs which are mere untyped handles. A huge part of the PPC Toolbox has been ported to CarbonLib in such a way that the subtle changes are handled almost transparently and many Toolbox calls continue to work without any change in your code.


  • [return to top]

    X-Files

    Normally, without the hard work made by Staz Software, this murky area should have been the real nightmare for the FB programmers. Most of the FB functions regarding file management used to rely upon the old and obsolete working directory reference number. Believe it or not, this abandoned reference still works in Carbon with FutureBASIC!

    In reality, Staz Software has brought back to life our old, time-tested working directories. Everything is done under the hood, and if you have been using the regular FutureBASIC statements to deal with the opening, reading and writing of files, you will notice no difference. This is really amazing!

    Problems will start to surface, if you have mixed working directories handled by FutureBASIC with Toolbox calls. This is often the case when we feed a parameter block to a Toolbox file function. Of course, there are solutions. The easiest is to call a built-in Runtime function that will handle the necessary conversion before calling the Toolbox:

    #IF CarbonLib
      FN FBWDToPBWD(parameterBlock)
    #ENDIF

    Obviously, you must also make sure that the Toolbox call you want to use is still present in Carbon (many have been removed).

    In other circumstances, you will greatly benefit from using the recommended File Spec structure. This will require many more changes in your code, but the Release 6 introduces the FSSpec Record in many of its file functions (the standard file dialogs can now return such a structure and you can even use it in the OPEN statement).

    Not only do you have at your disposal those two possibilities, but Release 6 comes with a bunch of new file user routines that can handle common tasks such as checking the existence of a given file, copying and moving files, even scanning an entire folder. And those work from 68K to Carbon in a totally transparent manner.

    As a result, you will be heavily assisted in the conversion process.


    [return to top]

    Clipboard

    The handling of the Clipboard is quite different in Carbon. But, if you know how to copy and paste, you will get by quite easily. With most of your programs, all you will have to do is to open the short example files on the FB^3 CD and copy the appropriate functions and plug them into your code.


    [return to top]

    Callback procedures

    If you are addicted to callback procedures, you will have a bit of work to do. But, honestly, not that much!

    Installing a callback procedure in Carbon demands that you use the appropriate Toolbox function for the job. In addition, the correct entry point for the procedure must be “calculated”.

    You might have to declare the installing function because not all of them are defined in the FB headers. As they follow the same design, the process is very simple. Let’s take a dialog filter as an example.

    To install a dialog filter, you need the NewModalFilterUPP Toolbox function. You can declare this function like so:

    #IF CarbonLib
      TOOLBOX FN NewModalFilterUPP(PTR)=PTR
    #ENDIF

    When it is time to install your procedure, all you have to do is to check if you are compiling for Carbon then send the correct entry point to the installing function. This might be done like so:

    DIM myProc AS PROC

    myProc = PROC "my filter proc"

    #IF CarbonLib
      myProc = FN NewModalFilterUPP( [myProc + ¬ _FBprocToProcPtrOffset] )
    #ENDIF

    itemHit = FN Alert(resID,myProc)

    Like I have already said, the same technique applies for all the callback procedures, so in short, the only real trick is for you to find the appropriate Toolbox installer function.


    [return to top]

    Screen updates

    Now that your program compiles without errors, you are ready to experience strange behavior. It is possible that your program will exhibit an unexpected severe slowdown or will fail to update the screen properly under OS X. Welcome to the buffered window feature.

    In OS X, all the drawing commands directed to a given window are stored in a temporary buffer that is emptied by the system at the next WaitNextEvent call. That means that in order to effectively see an update on screen your application must call HANDLEEVENTS. This is not always possible when the flow of your program is trapped in a loop that produces information that you would nevertheless like to display. For that reason, Release 6 introduces a new keyword forcing the system to empty the pending buffer. FLUSHWINDOWBUFFER will immediately update the screen in OS X, but as a side effect you will certainly notice a slowdown.

    While FLUSHWINDOWBUFFER is harmless under any other version of the system, you might have to develop another strategy regarding screen updates in your OS X programs. For that matter, you may find the demo called Faster Drawing in OS X and located in the Donations folder particularly interesting. This very short example, written by Robert Purves, times five different techniques for getting the display on screen. Try to adapt the most suitable among them for your needs. Perhaps it is also the opportunity to reconsider your way of coding: do you use properly the PPC registers (don’t leave out the floating point registers)? do you trigger needless drawing commands (performing calculation before hand is far easier and faster for the processor than drawing)? Examine the other example files on the CD that relate to speed, you will find there very useful information. Test your functions with the Profiler, you might be surprised by the gain in speed you can obtain with simple changes in your code. Every little bit will help your application in getting smoother under OS X.

    Also on the updating front, you should know that the InvalRect and ValidRect procedures have disappeared from the Toolbox in Carbon. Always ready to help, Release 6 provides built-in runtime functions to ease the conversion process. In fact, altering your code should be a breeze, you just have to replace the CALL (optional) keyword with the FN keyword and all will continue to work as usual:

    Change:
    CALL InvalRect(r) // or simply InvalRect(r)
    to:
    FN InvalRect(r)


    [return to top]

    GrafPorts

    Before Carbon we could consider a GrafPort as a structure embedded in the Window record. Since the GrafPort record was the first field of the Window record both structures started in memory at the same location and we could use a window pointer to refer indifferently to the GrafPort or to the whole Window record.

    The following would have worked:

    GET WINDOW wndNum%,wndPtr&
    CALL SetPort(wndPtr&)


    This is a no-no in Carbon and a free tour to crashola town is guaranteed. Window pointers and window GrafPorts are now separate entities. You will probably have to check all the sections in your code that deal with ports to make sure you are passing a real GrafPort to the Toolbox.

    Notice that Release 6 will help you with an enhanced WINDOW function that can return the Window CGrafPort or the WindowRef of the output window with the help of two new constants.

    WINDOW(_wndRef) will return the opaque reference of the window, whereas WINDOW(_wndPort) will return a pointer to the window GrafPort.


    [return to top]

    Debugging

    In OS X, allocating memory to your application is no longer your concern. This kind of thing is handled by the system.

    OK, that’s a cool thing especially for the end user. However, for you, as a programmer, it becomes more difficult to track down memory leaks in your programs. Your usual memory tools won’t help in OS X. It is better for you to force your carbonized programs to run in the Classic environment by adding the following simple statement in your code:

    KILL RESOURCES "plst",0

    The reason for this is that memory leaks will show up quickly in OS 9 but may go undetected in OS X. Obviously, you will have to remove that statement when building your final application.


    [return to top]

    If you have other issues in converting your code, don't hesitate to contact us, others are certainly in the same situation and we'll be completing this checklist and preparing some Conversion docs for you.

    Until then, have a great time coding with Release 6.

      © 2000 Pix&Mix  
      All Rights Reserved
    INFO  |  ACQUIRE  |  MAP  |  RESOURCES

      FutureBASIC is a registered trademark of Staz Software, Inc and is used with permission.