какао + файл DMG + проследить его путь

У меня есть ситуация, когда мой файл .dmg будет на моем съемном запоминающем устройстве, содержащем мое приложение. когда я дважды щелкаю по нему, он будет смонтирован на моем локальном компьютере, а внутри смонтированного тома будет мой .app (файл приложения). Теперь я хочу, чтобы мое приложение запускалось автоматически после того, как мой dmg-файл смонтирован на моем локальном компьютере. Также теперь моему приложению нужна информация о том, где находится фактический файл dmg, например, о его пути на съемном запоминающем устройстве. Возможно ли это, и если да, то как мне узнать путь к файлу dmg, из которого смонтирован том.

Спасибо


person King    schedule 23.11.2009    source источник
comment
Спасибо GS за код. Однако это не работает. несколько модификаций - это символы протокола: kIOPropertyProtocolCharacteristicsKey. Для меня мое дерево ioreg очень сложное, и у него нет такого родителя, как IODiskImageBlockStorageDeviceOutKernel, и факт заключается в том, что мое устройство хранения отображается над IODiskImageBlockStorageDeviceOutKernel в дереве.   -  person King    schedule 01.12.2009
comment
Итак, используя ваш код, моя служба становится нулевой.   -  person King    schedule 01.12.2009
comment
Можете ли вы куда-нибудь загрузить вывод ioreg (с установленным DMG)?   -  person Georg Schölly    schedule 01.12.2009
comment
Извините за задержку с ответом. На самом деле код, который вы указали, работает, но dmgpath возвращается в вашем коде как null. Подскажите, пожалуйста, где я могу найти правильный ключ для получения пути? Еще раз спасибо за код.   -  person King    schedule 08.12.2009


Ответы (1)


  1. В Mac OS X автоматический запуск приложения невозможен. Есть некоторые соображения безопасности. Единственное, что может быть запущено автоматически, это .pkg файл, и это только через Safari AFAIK.

  2. Можно определить файл DMG, в котором находится приложение. Для этого нужно использовать IOKit. Попробуйте поиграть с IORegistryExplorer.

Код, который может вам помочь

Это мои первые попытки использовать IOKit, он для другой цели, но, тем не менее, должен помочь.

// hopefully all needed headers
#include <sys/stat.h>

#include <IOKit/IOKitLib.h>
#include <IOKit/IOBSD.h>
#include <CoreFoundation/CoreFoundation.h>

/* First we want to get the major and minor BSD number
 * of the DMG that our app is residing on.
 *
 * char *path is the path of a file that resides on the disk image.
 * It is like this: /Volumes/Partition Name/SomeFile
 * The simplest method to get such a path is to ask
 * NSBundle for the path of the executable.
 */

// look up device number with stat
char *path = "path/to/app";

struct stat stats;
if (stat(path, &stats) != 0) {
    return;
}
int bsd_major = major(stats.st_dev);
int bsd_minor = minor(stats.st_dev);

/* Now that we've got the BSD numbers we have to locate the
 * IOService that has those numbers. IOKit works with
 * CoreFoundation types.
 */

CFTypeRef keys[2] = { CFSTR(kIOBSDMajorKey), CFSTR(kIOBSDMinorKey) };
CFTypeRef values[2];
values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &bsd_major);
values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &bsd_minor);

CFDictionaryRef matchingDictionary;
matchingDictionary = CFDictionaryCreate(kCFAllocatorDefault,
                                        &keys, &values,
                                        sizeof(keys) / sizeof(*keys),
                                        &kCFTypeDictionaryKeyCallBacks,
                                        &kCFTypeDictionaryValueCallBacks);

CFRelease(values[0]);
CFRelease(values[1]);
// IOServiceGetMatchingService uses up one reference to the dictionary
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault,
                                                   matchingDictionary);

if (!service) {
    return;
}

/* Now this part is quite different from what I need
 * for my application. I'm not sure how this works
 * because I'm currently not at my Mac and cannot try it.
 * 
 * You need to go up the IOService chain. It looks like this:
  +-o IOHDIXHDDriveOutKernelUserClient
    +-o IODiskImageBlockStorageDeviceOutKernel   <---- You want to get up here
      +-o IOBlockStorageDriver
        +-o Apple UDIF read-only compressed (zlib) Media
          +-o IOMediaBSDClient
          +-o IOApplePartitionScheme
            +-o Apple@1
            | +-o IOMediaBSDClient
            +-o disk image@2               <---- This is the matched IOService!
              +-o IOMediaBSDClient
 *
 * IODiskImage... has a property "Protocol Characteristics" which is a
 * dictionary that has the key "Virtual Interface Location Path" which is  
 * the path to the disk image. There are probably #defines somewhere in
 * IOKit for those keys.
 *
 * This code is NOT tested. It's out of my head and the documentation.
 * This goes up 4 times in the hierarchy. Hopefully there aren't more
 * than 1 parents.
 */

for (int i = 0; i < 4; i++) {
    io_service_t parent;
    IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
    IOObjectRelease(service);
    service = parent;
}

 /* Getting the property from the IOService is the last step:
  */

 CFDictionaryRef characteristics;
 characteristics = (CFDictionaryRef)IORegistryEntryCreateCFProperty(service,
                                          CFSTR("Protocol Characteristics"),
                                          kCFAllocatorDefault, 0)

 CFStringRef *dmgPath = CFDictionaryGetValue(characteristics,
                                    CFSTR("Virtual Interface Location Path"));
 // clean up
 IOObjectRelease(service);
 CFRetain(dmgPath);
 CFRelease(characteristics);

 // Use the path

 // later
 CFRelease(dmgPath);

Многое из этого можно сделать с помощью классов Foundation вместо классов CoreFoundation из-за поддержки бесплатного моста. Это делает его немного проще и разборчивее.

person Georg Schölly    schedule 23.11.2009
comment
Спасибо за ответ. Не могли бы вы подробнее рассказать, где я могу найти хорошие примеры на IOKit, например, книги и прочее. В настоящее время я просматриваю примеры, приведенные в / developer / iokit / examples. Спасибо - person King; 24.11.2009
comment
К сожалению, хороших примеров нет. Я постараюсь включить в ответ свой код. - person Georg Schölly; 24.11.2009
comment
Это было действительно полезно, хотя оказалось, что у меня не работает на Tiger - вызов IORegistryEntryGetParentEntry получает kIOReturnNoDevice. Однако отлично подходит для Snow Leopard. - person invalidname; 16.02.2010
comment
@invalidname: затем просмотрите иерархию с помощью ioreg или соответствующего инструмента с графическим интерфейсом. (Не могу вспомнить название на данный момент, но оно находится в папке инструментов разработчика.) - person Georg Schölly; 17.02.2010
comment
На самом деле я вызвал hdiutil info -plist из NSTask и преобразовал вывод в NSDictionary, по которому я мог затем пройти. Работает на 10.4-6. - person invalidname; 25.02.2010
comment
Этот код действительно помог мне получить io_service_t из пути к тому. Это было необходимо, поскольку FSGetVolumeInfo устарел в Mountain Lion. - person Bryce Kahle; 27.07.2012
comment
CFSTR (Характеристики протокола) = kIOPropertyProtocolCharacteristicsKey в #include ‹IOKit / storage / IOStorageProtocolCharacteristics.h› - person Nathan Moinvaziri; 06.11.2012