Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective c/c: Detect USB drive via IOKit only on Mac

Here is my code and it will detect the devices when I run the application at first, but it will not detect the new one after it is running.

//Just for testing
 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
   [self detectUSB];
}

void detectUSB()
{
  //dictionary
  CFMutableDictionaryRef matchingDict = matchingDict = IOServiceMatching(kIOUSBDeviceClassName);

  //create notification
  IONotificationPortRef notificationObject; //notification object to listen
  mach_port_t masterPort = 0; //received from IOMasterPort
  notificationObject = IONotificationPortCreate(masterPort);

  //create run loop
  CFRunLoopSourceRef notificationRunLoopSource;

  //use notification obejct received from notificationPortCreate
  notificationRunLoopSource = IONotificationPortGetRunLoopSource(notificationObject);

  CFRunLoopAddSource(CFRunLoopGetCurrent(), notificationRunLoopSource, kCFRunLoopDefaultMode);

  IOServiceAddMatchingNotification(notificationObject,kIOFirstMatchNotification, matchingDict,isAttached,(__bridge void*)self,&iter );

  isAttached(NULL, iter);
}

void isAttached(void *refcon, io_iterator_t iterator) {

    io_service_t usbDevice;
    while((usbDevice = IOIteratorNext(iterator))) {
         io_name_t name; 
         IORegistryEntryGetName(usbDevice, name);
         printf("\tName:\t\t%s\n", (char *)name);

         CFNumberRef idProduct = (CFNumberRef)IORegistryEntrySearchCFProperty(usbDevice, kIOServicePlane, CFSTR("idProduct"), kCFAllocatorDefault, 0);
         uint16_t PID;
         CFNumberGetValue(idProduct, kCFNumberSInt16Type, (void *)&PID);
         printf("\tidProduct:\t0x%x\n", PID);

         IOObjectRelease(usbDevice);
         CFRelease(idProduct);
      }
   IOObjectRelease(iterator);
 }

What's more, if I unplug one of USB drive, how should I detect that ? Should I add one more

  IOServiceAddMatchingNotification(notificationObject,kIOFirstMatchNotification, matchingDict,isDetached,(__bridge void*)self,&iter );

after isAttached function? Actually I added but it gives me bad access error. Could you guys tell me how to handle these problems? Thanks!!

like image 624
YU FENG Avatar asked Dec 05 '25 15:12

YU FENG


1 Answers

The problem lies with the IOObjectRelease() call in your handler function. You need to hold on to the iterator that you get from the IOServiceAddMatchingNotification for as long as you want to receive these notifications. If you remove the release call, the code works.

As for your second question: the call gives a bad access error, because matchingDict gets released by IOServiceAddMatchingNotification. If you do a CFRetain(matchingDict) before that call, you can add a second Notification using the same matching dictionary. (BTW: you should pass kIOTerminatedNotification instead of kIOFirstMatchNotification if you are interested in device removal notifications.

like image 51
Thorsten Karrer Avatar answered Dec 08 '25 08:12

Thorsten Karrer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!