首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >cocoa + dmg文件+回溯其路径

cocoa + dmg文件+回溯其路径
EN

Stack Overflow用户
提问于 2009-11-24 03:36:33
回答 1查看 1.2K关注 0票数 1

我遇到这样一种情况,即我的.dmg文件将存储在包含我的应用程序的可移动存储设备上。当我双击它时,它将被挂载到我的本地计算机上,在挂载的卷中将是我的.app (应用程序文件)。现在,我希望我的应用程序在我的本地计算机上挂载dmg文件后自动启动。另外,现在我的应用程序需要关于实际dmg文件所在位置的信息,比如它在可移动存储设备上的路径。这是可能的吗?如果可能,我如何找到从中挂载卷的dmg文件的路径。

谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2009-11-24 03:53:02

在Mac中,

  1. 不能自动启动应用程序。有一些安全原因。唯一可以自动启动的是.pkg文件,而且只能通过Safari AFAIK。

  1. 可以确定应用程序所在的DMG文件。为此,您必须使用IOKit。试着玩玩IORegistryExplorer.

一些可能对您有帮助的代码

这是我第一次尝试使用IOKit,这是另一个目的,但它应该会有所帮助。

代码语言:javascript
复制
// 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);

由于免费的桥接支持,大部分操作都可以使用基础类而不是CoreFoundation类来完成。这使得它更容易和更易读。

如果IOBlockStorageDriver的父IOService为IODiskImageBlockStorageDeviceOutKernel,则上面的示例代码可以正常工作。如果父IOService的名称是"AppleDiskImageDevice",则IOService链看起来有点不同:

代码语言:javascript
复制
  +-o IOHDIXHDDriveOutKernelUserClient
    +-o AppleDiskImageDevice        <---- You want to get up here
      +-o IOBlockStorageDriver
        +-o Apple Disk Image Media  <---- This is different
          +-o IOMediaBSDClient
          +-o IOApplePartitionScheme
            +-o Apple@1
            | +-o IOMediaBSDClient
            +-o disk image@2        <---- This is the matched IOService!
              +-o IOMediaBSDClient

通过上面的for循环,您可以获得如下所示的图片文件路径URL字符串:

代码语言:javascript
复制
CFMutableDictionaryRef properties = nil;
IORegistryEntryCreateCFProperties(service, &properties, kCFAllocatorDefault, kNilOptions);
if (properties) {
    CFStringRef url = CFDictionaryGetValue(properties, CFSTR("DiskImageURL"));
    CFRelease(properties);
}
IOObjectRelease(service);
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1785439

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档