Apple Developer Connection
Advanced Search
Member Login Log In | Not a Member? Support

Carbon Development Tips & Tricks

  1. How should I control the cursor in my CarbonEvent based application?
  2. How should I get the highlight color for drawing list selection?
  3. How do I tell the Finder to update information in one of its windows?
  4. WaitNextEvenet(), Sleep Time, and Event Loop Timers...
  5. How do I convert from CFNumber to CFString data type?
  6. Why do I get "Launch failed with error code 2857" when launching from the Terminal?
  7. How do I use MallocDebug in my Carbon CFM app?
  8. How do I create a floating window above all others?
  9. Can Unix read() or write() be called at interrupt time?
  10. How do I get a CFStringRef from an HFSUniStr255 returned by the File Manager?
  11. And how do I get a C-string from a CFStringRef?
  12. How do I handle Mouse Wheel support in my application?
  13. How do I get a list of all the mounted volumes?
  14. How to determine if my app is bundled?
  15. How do I get the icon of a bundled or non-bundled application?
  16. 10 ways of improving your apps performance.
  17. The background of my controls don't match the window background.
  18. How do you specify that an application is capable of opening a generic file/disk/folder using the Info.plist?
  19. Why do I get a (-42) too many files open error?
  20. How do I get "StdLog" like functionality on Mac OS X?
  21. What CarbonEvent gets sent when?
  22. How do I log in as "root"?
  23. My CFM application dies before it hits main(), how do I debug it?
  24. gdb helpful tips
  25. How should I check if a particular routine is available or not?
  26. How do I link against Carbon Mac OS X only API's
  27. How do I call a routine in InterfaceLib from a Carbon application?
  28. Can I turn control embedding off?
  29. Why does my Carbon application launch under Classic in Mac OS X?
  30. How do I open a resource fork stored in a data file?
  31. Carbon EventLoop timers and WaitNextEvent.
  32. Adding large icons to your application.
  33. How do I rebuild the LaunchServices database?
  34. How do I bring all my windows to the front.
  35. How do I detect a drag to the trash?
  36. Living in a Multiple User world.
  37. Do I need a localized CarbonLib?


1. How should I control the cursor in my CarbonEvent based application?

If you want the default cursor for your application to be an arrow, but turn to crosshairs whenever your cursor moves over certain windows, and maybe a pointing finger when it moves over a control I recommend installing sets of kEventClassMouse / kEventMouseMoved event handlers. The idea being that you install a kEventMouseMoved CarbonEnent Handler on the application which calls SetThemeCursor( kThemeArrowCursor ). You also install a kEventMouseMoved handler for your windows which call SetThemeCursor( kThemeCrossCursor ) and set the return code to noErr.

By returning noErr from your window or control event handler you stop the migration of the event to other handlers and therefore your applications kEventMouseMoved handler will not receive the event.

With Jaguar or CarbonLib 1.6 TrackMouseLocation and friends will also track the mouse when the button is not pressed and send kMouseTrackingMouseEntered/Exited messages.

2. How should I get the highlight color for drawing list selection?

The best way to get the color is to use the theme brush constant: kthemeBrushPrimaryHighlightColor (-3). According to Aqua guidelines, when a text area is inactive, the highlight color should be slightly lighter. You can retrieve the lighter highlight color with kThemeBrushSecondaryHighlightColor (-4).

These brushes are supported starting in Mac OS X 10.1, but you may first see the constants defined in the Appearance.h which ships with Jaguar.

3. How do I tell the Finder to update information in one of its windows?

You need to send a kAESync AppleEvent to the Finder passing it an alias to the file that was changed. See the MoreFinderEvents sample code for an example.

4. WaitNextEvenet(), Sleep Time, and Event Loop Timers...

If you are running animation, or other high frequency timer driven events from your WaitNextEvent based application you may get better performance by increasing your sleep time passed into WaitNextEvent. Yes, increasing your sleep time. Passing in a small sleep time such as 0 or 1 may cause a barrage of null events to be sent to your application. Event Loop Timers only fire while waiting on the Event Queue, i.e. while blocked in WaitNextEvent. So, passing in a larger sleep time may cause your high frequency timers to actually fire more often and your CPU usage to drop significantly.

5. How do I convert from CFNumber to CFString data type?

cfString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), cfNumber);

6. Why do I get "Launch failed with error code -2857" when launching from the Terminal?

There is a problem with the interaction between the Code Fragment Manager (CFM) and Core Foundation (CF) which causes LaunchCFMApp to sometimes fail when launched from the terminal (or gdb).

True, the error code means it can't find the 'cfrg' resource. This is because CF gets confused and thinks the application is "LaunchCFMApp" instead of your target bundle.

To work around the problem for the time being, define the environment variable "CFProcessPath" to be the full path to your executable. This will force CF to locate the correct "bundle" for your app. This should get you debugging again!

7. How do I use MallocDebug in my Carbon CFM app?

"Debugging environment variables for malloc" descibes all of the debugging variables and how to use them.

% gdb LaunchCFMApp
(gdb) set env MallocScribble 1
(gdb) set env MallocGuardEdges 1
(gdb) set env MallocStackLogging 1
(gdb) set env MallocCheckHeapStart 10000
(gdb) set env MallocCheckHeapEach 10000
(gdb) run path-to-cfm-executable

If you see a message that says "waiting 100 seconds...", then type control-Z to drop back into the debugger. At that point (or any time you get an error)

You can type "bt" to get a backtrace.

8. How do I create a floating window above all others?

Creating a Utility class window will put the window very high in the z-ordering. Utility windows continue to be above all other even when your application is in the background. Furthermore by setting the windowSpec.u.procID field we specify the type of window to draw. In this case a floating window with the title bar on the left side with only the close and collapse ornaments. This functionality works on both Mac OS X and through CarbonLib on Mac OS 8.6 and greater.

WindowDefSpec	windowSpec;
SetRect( &wRect, 20, 30, 300, 80 );
windowSpec.defType	= kWindowDefProcID;
windowSpec.u.procID	= floatSideProc;
err = CreateCustomWindow( &windowSpec, kUtilityWindowClass, 
     kWindowStandardFloatingAttributes | kWindowStandardHandlerAttribute, &wRect, &window );

9. Can Unix read() or write() be called at interrupt time?

Deferred Task time on Mac OS X isn't really "interrupt time" as we know it on Mac OS 9. Deferred tasks are actually executed from a separate MP thread, which is normal app-level execution as far as the kernel is concerned. Therefore, you may do anything from your deferred task that is thread-safe. read and write are thread-safe.

10. How do I get a CFStringRef from an HFSUniStr255 returned by the File Manager?

The easiest way to do this is:

HFSUniStr255 name;
...
CFStringRef str = CFStringCreateWithCharacters( kCFAllocatorDefault, 
                                                       name.unicode, name.length );
//	Do something with str
CFRelease( str );

And here is how to create a HFSUniStr255 from a CFStringRef:

name.length = CFStringGetBytes( input, CFRangeMake(0, MIN(CFStringGetLength(input), 255)), 
        kCFStringEncodingUnicode, 0, false, (UInt8 *)(name.unicode), 255, NULL );
if ( output->length == 0 ) 
    ;// handle error

11. And how do I get a C-string from a CFStringRef?

These routines assume a MacRoman encoded string. To preserve encodings it is always best to keep the strings as Unicode/CFStrings.

The following code converts a CFStringRef to a C-style string:

char      *CFStringToCString( CFStringRef input )
{
	char      *output = NewPtr(CFStringGetLength(input)+1);
	// check output for NULL
	if (CFStringGetCString(input, output, CFStringGetLength(input)+1, 
	                                              kCFStringEncodingMacRoman))
		return( output );
	return( NULL );
}

a Pascal string it's even easier:

void      CFStringToStr255( CFStringRef input, StringPtr output )
{
     output[0] = CFStringGetBytes( input, CFRangeMake(0, 
                                             MIN(CFStringGetLength(intput), 255)), 
             kTextEncodingMacRoman, '^', false, &(output[1]), 255, NULL );
     if ( output[0] == 0 )
          ;// handle error
}

12. How do I handle Mouse Wheel support in my application?

On Moac OS X, mouse wheel information is sent via Carbon Events. You can install Carbon Event handlers from A WaitNextEvent() based application as well as RunApplicationEventLoop() based applications.

Install an event handler on: { kEventClassMouse, kEventMouseWheelMoved },

...and the interesting parameter you extract when receiving that event is kEventParamMouseWheelDelta

Here's some code to handle the event:

case kEventClassMouse:
{
    switch ( GetEventKind(inEvent) )
    {
        case kEventMouseWheelMoved:
        {
            OSStatus status;
            UInt32 modifiers;
            EventMouseWheelAxis axis;
            SInt32 delta;
            
            status = GetEventParameter( inEvent, kEventParamKeyModifiers, typeUInt32, 
                    NULL, sizeof(modifiers), NULL, &modifiers );
            ASSERT_NO_ERR(status);
                        
            status = GetEventParameter( inEvent, kEventParamMouseWheelAxis, 
                    typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis );
            ASSERT_NO_ERR(status);

            status = GetEventParameter( inEvent, kEventParamMouseWheelDelta, 
                    typeLongInteger, NULL, sizeof(delta), NULL, &delta );
            ASSERT_NO_ERR(status);

            if ( axis == kEventMouseWheelAxisY )
            {
                SInt32 deltaPixels = 40 * delta;

                if (modifiers & optionKey)
                    deltaPixels *= 10;

                this->ScrollVertically( -deltaPixels );
                result = noErr;
            }
            break;
        }
    }
    break;
}

13. How do I get a list of all the mounted volumes?

If you iterate over all the mounted volumes during application init, you will notice servers, CD's and other volumes don't show up in the iteration. This was done for application launch performance reasons. In the past CD's would spin up, and networks were pinged during launch of any carbon application. Now, during File Manager initialization, it creates entries for local volumes and the volume the app was launched from, but does not wait for a reply from the Disk Arbitration server before continuing. The DiskArbitration Server sends messages to the Carbon application about server volumes that are mounted, and those messages aren't processed until you call the event loop. You should support the kEventClassVolume/kEventVolumeMounted and kEventClassVolume/kEventVolumeUnmounted events to be notified of volume mounts and unmounts while your application is running, as well as to be notified of the already mounted volumes described above. Having the Carbon Event handlers installed or not won't affect weather or not the volumes will show up in your volume iteration code at a later time. It's just the best way to find out as soon as possible when a volume is discovered.

14. How to determine if my app is bundled?

Here is a snippet of code which returns true if the currently running application is running as a bundle. This code will work on Mac OS X as well as CarbonLib 1.5 and later too (assuming you're running on 9.0 or later), but for 8.6 you will need to use the techniques from Tech Note 2015.

Boolean	AmIBundled()
{
	FSRef processRef;
	FSCatalogInfo processInfo;
	int isBundled;
	ProcessSerialNumber psn = {0, kCurrentProcess};

	GetProcessBundleLocation (&psn, &processRef);
	FSGetCatalogInfo (&processRef, kFSCatInfoNodeFlags, 
						&processInfo, NULL, NULL, NULL);
	isBundled = processInfo.nodeFlags & kFSNodeIsDirectoryMask;
	
	return( isBundled );
}

15. How do I get the icon of a bundled or non-bundled application?

This CFM based routine will return the icon of a bundle or single binary application, given its PSN. If the code is run on Mac OS 9 it will fall through and return the icon specified by the FSSpec.

---------------------------------------------------------------------------
//  Gets an IconRef for either a traditional single binary application or
//  a bundled application.

static OSStatus GetApplicationIconRef(const ProcessSerialNumber* inPSN,
const FSSpec* inExecutable, IconRef* outIcon)
{
    OSStatus            status;
    FSRef               bundleFSRef;
    FSSpec              bundleFSSpec;
    CFBundleRef         bundle;
    SInt16              label;
    LSItemInfoRecord    info;
    static GetProcessBundleLocationFunctionPointer    theGetProcessBundleLocation = NULL;

    if (theGetProcessBundleLocation == NULL)
    {
        status = LoadFrameworkBundle(CFSTR("Carbon.framework"), &bundle);
        if (bundle != NULL and status == noErr)
        {
            theGetProcessBundleLocation = (GetProcessBundleLocationFunctionPointer)
                CFBundleGetFunctionPointerForName(bundle, CFSTR("GetProcessBundleLocation"));
        }
    }
    if (theGetProcessBundleLocation != NULL)
    {
        status = (*theGetProcessBundleLocation)(inPSN, &bundleFSRef);
        if (status == noErr)
        {
            status = LSCopyItemInfoForRef(&bundleFSRef, (kLSRequestTypeCreator |
                kLSRequestBasicFlagsOnly), &info);
            if (status == noErr and (info.flags & kLSItemInfoIsPackage))
            {
                status = FSGetCatalogInfo(&bundleFSRef, kFSCatInfoNone, NULL, NULL, 
                                            &bundleFSSpec, NULL);
                if (status == noErr)
                    status = GetIconRefFromFile(&bundleFSSpec, outIcon, &label);
            }
            else if (status == noErr)
            {
                status = GetIconRef(inExecutable->vRefNum, info.creator, 
                                        info.filetype, outIcon);
            }
        }
    }
    else
    {
        status = GetIconRefFromFile(inExecutable, outIcon, &label);
    }

    return status;
}

16. 10 ways of improving your apps performance.

10. Sync or Async

  • Synchronous File Manager and OT calls on an MP thread yield better performance than Async calls on Mac OS X

9. Performance Tools

  • Sampler, top, QuartzDebug

8. Cache It

7. FlushVol() is Evil

  • Don't call FlushVol() to be "safe"
  • It's very slow, let the OS's Universal Buffer Cache do its thing

6. Don't abuse virtual memory

  • Minimize memory allocations
  • Allocating memory causes others to page which leads to a swapping frenzy.

5. Double Buffer, Users Suffer

  • Conditionalize your double buffering code
  • Mac OS X already buffers your windows which may lead to triple buffering windows.

4. Boing... Boing... Boing...

  • Calling WaitNextEvent(), RAEL(), etc. stops the bouncing.
  • Consider moving parts of application initialization until after your first call to the event loop.

3. Bulk up or tailor your calls

  • Use the "Bulk" File Manager calls when you can
  • Use the new FSRef based FSGetCatalogInfo(), etc. calls
  • Hitting the disk or network is costly, get what you need.

2. Idle Event Processing is a killer

  • Use Event Loop Timers instead of null event processing
  • Increase you WNE() sleep time

1. Don't wait for events, use Carbon Events

  • API encourages performance
  • Events Dispatched by Toolbox
  • Avoid polling for anything.
  • TrackMouseLocation() vs. StillDown() allows event dispatching
  • Sleeps during idle time

17. The background of my controls don't match the window background.

With Mac OS X, the themed backgrounds are no longer solid colors and therefore we sometimes see a misalignment of the striped background with respect to the background of the controls. This problem can usually be solved in one of two ways:

Make sure that your application is not resetting the origin. By keeping the origin at the top left corner of the window all striped theme backgrounds originate at the same place. If the origin were to be reset to the top left corner of a control, for instance, the background stripes for that control would be misaligned with the rest of the window.

When a control is drawn over a pattern drawn via tppearance APIs, the control takes the background of its container, not the Appearance pattern. To set the background of a control you have to call SetControlColorProc() and then call SetThemeBackground() from within your ControlColorUPP.

EXTERN_API( OSStatus ) SetControlColorProc( ControlRef inControl, 
                                                      ControlColorUPP inProc );

pascal OSStatus MyControlBackgroundProc( ControlRef control, SInt16 message, 
                                                      SInt16 depth, Boolean inColor)
{
    switch (message)
    {
       case kControlMsgSetUpBackground:
          SetThemeBackground( ThemeBrush inBrush, SInt16 inDepth, 
                                                      Boolean inIsColorDevice );
          break;
 
        default:
          return( paramErr );
    }

    return( noErr );
}

18. How do you specify that an application is capable of opening a generic file/disk/folder using the Info.plist?

Set up the info.plist file to contain the following key and attributes:

        <key>CFBundleDocumentTypes</key>
        <array>
            <dict>
                <key>CFBundleTypeOSTypes</key>
                <array>
                    <string>****</string>
                </array>
                <key>CFBundleTypeIconFile</key>
                <string>129</string>
                <key>CFBundleTypeRole</key>
                <string>Viewer</string>
            </dict>
        </array>

19. Why do I get a (-42) too many files open error?

The number of files allowed to be open by Mac OS X applications defaults to 256. You can raise this limit by calling setrlimit( RLIMIT_NOFILE, &rip ). Setrlimit() is a mach-o routine, so if your application is CFM, you may have to call through the CFM->Mach-O glue. For more information about setrlimit() type "man setrlimit" into the Terminal.

20. How do I get "StdLog" like functionality on Mac OS X?

Being a developer it is essential that you gain information about your application crashes, hence CrashReprter. At the time of an application crash, CrashReprter logs backtraces of all running threads, register values and other useful information. To enable CrashReprter do the following.

On Mac OS X 10.1 you can enable the logging of crashes through the "Console" applications preferences. Select the "Crashes" tab pane and click the "Log crash information" check box.

On Mac OS X 10.0:

From the Terminal, type:

sudo open -a /Applications/TextEdit.app/Contents/MacOS/TextEdit /etc/hostconfig

Then enter your administrator password when sudo asks and add the line:

CRASHREPORTER=-YES-

Now when an application crashes a dialog will be presented prompting the used to view the crash log, and the results will be appended to the file located at "/var/log/crash.log"

21. What CarbonEvent gets sent when?

If you want to see the Carbon Events that are sent to your app at runtime (on Mac OS X), you can issue the following commands via Terminal:

% setenv EventDebug 1
% LaunchCFMApp <pathToYourApplication> | grep -v "kEventMouseDown"

The "grep -v" is for events you don't want to see.

22. How do I log in as "root"??

By default, for security reasons, Mac OS X ships with the root account disabled. If you need to log in as root you will first have to enable the root account. To enable the root account, follow these steps:

  • Launch the "NetInfo Manager" located at "/Applications/Utilities/NetInfo Manager"
  • From the "Domain" menu, choose "Security:Authenticate..." and enter the admin password
  • From the "Domain" menu, choose "Security:Enable Root User...". At this point you will be prompted twice for a new root password
  • Now you can either log in as "root" or "su root" from the terminal

One note, many times developers want to be logged in as root to bypass file system privileges issues. A better approach may be to do a "Get Info" on a volume from the Finder and choose the "Privileges" pop-up, then check the "Ignore privileges on this volume" checkbox.

23. My CFM application dies before it hits main(), how do I debug it?

From the Terminal application try debugging your application with gdb.

gdb "/System/Library/Frameworks/Carbon.framework/Versions/Current/Support/LaunchCFMApp"
set env CFMDebugFull 1
r "path/to/your/CFMapp"

This should give you some more information.

The path to LaunchCFMApp may be different.

Although the gdb debugger is not fully integrated to work with CFM binaries, as it is with Mach-O, there are some tricks you can try while debugging your application from gdb. gdb will break on any Mach-O routine, so you can set breakpoints on system routines. For instance, you may want to type "b InitCursor", or "b DebugStr", after gdb hits your breakpoint you can get a valid stack back trace showing the current routine call nesting by typing "bt". You will also notice that all DebugStr() messages now appear within the Terminal window.

24. gdb helpful tips

There are two ways to debug your application with gdb. One method is mentioned above, and the other is to use the attach command. Follow these steps to "attach" to your application.

  • Double click your application to launch it
  • From the Terminal, type "ps -x" to list the running processes
  • From the Terminal, type "gdb attach <your PID here>"

From gdb you can call functions from both within your application or in the ToolBox. Over time many helpful debugging routines have been added to the ToolBox. For instance if you wanted to examine the control hierarchy of a window you would execute the following commands within gdb:

call (void)DebugPrintWindowList()<- to display information about the windows
call (void)GDBShowControlHierarchy( <address of WindowRef> )

The easiest way to see which functions are callable from within gdb is to type "call" and the first few characters of a function and hit <tab> twice. For instance typing the following yields:

(gdb) call GDB<tab><tab>
GDBComponentList                            GDBShowMenuInfo
GDBPrintAEDesc                              GDBShowMenuInfo_bp
GDBPrintAEDesc_bp                           GDBShowMenuItemInfo
GDBPrintEventQueue                          GDBShowMenuList
GDBPrintHelpDebuggingAppleEvents            GDBShowMenuList_bp
GDBPrintHelpDebuggingAppleEvents_bp         GDBShowTELines
GDBShowControlHierarchy(OpaqueWindowPtr *)  GDBShowTENullScrap
GDBShowControlInfo(OpaqueControlRef *)      GDBShowTEStyleRuns
GDBShowDialogInfo                           GDBShowTEStyles
GDBShowExtendedMenuInfo

Try the same with "Debug" to see other useful debug functions.

(gdb) call Debug<tab><tab>
DebugPrintCGRegion(char *, void *)         DebugGestalt
DebugCStr                                  DebugPrintPlatformWindowList(void)
DebugPrintDragMessageFmt                   DebugPrintQDRegion(char *, OpaqueRgnHandle *)
DebugFlashWindowUpdateRgn                  DebugPrintWindow
DebugFlashWindowVisRgn                     DebugPrintWindowList
DebugTypeHello                             DebugDisplayGestalt
DebugGestaltStr                            DebugPrintMenu
DebugPrint                                 DebugTypeChar
DebugPrintAllWindowGroups                  DebugTypeCommandChar
DebugPrintDragInfo                         DebugWindowMessage(OpaqueWindowPtr *, char const *)
DebugPrintDragMessage                      DebugWindowMessageFmt(OpaqueWindowPtr *, char *,...)
DebugDumpGestalt                           DebugWriteChatterbox(char *, long)
DebugPrintMenuItem                         DebugPrintWindowGroup
DebugPrintMenuList

From gdb, typing call (void)CFShow(someCFObj) will output the description (the contents) of the object to stdout. Note that if you have attached to a running process in gdb (as opposed to launching the app from within gdb itself) this stdout may be to the console, etc., not to gdb, unless you have hooked up stdout to your gdb session explicitly.

You may on occasion have seen messages like this when launching your application from the Terminal:
*** malloc[983]: Deallocation of a pointer not malloced: 0x9c2dd0; This could be a double free(), or free() called with the middle of an allocated block; Try setting environment variable MallocHelp to see tools to help debug
An easy way of catching these types of errors is to put a breakpoint on fprintf. Bellow is a gdb session demonstrating how to isolate the double free bug within the applications routine MyVeryBadFunction().

(gdb) b InitCursor
(gdb) run
Breakpoint 1, 0x73da8d6c in InitCursor ()
(gdb) b fprintf
Breakpoint 2 at 0x700017b0
(gdb) c
Continuing.

Breakpoint 2, 0x700017d8 in fprintf ()
(gdb) bt
#0  0x700017d8 in fprintf ()
#1  0x70000994 in free ()
#2  0x70264578 in DisposePtr ()
#3  0x0004b404 in MyVeryBadFunction ()
#4  0x0004b470 in main ()
(gdb) q

25. How should I check if a particular routine is available or not?

CarbonLib brings most of the Carbon functionality back to Mac OS 8.1 through Mac OS 9.x. How should I check if a particular routine is available or not?

There are a couple things you should note when developing your Carbon application. The CarbonLib stub library is split into two parts. The first contains symbols which are hard-linked and will always be present. The second contains symbols which may or may not be present and will be weak-linked into your binary. Some symbols such as those contained within QuickTime may be disabled by the user and therefore should be checked using Gestalt.

if ( Gestalt( gestaltQuickTimeVersion, &the_version ) == noErr )
	if ( the_version >= ???? ) { ....do this stuff.... }

The recommended method of checking the availability of a routine is to check its T-Vector directly.

if ( (UInt32)CreateStandardSheet == (UInt32)kUnresolvedCFragSymbolAddress )
{ ....CreateStandardSheet is NOT available.... }

26. How do I link against symbol like CreateStandardSheet() which is available on Mac OS X but not available on Mac OS 8/9?

While Mac OS X continues to evolve, CarbonLib remains a moving target. If you want to take advantage of the very latest Mac OS X technologies not yet being exported by CarbonLib you may want to create your own stub library to link against in addition to CarbonLib. Follow these steps to create a stub library:

  • Create a text file, "MissingCarbonAPIs.exp" whose contents are:
    # This is a Mac OS X Only API
    CreateStandardSheet
  • From MPW Type:
    MakeStub MissingCarbonAPIs.exp -o MissingCarbonAPIs.stub -fragname CarbonLib -weakstub on

27. How do I call a routine in InterfaceLib from a Carbon application?

This example checks the existence of the routine, NSetTrapAddress() within InterfaceLib, and if available calls it.

Typedef pascal void (*NSetTrapAddressProcPtr) ((UniversalProcPtr)trapAddr,
                                                       UInt16 trapNum, TrapType tTyp)

OSErr                        err;
  CFragConnectionID            connID        = kInvalidID;
NSetTrapAddressProcPtr        myNsetTrapAddressProcPtr = nil;

err = GetSharedLibrary( "\pInterfaceLib", kCompiledCFragArch, 
                                             kReferenceCFrag, &connID, NULL, NULL );

if ( err == noErr )
{
   err = FindSymbol( connID, "\pNSetTrapAddress", (Ptr *) & myNsetTrapAddressProcPtr, NULL );
}

      if ( err == noErr )
{
          // Routine is available!
        (*myNsetTrapAddressProcPtr ) ( trapAddr, trapNum, tTyp );
}

28. Can I turn control embedding off?

No. Control embedding is turned on by default on Mac OS X. On Mac OS X, the Control Manager automatically creates the control hierarchy, but on Mac OS 8/9 it does not (and cannot). It is up to the app developer to ensure that the hierarchy is created on 8 and 9 if they want runtime equivalence on Mac OS X.

More information on Control embedding is available at:

Inside Macintosh:Embedding Controls

29. Why does my Carbon application launch under Classic in Mac OS X?

Your application must contain a 'plst' (0) resource in order for the Mac OS X Launch Services manager to recognize it as a Carbon CFM application, otherwise it assumes it to be a legacy Classic based CFM application. Carbonized applications are actually launched by the "LaunchCFMApp" tool. To allow applications to provide more information about themselves in a way that is integrated well with the Mac OS X runtime environment, developers now provide a 'plst' (0) resource in the resource fork of their carbonized applications instead of a 'carb' (0) resource. The 'plst' resource should contain a binary representation of an applications xml based "Info.plist" file.

These are the minimum keys for a 'plst' (for example):

  <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE plist SYSTEM
  "file://localhost/System/Library/DTDs/PropertyList.dtd">
  <plist version="0.9">
  <dict>
     <key>CFBundleInfoDictionaryVersion</key>
     <string>6.0</string>
     <key>CFBundleIdentifier</key>
     <string>com.GreatSoftware.HelloWorld</string>
     <key>CFBundleVersion</key>
     <string>1.0</string>
     <key>CFBundleDevelopmentRegion</key>
     <string>English</string>
     <key>CFBundleName</key>
     <string>HelloWorld</string>
     <key>CFBundlePackageType</key>
     <string>APPL</string>
     <key>CFBundleSignature</key>
     <string>????</string>
  </dict>
  </plist>

For more information, please read Tech Note 2013 The 'plst' Resource.

30. How do I open a resource fork stored in a data file?

Resources are often stored in the data fork of files within Mac OS X bundles to allow for maximum interchange between different volume formats. For instance, UFS disks don't inherently have a concept of resource forks, so if you were to copy a file to and from a non-mac disk via ftp you may lose your resource fork. To get around this problem, Mac OS X advocates the use of bundles and storing resources in the data fork of files. To open these resource files simply call: FSOpenResourceFile() and pass in the FSRef to the data-fork based resource file, and NULL for the fork name.

31. Carbon EventLoop timers and WaitNextEvent.

The sleep time passed into WaitNextEvent() is now fully respected within Carbon applications, so you may want to rethink your idle event processing strategy. For better performance you should keep the sleep time large and use Carbon timers for idle event processing. Carbon timers fire at task time while blocked within WaitNextEvent(), RunApplicationEventLoop, or TrackMouseLocation(). Here is an example of a timer which calls MyTimerProc() every 5 seconds.

InstallEventLoopTimer(
	GetCurrentEventLoop(),
	0,
	kEventDurationSecond * 5,
	NewEventLoopTimerUPP( MyTimerProc ),
	myUserData,
	&timer );

32. How do I add large icons to my application?

You should modify your "Info.plist" file if bundled or 'plst' (0) resource for single file applications to contain the CFBundleIconFile key. Single file binaries should then enter the 'icns' resource ID of the appropriate icon within the 'plst' (0) resource. Bundled applications should enter the name of the icon file to be located within the "Resources" sub-directory. After you have made the changes, log out, and log back in to see them take affect.

		<key>CFBundleIconFile</key>
		<string>MyApplicationIcon.icns</string>

You can verify the "Info.plist" file is correctly constructed by launching the "Terminal" application then type: pl < pathToTheInfoPListFile

33. How do I rebuild the LaunchServices database?

So you've just added a beautiful large icon to your application but it's not showing up. The problem may be that the LaunchServices database needs refreshing. The best way to force LaunchServices to rebuild its database is to delete its files by do the following:

From the "Terminal" application:

	cd ~/Library/Preferences/
	rm LS*
	rm .LS*	

Then log out and log back in.

34. How do I bring all my windows to the front?

Mac OS X introduced a new paradigm of window layering which allows windows of different applications to be interwoven with one another. This paradigm makes dragging from one applications window to another much easier but there are also time in which you may want to force all your applications windows to the foreground. There are two ways of doing this. Mac OS X 10.1 introduced a new HI command, kHICommandBringAllToFront. By sending this command to yourself, and letting the default handlers process the event your application windows will be brought to the front. Another choice which works on all versions of the OS is to force your applications process to the front with the Process Manager.

void    MakeMeTheFrontProcess()
{
    ProcessSerialNumber    psn;
    OSErr                err;
    
    err    = GetCurrentProcess( &psn );
    if ( err == noErr )
        (void) SetFrontProcess( &psn );
}

35. How do I detect a drag to the trash?

Below is a sample code snippet which identifies whether or not a drag was dropped in the trash. This code should work on Mac OS 8.6 through Mac OS X.

    err    = GetDropLocation( theDrag, &descLocation );
    if ( err == noErr )
    {
        FSSpec    spec, specTrash;
        AEDesc    resultDesc;
        
        err = AECoerceDesc( &descLocation, typeFSS, &resultDesc );
        if ( err == noErr )
            err = AEGetDescData( &resultDesc, &spec, sizeof(FSSpec) );
        if ( err == noErr )
        {
            CInfoPBRec    cpb;
            
            cpb.hFileInfo.ioFDirIndex    = 0;
            cpb.hFileInfo.ioNamePtr        = spec.name;
            cpb.hFileInfo.ioVRefNum        = spec.vRefNum;
            cpb.hFileInfo.ioDirID        = spec.parID;
            err    = PBGetCatInfoSync( &cpb );
        }
        if ( err == noErr )
        {
            err = FindFolder(kOnAppropriateDisk, kTrashFolderType, true, 
                    &specTrash.vRefNum, &specTrash.parID);

            if ( (err == noErr) && (specTrash.vRefNum == cpb.hFileInfo.ioVRefNum) && 
                 (specTrash.parID == cpb.hFileInfo.ioDirID) )
            {
                //    Delete my object here
                SysBeep(0);
            }
        }

36. Living in a Multiple User world.

You may notice that FindFolder() may be failing on Mac OS X in ways that you never would have expected it to fail. For instance looking for the "Temporary Items" folder may return a fnfErr. Multiple Users on Mac OS 9 started the process of dealing with permission errors on local volumes, but you'll find Mac OS X is much more rigid in adhering to those rules. Always use FindFolder() when looking for folders and be prepared to create them if need be, and recover from returned errors. In addition to recovering from FindFolder() errors your application should also be prepared to recover from access violations when trying to read and write files. Below is an example which sets the permissions of a folder so that everyone is able to write to it.

OSErr MakeWritableByAll( FSRef *fsRef )
{
    OSErr                err;
    FSPermissionInfo    *permissions;
    FSCatalogInfo        catalogInfo;
    
    err = FSGetCatalogInfo( fsRef, kFSCatInfoPermissions, &catalogInfo, 
                                                             NULL, NULL, NULL );
    if ( err != noErr ) goto Bail;
    permissions    = (FSPermissionInfo*)(catalogInfo.permissions);
    
    permissions->mode    |= 0222; //Octal 222, write access for user, group, world
                                  //Read : Write : Execute 

    err = FSSetCatalogInfo( fsRef, kFSCatInfoPermissions, &catalogInfo );

Bail:
    return( err );
}

37. Do I need a localized CarbonLib?

No. CarbonLib is a multilingual component. It already contains multiple localizations within the binary and will display the localization corresponding to the boot System.