- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试在 MAC OSX 下发现 USB 大容量存储设备。我希望获得设备类别,并在此基础上确定该设备是否为大容量存储器。但是,对于我拥有的所有 USB 闪存驱动器,我得到的设备类 == 0,这似乎是一个复合设备。请帮我弄清楚,我做错了什么,或者,也许还有什么其他可靠的方法来发现 USB 大容量存储设备(我需要获取 PID、VID 和挂载点)。这是我的代码:
#import <iostream>
#import <IOKit/IOkitLib.h>
#import <IOKit/usb/IOUSBLib.h>
#import <IOKit/IOCFPlugIn.h>
#import <IOKit/usb/USBSpec.h>
#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
CFMutableDictionaryRef matchingDictionary = NULL;
io_iterator_t foundIterator = 0;
io_service_t usbDevice;
matchingDictionary = IOServiceMatching(kIOUSBDeviceClassName);
IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &foundIterator);
for(usbDevice = IOIteratorNext(foundIterator); usbDevice; usbDevice = IOIteratorNext(foundIterator))
{
IOCFPlugInInterface** plugin = NULL;
SInt32 theScore=0;
IOReturn err;
err = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &theScore);
if (err!= 0){
std::cout<<"error, error code: "<<err_get_code(err) <<std::endl;
}
else if (plugin && *plugin)
{
IOUSBDeviceInterface182** usbInterface = NULL;
(*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID182),(LPVOID*)&usbInterface);
(*plugin)->Release(plugin);
if (usbInterface && *usbInterface)
{
UInt8 devClass;
UInt8 devSubClass;
UInt16 productId;
UInt16 vendorID;
//here I'm getting 0 for all my USB flash cards
(*usbInterface)->GetDeviceClass(usbInterface,&devClass);
(*usbInterface)->GetDeviceVendor(usbInterface, &vendorID);
(*usbInterface)->GetDeviceProduct(usbInterface, &productId);
(*usbInterface)->GetDeviceSubClass(usbInterface, &devSubClass);
std::cout<<"device class: "<<+devClass<<std::endl;
std::cout<<"device sub class: "<<+devSubClass<<std::endl;
std::cout<<"vendor ID: "<<vendorID<<std::endl;
std::cout<<"product ID: "<<productId<<std::endl;
}
}
IOObjectRelease(usbDevice);
}
IOObjectRelease(foundIterator);
return 0;
最佳答案
对我来说,以下遍历 USB 的方法适用于 OSX:
void scanUsbMassStorage()
{
CFMutableDictionaryRef matchingDictionary = IOServiceMatching(kIOUSBInterfaceClassName);
//now specify class and subclass to iterate only through USB mass storage devices:
CFNumberRef cfValue;
SInt32 deviceClassNum = kUSBMassStorageInterfaceClass;
cfValue = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &deviceClassNum);
CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBInterfaceClass), cfValue);
CFRelease(cfValue);
SInt32 deviceSubClassNum = kUSBMassStorageSCSISubClass;
cfValue = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &deviceSubClassNum);
CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBInterfaceSubClass), cfValue);
CFRelease(cfValue);
//NOTE: if you will specify only device class and will not specify subclass, it will return an empty iterator,
//and I don't know how to make a query for *any* subclass.
//BUT: all the devices I've checked had kUSBMassStorageSCSISubClass
io_iterator_t foundIterator = 0;
io_service_t usbInterface;
IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &foundIterator);
//iterate through USB mass storage devices
for(usbInterface = IOIteratorNext(foundIterator); usbInterface; usbInterface = IOIteratorNext(foundIterator))
{
CFTypeRef bsdName = IORegistryEntrySearchCFProperty(usbInterface,
kIOServicePlane,
CFSTR(kIOBSDNameKey),
kCFAllocatorDefault,
kIORegistryIterateRecursively);
CFTypeRef serial = IORegistryEntrySearchCFProperty(usbInterface,
kIOServicePlane,
CFSTR(kUsbSerialPropertyName),
kCFAllocatorDefault,
kIORegistryIterateRecursively|kIORegistryIterateParents);
CFTypeRef pid = IORegistryEntrySearchCFProperty(usbInterface,
kIOServicePlane,
CFSTR(kUsbPidPropertyName),
kCFAllocatorDefault,
kIORegistryIterateRecursively|kIORegistryIterateParents);
CFTypeRef vid = IORegistryEntrySearchCFProperty(usbInterface,
kIOServicePlane,
CFSTR(kUsbVidPropertyName),
kCFAllocatorDefault,
kIORegistryIterateRecursively|kIORegistryIterateParents);
//now we can perform checks and casts from CFTypeRef like this:
std::string filePathStr;
std::string serialStr;
uint16_t pidInt;
uint16_t vidInt;
//getMountPathByBSDName - see below
bool stillOk = getMountPathByBSDName(bsdName, filePath);
if (stillOk)
{
stillOk = CFTypeRef2AsciiString(serial, serialStr);
}
if (stillOk)
{
stillOk = CFTypeRef2uint16(pid, pidInt);
}
if (stillOk)
{
stillOk = CFTypeRef2uint16(vid, vidInt);
}
if (stillOK)
{
//can do something with the values here
}
}
不过,从 BSD 名称获取挂载路径对我来说出乎意料地棘手,如果有人知道更好的方法,请分享。这是我的方法。有很多代码,但至少这适用于几个不同的 OSX 版本:
bool getMountPathByBSDName(CFTypeRef bsdName, std::string& dest)
{
std::list<std::string> bsdNames;
//for getChildBsdNames - see below =)
getChildBsdNames(bsdName, bsdNames);
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
if (!session)
{
return false;
}
for (const auto& bsdNameStr : bsdNames)
{
DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, bsdNameStr.c_str());
if (disk)
{
CFDictionaryRef diskInfo = DADiskCopyDescription(disk);
if (diskInfo)
{
char buf[1024];
CFURLRef fspath = (CFURLRef)CFDictionaryGetValue(diskInfo, kDADiskDescriptionVolumePathKey);
if (CFURLGetFileSystemRepresentation(fspath, false, (UInt8 *)buf, 1024))
{
//for now, return the first found partition
dest = std::string(buf);
return true;
}
}
}
}
return false;
}
最后 - getChildBsdNames 函数:
void getChildBsdNames(CFTypeRef bsdName, std::list<std::string>& tgtList)
{
std::string bsdNameStr;
if(!CFTypeRef2AsciiString(bsdName, bsdNameStr))
{
return;
}
CFDictionaryRef matchingDictionary = IOBSDNameMatching(kIOMasterPortDefault, 0, bsdNameStr.c_str());
io_iterator_t it;
IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &it);
io_object_t service;
while ((service = IOIteratorNext(it)))
{
io_iterator_t children;
io_registry_entry_t child;
IORegistryEntryGetChildIterator(service, kIOServicePlane, &children);
while((child = IOIteratorNext(children)))
{
CFTypeRef bsdNameChild = IORegistryEntrySearchCFProperty(child,
kIOServicePlane,
CFSTR (kIOBSDNameKey),
kCFAllocatorDefault,
kIORegistryIterateRecursively);
std::string bsdNameChildStr;
if (CFTypeRef2AsciiString(bsdNameChild, bsdNameChildStr))
{
tgtList.push_back(bsdNameChildStr);
}
}
}
/**
* The device could get name 'disk1s1, or just 'disk1'. In first case, the original bsd name would be
* 'disk1', and the child bsd name would be 'disk1s1'. In second case, there would be no child bsd names,
* but the original one is valid for further work (obtaining various properties).
*/
if (tgtList.empty())
{
tgtList.push_back(bsdNameStr);
}
}
附言有一个基于事件的机制,但由于某些原因对我来说这不是解决方案。我选择了轮询,但修改此代码以使其基于事件并不难。但请注意,该事件可能会在设备安装之前发生。
关于c++ - OSX,USB 海量存储发现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45173124/
“大规模”的微型 ORM 是否有处理继承的方法? robconery / massive 为 Massive 编写提供程序很难吗? 我需要非常接近 SQL Server 的东西。作为第一步,最好拦截
我编写了一个服务器可以使用的应用程序。此应用程序收集信息,并将其发送到服务器。每 10 秒执行一次。数据量取决于玩游戏的玩家,但让我们将其保持在大约 50 个服务器,每个服务器发送 100 条数据(每
我有一个表,其中包含 3 个字段(用户名、目标值、分数),由用户名 (~400,000) 和目标值 (~4000) 的完整交叉在外部生成,并计算出分数,导致总行数约为 16 亿. 我在这个表上的所有查
我们包括了这个 AndroidPdfViewer library支持在应用程序中查看 PDF 报告。它导致 APK 大小从 4.7Mb 大幅增加到 20.1Mb。 有没有办法减小这个尺寸。让我知道在哪
我在脑海中争论是否应该在 MySQL 中使用大量的多维数组或数据库。我正在为一个业务有很多产品的客户开发。在这个多维数组中,我将包括每个产品的产品标题、描述、图片链接和类别。 我的客户可能有 1000
我是一名优秀的程序员,十分优秀!