StuffIt ContextualMenu for MacOSX 10.6

Posted: September 21st, 2010 | Author: | Filed under: macOS, Programming | Tags: , , , , , , , , | 3 Comments »

Smith Micro Software released StuffIt Deluxe® 2011 this week. If you don’t know StuffIt Deluxe®, it is described like this:

The StuffIt Deluxe® package gives you all the features you need to backup, share, archive, encrypt and shrink your photos, music, and other documents without compromising quality. StuffIt’s advanced technology specializes in the compression of MP3, PDF and graphics files with no quality loss. Shrink documents up to 98% of their original size. Use StuffIt to free-up space on your computer and to fit more compressed files onto CD/DVDs or other drives.

With MacOS X 10.5 (and older), it was possible to access some features of StuffIt directly from the Finder using a Contextual Menu. Here is the description in the StuffIt User Guide of The StuffIt Contextual Menu:

StuffItCM is an alternative to MagicMenu. Except for keyboard shortcuts, all the commands available in MagicMenu are also available in the StuffIt Contextual Menu. Rather than appearing in the Finder menubar, the Contextual Menu appears when you hold down the Control (Ctrl) key or right-click while selecting a file in the Finder.

Mac OS 10.4 (Tiger) users will find the “StuffIt” option at the top-level of the Finder’s contextual menu.

Mac OS 10.5 (Leopard) users will find non-Apple contextual menus under “More”.

In Mac OS 10.6 (Snow Leopard), Apple has removed support for third party contextual menu plugins. As a result, the StuffIt Contextual Menu is not available.

This is yet partially true. Apple indeed removed the old contextual menu API in MacOSX 10.6. But Apple added a new API. You may have heared about it in my previous post “Implementing a Service on 10.6”.

To reenable this missing feature for 10.6 users, I built a Service that adds 2 menu items in the Contextual Menu of the Finder: ‘UnStuff with StuffIt’ and ‘Stuff with StuffIt’. The ‘UnStuff with StuffIt’ menu item is only visible when you select a file compressed by StuffIt in the Finder. The ‘Stuff with StuffIt’ menu item will appear for any file.

Figure 1: ‘UnStuff with StuffIt’ in the Finder contextual menu


UnStuff with StuffIt

Figure 2: These 2 menu items are also available in the ‘Services’ menu


Stuff with StuffIt

The implementation of this Service is really simple: It uses the 2 command line tools ‘stuff’ and ‘unstuff’ installed by StuffIt Deluxe® 2011 and StuffIt Deluxe® 2010 (I don’t know if previous versions of StuffIt Deluxe® install these 2 command line tools).

Download: You can download here the compiled StuffIt Service. To install it, unzip it, then move the ‘StuffItService.service’ in your ~/Library/Services folder and log out. If you are interested by the source code, the full sources are available here.


Cornichon

Posted: March 17th, 2010 | Author: | Filed under: Cornichon, macOS | Tags: , , , , , , , , | No Comments »

Cornichon is a powerful tool you can use to dynamically profile Mac OS X applications on the system and track the process’ performance over time.

Figure 1: Profiling Safari with Cornichon

screenshot-small

The Cornichon application includes the ability to:

  • Profile Mac OS X applications
  • Profile iPhone applications running in the iPhone simulator
  • Examine the behavior of one or more processes
  • See the different collected data of a process in real time in a graph
  • Export the data as TAB files that you can later easily import in Apple Numbers or Microsoft Excel

With the Cornichon application, you can inspect different aspects of a process’ behavior:

  • CPU usage
  • Resident memory size (RSIZE)
  • Resident private address space size (RPRVT)
  • Total memory size (VSIZE)
  • Number of threads

Why using Cornichon?

Apple provides several tools that allow you to profile Mac OS X applications: Activity Monitor, Instruments, and some command line tools like ‘top’ or ‘ps’.
But none of these tools provide a real-time graph to profile a specific application:

  • Activity Monitor has no graph view which makes it difficult to see how the process’ performance evolves over time.
  • The ‘Activity Monitor’ template of Instruments only monitors the system workload but not the workload of a specific application.

Cornichon System Requirements

  • Mac OS X 10.5.8 or later.
  • Universal application (for both Intel and PowerPC-based Macs).

FAQ


Determining the running kernel mode on 10.6

Posted: March 6th, 2010 | Author: | Filed under: macOS, Programming | Tags: , , , , , , , | 1 Comment »

It might be useful in some cases to know if the MacOS kernel is running in the 32-bit or 64-bit (K64) mode. This is useful for example if you write an application like ‘System Profiler’ that displays the details of the currently running system:

'System Software Overview' in the 'System Profiler' app

Obviously this post only applies to intel machines running on Snow Leopard (see my previous post ‘Intel 64-bit summary’). To simplify the code, I assume that you compiled your application with the 10.6 SDK.

In the IOKit framework on 10.6 the function OSKextGetRunningKernelArchitecture is defined as followed in the OSKext.h header:


/*!
 * @function OSKextGetRunningKernelArchitecture
 * @abstract Returns the architecture of the running kernel.
 *
 * @result
 * The architecture of the running kernel.
 * The caller does not own the returned pointer and should not free it.
 *
 * @discussion
 * This function consults the kernel task and returns a pointer to the
 * NXArchInfo struct representing its architecture.
 * The running kernel's architecture does not necessarily match that
 * of user space tasks (for example, a 32-bit user space task could be
 * running with a 64-bit kernel, or vice-versa).
 */
CF_EXPORT const NXArchInfo *
OSKextGetRunningKernelArchitecture(void)
                AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER;

This function is the one I use to determine the current running kernel mode:

#import <Foundation/Foundation.h>
#import <mach-o/arch.h>

// OSKextGetRunningKernelArchitecture is not available in
// the 10.6 SDK headers, but exported since 10.6.
extern const NXArchInfo *OSKextGetRunningKernelArchitecture(void);

static BOOL Is64BitKernel()
{
	BOOL isK64 = NO;
	
	const NXArchInfo *archInfo = OSKextGetRunningKernelArchitecture();
	if (archInfo != NULL)
	{
		isK64 = ((archInfo->cputype & CPU_ARCH_ABI64) != 0);
	}
	
    return isK64;
}

int main (int argc, const char * argv[])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	
	fprintf(stderr, "Is 64-bit kernel: %d\n", Is64BitKernel());
   
    [pool drain];
    return 0;
}

And don’t forget to link against the IOKit framework.

Also note that it is quite easy to make the previous code compiling with the 10.5 (or earlier) SDK by dynamically getting the address of the OSKextGetRunningKernelArchitecture function and checking if the address is not NULL.


‘Open in 32-bit mode’ – ‘Open using Rosetta’

Posted: January 30th, 2010 | Author: | Filed under: macOS, Programming | Tags: , , , , , , , , | No Comments »

As you know, it is possible to force an Universal Binary (ppc, i386, x86_64) to run in 32-bit mode (i386) even if the machine could run x86_64 binaries. And you can even force the application to run in Rosetta (ppc). To select in which mode the application should run, simply display the info of the application in the Finder and you should see 2 checkboxes:

  • Open in 32-bit mode
  • Open using Rosetta

As far as I know, the first checkbox should always be visible on an Intel machine as long as the application binary contains the x86_64 and i386 architecture.

The Rosetta checkbox will only be visible on an Intel machine if the application binary contains the ppc architecture. Note also that the developer can prevent the checkbox to appear in the Finder by setting the key ‘LSRequiresNativeExecution‘ to true in the ‘Info.plist’ file.

'Open in 32-bit mode' checkbox in the Finder

You may wonder where these flags are stored on the machine. You might have noticed that if you set one flag on an application, trash the application and the preferences, and reinstall it, the flag will still be set. So the flag is definitively not stored in the application package or in the application preferences.

In fact the flags are stored in the file ‘com.apple.LaunchServices.plist’ in the user Preferences folder (~/Library/Preferences/com.apple.LaunchServices.plist). That means that several users on the same machine could have different flags set for the same applications.

Before looking at this file, let’s imagine you have an application called ‘MyApp’ which was compiled for the ppc, i386 and x86_64 architectures. In the Finder you can duplicate this application 2 times. For one instance, check the ‘run in 32-bit mode’, force another instance to run in Rosetta, and leave the original instance unchanged (run as x86_64):

The same application but different checkbox selected in the Finder

Here is what you will see if you open now the file ‘~/Library/Preferences/com.apple.LaunchServices.plist’ with Property List Editor:

The content of the file com.apple.LaunchServices.plist

It’s fairly easy to understand how the flags are stored. The file contains a dictionary ‘LSArchitecturesForX86_64’. The keys of this dictionary are the applicationIDs (‘org.timac.MyApp’ for example). For each applicationID, there is an array containing the information for the different instances of the application. The information of each instance is a pair (path of the application, architecture of the application):

  • The first item in the array is an alias to the first instance of application.
  • The second item is the architecture of the first instance of the application.
  • The third item is an alias to the second instance of application.
  • The fourth is the architecture of the second instance of the application.

Following is the source code for a small application that will read the content of the file ‘com.apple.LaunchServices.plist’ and will print the paths of each application whose flags (‘Open in 32-bit mode’ or ‘Open using Rosetta’) were changed in the Finder. It will also display the architecture selected in the Finder for each of the application. This application will output something like:

applicationID: org.timac.MyApp

Path: /Applications/MyApp.app
will run as: x86_64

Path: /Applications/MyApp 32-bit.app
will run as: i386

Path: /Applications/MyApp Rosetta.app
will run as: ppc

The source code:


#import <Foundation/Foundation.h>

// This function takes as parameter the data of the aliases
// stored in the com.apple.LaunchServices.plist file.
// It returns the resolved path as string.
static NSString *getResolvedAliasPath(NSData* inData)
{
	NSString *outPath = nil;
	if(inData != nil)
	{
		const void *theDataPtr = [inData bytes];
		NSUInteger theDataLength = [inData length];
		if(theDataPtr != nil && theDataLength > 0)
		{
			// Create an AliasHandle from the NSData
			AliasHandle theAliasHandle;
			theAliasHandle = (AliasHandle)NewHandle(theDataLength);
			bcopy(theDataPtr, *theAliasHandle, theDataLength);
			
			FSRef theRef;
			Boolean wChang;
			OSStatus err = noErr;
			err = FSResolveAlias(NULL, theAliasHandle, &theRef, &wChang);
			if(err == noErr)
			{
				// The path was resolved.
				char path[1024];
				err = FSRefMakePath(&theRef, (UInt8*)path, sizeof(path));
				if(err == noErr)
					outPath = [NSString stringWithUTF8String:path];
			}
			else
			{
				// If we can't resolve the alias (file not found),
				// we can still return the path.
				CFStringRef tmpPath = NULL;
				err = FSCopyAliasInfo(theAliasHandle, NULL, NULL,
									  &tmpPath, NULL, NULL);
				
				if(err == noErr && tmpPath != NULL)
					outPath = [(NSString*)tmpPath autorelease];
			}
			
			DisposeHandle((Handle)theAliasHandle);
		}
	}
	
	return outPath;
}

// This function prints the architecture for each application
// in the com.apple.LaunchServices.plist file
static void dumpLSArchitecturesForX86_64()
{
	// The path of the com.apple.LaunchServices.plist file.
	NSString *prefsPath = 
			@"~/Library/Preferences/com.apple.LaunchServices.plist";
	prefsPath = [prefsPath stringByExpandingTildeInPath];
	
	NSDictionary *mainDict = 
			[NSDictionary dictionaryWithContentsOfFile:prefsPath];
	if(mainDict != nil)
	{
		// We are only interested by the
		// "LSArchitecturesForX86_64" dictionary.
		NSDictionary *architectureDict = 
				[mainDict objectForKey:@"LSArchitecturesForX86_64"];
		
		// Get the list of applications.
		// The array is ordered by applicationID.
		NSArray *applicationIDArray = [architectureDict allKeys];
		if(applicationIDArray != nil)
		{
			// For each applicationID
			NSUInteger i = 0;
			for(i = 0 ; i < [applicationIDArray count] ; i++)
			{
				NSString *applicationID =
						[applicationIDArray objectAtIndex:i];
				
				NSArray *appArray =
						[architectureDict objectForKey:applicationID];
				
				NSLog(@"-------------------------");
				NSLog(@"applicationID: %@", applicationID);
				
				// For each instance of the application,
				// there is a pair (Alias, architecture).
				// The alias is stored as a NSData
				// and the architecture as a NSString.
				NSUInteger j = 0;
				for(j = 0 ; j < [appArray count] / 2 ; j++)
				{
					NSLog(@"\n");
					
					// Just for safety
					if(j * 2 + 1 < [appArray count])
					{
						NSData *aliasData =
							[appArray objectAtIndex:j * 2];
						
						NSString *theArch =
							[appArray objectAtIndex:j * 2 + 1];
						
						if(aliasData != nil && theArch != nil)
						{
							// Get the path of the application
							NSString *resolvedPath =
										getResolvedAliasPath(aliasData);
							
							NSLog(@"\t Path: %@", resolvedPath);
							NSLog(@"\t will run as: %@", theArch);
						}
					}
				}
			}
		}
	}
}

int main (int argc, const char * argv[])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
	dumpLSArchitecturesForX86_64();
		
	[pool drain];
    return 0;
}


Intel 64-bit summary

Posted: January 8th, 2010 | Author: | Filed under: macOS | Tags: , , , , , , , , , , | 6 Comments »

Since people are confused regarding Intel 64-bit, here is a brief summary of what can run on which Intel processor.

To run a 64-bit application, you obviously need a 64-bit processor. All the machines that Apple currently ships have a 64-bit processor.

  • Only the ‘Intel Core Solo‘ and ‘Intel Core Duo‘ processors are 32-bit. On such machines, you won’t be able to run 64-bit apps.
  • The ‘Intel Core 2 Duo‘ and ‘Xeon‘ processors are 64-bit.

Useful link on Apple Support: How to tell if your Intel-based Mac has a 32-bit or 64-bit processor.

If you have a 64-bit processor (‘Intel Core 2 Duo’ or better), there are 3 levels of 64-bit applications:

  • to run a 64-bit faceless application: you need 10.4 and later.
  • to run a 64-bit application with UI (Cocoa): you need 10.5 and later.
  • to run the 64-bit kernel (and run 64-bit kernel extensions): you need 10.6 and later and a K64-capable machine (the EFI needs to be 64-bit). By default only the Xserve (2008 and later) will run the 64-bit kernel. On other K64-capable machines, you have to explicitely turn on the 64-bit kernel to use it.

Useful link on Apple Developer: Introduction to 64-Bit Transition Guide.