I have an app which can change the volume under OSX. What it lacks is the visual feedback provided when one presses the sound up/down keys. Does anyone know how to programmatically invoke that behavior?
Thanks
Here's a little code from George Warner and Casey Fleser that does this trick. Think carefully that this is really the way you want to do things.
// Save as sound_up.m
// Compile: gcc -o sound_up sound_up.m -framework IOKit -framework Cocoa
#import <Cocoa/Cocoa.h>
#import <IOKit/hidsystem/IOHIDLib.h>
#import <IOKit/hidsystem/ev_keymap.h>
static io_connect_t get_event_driver(void)
{
static mach_port_t sEventDrvrRef = 0;
mach_port_t masterPort, service, iter;
kern_return_t kr;
if (!sEventDrvrRef)
{
// Get master device port
kr = IOMasterPort( bootstrap_port, &masterPort );
check( KERN_SUCCESS == kr);
kr = IOServiceGetMatchingServices( masterPort, IOServiceMatching( kIOHIDSystemClass ), &iter );
check( KERN_SUCCESS == kr);
service = IOIteratorNext( iter );
check( service );
kr = IOServiceOpen( service, mach_task_self(),
kIOHIDParamConnectType, &sEventDrvrRef );
check( KERN_SUCCESS == kr );
IOObjectRelease( service );
IOObjectRelease( iter );
}
return sEventDrvrRef;
}
static void HIDPostAuxKey( const UInt8 auxKeyCode )
{
NXEventData event;
kern_return_t kr;
IOGPoint loc = { 0, 0 };
// Key press event
UInt32 evtInfo = auxKeyCode << 16 | NX_KEYDOWN << 8;
bzero(&event, sizeof(NXEventData));
event.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
event.compound.misc.L[0] = evtInfo;
kr = IOHIDPostEvent( get_event_driver(), NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE );
check( KERN_SUCCESS == kr );
// Key release event
evtInfo = auxKeyCode << 16 | NX_KEYUP << 8;
bzero(&event, sizeof(NXEventData));
event.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
event.compound.misc.L[0] = evtInfo;
kr = IOHIDPostEvent( get_event_driver(), NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE );
check( KERN_SUCCESS == kr );
}
int main(int argc, char *argv[]) {
HIDPostAuxKey(NX_KEYTYPE_SOUND_UP);
}
Other interesting keycodes include: NX_KEYTYPE_SOUND_DOWN, NX_KEYTYPE_MUTE, NX_KEYTYPE_PLAY.
I would implement this by simulating the physical press of the up/down volume keys, and letting the OS deal with the details. Perhaps the user has disabled the visual feedback, perhaps it changes, etc. - this is the safest way of pulling it off.
Have a look at this: Simulating key press events in Mac OS X
Related
In my project I must use SDL_BLENDOPERATION_MAXIMUM via SDL_ComposeCustomBlendMode() which is supported in SDL 2.0.9 by direct3d11 renderer only. I have Windows 8.1 and GeForce GTX750 Ti with updated drivers. My system should support DirectX 11 renderending.
Changing defines in SDL_config.h or SDL_config_windows.h (SDL_VIDEO_RENDER_D3D11 to 1 and SDL_VIDEO_RENDER_D3D to 0) doesn't help.
I tried to fill preprocessor difinitions with defines SDL_VIDEO_RENDER_D3D11 or WINRT according to SDL source code. But it doesn't help.
What should I do to activate direct3d11 renderer so I can use blend mode max?
My test code:
#include "SDL.h"
#include "SDL_image.h"
#include <string>
using namespace std;
int main( int argc, char *argv[] ) {
SDL_Init( SDL_INIT_VIDEO );
IMG_Init( IMG_INIT_PNG );
SDL_SetHintWithPriority( SDL_HINT_RENDER_DRIVER, "direct3d11", SDL_HINT_OVERRIDE );
SDL_Window *window = SDL_CreateWindow( "Testing", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
1200, 600, SDL_WINDOW_RESIZABLE );
SDL_Renderer *renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED );
SDL_RendererInfo *rendererInfo = new SDL_RendererInfo();
SDL_RendererInfo *driverInfo = new SDL_RendererInfo();
SDL_GetRendererInfo( renderer, rendererInfo );
int drivers = SDL_GetNumRenderDrivers();
string availableDrivers = " (";
for ( int i = 0; i < drivers; ++i ) {
SDL_GetRenderDriverInfo( i, driverInfo );
string driverName = driverInfo->name;
if ( i == drivers - 1 ) {
availableDrivers += driverName;
}
else {
availableDrivers += driverName + ", ";
}
}
availableDrivers += ")";
string path = SDL_GetBasePath();
SDL_Surface *surfRed = IMG_Load( (path + "\\Red.png").c_str() );
SDL_Texture *textRed = SDL_CreateTextureFromSurface( renderer, surfRed );
SDL_FreeSurface( surfRed );
SDL_Surface *surfBlue = IMG_Load( ( path + "\\Blue.png" ).c_str() );
SDL_Texture *textBlue = SDL_CreateTextureFromSurface( renderer, surfBlue );
SDL_FreeSurface( surfBlue );
SDL_Rect destRed, destBlue;
destRed.x = 128;
destRed.y = 128;
destBlue.x = 196;
destBlue.y = 196;
SDL_QueryTexture( textRed, NULL, NULL, &destRed.w, &destRed.h );
SDL_QueryTexture( textBlue, NULL, NULL, &destBlue.w, &destBlue.h );
SDL_BlendMode blendMode = SDL_ComposeCustomBlendMode( SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_MAXIMUM,
SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_MAXIMUM );
SDL_SetTextureBlendMode( textRed, blendMode );
SDL_SetTextureBlendMode( textBlue, blendMode );
// SDL_SetRenderDrawBlendMode( renderer, blendMode );
string info = rendererInfo->name + availableDrivers + " " + SDL_GetError();
SDL_SetWindowTitle( window, info.c_str() );
SDL_SetRenderDrawColor( renderer, 0, 0, 0, 255 );
SDL_Event event;
bool isRunning = true;
while ( isRunning ) {
if ( SDL_PollEvent( &event ) ) {
if ( event.type == SDL_QUIT ) {
isRunning = false;
}
}
SDL_RenderClear( renderer );
SDL_RenderCopy( renderer, textRed, NULL, &destRed );
SDL_RenderCopy( renderer, textBlue, NULL, &destBlue );
SDL_RenderPresent( renderer );
}
delete driverInfo;
delete rendererInfo;
SDL_DestroyTexture( textRed );
SDL_DestroyTexture( textBlue );
SDL_DestroyRenderer( renderer );
SDL_DestroyWindow( window );
IMG_Quit();
SDL_Quit();
return 0;
}
Window title is "direct3d (direct3d, opengl, opengles2, software) This operration is not supported". It works fine when I change to SDL_BLENDOPERATION_ADD, but it's not what I want. If I uncomment renderer blend mode it doesn't help too.
Enumerate the supported renderer backends via SDL_GetNumRenderDrivers() and SDL_GetRenderDriverInfo().
Note the index of the direct3d11 driver, if it exists.
Pass index into SDL_CreateRenderer().
All together:
SDL_Init( SDL_INIT_VIDEO );
SDL_Window* window = SDL_CreateWindow( "SDL2", 0, 0, 640, 480, SDL_WINDOW_SHOWN );
SDL_Renderer* renderer = nullptr;
for( int i = 0; i < SDL_GetNumRenderDrivers(); ++i )
{
SDL_RendererInfo rendererInfo = {};
SDL_GetRenderDriverInfo( i, &rendererInfo );
if( rendererInfo.name != std::string( "direct3d11" ) )
{
continue;
}
renderer = SDL_CreateRenderer( window, i, 0 );
break;
}
Note that what you are setting with SDL_VIDEO_RENDER_D3D and friends are compile time definitions for building SDL with D3D support.
To do this at runtime:
Sometime after SDL_Init() and before creating your window/renderer set a hint for it.
// returns true on success or false on failure
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "direct3d11");
However, this will only work on Windows, and I believe d3d is already the default renderer for windows. If your version of windows supports d3d11 that is what SDL should use. I strongly suspect you already have a d3d11 renderer and your problem is with how you instantiate or use your custom blend mode.
To verify you have a d3d11 renderer:
SDL_RendererInfo info;
SDL_GetRendererInfo(renderer, &info);
printf("%s", info.name);
To create a custom blend mode with SDL_BLENDOPERATION_MAXIMUM
SDL_BlendMode blender = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_SRC_ALPHA, // change this to suit your needs
SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, // change this to suit your needs
SDL_BLENDOPERATION_MAXIMUM,
SDL_BLENDFACTOR_ONE, // change this to suit your needs
SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, // change this to suit your needs
SDL_BLENDOPERATION_MAXIMUM);
SDL_SetTextureBlendMode(texture, blender); // blender is your custom mode
SDL_SetRenderDrawBlendMode(renderer, blender); // blender is your custom mode
I cant imagine the above blender is actually the combination of factors/operations you want, but you didn't post your actual code to work off.
I've been trying to implement a systray icon using straight C and Xlib, going along with the freedesktop specification [0]. I can't seem to get my Window to embed into my desktop manager's systray[1], while other apps seem to be able to do it. I am not sure how to go forward debugging this, but I've provided minimal sample code below.
I haven't been able to find any sample code using straight Xlib and C, and all the suggestions I've seen have been with regard to some framework like Gtk/Qt/Mono/whatever, but I want to understand what is supposed to be happening here as per the spec, and what I'm doing wrong.
#include <X11/Xutil.h>
#include <string.h>
#define MIN(A, B) ((A) < (B) ? (A) : (B))
/* --------- XEMBED and systray stuff */
#define SYSTEM_TRAY_REQUEST_DOCK 0
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
static int trapped_error_code = 0;
static int (*old_error_handler) (Display *, XErrorEvent *);
static int
error_handler(Display *display, XErrorEvent *error) {
trapped_error_code = error->error_code;
return 0;
}
void
trap_errors(void) {
trapped_error_code = 0;
old_error_handler = XSetErrorHandler(error_handler);
}
int
untrap_errors(void) {
XSetErrorHandler(old_error_handler);
return trapped_error_code;
}
void
send_systray_message(Display* dpy, Window w, long message, long data1, long data2, long data3) {
XEvent ev;
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = w;
ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
ev.xclient.format = 32;
ev.xclient.data.l[0] = CurrentTime;
ev.xclient.data.l[1] = message;
ev.xclient.data.l[2] = data1;
ev.xclient.data.l[3] = data2;
ev.xclient.data.l[4] = data3;
trap_errors();
XSendEvent(dpy, w, False, NoEventMask, &ev);
XSync(dpy, False);
if (untrap_errors()) {
/* Handle errors */
}
}
/* ------------ Regular X stuff */
int
main(int argc, char **argv) {
int width, height;
XWindowAttributes wa;
XEvent ev;
Display *dpy;
int screen;
Window root, win;
/* init */
if (!(dpy=XOpenDisplay(NULL)))
return 1;
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
if(!XGetWindowAttributes(dpy, root, &wa))
return 1;
width = height = MIN(wa.width, wa.height);
/* create window */
win = XCreateSimpleWindow(dpy, root, 0, 0, width, height, 0, 0, 0xFFFF9900);
send_systray_message(dpy, win, SYSTEM_TRAY_REQUEST_DOCK, win, 0, 0);
XMapWindow(dpy, win);
XSync(dpy, False);
/* run */
while(1) {
while(XPending(dpy)) {
XNextEvent(dpy, &ev); /* just waiting until we error because window closed */
}
}
}
Any help would be greatly appreciated. I think this problem is language-agnostic, and more to do with me misunderstanding the protocols, so answers in any language are acceptable, as long as they help me iron out this XEvent stuff.
[0] https://specifications.freedesktop.org/systemtray-spec/systemtray-spec-0.2.html
[1] I'm using dwm with the systray patch http://dwm.suckless.org/patches/systray
You are sending the message to a wrong window. The documentation isn't really helpful, it makes no sense whatsoever to send a tray embed message to your own window!. You need to send it to the tray window.
Here's a a fixed send_systray_message
void
send_systray_message(Display* dpy, long message, long data1, long data2, long data3) {
XEvent ev;
Atom selection_atom = XInternAtom (dpy,"_NET_SYSTEM_TRAY_S0",False);
Window tray = XGetSelectionOwner (dpy,selection_atom);
if ( tray != None)
XSelectInput (dpy,tray,StructureNotifyMask);
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = tray;
ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
ev.xclient.format = 32;
ev.xclient.data.l[0] = CurrentTime;
ev.xclient.data.l[1] = message;
ev.xclient.data.l[2] = data1; // <--- your window is only here
ev.xclient.data.l[3] = data2;
ev.xclient.data.l[4] = data3;
trap_errors();
XSendEvent(dpy, tray, False, NoEventMask, &ev);
XSync(dpy, False);
usleep(10000);
if (untrap_errors()) {
/* Handle errors */
}
}
and a call to it
send_systray_message(dpy, SYSTEM_TRAY_REQUEST_DOCK, win, 0, 0); // pass win only once
Credits: http://distro.ibiblio.org/vectorlinux/Uelsk8s/GAMBAS/gambas-svn/gambas2/gb.gtk/src/gtrayicon.cpp
I'm trying to programmatically access the ambient light sensor in a Mac application running on OS X 10.5 and above, but can't find a way to do this.
Two other questions had been posed about this here, "Accessing mac's sensor data" and "Disable ambient-light sensor screen dimming programmatically on OS X", but they either didn't address this or present solutions that break on 10.5 and up.
What private API does Apple use to access the ambient light-sensor data on OS X and/or how would I find it?
I've found the closest thing I can -- example code from a Firefox bug report last modified in April 2013. The following works, producing a simple CLI program to query the sensor (taken freely from https://bugzilla.mozilla.org/show_bug.cgi?id=793728#attach_664102). The service polled is "AppleLMUController", which you can then extract relevant information from -- the snippet below creates a serviceObject=IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleLMUController")), which is then used.
// lmutracker.mm
//
// clang -o lmutracker lmutracker.mm -framework IOKit -framework CoreFoundation
#include <mach/mach.h>
#import <IOKit/IOKitLib.h>
#import <CoreFoundation/CoreFoundation.h>
static double updateInterval = 0.1;
static io_connect_t dataPort = 0;
void updateTimerCallBack(CFRunLoopTimerRef timer, void *info) {
kern_return_t kr;
uint32_t outputs = 2;
uint64_t values[outputs];
kr = IOConnectCallMethod(dataPort, 0, nil, 0, nil, 0, values, &outputs, nil, 0);
if (kr == KERN_SUCCESS) {
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b%8lld %8lld", values[0], values[1]);
return;
}
if (kr == kIOReturnBusy) {
return;
}
mach_error("I/O Kit error:", kr);
exit(kr);
}
int main(void) {
kern_return_t kr;
io_service_t serviceObject;
CFRunLoopTimerRef updateTimer;
serviceObject = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleLMUController"));
if (!serviceObject) {
fprintf(stderr, "failed to find ambient light sensors\n");
exit(1);
}
kr = IOServiceOpen(serviceObject, mach_task_self(), 0, &dataPort);
IOObjectRelease(serviceObject);
if (kr != KERN_SUCCESS) {
mach_error("IOServiceOpen:", kr);
exit(kr);
}
setbuf(stdout, NULL);
printf("%8ld %8ld", 0L, 0L);
updateTimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
CFAbsoluteTimeGetCurrent() + updateInterval, updateInterval,
0, 0, updateTimerCallBack, NULL);
CFRunLoopAddTimer(CFRunLoopGetCurrent(), updateTimer, kCFRunLoopDefaultMode);
CFRunLoopRun();
exit(0);
}
While #Landak's answer is good for the time, that ambient light sensor api seems to have been deprecated.
The code that works now is as follows:
// lmutracker.mm
//
// clang -o lmutracker lmutracker.mm -F /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks -framework Foundation -framework IOKit -framework CoreFoundation -framework BezelServices
#include <mach/mach.h>
#import <Foundation/Foundation.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/hidsystem/IOHIDServiceClient.h>
typedef struct __IOHIDEvent *IOHIDEventRef;
#define kAmbientLightSensorEvent 12
#define IOHIDEventFieldBase(type) (type << 16)
extern "C" {
IOHIDEventRef IOHIDServiceClientCopyEvent(IOHIDServiceClientRef, int64_t, int32_t, int64_t);
double IOHIDEventGetFloatValue(IOHIDEventRef, int32_t);
IOHIDServiceClientRef ALCALSCopyALSServiceClient(void);
}
static double updateInterval = 0.1;
static IOHIDServiceClientRef client;
static IOHIDEventRef event;
void updateTimerCallBack(CFRunLoopTimerRef timer, void *info) {
double value;
event = IOHIDServiceClientCopyEvent(client, kAmbientLightSensorEvent, 0, 0);
value = IOHIDEventGetFloatValue(event, IOHIDEventFieldBase(kAmbientLightSensorEvent));
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b%8f", value);
CFRelease(event);
}
int main(void) {
kern_return_t kr;
CFRunLoopTimerRef updateTimer;
client = ALCALSCopyALSServiceClient();
if (client) {
event = IOHIDServiceClientCopyEvent(client, kAmbientLightSensorEvent, 0, 0);
}
if (!event) {
fprintf(stderr, "failed to find ambient light sensors\n");
exit(1);
}
CFRelease(event);
setbuf(stdout, NULL);
printf("%8f", 0.0);
updateTimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
CFAbsoluteTimeGetCurrent() + updateInterval, updateInterval,
0, 0, updateTimerCallBack, NULL);
CFRunLoopAddTimer(CFRunLoopGetCurrent(), updateTimer, kCFRunLoopDefaultMode);
CFRunLoopRun();
exit(0);
}
I found this in DarkModeBuddy (BSD 2-clause license), and adapted it into a cli tool in my dotfiles.
You can get the value of ambient light sensor using terminal.
For get the value first you should install the system management controller smc .exec then run it using terminal. After that run this command ./smc -l it's show's the list of all sensor's which exist on mac after that try to find the key which is ALSL this key give's the actual value of light ambient sensor of every mac.
Assuming my code (DLL) already runs inside application that runs as service.
How to find the service name ?
I would like more elegant way than getting process path and enumerating services in registry.
I would suggest using GetCurrentProcessId to get the process ID of the service you're running in. Then use EnumServiceStatusEx to enumerate the services (without having to use the registry yourself).
You can match the process id from ENUM_SERVICE_STATUS_PROCESS.ServiceStatusProcess.dwProcessId to your current process ID and get the name. For example:
void enumerateServices( DWORD processId )
{
SC_HANDLE hSCM = OpenSCManager(NULL, NULL,
SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT);
if (hSCM == NULL)
{
return;
}
DWORD bufferSize = 0;
DWORD requiredBufferSize = 0;
DWORD totalServicesCount = 0;
EnumServicesStatusEx( hSCM,
SC_ENUM_PROCESS_INFO,
SERVICE_WIN32,
SERVICE_STATE_ALL,
nullptr,
bufferSize,
&requiredBufferSize,
&totalServicesCount,
nullptr,
nullptr );
std::vector<BYTE> buffer( requiredBufferSize );
EnumServicesStatusEx( hSCM,
SC_ENUM_PROCESS_INFO,
SERVICE_WIN32,
SERVICE_STATE_ALL,
buffer.data(),
buffer.size(),
&requiredBufferSize,
&totalServicesCount,
nullptr,
nullptr );
LPENUM_SERVICE_STATUS_PROCESS services =
reinterpret_cast<LPENUM_SERVICE_STATUS_PROCESS>( buffer.data() );
for ( unsigned int i = 0; i < totalServicesCount; ++i )
{
ENUM_SERVICE_STATUS_PROCESS service = services[i];
if ( service.ServiceStatusProcess.dwProcessId == processId )
{
// This is your service.
std::wcout << service.lpServiceName << L"PID: " <<
service.ServiceStatusProcess.dwProcessId << std::endl;
}
}
( void )CloseServiceHandle( hSCM );
}
Usual disclaimers about error handling apply. I've also not properly checked buffer sizes, etc.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Unique Identifier of a Mac?
On iOS, retrieving a unique and anonymous string for the current device is fairly easy ([[UIDevice currentDevice] uniqueIdentifier]). And I'm not referring here to the computer's serial number but at a hash made out of different components characteristics/sn, like the iOS udid's.
Is there something similar on Mac OS X side, and how to access it?
See Tech Note 1103:
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
// Returns the serial number as a CFString.
// It is the caller's responsibility to release the returned CFString when done with it.
void CopySerialNumber(CFStringRef *serialNumber)
{
if (serialNumber != NULL) {
*serialNumber = NULL;
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpert) {
CFTypeRef serialNumberAsCFString =
IORegistryEntryCreateCFProperty(platformExpert,
CFSTR(kIOPlatformSerialNumberKey),
kCFAllocatorDefault, 0);
if (serialNumberAsCFString) {
*serialNumber = serialNumberAsCFString;
}
IOObjectRelease(platformExpert);
}
}
}
Don't use the computer serial number— it's only valid on initial factory installations. If your motherboard gets replaced at any point, you'll no longer have a serial number, since it wasn't setup to have one as part of a full machine at the factory.
Instead, you should use the hardware ethernet ID, specifically the one for device 'en0'. The following (quite similar) code will give you that:
//
// MACAddress.m
// XPPublisherCore
//
// Created by Jim Dovey on 11-01-30.
// Copyright 2011 XPlatform Inc. All rights reserved.
//
#import "MACAddress.h"
#import <IOKit/IOKitLib.h>
NSData * GetMACAddress( void )
{
kern_return_t kr = KERN_SUCCESS;
CFMutableDictionaryRef matching = NULL;
io_iterator_t iterator = IO_OBJECT_NULL;
io_object_t service = IO_OBJECT_NULL;
CFDataRef result = NULL;
matching = IOBSDNameMatching( kIOMasterPortDefault, 0, "en0" );
if ( matching == NULL )
{
fprintf( stderr, "IOBSDNameMatching() returned empty dictionary\n" );
return ( NULL );
}
kr = IOServiceGetMatchingServices( kIOMasterPortDefault, matching, &iterator );
if ( kr != KERN_SUCCESS )
{
fprintf( stderr, "IOServiceGetMatchingServices() returned %d\n", kr );
return ( NULL );
}
while ( (service = IOIteratorNext(iterator)) != IO_OBJECT_NULL )
{
io_object_t parent = IO_OBJECT_NULL;
kr = IORegistryEntryGetParentEntry( service, kIOServicePlane, &parent );
if ( kr == KERN_SUCCESS )
{
if ( result != NULL )
CFRelease( result );
result = IORegistryEntryCreateCFProperty( parent, CFSTR("IOMACAddress"), kCFAllocatorDefault, 0 );
IOObjectRelease( parent );
}
else
{
fprintf( stderr, "IORegistryGetParentEntry returned %d\n", kr );
}
IOObjectRelease( service );
}
return ( (NSData *)NSMakeCollectable(result) );
}
NSString * GetMACAddressDisplayString( void )
{
NSData * macData = GetMACAddress();
if ( [macData length] == 0 )
return ( nil );
const UInt8 *bytes = [macData bytes];
NSMutableString * result = [NSMutableString string];
for ( NSUInteger i = 0; i < [macData length]; i++ )
{
if ( [result length] != 0 )
[result appendFormat: #":%02hhx", bytes[i]];
else
[result appendFormat: #"%02hhx", bytes[i]];
}
return ( [[result copy] autorelease] );
}