How To Check Computer Type / OS?

Discussion in 'Mac Programming' started by Darkroom, Nov 28, 2008.

  1. Darkroom Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #1
    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?
     
  2. Sayer macrumors 6502a

    Sayer

    Joined:
    Jan 4, 2002
    Location:
    Austin, TX
    #2
    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;
    }
     
  3. Darkroom thread starter Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #3
    humm... guess there's no real way to tell if the machine is a desktop or laptop? :eek:
     
  4. HiRez macrumors 603

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #4
    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.
     
  5. HiRez macrumors 603

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #5
    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...
     
  6. eviltobz macrumors member

    Joined:
    Nov 12, 2007
    #6
    a check to see if there is a battery may be the best way to look for a luggable.
     
  7. Darkroom thread starter Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #7
    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);
    }
    
     
  8. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #8
    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.
     
  9. Krevnik macrumors 68040

    Krevnik

    Joined:
    Sep 8, 2003
    #9
    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.
     
  10. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #10
    Unless your app is a super-battery-monitor, i.e. Coconut Battery =).

    -Lee
     
  11. Darkroom thread starter Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #11
    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...
     
  12. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #12
    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:
    http://forums.macrumors.com/showthread.php?t=474628

    -Lee
     
  13. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #13
    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:
     
  14. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #14
    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
     
  15. Darkroom thread starter Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #15
    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?
     
  16. SP-NewToMac macrumors newbie

    Joined:
    May 11, 2009
    #16
    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];
     
  17. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #17
    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];
     
  18. SP-NewToMac macrumors newbie

    Joined:
    May 11, 2009
    #18
    Debug mode

    I was trying debug mode. It worked when I ran my app directly by double clicking.
     
  19. SP-NewToMac macrumors newbie

    Joined:
    May 11, 2009
    #19
    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?
     
  20. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #20
    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?
     

Share This Page