In the meantime I have also solved the errors with setting measurement unit and scan area ("Object is nil."). The setting of measurement unit and scan area had to be moved to the callback didSelectFunctionalUnit(). Now the modified code example below works like a charm on both Snow Leopard and Mavericks.
The only quirk remaining is that setting the scan area doesn't seem to have any effect: the resulting image MyScan.png is always a whole page although for testing I even changed the measurement unit to the (for me) more familiar centimeters and a smaller area...
Code: Select all
#ICDeviceLocationTypeMaskLocal     = $00000100
#ICDeviceLocationTypeMaskRemote    = $0000FE00
#ICDeviceTypeMaskScanner           = $00000002
#ICDeviceTypeScanner               = $00000002
ImportC ""
  class_addMethod(Class.i, Selector.i, *Callback, Types.P-ASCII)
  class_createInstance(Class.i, ExtraBytes.i)
  class_addProtocol(Class.i, Protocol.i)
  objc_allocateClassPair(ModelClass.i, NewClassName.P-ASCII, ExtraBytes.i)
  objc_lookUpClass(ClassName.P-ASCII)
  object_setClass(ObjectToModify.i, NewClass.i)
  objc_registerClassPair(NewClass.i)
  objc_getProtocol(ProtocolName.P-ASCII)
  sel_registerName(MethodName.P-ASCII)
EndImport
ImportC "/System/Library/Frameworks/ImageCaptureCore.framework/ImageCaptureCore"
EndImport
ImportC "/System/Library/Frameworks/Quartz.framework/Quartz"
EndImport
Enumeration
  #MainWindow
  #scannerList
  #scanButton
EndEnumeration
Global Dim scanners.i(0)
Global.i delegateClass, activeScanner, selectedScanner, scanning, selectedFunctionalUnit
Procedure scan()
  Debug "initiating scan..."
  scanning = 1
  CocoaMessage(0, activeScanner, "requestScan")   
EndProcedure
ProcedureC deviceDidBecomeReady(object.i, selector.i, device.i)
  Protected FunctionalUnitArray.I
  Protected NumFunctionalUnits.I
  Debug "selected device is ready..."
 
  scanFolder = CocoaMessage(0, 0, "NSURL fileURLWithPath:$", @"/Users/Shardik/Scans/")
  scanFile = CocoaMessage(0, 0, "NSString stringWithString:$", @"MyScan")
 
  ; CocoaMessage(0, device, "requestSelectFunctionalUnit:", 0)   ;0 for flatbed type
  CocoaMessage(0, device, "requestSelectFunctionalUnit:", 3)   ;3 for document feeder type
  CocoaMessage(0, activeScanner, "setTransferMode:", 0)        ;0 for file-mode
  CocoaMessage(0, activeScanner, "setDownloadsDirectory:", scanFolder)
  CocoaMessage(0, activeScanner, "setDocumentName:$", @"MyScan")
  CocoaMessage(0, activeScanner, "setDocumentUTI:$", @"public.png")
  FunctionalUnitArray = CocoaMessage(0, device, "availableFunctionalUnitTypes")
  If FunctionalUnitArray
    NumFunctionalUnits = CocoaMessage(0, FunctionalUnitArray, "count")
    If NumFunctionalUnits
      Debug "Functional unit types:"
      For i = 0 To NumFunctionalUnits - 1
        Select CocoaMessage(0, CocoaMessage(0, FunctionalUnitArray,
          "objectAtIndex:", i), "integerValue")
          Case 0
            Debug "- Flatbed"
          Case 1
            Debug "- Positive transparency"
          Case 2
            Debug "- Negative transparency"
          Case 3
            Debug "- Document feeder"
        EndSelect    
      Next i
    EndIf
  EndIf
EndProcedure
ProcedureC didAddDevice(object.i, selector.i, deviceBrowser.i, addedDevice.i, moreComing.i)
  Debug "device found and added..."
 
  deviceType.i = CocoaMessage(0, addedDevice, "type")   
  deviceName.s = PeekS(CocoaMessage(0, CocoaMessage(0, addedDevice, "name"), "UTF8String"), -1, #PB_UTF8)
 
  If moreComing = #NO And (deviceType & #ICDeviceTypeMaskScanner) = #ICDeviceTypeScanner
    newIndex = ArraySize(scanners()) + 1
    ReDim scanners(newIndex)
    scanners(newIndex) = addedDevice
    AddGadgetItem(#scannerList, -1, deviceName)
    CocoaMessage(0, addedDevice, "setDelegate:",
                 class_createInstance(delegateClass, 0))   ;PureBasic app controls the scanner
  EndIf
EndProcedure
ProcedureC didRemoveDevice(object.i, selector.i, removedDevice.i)
  Debug "device removed"
EndProcedure
ProcedureC didRemoveDeviceInBrowser(object.i, selector.i, deviceBrowser.i, removedDevice.i, moreGoing.i)
  Debug "device removed in browser..."
  CocoaMessage(0, removedDevice, "requestCloseSession")
  CocoaMessage(0, removedDevice, "setDelegate:", 0)
  RemoveGadgetItem(#scannerList, selectedScanner - 1)
  ReDim scanners(ArraySize(scanners()) - 1)
  If activeScanner = removedDevice
    activeScanner = 0
  EndIf
EndProcedure
ProcedureC didOpenSessionWithError(object.i, selector.i, device.i, error.i)
  Debug "session opened... errors: " + Str(error)
EndProcedure
ProcedureC didCloseSessionWithError(object.i, selector.i, device.i, error.i)
  Debug "session closed... errors: " + Str(error)
EndProcedure
ProcedureC didSelectFunctionalUnit(object.i, selector.i, scannerDevice.i, functionalUnit.i, error.i)
  Protected scanArea.NSRect
  If error = 0
    If functionalUnit <> 0
      Debug "functional unit selected: " + functionalUnit
      CocoaMessage(0, functionalUnit, "setMeasurementUnit:", 0)
      Debug "MeasurementUnit set to Inches"
      With scanArea
        \origin\x = 0
        \origin\y = 0
        \size\width = 10
        \size\height = 10
      EndWith
 
      CocoaMessage(0, functionalUnit, "setScanArea:@", @scanArea)
      CocoaMessage(@scanArea, functionalUnit, "scanArea")
      Debug "scanArea set to (" + Str(scanArea\origin\x) + "," +
        Str(scanArea\origin\y) + ")-(" +
        Str(scanArea\origin\x + scanArea\size\width) + "," +
        Str(scanArea\origin\y + scanArea\size\height) + ")"
    EndIf
  Else
    Debug "functional unit selected... errors: " + Str(error)
  EndIf
EndProcedure
ProcedureC didReceiveStatusInformation(object.i, selector.i, device.i, StatusDictionary.i)
  Debug "receiving status info..."
  If StatusDictionary
    Debug PeekS(CocoaMessage(0, CocoaMessage(0, StatusDictionary,
      "valueForKey:$", @"ICLocalizedStatusNotificationKey"), "UTF8String"),
      -1, #PB_UTF8)
  EndIf
EndProcedure
ProcedureC didScanToURL(object.i, selector.i, scannerDevice.i, URL.i, *data) 
  Debug "scanned to " +
    PeekS(CocoaMessage(0, CocoaMessage(0, URL, "absoluteString"), "UTF8String"),
    -1, #PB_UTF8)
  scanning = 0
EndProcedure
ProcedureC didCompleteScanWithError(object.i, selector.i, scannerDevice.i, error.i)
  Debug "scan completed... errors: " + Str(error)
  scanning = 0
EndProcedure
 
ProcedureC didEncounterError(object.i, selector.i, device.i, error.i)
  Debug "encountered error: " + Str(error)
  scanning = 0
EndProcedure
wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
OpenWindow(#MainWindow, 100, 100, 800, 500, "Scanner Application", wFlags)
ListViewGadget(#scannerList, 0, 0, 200, 500)
ButtonGadget(#scanButton, 220, 10, 100, 30, "SCAN")
SetGadgetColor(#scannerList, #PB_Gadget_BackColor, RGB(200, 200, 255))
deviceBrowser = CocoaMessage(0, 0, "ICDeviceBrowser new")
delegateClass = objc_allocateClassPair(objc_lookUpClass("NSObject"), "PB_Delegate", 0)   ;PureBasic app class
class_addMethod(delegateClass,
                sel_registerName("didRemoveDevice:"), @didRemoveDevice(), "v@:@")
class_addMethod(delegateClass,
                sel_registerName("deviceDidBecomeReady:"), @deviceDidBecomeReady(), "v@:@")
class_addMethod(delegateClass,
                sel_registerName("device:didEncounterError:"), @didEncounterError(), "v@:@@")
class_addMethod(delegateClass,
                sel_registerName("device:didOpenSessionWithError:"), @didOpenSessionWithError(), "v@:@@")
class_addMethod(delegateClass,
                sel_registerName("device:didCloseSessionWithError:"), @didCloseSessionWithError(), "v@:@@")
class_addMethod(delegateClass,
                sel_registerName("device:didReceiveStatusInformation:"), @didReceiveStatusInformation(), "v@:@@")
class_addMethod(delegateClass,
                sel_registerName("deviceBrowser:didAddDevice:moreComing:"), @didAddDevice(), "v@:@@@")
class_addMethod(delegateClass,
                sel_registerName("deviceBrowser:didRemoveDevice:moreGoing:"), @didRemoveDeviceInBrowser(), "v@:@@@")
class_addMethod(delegateClass,
                sel_registerName("scannerDevice:didScanToURL:data:"), @didScanToURL(), "v@:@@@")
class_addMethod(delegateClass,
                sel_registerName("scannerDevice:didCompleteScanWithError:"), @didCompleteScanWithError(), "v@:@@")
class_addMethod(delegateClass,
                sel_registerName("scannerDevice:didSelectFunctionalUnit:error:"), @didSelectFunctionalUnit(), "v@:@@@")
objc_registerClassPair(delegateClass)
CocoaMessage(0, deviceBrowser, "setDelegate:", class_createInstance(delegateClass, 0))   ;PureBasic app controls the browser
CocoaMessage(0, deviceBrowser, "setBrowsedDeviceTypeMask:", #ICDeviceLocationTypeMaskLocal |
                                                            #ICDeviceLocationTypeMaskRemote |
                                                            #ICDeviceTypeMaskScanner)
CocoaMessage(0, deviceBrowser, "start")
Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      appQuit = 1
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #scanButton
          scan()
        Case #scannerList
          Select EventType()
            Case #PB_EventType_LeftDoubleClick
              selectedScanner = GetGadgetState(#scannerList) + 1
              activeScanner = scanners(selectedScanner)
              CocoaMessage(0, activeScanner, "requestOpenSession")
          EndSelect
      EndSelect
  EndSelect
Until appQuit = 1
If activeScanner
  CocoaMessage(0, activeScanner, "release")
EndIf
CocoaMessage(0, deviceBrowser, "stop")
; CocoaMessage(0, deviceBrowser, "release")
 
: I have modified the didReceiveStatusInformation() callback to also display the status which is contained in the status dictionary passed as a parameter to this callback.
: I have modified the deviceDidBecomeReady() callback to also display the available functional unit types.
: To prevent an invalid memory access (IMA) when closing the program after the scanner's power button had already been switched off, I have added
at the end of the code example. I have tested this code successfully with PB 5.44 x86 in both ASCII and Unicode mode on MacOS 10.6.8 (Snow Leopard) and with PB 5.44 x86 and x64 in both ASCII and Unicode mode on MacOS 10.7.5 (Lion).