2016-12-08 126 views
3

我想這個USB探測器轉換爲斯威夫特3 https://gist.github.com/zachbadgett/471d72e83fee413d0f38如何調用IOCFPlugInInterface.QueryInterface()查詢USB設備

但我被困在這條線:

let deviceInterfaceResult = plugInInterface.QueryInterface(
     plugInInterfacePtrPtr, 
     CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), 
&deviceInterfaceVoidPtr) 

不能調用值(@convention(c) (UnsafeMutableRawPointer?,REFIID,UnsafeMutablePointer?) - > HRESULT)!'

enter image description here

來源QueryInterface

public var QueryInterface: (@convention(c) (UnsafeMutableRawPointer?, REFIID, UnsafeMutablePointer<LPVOID?>?) -> HRESULT)! 

怎樣調用這個函數? Using CFNotificationCallback in Swift, or, @convention(c) blocks in Swift這個答案沒有幫助我。

+0

@JAL'''讓deviceInterfaceResult:HRESULT = {(_:plugInInterfacePtrPtr,_:CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),_:&deviceInterfaceVoidPtr) - >在 HRESULT }()'''不行的 – Arti

回答

3

心教堂的答案是非常接近的一個。 plugInInterface.QueryInterface() 預計,作爲最後一個參數一個 -indirect指針

UnsafeMutablePointer<UnsafeMutablePointer<IOUSBDeviceInterface>?>? 

的地址,而是「僞裝」成一個指針LPVOID?又名UnsafeMutableRawPointer。因此,所獲得的指針必須被解除引用兩次。 withMemoryRebound()可用於此指針強制轉換。

我做了一些修改代碼:

  • 使用defer繼續下一個USB設備即使 當前迭代是「中止」由於一個錯誤。
  • 刪除不必要的類型註釋。使用MemoryLayout<io_name_t>.size代替128
  • 版本usbDevice和使用後的接口指針,以避免內存泄漏。
  • 將一些變量聲明從頂部移到需要的地方。

全部放在一起:

import Foundation 
import IOKit 
import IOKit.usb 
import IOKit.usb.IOUSBLib 

print("Scanning USB Bus.....\n\n\n") 

// 
// These constants are not imported into Swift from IOUSBLib.h as they 
// are all #define constants 
// 

let kIOUSBDeviceUserClientTypeID = CFUUIDGetConstantUUIDWithBytes(kCFAllocatorDefault, 
                    0x9d, 0xc7, 0xb7, 0x80, 0x9e, 0xc0, 0x11, 0xD4, 
                    0xa5, 0x4f, 0x00, 0x0a, 0x27, 0x05, 0x28, 0x61) 

let kIOCFPlugInInterfaceID = CFUUIDGetConstantUUIDWithBytes(kCFAllocatorDefault, 
                  0xC2, 0x44, 0xE8, 0x58, 0x10, 0x9C, 0x11, 0xD4, 
                  0x91, 0xD4, 0x00, 0x50, 0xE4, 0xC6, 0x42, 0x6F) 

let kIOUSBDeviceInterfaceID = CFUUIDGetConstantUUIDWithBytes(kCFAllocatorDefault, 
                  0x5c, 0x81, 0x87, 0xd0, 0x9e, 0xf3, 0x11, 0xD4, 
                  0x8b, 0x45, 0x00, 0x0a, 0x27, 0x05, 0x28, 0x61) 


// Create dictionary with IOUSBDevice as IOProviderClass. 
let matchingDictionary: NSMutableDictionary = IOServiceMatching(kIOUSBDeviceClassName) 

// Get iterator for matching USB devices. 
var usbIterator = io_iterator_t() 
let matchingServicesResult = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &usbIterator) 
if matchingServicesResult != kIOReturnSuccess { 
    print("Error getting deviceList!") 
    exit(EXIT_FAILURE) 
} 

// Iterate devices until usbDevice == 0. 
var usbDevice = IOIteratorNext(usbIterator) 
while usbDevice != 0 { 
    defer { 
     usbDevice = IOIteratorNext(usbIterator) 
    } 

    // io_name_t imports to Swift as a tuple (Int8, ..., Int8) with 128 ints 
    // although in device_types.h it is defined as 
    //  typedef char io_name_t[128]; 
    var deviceNameCString = [CChar](repeating: 0, count: MemoryLayout<io_name_t>.size) 
    let deviceNameResult = IORegistryEntryGetName(usbDevice, &deviceNameCString) 
    if deviceNameResult != kIOReturnSuccess { 
     print("Error getting device name") 
     continue 
    } 
    let deviceName = String(cString: &deviceNameCString) 
    print("USB device name: \(deviceName)") 

    // Get plug-in interface for current USB device 
    var plugInInterfacePtrPtr: UnsafeMutablePointer<UnsafeMutablePointer<IOCFPlugInInterface>?>? 
    var score: Int32 = 0 
    let plugInInterfaceResult = IOCreatePlugInInterfaceForService(
     usbDevice, 
     kIOUSBDeviceUserClientTypeID, 
     kIOCFPlugInInterfaceID, 
     &plugInInterfacePtrPtr, 
     &score) 

    // USB device object is no longer needed. 
    IOObjectRelease(usbDevice) 

    // Dereference pointer for the plug-in interface 
    guard plugInInterfaceResult == kIOReturnSuccess, 
     let plugInInterface = plugInInterfacePtrPtr?.pointee?.pointee else { 
      print("Unable to get Plug-In Interface") 
      continue 
    } 

    // Use plug-in interface to get a device interface. 
    var deviceInterfacePtrPtr: UnsafeMutablePointer<UnsafeMutablePointer<IOUSBDeviceInterface>?>? 
    let deviceInterfaceResult = withUnsafeMutablePointer(to: &deviceInterfacePtrPtr) { 
     $0.withMemoryRebound(to: Optional<LPVOID>.self, capacity: 1) { 
      plugInInterface.QueryInterface(
       plugInInterfacePtrPtr, 
       CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), 
       $0) 
     } 
    } 

    // Plug-in interface is no longer needed. 
    _ = plugInInterface.Release(plugInInterfacePtrPtr) 

    // Dereference pointer for the device interface. 
    guard deviceInterfaceResult == kIOReturnSuccess, 
     let deviceInterface = deviceInterfacePtrPtr?.pointee?.pointee else { 
      print("Unable to get Device Interface") 
      continue 
    } 

    // Use device interface to get vendor ID. 
    var usbVendorID: UInt16 = 0 
    let vendorResult = deviceInterface.GetDeviceVendor(deviceInterfacePtrPtr, &usbVendorID) 

    // Device interface is no longer needed: 
    _ = deviceInterface.Release(deviceInterfacePtrPtr) 

    if vendorResult != kIOReturnSuccess { 
     print("Unable to get device Vendor ID") 
     continue 
    } 

    print("USB Vendor ID: \(usbVendorID)") 
} 

exit(EXIT_SUCCESS) 
+0

將嘗試您的代碼 – Arti

+0

你真棒,謝謝:) – Arti

+0

@Arti:不客氣。我已經編輯了代碼來修復一些內存泄漏。我也冒昧地編輯你的問題標題,'@convention(c)'與這個問題並不相關。 –

2

不知道它是否正確,但是這是用Swift 3和Xcode 8.0構建的。關鍵是編寫var deviceInterfaceVoidPtr: UnsafeMutableRawPointer? = nil

import IOKit 
import IOKit.usb 
import IOKit.usb.IOUSBLib 

print("Scanning USB Bus.....\n\n\n") 

// 
// These constants are not imported into Swift from IOUSBLib.h as they 
// are all #define constants 
// 

let kIOUSBDeviceUserClientTypeID: CFUUID = CFUUIDGetConstantUUIDWithBytes(kCFAllocatorDefault, 
                     0x9d, 0xc7, 0xb7, 0x80, 0x9e, 0xc0, 0x11, 0xD4, 
                     0xa5, 0x4f, 0x00, 0x0a, 0x27, 0x05, 0x28, 0x61) 

let kIOCFPlugInInterfaceID:   CFUUID = CFUUIDGetConstantUUIDWithBytes(kCFAllocatorDefault, 
                     0xC2, 0x44, 0xE8, 0x58, 0x10, 0x9C, 0x11, 0xD4, 
                     0x91, 0xD4, 0x00, 0x50, 0xE4, 0xC6, 0x42, 0x6F) 

let kIOUSBDeviceInterfaceID:  CFUUID = CFUUIDGetConstantUUIDWithBytes(kCFAllocatorDefault, 
                     0x5c, 0x81, 0x87, 0xd0, 0x9e, 0xf3, 0x11, 0xD4, 
                     0x8b, 0x45, 0x00, 0x0a, 0x27, 0x05, 0x28, 0x61) 

var usbIterator: io_iterator_t = io_iterator_t() 
var usbDevice:  io_service_t = io_service_t() 
var usbVendorID: UInt16   = 0 
var score:   Int32   = 0 

func ptrFromAddress<T>(_ p: UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T> { 
    return p 
} 
var myInterface:IOCFPlugInInterface = IOCFPlugInInterface() 
var plugInInterfacePtr: UnsafeMutablePointer<IOCFPlugInInterface>? = ptrFromAddress(&myInterface) 
var plugInInterfacePtrPtr: UnsafeMutablePointer<UnsafeMutablePointer<IOCFPlugInInterface>?>? = ptrFromAddress(&plugInInterfacePtr) 

// From: CFPlugInCOM.h: public typealias LPVOID = UnsafeMutablePointer<Void>() 
var deviceInterfaceVoidPtr: UnsafeMutableRawPointer? = nil 

// create dictionary with IOUSBDevice as IOProviderClass 
let matchingDictionary: NSMutableDictionary = IOServiceMatching(kIOUSBDeviceClassName) 

// get iterator for matching USB devices 
let matchingServicesResult = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &usbIterator) 
if matchingServicesResult != kIOReturnSuccess { 
    print("Error getting deviceList!") 
    exit(EXIT_FAILURE) 
} 

// usbDevice = 0 when finished iterating all devices 
repeat { 
    usbDevice = IOIteratorNext(usbIterator) 
    // io_name_t imports to swift as a tuple (Int8, ..., Int8) 128 ints 
    // although in device_types.h it's defined: 
    // typedef char io_name_t[128]; 
    var deviceNameCString: [CChar] = [CChar](repeating: 0, count: 128) 
    let deviceNameResult = IORegistryEntryGetName(usbDevice, &deviceNameCString) 

    if deviceNameResult != kIOReturnSuccess { 
     print("Error getting device name") 
     exit(EXIT_FAILURE) 
    } 

    let deviceName = String(cString: &deviceNameCString) 
    print("usb Device Name: \(deviceName)") 

    // Get plugInInterface for current USB device 
    let plugInInterfaceResult = IOCreatePlugInInterfaceForService(
     usbDevice, 
     kIOUSBDeviceUserClientTypeID, 
     kIOCFPlugInInterfaceID, 
     &plugInInterfacePtrPtr, 
     &score) 

    if (plugInInterfacePtrPtr == nil) || (plugInInterfaceResult != kIOReturnSuccess) { 
     print("Unable to get Plug-In Interface") 
     continue 
    } 

    // dereference pointer for the plug in interface 
    let plugInInterface: IOCFPlugInInterface = plugInInterfacePtrPtr!.pointee!.pointee 

    // use plug in interface to get a device interface 
    // public var QueryInterface: (@convention(c) (UnsafeMutablePointer<Void>, REFIID, UnsafeMutablePointer<LPVOID>) -> HRESULT)! 

    let deviceInterfaceResult = plugInInterface.QueryInterface(
     plugInInterfacePtrPtr, 
     CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), 
     &deviceInterfaceVoidPtr) 

    if (deviceInterfaceResult != kIOReturnSuccess) || (deviceInterfaceVoidPtr == nil) { 
     print("Unable to get Device Interface") 
     exit(EXIT_FAILURE) 
    } 

    // dereference the IOUSBDeviceInterface struct from pointer var after 
    // converting from a void to a IOUSBDeviceInterface pointer 
    let opaquePtr = OpaquePointer(deviceInterfaceVoidPtr!) 
    let deviceInterface = UnsafeMutablePointer<IOUSBDeviceInterface>(opaquePtr).pointee 

    // get USB Vendor ID --> CRASH 
    let vendorResult = deviceInterface.GetDeviceVendor(deviceInterfaceVoidPtr!, &usbVendorID) 

    if vendorResult != kIOReturnSuccess { 
     print("Unable to get Device Vendor ID") 
     exit(EXIT_FAILURE) 
    } 

    print("usb Vendor ID: \(usbVendorID)") 

    usbDevice = IOIteratorNext(usbIterator) 
} while (usbDevice != 0) 

exit(EXIT_SUCCESS) 

而且,請注意,根據從cellininicholas要點評論, 你應該刪除的兩次出現

usbDevice = IOIteratorNext(usbIterator) 
+0

哦,真遺憾。我忘了導入'IOKit',這就是爲什麼我有很多麻煩。 – Arti

+0

啊,等你重做代碼。謝謝,我會嘗試 – Arti

+0

我碰到這裏:'''//獲取USB供應商ID - > CRASH let vendorResult = deviceInterface.GetDeviceVendor(deviceInterfaceVoidPtr !,&usbVendorID)''' – Arti