Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
what methods are available to check the computer type or OS of which the application is running?

for example, if i have 10.4 or higher app that has a Time Machine plugin (or something)... how can i find out if the computer is running 10.4 or 10.5, is intel or PPC? is a desktop or laptop?
 
I found this on the Inter-web (they have it on computers now!):

Code:
- (NSString *) systemInfoString {
    
    static NSString *systemInfoString = NULL;
    
    if (systemInfoString) {
        return systemInfoString;
    }
    
    int error = 0 ;
	int value = 0 ;
	unsigned long length = sizeof(value) ;
    
    NSString *visibleCPUSubType = @"";
    NSString *visibleCPUType    = @"an Unknown Processor";
    
    
	// CPU type (decoder info for values found here is in mach/machine.h)
	error = sysctlbyname("hw.cputype", &value, &length, NULL, 0);
	int cpuType = -1;
	if (error == 0) {
		cpuType = value;
		switch(value) {
			case 7:		visibleCPUType=@"Intel";	break;
			case 18:	visibleCPUType=@"a PowerPC";	break;
			default:	visibleCPUType=@"an Unknown";	break;
		}
	}
	error = sysctlbyname("hw.cpusubtype", &value, &length, NULL, 0);
	if (error == 0) {
		if (cpuType == 7) {
			// Intel
			visibleCPUSubType = @"";	// If anyone knows how to tell a Core Duo from a Core Solo, please email tph@atomicbird.com
		} else if (cpuType == 18) {
			// PowerPC
			switch(value) {
				case 9:					visibleCPUSubType=@" G3";	break;
				case 10:	case 11:	visibleCPUSubType=@" G4";	break;
				case 100:				visibleCPUSubType=@" G5";	break;
				default:				visibleCPUSubType=@" Other";	break;
			}
		} else {
			visibleCPUSubType = @"Other";
		}
	}
    
    int cpuCount = 1;
	// Number of CPUs
	error = sysctlbyname("hw.ncpu", &value, &length, NULL, 0);
	if (error == 0)
		cpuCount = value;
	
    
    int clockSpeed;
    
	OSErr err;
	SInt32 gestaltInfo;
	err = Gestalt(gestaltProcClkSpeedMHz,&gestaltInfo);
	if (err == noErr)
		clockSpeed = gestaltInfo;
	
	int ram;
	err = Gestalt(gestaltPhysicalRAMSizeInMegabytes,&gestaltInfo);
	if (err == noErr)
		ram = gestaltInfo;
	
    
    NSString *extra = @"";
    if (cpuCount > 7 or clockSpeed > 3100) {
        extra = @" It's super fast and I love it.";
    }
    
    NSString *currentSystemVersion = SUCurrentSystemVersionString();
    
    systemInfoString = [[NSString stringWithFormat:@"(I'm running Mac OS X %@ on %@%@, with %d CPU(s) running at %d MHz and %d MB of ram.%@)", currentSystemVersion, visibleCPUType, visibleCPUSubType, cpuCount, clockSpeed, ram, extra] retain];
    
    return systemInfoString;
}
 
You can just call the system_profiler command-line tool via NSTask or system() if you don't want to deal with that low-level C-Pascal crap. A run on mine reveals:

Code:
   Hardware Overview:

      Model Name: iMac
      Model Identifier: iMac8,1
      Processor Name: Intel Core 2 Duo
      Processor Speed: 3.06 GHz
      Number Of Processors: 1
      Total Number Of Cores: 2
      L2 Cache: 6 MB
      Memory: 2 GB
      Bus Speed: 1.07 GHz
and a lot more (this is just a snippet). You'll still have to do some text parsing though.
 
humm... guess there's no real way to tell if the machine is a desktop or laptop? :eek:
Going with the system_profiler thing, under Displays, there's a Built-In: (Yes/No), if that = "Yes", and the type is not an iMac, it's probably a laptop. There might be easier things to check too...
 
a check to see if there is a battery may be the best way to look for a luggable.
 
ok... so i did a bit of research and came up with a bit of code... but i have no idea where to go from here. i'm looking for the "Battery Information" under "Power:" from the system_profiler output, but how do i search for that with this information return?

Code:
- (NSXMLElement *)information
{
NSPipe *theOutputPipe = [NSPipe pipe];

NSTask *theTask = [[[NSTask alloc] init] autorelease];
[theTask setLaunchPath: @"/usr/sbin/system_profiler"];
[theTask setArguments:[NSArray arrayWithObjects:@"-xml", @"SPPowerDataType", @"-detailLevel", @"mini", NULL]];
[theTask setStandardOutput:theOutputPipe];
[theTask launch];
NSData *theData = [[theOutputPipe fileHandleForReading] readDataToEndOfFile];
//	[theTask setStandardError:[NSPipe pipe]];
[theTask waitUntilExit];


int theStatus = [theTask terminationStatus];
if (theStatus != 0)
	[NSException raise:NSGenericException format:@"Could not get system profile"];

NSString *theString = [[[NSString alloc] initWithData:theData encoding:NSASCIIStringEncoding] autorelease];
NSXMLElement *theInformation = [NSXMLNode elementWithName:@"systemProfile" stringValue:theString];

return(theInformation);
}
 
The XML format is a property list. You can do something like this in Terminal to open the data in Property List Editor to visually see how to obtain which parts you want:
Code:
/usr/sbin/system_profiler -xml SPPowerDataType -detailLevel mini > ~/desktop/s.plist;
The NSPropertyListSerialization class can then be used to create an NSArray object from the data.
 
ok... so i did a bit of research and came up with a bit of code... but i have no idea where to go from here. i'm looking for the "Battery Information" under "Power:" from the system_profiler output, but how do i search for that with this information return?

You will need to parse the strings yourself. NSString might be able to help. Although something that can run a regular expression on an NSString will likely be better (which might be a third party piece of code floating around).

Another way to detect a battery is to use IOKit.

Out of curiosity, why do you want to check laptop/desktop? Functionality is likely not going to be that different between the two.
 
what's confusing me is that on desktop macs there just simply isn't any mention of a battery, but macbooks have both Battery and AC listed under power... i totally assumed this would be a cinch, like [system hasBattery], but now i think it's complications is far beyond my capabilities...

i couldn't find any info on detecting a battery in I/O Kit's documentation...
 
This might work? The methods could easily be made into class or instance methods, just trying to get this going:
Code:
#import <Foundation/Foundation.h>
#import <IOKit/ps/IOPowerSources.h>
#import <IOKit/ps/IOPSKeys.h>

BOOL isPortableMachine();
int getNumBatteries();

int main(int argc, char *argv[]) {
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  NSLog(@"There are %d batter(y|ies), this %@ a portable!\n",getNumBatteries(),isPortableMachine()?@"is":@"is not");
  [pool release];
}

int getNumBatteries() {
  CFTypeRef blob = IOPSCopyPowerSourcesInfo();
  CFArrayRef sources = IOPSCopyPowerSourcesList(blob);
  return CFArrayGetCount(sources);
}

BOOL isPortableMachine() {
  return getNumBatteries() != 0;
}

I found the basic principles used here:
https://forums.macrumors.com/threads/474628/

-Lee
 
This might work? The methods could easily be made into class or instance methods, just trying to get this going:
Code:
#import <Foundation/Foundation.h>
#import <IOKit/ps/IOPowerSources.h>
#import <IOKit/ps/IOPSKeys.h>

BOOL isPortableMachine();
int getNumBatteries();

int main(int argc, char *argv[]) {
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  NSLog(@"There are %d batter(y|ies), this %@ a portable!\n",getNumBatteries(),isPortableMachine()?@"is":@"is not");
  [pool release];
}

int getNumBatteries() {
  CFTypeRef blob = IOPSCopyPowerSourcesInfo();
  CFArrayRef sources = IOPSCopyPowerSourcesList(blob);
  return CFArrayGetCount(sources);
}

BOOL isPortableMachine() {
  return getNumBatteries() != 0;
}

I found the basic principles used here:
https://forums.macrumors.com/threads/474628/

-Lee

I think this will mostly work, but it will return the number of attached batteries, and it counts UPSes as batteries. So a MacPro with UPS will be reported as portable :-(

I think you have to check out IOPSKeys.h. For each powersource, you need to read the key kIOPSTransportTypeKey, which will usually return an indication whether a UPS is connected via Serial, USB or Ethernet. If it is an internal battery, this will return kIOPSInternalType = "Internal". That will work until Apple makes a MacPro with a built-in UPS battery :mad:
 
I think this will mostly work, but it will return the number of attached batteries, and it counts UPSes as batteries. So a MacPro with UPS will be reported as portable :-(

I think you have to check out IOPSKeys.h. For each powersource, you need to read the key kIOPSTransportTypeKey, which will usually return an indication whether a UPS is connected via Serial, USB or Ethernet. If it is an internal battery, this will return kIOPSInternalType = "Internal". That will work until Apple makes a MacPro with a built-in UPS battery :mad:

Ah, balls. I guess this method would also fail if one were to be in the unusual state of running a laptop with the AC connected, and the battery detached. This seems like a bugger of a problem, when one would think it would be quite simple. It almost seems easier to get the Model Identifier from IOKit (I don't know how to do this) and compare against a known list which you must update from time to time.

-Lee
 
ouf... if you guys can't figure it out then i certainly don't have a chance in hell :)...

humm... all of apple's portables with battery options have the word "Book" in their titles (MacBook, MacBook Pro, MacBook Air, PowerBook, iBook), while the other desktop computers without battery power options do not...

how difficult would it be to (somehow) obtain the Model Name under Hardware Overview, turn it into a string and compare it... regular expression with wildcards? "%Book%"? something like that?
 
System profiler - launch path not accessible

Hello,

I am getting "launch path not accessible" exception when I try to invoke system_profiler. Please help.

I tried "[profTask setLaunchPath:mad:"/Applications/Utilities/system_profiler"];" path as well, resulted in the same exception. What am I doing wrong? The tool runs fine on commandline

--------------------Code---------------------

NSTask *profTask = [[NSTask alloc] init];
NSString *profPath;
[profTask setLaunchPath:mad:"/usr/sbin/system_profiler SPApplicationsDataType"];

NSArray *args = [NSArray arrayWithObjects:mad:"-detailLevel", @"mini" , @"-xml", nil];
[profTask setArguments:args];

NSPipe *outPipe = [[NSPipe alloc] init];
[profTask setStandardOutput:eek:utPipe];

[profTask launch];
 
NSTask's launch path is the absolute path of the executable - you cannot pass arguments there. So you could try:
Code:
[profTask setLaunchPath:@"/usr/sbin/system_profiler"];
NSArray *args = [NSArray arrayWithObjects:@"SPApplicationsDataType", @"-detailLevel", @"mini" , @"-xml", nil];
 
NSTask's launch path is the absolute path of the executable - you cannot pass arguments there. So you could try:
Code:
[profTask setLaunchPath:@"/usr/sbin/system_profiler"];
NSArray *args = [NSArray arrayWithObjects:@"SPApplicationsDataType", @"-detailLevel", @"mini" , @"-xml", nil];

Thanks, kainjow. I tried without SPApplicationsDataType also, but got same error. I think the problem was I was expecting it to not throw exception in debug mode. Is this behavior normal for NSTask?
 
what methods are available to check the computer type or OS of which the application is running?

for example, if i have 10.4 or higher app that has a Time Machine plugin (or something)... how can i find out if the computer is running 10.4 or 10.5, is intel or PPC? is a desktop or laptop?

If you have a universal binary: When your Intel code is running, you are on an Intel CPU. When your PowerPC code is running, you are on a PowerPC CPU :rolleyes:

Usually you don't want to check for the operating system version, you want to check whether a feature is available or not. You can find out which Macintosh model you are running on, but usually it doesn't matter. You may be more interested in knowing whether the computer has power available or is running on batteries, not whether it is a desktop or laptop.

Try to find out what you _really_ want to know. Why does it matter whether it is desktop or laptop? If I use a MacBook with closed lid, external mouse and keyboard, and a large monitor attached, how is that different from a desktop machine?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.