Sign in to follow this  
Followers 0
GPinzone

PTRobot API DLLs for Primera

6 posts in this topic

#1 ·  Posted (edited)

Primera makes CD/DVD/Bluray disc duplicators. I own one, but I'm not happy with the software I'm forced to use. Unfortunately, most other software products can't recognize or control the robot. (IMGBurn does but it will not send the disc to the printer and it doesn't handle certain error conditions to my satisfaction.)

This AutoIt script requires the Primera API which contains a few DLLs that AutoIt interfaces with. I create a number of AutoIt functions that match the ones in the API, plus a few new ones to help streamline the process. There's no GUI as I designed this to be for the command line. The program gives the commands to load, burn, print, and unload a disc. It implements IMGBurn through a command line interface to do the burning, but you can use any disc burning program you like. (Do NOT turn on support for Primera duplicators in IMGBurn if using this script.) Refer to the Primera API documentation for more info.

I did not provide functions for every possible API feature. However, I included everything you would need for normal disc processing.

This is my largest AutoIt script for me and it was the first time I attempted calls to DLL files.

UPDATED CODE IN POST #3

Gerard J. Pinzone

gpinzone AT yahoo.com

Edited by GPinzone

Gerard J. Pinzonegpinzone AT yahoo.com

Share this post


Link to post
Share on other sites



Nice intro to DLLs! :(

Very cool that Primera supports a usable API, too.

Might have to look into the Pimera as they appear to have more of an open mind.

I have a Rimage burner/printer at work, but that company is openly hostile to anyone wanting to program for it. You will pay (dearly) for their software or get stuffed. I dared to ask one of their tech support reps about drivers for Linux once and he reacted like I had asked him for bomb grade plutonium. This will be our last Rimage.

:graduated:


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Updated code:

#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GuiListBox.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <ListboxConstants.au3>

#include <Array.au3>
#include <INet.au3>
#include <Misc.au3>

If _Singleton("Primera", 1) = 0 Then
    ; We know the script is already running. Let the user know.
    MsgBox(0, "Error: Multiple Copies", "This script is already running. Using multiple copies of this script at the same time is unsupported!")
    Exit
EndIf

Opt('MustDeclareVars', 1)

Global Const $aisEntities[246][2] = [[34, 'quot'],[38, 'amp'],[39, 'apos'],[60, 'lt'],[62, 'gt'],[160, 'nbsp'],[161, 'iexcl'],[162, 'cent'],[163, 'pound'],[164, 'curren'],[165, 'yen'],[166, 'brvbar'],[167, 'sect'],[168, 'uml'],[169, 'copy'],[170, 'ordf'],[171, 'laquo'],[172, 'not'],[173, 'shy'],[174, 'reg'],[175, 'macr'],[176, 'deg'],[177, 'plusmn'],[180, 'acute'],[181, 'micro'],[182, 'para'],[183, 'middot'],[184, 'cedil'],[186, 'ordm'],[187, 'raquo'],[191, 'iquest'],[192, 'Agrave'],[193, 'Aacute'],[194, 'Acirc'],[195, 'Atilde'],[196, 'Auml'],[197, 'Aring'],[198, 'AElig'],[199, 'Ccedil'],[200, 'Egrave'],[201, 'Eacute'],[202, 'Ecirc'],[203, 'Euml'],[204, 'Igrave'],[205, 'Iacute'],[206, 'Icirc'],[207, 'Iuml'],[208, 'ETH'],[209, 'Ntilde'],[210, 'Ograve'],[211, 'Oacute'],[212, 'Ocirc'],[213, 'Otilde'],[214, 'Ouml'],[215, 'times'],[216, 'Oslash'],[217, 'Ugrave'],[218, 'Uacute'],[219, 'Ucirc'],[220, 'Uuml'],[221, 'Yacute'],[222, 'THORN'],[223, 'szlig'],[224, 'agrave'],[225, 'aacute'],[226, 'acirc'],[227, 'atilde'],[228, 'auml'],[229, 'aring'],[230, 'aelig'],[231, 'ccedil'],[232, 'egrave'],[233, 'eacute'],[234, 'ecirc'],[235, 'euml'],[236, 'igrave'],[237, 'iacute'],[238, 'icirc'],[239, 'iuml'],[240, 'eth'],[241, 'ntilde'],[242, 'ograve'],[243, 'oacute'],[244, 'ocirc'],[245, 'otilde'],[246, 'ouml'],[247, 'divide'],[248, 'oslash'],[249, 'ugrave'],[250, 'uacute'],[251, 'ucirc'],[252, 'uuml'],[253, 'yacute'],[254, 'thorn'],[255, 'yuml'],[338, 'OElig'],[339, 'oelig'],[352, 'Scaron'],[353, 'scaron'],[376, 'Yuml'],[402, 'fnof'],[710, 'circ'],[732, 'tilde'],[913, 'Alpha'],[914, 'Beta'],[915, 'Gamma'],[916, 'Delta'],[917, 'Epsilon'],[918, 'Zeta'],[919, 'Eta'],[920, 'Theta'],[921, 'Iota'],[922, 'Kappa'],[923, 'Lambda'],[924, 'Mu'],[925, 'Nu'],[926, 'Xi'],[927, 'Omicron'],[928, 'Pi'],[929, 'Rho'],[931, 'Sigma'],[932, 'Tau'],[933, 'Upsilon'],[934, 'Phi'],[935, 'Chi'],[936, 'Psi'],[937, 'Omega'],[945, 'alpha'],[946, 'beta'],[947, 'gamma'],[948, 'delta'],[949, 'epsilon'],[950, 'zeta'],[951, 'eta'],[952, 'theta'],[953, 'iota'],[954, 'kappa'],[955, 'lambda'],[956, 'mu'],[957, 'nu'],[958, 'xi'],[959, 'omicron'],[960, 'pi'],[961, 'rho'],[962, 'sigmaf'],[963, 'sigma'],[964, 'tau'],[965, 'upsilon'],[966, 'phi'],[967, 'chi'],[968, 'psi'],[969, 'omega'],[977, 'thetasym'],[978, 'upsih'],[982, 'piv'],[8194, 'ensp'],[8195, 'emsp'],[8201, 'thinsp'],[8204, 'zwnj'],[8205, 'zwj'],[8206, 'lrm'],[8207, 'rlm'],[8211, 'ndash'],[8212, 'mdash'],[8216, 'lsquo'],[8217, 'rsquo'],[8218, 'sbquo'],[8220, 'ldquo'],[8221, 'rdquo'],[8222, 'bdquo'],[8224, 'dagger'],[8225, 'Dagger'],[8226, 'bull'],[8230, 'hellip'],[8240, 'permil'],[8242, 'prime'],[8243, 'Prime'],[8249, 'lsaquo'],[8250, 'rsaquo'],[8254, 'oline'],[8260, 'frasl'],[8364, 'euro'],[8465, 'image'],[8472, 'weierp'],[8476, 'real'],[8482, 'trade'],[8501, 'alefsym'],[8592, 'larr'],[8593, 'uarr'],[8594, 'rarr'],[8595, 'darr'],[8596, 'harr'],[8629, 'crarr'],[8656, 'lArr'],[8657, 'uArr'],[8658, 'rArr'],[8659, 'dArr'],[8660, 'hArr'],[8704, 'forall'],[8706, 'part'],[8707, 'exist'],[8709, 'empty'],[8711, 'nabla'],[8712, 'isin'],[8713, 'notin'],[8715, 'ni'],[8719, 'prod'],[8721, 'sum'],[8722, 'minus'],[8727, 'lowast'],[8730, 'radic'],[8733, 'prop'],[8734, 'infin'],[8736, 'ang'],[8743, 'and'],[8744, 'or'],[8745, 'cap'],[8746, 'cup'],[8747, 'int'],[8764, 'sim'],[8773, 'cong'],[8776, 'asymp'],[8800, 'ne'],[8801, 'equiv'],[8804, 'le'],[8805, 'ge'],[8834, 'sub'],[8835, 'sup'],[8836, 'nsub'],[8838, 'sube'],[8839, 'supe'],[8853, 'oplus'],[8855, 'otimes'],[8869, 'perp'],[8901, 'sdot'],[8968, 'lceil'],[8969, 'rceil'],[8970, 'lfloor'],[8971, 'rfloor'],[9001, 'lang'],[9002, 'rang'],[9674, 'loz'],[9824, 'spades'],[9827, 'clubs'],[9829, 'hearts'],[9830, 'diams']]

Global $hPTROBOTDLL = DllOpen("U:\Macros\PTRobot.dll")
Global $RobotType
Global $RobotAddress
Global $NumRobots
Global $DriveAddress[10]
Global $NumDrives
Global $NumPrinters
Global $NumBins
Global $SystemState
Global $SystemError
Global $NumDiscsProcessed = 0
Global $DriveLetter[10]
Global $NumSets = 1
Global $NoDocDisc = False

Global $Form_Status = GUICreate("IMGBurn AutoIt Script", 614, 163, 193, 124, BitOR($GUI_SS_DEFAULT_GUI, $WS_SIZEBOX, $WS_THICKFRAME))
Global $Label_Status = GUICtrlCreateLabel("", 16, 104, 580, 50, BitOR($SS_NOPREFIX, $SS_SUNKEN, $WS_BORDER))
Global $Label_Status_Title = GUICtrlCreateLabel("Status:", 16, 80, 37, 17, $SS_NOPREFIX)
Global $Label_NumSets_Title = GUICtrlCreateLabel("Total Number of Sets:", 424, 8, 107, 17, $SS_NOPREFIX)
Global $Label_NumSets = GUICtrlCreateLabel($NumSets, 568, 8, 26, 17, $SS_NOPREFIX)
Global $Label_Set_Title = GUICtrlCreateLabel("Current Set:", 424, 32, 60, 17, $SS_NOPREFIX)
Global $Label_Set = GUICtrlCreateLabel("1", 568, 32, 26, 17, $SS_NOPREFIX)
Global $Label_Title = GUICtrlCreateLabel("", 16, 24, 392, 17, $SS_NOPREFIX)
Global $Label_Job_Title = GUICtrlCreateLabel("Job:", 16, 8, 24, 17)
Global $Label_DiscsProcessed_Title = GUICtrlCreateLabel("Number of discs processed:", 424, 80, 135, 17, $SS_NOPREFIX)
Global $Label_DiscsProcessed = GUICtrlCreateLabel($NumDiscsProcessed, 568, 80, 26, 17)
Global $Label_Disc_Title = GUICtrlCreateLabel("Disc:", 424, 56, 28, 17, $SS_NOPREFIX)
Global $Label_Disc = GUICtrlCreateLabel("1", 456, 56, 28, 17, BitOR($SS_CENTER, $SS_NOPREFIX))
Global $Label_NumDiscss_Title = GUICtrlCreateLabel("of", 488, 56, 21, 17, BitOR($SS_CENTER, $SS_NOPREFIX))
Global $Label_NumDiscs = GUICtrlCreateLabel("", 512, 56, 39, 17, BitOR($SS_CENTER, $SS_NOPREFIX))

Global Const $MAX_NUMSETS = 50

Global Const $LOCATION_AUTO = 0
Global Const $LOCATION_RIGHT = 1
Global Const $LOCATION_LEFT = 2
Global Const $LOCATION_PRINTER = 100
Global Const $LOCATION_REJECT = 200

Global Const $CLEARDRIVE_NO = 0
Global Const $CLEARDRIVE_YES = 1

Global Const $DRIVE_OPEN = 0
Global Const $DRIVE_CLOSE = 1

; SET OUTPUT BINS HERE
Global Const $CD_BIN_INPUT = $LOCATION_LEFT
Global Const $DVD_BIN_INPUT = $LOCATION_RIGHT
Global Const $BIN_OUTPUT = $LOCATION_REJECT

Global Const $PQ_LOW = 0
Global Const $PQ_MED = 1
Global Const $PQ_BETTER = 2
Global Const $PQ_HIGH = 3
Global Const $PQ_BEST = 4

Global Const $PTACT_ALIGNPRINTER = 0x00000001
Global Const $PTACT_IGNOREINKLOW = 0x00000002
Global Const $PTACT_DISABLEPWRBUTTON = 0x00000004
Global Const $PTACT_REINIT_DRIVES = 0x00000008
Global Const $PTACT_IDENTIFY = 0x00000010
Global Const $PTACT_CANCELCMD = 0x00000020
Global Const $PTACT_ENABLEPWRBUTTON = 0x00000040
Global Const $PTACT_RESETSYSTEM = 0x00000080
Global Const $PTACT_CHECKDISCS = 0x00000100 ; Check number of discs in bins
Global Const $PTACT_CLEANCARTRIDGES = 0x00000200 ; Clean the cartridges
Global Const $PTACT_CALIBRATE_ONE_DISC = 0x00000400 ; SE, II, Pro: Calibrate for one disc (user must put one disc in each bin).
Global Const $PTACT_CHANGE_CARTRIDGE = 0x00000800 ; SE, II, Pro: Start the cartridge change procedure
Global Const $PTACT_END_CARTRIDGE_CHANGE = 0x00001000 ; SE: End the cartridge change (can close lid also)
Global Const $PTACT_SHIP_POSITION = 0x00002000 ; SE, II, Pro: Move the picker to the shipping position
Global Const $PTACT_RESET_LEFT_INK_LEVELS = 0x00004000 ; II: Clears the ink spits for the LEFT cartridge
Global Const $PTACT_RESET_RIGHT_INK_LEVELS = 0x00008000 ; II: Clears the ink spits for the RIGHT cartridge
Global Const $PTACT_ALLOW_NO_CARTRIDGES = 0x00010000 ; SE, II, Pro: Allows unit to operate non-printing robotics without a cartridge
Global Const $PTACT_XI_LIGHT_OFF = 0x00020000
Global Const $PTACT_XI_LIGHT_ON = 0x00040000
Global Const $PTACT_XI_LIGHT_FLASH = 0x00080000
Global Const $PTACT_UNHOOK_PICKER = 0x00100000
Global Const $PTACT_AUTOPRINTER_MODE = 0x00200000 ; DP4100: can perform a faster multiple copy print-only job by calling PTRobot_SetPrintCopies() prior to calling the print function (e.g. PTRobot_PrintFile()).
Global Const $PTACT_FAN_ON = 0x00400000 ; DP4100: turn on system fan
Global Const $PTACT_FAN_OFF = 0x00800000 ; DP4100: turn off system fan

Global Const $SYSERR_PTR_TRAY = 1
Global Const $SYSERR_CART_CODE = 2
Global Const $SYSERR_INPUT_EMPTY = 3
Global Const $SYSERR_PTR_COMM = 4
Global Const $SYSERR_CLR_EMPTY = 5
Global Const $SYSERR_BLK_EMPTY = 6
Global Const $SYSERR_BOTH_EMPTY = 7
Global Const $SYSERR_PICK = 8
Global Const $SYSERR_ARM_MOVE = 9
Global Const $SYSERR_CART_MOVE = 10
Global Const $SYSERR_INTERNAL_SW = 12
Global Const $SYSERR_NO_ROBODRIVES = 13
Global Const $SYSERR_OFFLINE = 14
Global Const $SYSERR_COVER_OPEN = 15
Global Const $SYSERR_PRINTER_PICK = 16
Global Const $SYSERR_MULTIPLE_PICK = 17
Global Const $SYSERR_MULTIPLEDISCS_IN_PRINTER = 18
Global Const $SYSERR_MULTIPLEDISCS_IN_RECORDER = 19
Global Const $SYSERR_DROPPED_DISC_RECORDER = 20
Global Const $SYSERR_DROPPED_DISC_BIN1 = 28
Global Const $SYSERR_DROPPED_DISC_BIN2 = 29
Global Const $SYSERR_DROPPED_DISC_PRINTER = 33
Global Const $SYSERR_DROPPED_DISC_REJECT = 34
Global Const $SYSERR_DROPPED_DISC_UNKNOWN = 35
Global Const $SYSERR_ALIGNNEEDED = 36
Global Const $SYSERR_COLOR_INVALID = 37
Global Const $SYSERR_BLACK_INVALID = 38
Global Const $SYSERR_BOTH_INVALID = 39
Global Const $SYSERR_NOCARTS = 40
Global Const $SYSERR_K_IN_CMY = 41
Global Const $SYSERR_CMY_IN_K = 42
Global Const $SYSERR_SWAPPED = 43
Global Const $SYSERR_PIGONPRO = 44
Global Const $SYSERR_ALIGNFAILED = 45
Global Const $SYSERR_DROPPED_DISC_PRINTER_FATAL = 46
Global Const $SYSERR_MULTIPLEDISCS_IN_RIGHTBIN = 47
Global Const $SYSERR_MULTIPLEDISCS_IN_LEFTBIN = 48
Global Const $SYSERR_CLR_EMPTY_FINAL = 49
Global Const $SYSERR_BLK_EMPTY_FINAL = 50
Global Const $SYSERR_BOTH_EMPTY_FINAL = 51
Global Const $SYSERR_WAITING_FOR_PRINTER = 52
Global Const $SYSERR_NO_DISC_IN_PRINTER = 53
Global Const $SYSERR_BUSY = 54
Global Const $SYSERR_PURGE = 55
Global Const $SYSERR_DOCK_SENSOR = 56
Global Const $SYSERR_ALREADY_PRINTED = 57
Global Const $SYSERR_UNKNOWN_HARDWARE = 58

Global Const $SYSSTATE_IDLE = 0
Global Const $SYSSTATE_BUSY = 1
Global Const $SYSSTATE_ERROR = 2

Global Const $ROBOT_DISCPUBLISHER = 0 ; Disc Publisher I
Global Const $ROBOT_DISCPUBLISHERII = 1 ; Disc Publisher II
Global Const $ROBOT_DISCPUBLISHERPRO = 2 ; Disc Publisher PRO
Global Const $ROBOT_COMPOSERMAX = 3 ; ComposerMAX
Global Const $ROBOT_RACKMOUNT_DPII = 4 ; Disc Publisher XR
Global Const $ROBOT_DISCPUBLISHER_XRP = 5 ; Disc Publisher XRP
Global Const $ROBOT_DISCPUBLISHER_SE = 6 ; Disc Publisher SE
Global Const $ROBOT_DISCPUBLISHERPRO_XI = 7 ; Disc Publisher Xi Series
Global Const $ROBOT_DISCPUBLISHER_4100 = 8 ; Disc Publisher 4100 Series

Global Const $PTROBOT_FEATURE_NOT_IMPLEMENTED = 520

Global Const $CUSTOM_FILE_NOT_FOUND = 901
Global Const $CUSTOM_FILE_FORMAT_WRONG = 902
Global Const $CUSTOM_INVALID_DRIVE_LETTER = 903

Func processJobs($Title, $Queue)

    Local $TimeStamp, $DupeTime, $DiscSet
    Local $QueueSize = UBound($Queue, 1)

    ; Store the time the process begins
    $TimeStamp = TimerInit()

    ; Exit script if ImgBurn is already running
    If ProcessExists("ImgBurn.exe") Then
        MsgBox(0, "IMGBurn AutoIt Script", "ImgBurn is already running.")
        Exit
    EndIf

    ; Configure GUI
    GUICtrlSetData($Label_Title, $Title)
    GUICtrlSetData($Label_NumSets, $NumSets)
    GUICtrlSetData($Label_NumDiscs, $QueueSize)

    GUISetState(@SW_SHOW, $Form_Status)

    ; Disable Screen Saver
    disableScreenSaver()

    PTRobot_Initialize()
    PTRobot_EnumRobots()
    PTRobot_EnumDrives()
    PTRobot_GetRobotInfo()

    ; Repeat process for each set of discs
    For $DiscSet = 1 To $NumSets

        ; Process the Queue
        PTRobot_ProcessQueue($Queue)
        ; Update GUI
        GUICtrlSetData($Label_Set, $DiscSet)

    Next

    PTRobot_Destroy()

    ; Enable Screen Saver
    enableScreenSaver()

    ; Calculate how long the process took
    $DupeTime = CalcDupeTime(TimerDiff($TimeStamp))

    sendEmail($Title, $Queue, $NumSets, $DupeTime)

EndFunc   ;==>processJobs

Func getNumSets()

    Local $nNumSets

    ; Check command line
    If $CmdLine[0] > 0 Then
        If $CmdLine[1] < 1 Or $CmdLine[1] > $MAX_NUMSETS Then
            MsgBox(0, "IMGBurn AutoIt Script", "Number of jobs must be between 1 and " & $MAX_NUMSETS & ".")
            Exit
        Else
            $nNumSets = $CmdLine[1]
        EndIf
    Else
        ; Return -1 if no command line argument given
        $nNumSets = -1
    EndIf

    Return $nNumSets

EndFunc   ;==>getNumSets

Func PTRobot_ProcessQueue($Queue)
    Local $QueueSize = UBound($Queue, 1)
    Local $Disc, $SourceBin
    Local $MissingFiles, $WrongFileFormat
    Local $result
    Local Const $LABEL_COL = 0 ; Array column used for disc labels.
    Local Const $IMAGE_COL = 1 ; Array column used for disc image files.

    ; Verify files exist.
    For $Disc = 0 To $QueueSize - 1
        If Not $Queue[$Disc][$LABEL_COL] = "" Then
            If Not FileExists($Queue[$Disc][$LABEL_COL]) Then
                $MissingFiles = $MissingFiles & $Queue[$Disc][$LABEL_COL] & @CRLF
            ElseIf Not _ValidateImageFile($Queue[$Disc][$LABEL_COL]) Then
                $WrongFileFormat = $WrongFileFormat & $Queue[$Disc][$LABEL_COL] & @CRLF
            EndIf
        EndIf
        If Not FileExists($Queue[$Disc][$IMAGE_COL]) Then
            $MissingFiles = $MissingFiles & $Queue[$Disc][$IMAGE_COL] & @CRLF
        EndIf
    Next

    If Not $MissingFiles = "" Then
        MsgBox(48, "Queue Error", "Files not found:" & @CRLF & $MissingFiles)
        PTRobot_Destroy()
        Exit ($CUSTOM_FILE_NOT_FOUND)
    EndIf

    If Not $WrongFileFormat = "" Then
        MsgBox(48, "Queue Error", "File format incorrect:" & @CRLF & $WrongFileFormat)
        PTRobot_Destroy()
        Exit ($CUSTOM_FILE_FORMAT_WRONG)
    EndIf

    PTRobot_Wait()

    For $Disc = 0 To $QueueSize - 1

        If StringInStr($Queue[$Disc][$LABEL_COL], "DVD", 1) Or StringInStr($Queue[$Disc][$IMAGE_COL], "DVD", 1) Then
            $SourceBin = $DVD_BIN_INPUT
        Else
            $SourceBin = $CD_BIN_INPUT
        EndIf

        GUICtrlSetData($Label_Disc, $Disc + 1) ; Update GUI

        WriteStatus("Loading drive..." & @CRLF)
        If $NumDiscsProcessed < $NumDrives Then ; First disc load in drive should check for disc in burner.
            PTRobot_LoadDrive(Mod($NumDiscsProcessed, $NumDrives), $SourceBin, $CLEARDRIVE_YES) ; Load first disc from source bin.
        Else
            PTRobot_LoadDrive(Mod($NumDiscsProcessed, $NumDrives), $SourceBin, $CLEARDRIVE_NO) ; Load subsequent disc from source bin.
        EndIf

        PTRobot_Wait()

        WriteStatus("Starting disc writer..." & @CRLF)
        $result = PTRobot_BurnImage(Mod($NumDiscsProcessed, $NumDrives), $Queue[$Disc][$IMAGE_COL]) ; Burn image file to disc.

        ; If disc was aborted, skip to next disc.
        If $result = 1 Then
            WriteStatus("Skipping " & $Queue[$Disc][$IMAGE_COL] & "..." & @CRLF)
            $NumDiscsProcessed = $NumDiscsProcessed + 1 ; Increment global counter.
            GUICtrlSetData($Label_DiscsProcessed, $NumDiscsProcessed)

            ContinueLoop
        EndIf

        PTRobot_Wait()

        If $Queue[$Disc][$LABEL_COL] = "" Or $NumPrinters < 1 Then
            WriteStatus("Unloading drive..." & @CRLF)
            PTRobot_UnLoadDrive(Mod($NumDiscsProcessed, $NumDrives), $BIN_OUTPUT) ; Unload disc to output bin.
        Else
            ; Check if burn was ignored.
            If $result = 2 Then
                $result = MsgBox(36, "Print...", "Print disc?" & @CRLF)
                ; No
                If $result = 7 Then
                    PTRobot_UnLoadDrive(Mod($NumDiscsProcessed, $NumDrives), $BIN_OUTPUT) ; Unload disc to output bin.
                    PTRobot_Wait()
                    $NumDiscsProcessed = $NumDiscsProcessed + 1 ; Increment global counter.
                    GUICtrlSetData($Label_DiscsProcessed, $NumDiscsProcessed)
                    ContinueLoop
                EndIf
            EndIf

            WriteStatus("Loading printer..." & @CRLF)
            PTRobot_LoadPrinterFromDrive(Mod($NumDiscsProcessed, $NumDrives)) ; Send disc to printer.

            PTRobot_Wait()

            WriteStatus("Printing label..." & @CRLF)
            PTRobot_PrintFile($Queue[$Disc][$LABEL_COL]) ; Print label.

            PTRobot_Wait()

            WriteStatus("Unloading printer..." & @CRLF)
            PTRobot_UnLoadPrinter($BIN_OUTPUT) ; Unload disc to output bin.
        EndIf

        $NumDiscsProcessed = $NumDiscsProcessed + 1 ; Increment global counter.
        GUICtrlSetData($Label_DiscsProcessed, $NumDiscsProcessed)

        PTRobot_Wait()
    Next
EndFunc   ;==>PTRobot_ProcessQueue

Func PTRobot_BurnImage($num, $Filename)
    Local $ErrorLevel
    Local $result = 0

    While 1 ; Infinte loop for "Retry" on failure.
        $ErrorLevel = RunWait('"C:\Program Files (x86)\ImgBurn\ImgBurn.exe" /MODE WRITE /SRC "' & $Filename & '" /DEST ' & $DriveLetter[$num] & ': /COPIES 1 /VERIFY NO /SPEED AUTO /TESTMODE NO /DELETEIMAGE NO /EJECT YES /WAITFORMEDIA /START /CLOSE /NOSAVESETTINGS')

        If $ErrorLevel Then
            PTRobot_OpenCloseDrive($num, $DRIVE_OPEN)
            WriteStatusError("Error: Disc write failed! - Exit Code: " & $ErrorLevel & @CRLF)
            WriteStatusError("Error: " & $Filename & " not successfully written!" & @CRLF)
            $result = MsgBox(50, "Burn Error", "Disc write failed!" & @CRLF & "Exit Code: " & $ErrorLevel)
            ; Abort
            If $result = 3 Then
                WriteStatus("Rejecting disc..." & @CRLF)
                PTRobot_UnLoadDrive($num, $LOCATION_REJECT) ; Send to reject pile.
                $result = MsgBox(36, "Burn Error", "Close program?" & @CRLF)
                PTRobot_Wait()
                ; Yes
                If $result = 6 Then
                    PTRobot_Destroy()
                    Exit ($ErrorLevel)
                    ; No
                Else
                    $result = 1 ; Return value for aborted error.
                    ExitLoop
                EndIf
                ; Retry
            ElseIf $result = 4 Then
                PTRobot_OpenCloseDrive($num, $DRIVE_CLOSE)
                ; Ignore
            ElseIf $result = 5 Then
                $result = 2 ; Return value for ignored error.
                ExitLoop
            EndIf
            ; Success
        Else
            WriteStatus("File: " & $Filename & " successfully written." & @CRLF)
            ExitLoop
        EndIf
    WEnd

    Return $result
EndFunc   ;==>PTRobot_BurnImage

Func PTRobot_Wait()
    Local $ErrorMsg

    Sleep(1000)
    While Not PTRobot_GetRobotStatus()
        If $SystemError Then
            PTRobot_ErrorMsgBox($SystemError)
        ElseIf Not $SystemState Then
            ExitLoop
        Else
            Sleep(1000)
        EndIf
    WEnd

    Sleep(1000)
    While Not PTRobot_GetRobotStatus()
        If $SystemError Then
            If $SystemError = $SYSERR_CLR_EMPTY Then
                $ErrorMsg = "WARNING:  The color cartridge is LOW on ink."
                WriteStatusError("Error: " & $ErrorMsg & @CRLF)
                PTRobot_KillSystemError(0)
                Sleep(1000)
            ElseIf $SystemError = $SYSERR_BLK_EMPTY Then
                $ErrorMsg = "WARNING:  The black cartridge is LOW on ink."
                WriteStatusError("Error: " & $ErrorMsg & @CRLF)
                PTRobot_KillSystemError(0)
                Sleep(1000)
            ElseIf $SystemError = $SYSERR_BOTH_EMPTY Then
                $ErrorMsg = "WARNING:  Both ink cartridges are LOW on ink."
                WriteStatusError("Error: " & $ErrorMsg & @CRLF)
                PTRobot_KillSystemError(0)
                Sleep(1000)
            Else
                PTRobot_ErrorMsgBox($SystemError)
            EndIf
        ElseIf Not $SystemState Then
            ExitLoop
        Else
            Sleep(1000)
        EndIf
    WEnd




EndFunc   ;==>PTRobot_Wait

Func PTRobot_GetErrorString()
    Local $result
    Local $err = @error

    Local $dwErrorNum
    Local $wszErrorString
    Local $dwMaxLength
    Local $dwLanguage

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_GetErrorString", "hwnd", $RobotAddress, "dword", $dwErrorNum, "wstr", $wszErrorString, "dword", $dwMaxLength, "dword", $dwLanguage)

    $dwErrorNum = $result[2]
    $wszErrorString = $result[3]
    $dwMaxLength = $result[4]
    $dwLanguage = $result[5]

    MsgBox(0, "", "Status: " & $result[0] & @CRLF & _
            "System Number Error: " & $dwErrorNum & @CRLF & _
            "Error String: " & $wszErrorString & @CRLF & _
            "Max Length: " & $dwMaxLength & @CRLF & _
            "Language: " & $dwLanguage)

    Return $result[0]
EndFunc   ;==>PTRobot_GetErrorString

Func PTRobot_Initialize()
    Local $result
    Local $err = @error

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_Initialize")

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf

EndFunc   ;==>PTRobot_Initialize

Func PTRobot_Destroy()
    Local $result
    Local $err = @error

    PTRobot_Wait()
    DllCall($hPTROBOTDLL, "int", "PTRobot_SystemAction", "hwnd", $RobotAddress, "dword", $PTACT_XI_LIGHT_OFF)
    PTRobot_Wait()

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_Destroy")

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        Exit ($result[0])
    EndIf

EndFunc   ;==>PTRobot_Destroy

Func PTRobot_EnumRobots()
    Local $result
    Local $err = @error

    Local $hRobots = DllStructCreate("hwnd[10]")
    Local $dwNumRobots = DllStructCreate("dword")
    DllStructSetData($dwNumRobots, 1, 10) ; Set input to be the size of the array

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_EnumRobots", "ptr", DllStructGetPtr($hRobots), "ptr", DllStructGetPtr($dwNumRobots))

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf

    ; Set Global Variables
    $RobotAddress = DllStructGetData($hRobots, 1, 1)
    $NumRobots = DllStructGetData($dwNumRobots, 1)
EndFunc   ;==>PTRobot_EnumRobots

Func PTRobot_EnumDrives()
    Local $result
    Local $err = @error

    Local $hDrives = DllStructCreate("hwnd[10]")
    Local $dwNumDrives = DllStructCreate("dword")
    DllStructSetData($dwNumDrives, 1, 10) ; Set input to be the size of the array

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_EnumDrives", "hwnd", $RobotAddress, "ptr", DllStructGetPtr($hDrives), "ptr", DllStructGetPtr($dwNumDrives))

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf

    ; Set Global Variables
    $NumDrives = DllStructGetData($dwNumDrives, 1)
    ReDim $DriveAddress[$NumDrives]
    ReDim $DriveLetter[$NumDrives]
    For $i = 0 To $NumDrives - 1
        $DriveAddress[$i] = DllStructGetData($hDrives, 1, $i + 1)
        $DriveLetter[$i] = Chr(Dec(StringRight($DriveAddress[$i], 2)))
        ;MsgBox(0, "Debug", "Drive " & $i & ": " & $DriveLetter[$i])
        If Not StringRegExp($DriveLetter[$i], "^[A-Z]$") Then
            PTRobot_ErrorMsgBox($CUSTOM_INVALID_DRIVE_LETTER)
            PTRobot_Destroy()
            Exit ($CUSTOM_INVALID_DRIVE_LETTER)
        EndIf
    Next

EndFunc   ;==>PTRobot_EnumDrives

Func PTRobot_GetRobotStatus()
    Local $result
    Local $err = @error

    Local $dRobotStatus = DllStructCreate("dword dwSystemState;dword dwSystemError;dword dwCurrColorSpits;dword dwCurrBlackSpits;dword dwFullColorSpits;dword dwFullBlackSpits")

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_GetRobotStatus", "hwnd", $RobotAddress, "ptr", DllStructGetPtr($dRobotStatus))

    ;MsgBox(0, "", "Status: "         & $result[0]                                          & @CRLF & _
    ;              "System State: "   & DllStructGetData($dRobotStatus, "dwSystemState")    & @CRLF & _
    ;              "System Error: "   & DllStructGetData($dRobotStatus, "dwSystemError")    & @CRLF & _
    ;              "CurrColorSpits: " & DllStructGetData($dRobotStatus, "dwCurrColorSpits") & @CRLF & _
    ;              "CurrBlackSpits: " & DllStructGetData($dRobotStatus, "dwCurrBlackSpits") & @CRLF & _
    ;              "FullColorSpits: " & DllStructGetData($dRobotStatus, "dwFullColorSpits") & @CRLF & _
    ;              "FullBlackSpits: " & DllStructGetData($dRobotStatus, "dwFullBlackSpits"));

    ; Set Global Variables
    $SystemState = DllStructGetData($dRobotStatus, "dwSystemState")
    $SystemError = DllStructGetData($dRobotStatus, "dwSystemError")

    Return $result[0]
EndFunc   ;==>PTRobot_GetRobotStatus

Func PTRobot_GetRobotInfo()
    Local $result
    Local $err = @error

    Local $dRobotInfo = DllStructCreate("hwnd hRobot;char tszRobotDesc[100];dword dwRobotType;dword dwNumDrives;dword dwNumPrinters;dword dwNumBins;dword dwDriveColumns;dword dwDriveRows;char tszRobotFirmware[20];dword dwOptions;dword dwAction;hwnd hDrives[10];dword dwDriveBusType")

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_GetRobotInfo", "hwnd", $RobotAddress, "ptr", DllStructGetPtr($dRobotInfo))

    ;MsgBox(0, "", "Status: "                  & $result[0]                                        & @CRLF & _
    ;              "Robot: "                   & DllStructGetData($dRobotInfo, "hRobot")           & @CRLF & _
    ;              "Robot Type: "              & DllStructGetData($dRobotInfo, "tszRobotDesc")     & @CRLF & _
    ;              "Number of Drives: "        & DllStructGetData($dRobotInfo, "dwNumDrives")      & @CRLF & _
    ;              "Number of Printers: "      & DllStructGetData($dRobotInfo, "dwNumPrinters")    & @CRLF & _
    ;              "Number of Bins: "          & DllStructGetData($dRobotInfo, "dwNumBins")        & @CRLF & _
    ;              "Number of Drive Columns: " & DllStructGetData($dRobotInfo, "dwDriveColumns")   & @CRLF & _
    ;              "Number of Drive Rows: "    & DllStructGetData($dRobotInfo, "dwDriveRows")      & @CRLF & _
    ;              "Robot FW Version: "        & DllStructGetData($dRobotInfo, "tszRobotFirmware") & @CRLF & _
    ;              "Robot Options: "           & DllStructGetData($dRobotInfo, "dwOptions")        & @CRLF & _
    ;              "Robot Actions: "           & DllStructGetData($dRobotInfo, "dwAction")         & @CRLF & _
    ;              "Drive Bus Type: "          & DllStructGetData($dRobotInfo, "dwDriveBusType"))

    $RobotType = DllStructGetData($dRobotInfo, "tszRobotDesc")
    $NumDrives = DllStructGetData($dRobotInfo, "dwNumDrives")
    $NumPrinters = DllStructGetData($dRobotInfo, "dwNumPrinters")
    $NumBins = DllStructGetData($dRobotInfo, "dwNumBins")

    Return $result[0]
EndFunc   ;==>PTRobot_GetRobotInfo

Func PTRobot_GetDriveInfo($num)
    Local $result
    Local $err = @error

    Local $dDrvInfo = DllStructCreate("hwnd hDrive;char tszDriveName[132];char tszFirmwareVer[40];char tszSerialNum[40];hwnd hRobot;dword dwDriveColumn;dword dwDriveRow")

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_GetDriveInfo", "hwnd", $DriveAddress[$num], "ptr", DllStructGetPtr($dDrvInfo))

    ;MsgBox(0, "", "Status: "           & $result[0] & @CRLF & _
    ;              "Drive: "            & DllStructGetData($dDrvInfo, "hDrive")         & @CRLF & _
    ;              "Drive Name: "       & DllStructGetData($dDrvInfo, "tszDriveName")   & @CRLF & _
    ;              "Firmware Version: " & DllStructGetData($dDrvInfo, "tszFirmwareVer") & @CRLF & _
    ;              "Serial Number: "    & DllStructGetData($dDrvInfo, "tszSerialNum")   & @CRLF & _
    ;              "Robot: "            & DllStructGetData($dDrvInfo, "hRobot")         & @CRLF & _
    ;              "Drive Column: "     & DllStructGetData($dDrvInfo, "dwDriveColumn")  & @CRLF & _
    ;              "Drive Row: "        & DllStructGetData($dDrvInfo, "dwDriveRow"))

    Return $result[0]
EndFunc   ;==>PTRobot_GetDriveInfo

Func PTRobot_LoadDrive($num, $dwFromLocation, $dwFirstDiscLoad)
    Local $result
    Local $err = @error

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_LoadDrive", "hwnd", $RobotAddress, "hwnd", $DriveAddress[$num], "dword", $dwFromLocation, "dword", $dwFirstDiscLoad)

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf
EndFunc   ;==>PTRobot_LoadDrive

Func PTRobot_LoadPrinter($dwFromLocation)
    Local $result
    Local $err = @error

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_LoadPrinter", "hwnd", $RobotAddress, "dword", $dwFromLocation)

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf
EndFunc   ;==>PTRobot_LoadPrinter

Func PTRobot_LoadPrinterFromDrive($num)
    Local $result
    Local $err = @error

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_LoadPrinterFromDrive", "hwnd", $RobotAddress, "hwnd", $DriveAddress[$num])

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf
EndFunc   ;==>PTRobot_LoadPrinterFromDrive

Func PTRobot_PrintFile($strFilename)
    Local $result
    Local $err = @error

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_PrintFile", "hwnd", $RobotAddress, "str", $strFilename, "dword", 0)

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit
    EndIf
EndFunc   ;==>PTRobot_PrintFile

Func PTRobot_UnLoadPrinter($dwToLocation)
    Local $result
    Local $err = @error

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_UnLoadPrinter", "hwnd", $RobotAddress, "dword", $dwToLocation)

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf
EndFunc   ;==>PTRobot_UnLoadPrinter

Func PTRobot_UnLoadDrive($num, $dwToLocation)
    Local $result
    Local $err = @error

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_UnLoadDrive", "hwnd", $RobotAddress, "hwnd", $DriveAddress[$num], "dword", $dwToLocation)

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf
EndFunc   ;==>PTRobot_UnLoadDrive

Func PTRobot_MoveDiscBetweenLocations($dwFromLocation, $dwToLocation)
    Local $result
    Local $err = @error

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_MoveDiscBetweenLocations", "hwnd", $RobotAddress, "dword", $dwFromLocation, "dword", $dwToLocation)

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf
EndFunc   ;==>PTRobot_MoveDiscBetweenLocations

Func PTRobot_OpenCloseDrive($num, $dwOpen)
    Local $result
    Local $err = @error

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_OpenCloseDrive", "hwnd", $DriveAddress[$num], "dword", $dwOpen)

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf
EndFunc   ;==>PTRobot_OpenCloseDrive

Func PTRobot_SystemAction($dwAction)
    Local $result
    Local $err = @error

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_SystemAction", "hwnd", $RobotAddress, "dword", $dwAction)

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf
EndFunc   ;==>PTRobot_SystemAction

Func PTRobot_KillSystemError($dwResetPrinter)
    Local $result
    Local $err = @error

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_KillSystemError", "hwnd", $RobotAddress, "dword", $dwResetPrinter)

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf
EndFunc   ;==>PTRobot_KillSystemError

Func PTRobot_GetManufactureInfo() ; WARNING: This function has not been thoroughly tested.
    Local $result
    Local $err = @error

    Local $dPTManufactureInfo = DllStructCreate("hwnd hRobot;char tszSerialNum[11];char tszManufactureDate[12];dword dwFiller[20]")

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_GetManufactureInfo", "hwnd", $RobotAddress, "ptr", DllStructGetPtr($dPTManufactureInfo))

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf

    MsgBox(0, "", "Serial Number: " & DllStructGetData($dPTManufactureInfo, "tszSerialNum") & @CRLF & _
            "Manufacture Date: " & DllStructGetData($dPTManufactureInfo, "tszManufactureDate") & @CRLF & _
            "Filler: " & DllStructGetData($dPTManufactureInfo, "dwFiller", 1))

    Return $result[0]
EndFunc   ;==>PTRobot_GetManufactureInfo

Func PTRobot_GetPrinterSettings()
    Local $result
    Local $err = @error

    Local $dPrinterSettings = DllStructCreate("dword dwPrintQuality;dword dwInnerDiam;dword dwOuterMargin")
    Local $PrintQuality

    $result = DllCall($hPTROBOTDLL, "int", "PTRobot_GetPrinterSettings", "hwnd", $RobotAddress, "ptr", DllStructGetPtr($dPrinterSettings))

    If $result[0] Then
        PTRobot_ErrorMsgBox($result[0])
        PTRobot_Destroy()
        Exit ($result[0])
    EndIf

    Switch DllStructGetData($dPrinterSettings, "dwPrintQuality")
        Case $PQ_LOW
            $PrintQuality = "Low"
        Case $PQ_MED
            $PrintQuality = "Medium"
        Case $PQ_BETTER
            $PrintQuality = "Better" ; Default
        Case $PQ_HIGH
            $PrintQuality = "High"
        Case $PQ_BEST
            $PrintQuality = "Best"
        Case Else ; This shouldn't happen.
            $PrintQuality = "UNKNOWN"
    EndSwitch

    MsgBox(0, "", "Print Quality: " & $PrintQuality & @CRLF & _
            "Inner Diameter: " & DllStructGetData($dPrinterSettings, "dwInnerDiam") & @CRLF & _
            "Outer Margin: " & DllStructGetData($dPrinterSettings, "dwOuterMargin"))

EndFunc   ;==>PTRobot_GetPrinterSettings

Func PTRobot_ErrorMsgBox($ErrorNum)
    Local $ErrorMsg

    Switch $ErrorNum
        Case $SYSERR_PTR_TRAY
            $ErrorMsg = "Tray movement error.  Press the left button on the unit to try again."
        Case $SYSERR_CART_CODE
            $ErrorMsg = "There was a problem finding the ink cartridges.  Open the cover and press the left button. Make sure the color cartridge is installed on the left and the black is on the right.  Then close the cover."
        Case $SYSERR_INPUT_EMPTY
            $ErrorMsg = "The input bin is empty.  Open the cover and add more discs.  Then close the cover and push the left button on the unit."
        Case $SYSERR_PTR_COMM
            $ErrorMsg = "There was an internal printer communications error.  Press the left button on the unit to try again."
        Case $SYSERR_CLR_EMPTY
            $ErrorMsg = "WARNING:  The color cartridge is LOW on ink.  To replace the cartridge, open the cover on the unit and press the left button.  Then install the new cartridge and close the cover.  To ignore the warning, press the left button."
        Case $SYSERR_BLK_EMPTY
            $ErrorMsg = "WARNING:  The black cartridge is LOW on ink.  To replace the cartridge, open the cover on the unit and press the left button.  Then install the new cartridge and close the cover.  To ignore the warning, press the left button."
        Case $SYSERR_BOTH_EMPTY
            $ErrorMsg = "WARNING:  Both ink cartridges are LOW on ink.  To replace the cartridges, open the cover on the unit and press the left button.  Then install the new cartridges and close the cover.  To ignore the warning, press the left button."
        Case $SYSERR_PICK
            $ErrorMsg = "The disc was not picked.  Press the left button on the unit to try again."
        Case $SYSERR_ARM_MOVE
            $ErrorMsg = "There was an arm movement error.  Press the left button on the unit to try again."
        Case $SYSERR_CART_MOVE
            $ErrorMsg = "Arm picker error.  Press the left button on the unit to try again."
        Case $SYSERR_INTERNAL_SW
            $ErrorMsg = "There was an internal software error.  Please re-start the software."
        Case $SYSERR_NO_ROBODRIVES
            $ErrorMsg = "No external recorder drives were found.  Re-power the computer and unit, and then re-start the software."
        Case $SYSERR_OFFLINE
            $ErrorMsg = "The unit is offline.  Please ensure the unit is connected and powered on.  You may need to shut down and restart the software."
        Case $SYSERR_COVER_OPEN
            $ErrorMsg = "The unit’s cover is open.  Please close the cover."
        Case $SYSERR_PRINTER_PICK
            $ErrorMsg = "The disc was not picked from the printer.  Press the left button to retry."
        Case $SYSERR_MULTIPLE_PICK
            $ErrorMsg = "Multiple discs were picked up and moved.  Please manually remove any extra discs that were moved, keeping a single disc in place.  Then close the cover and press the left button."
        Case $SYSERR_MULTIPLEDISCS_IN_PRINTER
            $ErrorMsg = "Multiple discs were placed in the printer.  Please manually remove any extra discs from the printer, keeping a single disc in place.  Then close the cover and press the left button."
        Case $SYSERR_MULTIPLEDISCS_IN_RECORDER
            $ErrorMsg = "Multiple discs were placed in the recorder.  Please manually remove any extra discs from the recorder, keeping a single disc in place.  Then close the cover and press the left button."
        Case $SYSERR_DROPPED_DISC_RECORDER
            $ErrorMsg = "The disc was dropped while moving into the recorder.  Please manually place the disc into the recorder tray.  Then close the cover and press the left button."
        Case $SYSERR_DROPPED_DISC_BIN1
            $ErrorMsg = "The disc was dropped while moving into the right bin.  Please manually place the disc into the right bin.  Then close the cover and press the left button."
        Case $SYSERR_DROPPED_DISC_BIN2
            $ErrorMsg = "The disc was dropped while moving into the left bin.  Please manually place the disc into the left bin.  Then close the cover and press the left button."
        Case $SYSERR_DROPPED_DISC_PRINTER
            $ErrorMsg = "The disc was dropped while moving into the printer.  Please manually place the disc into the printer tray.  Then close the cover and press the left button."
        Case $SYSERR_DROPPED_DISC_REJECT
            $ErrorMsg = "The disc was dropped while moving to the reject area.  Please remove the dropped disc.  Then close the cover and press the left button."
        Case $SYSERR_DROPPED_DISC_UNKNOWN
            $ErrorMsg = "The disc was dropped. Please remove the dropped disc.  Then close the cover and press the left button."
        Case $SYSERR_ALIGNNEEDED
            $ErrorMsg = "The printer cartridges need to be aligned."
        Case $SYSERR_COLOR_INVALID
            $ErrorMsg = "The color cartridge is invalid.  Open the cover and press the left button.  Change the cartridge and close the cover."
        Case $SYSERR_BLACK_INVALID
            $ErrorMsg = "The black cartridge is invalid.  Open the cover and press the left button.  Change the cartridge and close the cover."
        Case $SYSERR_BOTH_INVALID
            $ErrorMsg = "Both cartridges are invalid.  Open the cover and press the left button.  Change the cartridges and close the cover."
        Case $SYSERR_NOCARTS
            $ErrorMsg = "No cartridges are installed.  Open the cover and press the left button.  Install the cartridges and close the cover."
        Case $SYSERR_K_IN_CMY
            $ErrorMsg = "The black cartridge is installed in the color position.  Open the cover and press the left button.  Change the cartridge and close the cover."
        Case $SYSERR_CMY_IN_K
            $ErrorMsg = "The color cartridge is installed in the black position.  Open the cover and press the left button.  Change the cartridge and close the cover."
        Case $SYSERR_SWAPPED
            $ErrorMsg = "The black and color cartridges are swapped.  Open the cover and press the left button.  Swap the cartridges and close the cover."
        Case $SYSERR_PIGONPRO
            $ErrorMsg = "This printer is not compatible with a pigment-based black cartridge.  Open the cover and press the left button.  Install a dye-based black cartridge and close the cover."
        Case $SYSERR_ALIGNFAILED
            $ErrorMsg = "The alignment print failed."
        Case $SYSERR_DROPPED_DISC_PRINTER_FATAL
            $ErrorMsg = "The disc was dropped while moving to/from the printer.  Please open the cover and manually remove and discard the disc.  Then place a new disc in the recorder, close the cover and press the left button."
        Case $SYSERR_MULTIPLEDISCS_IN_RIGHTBIN
            $ErrorMsg = "Multiple discs were placed in the right bin.  Please manually move any extra discs to the left bin, keeping a single disc in place.  Then close the cover and press the left button."
        Case $SYSERR_MULTIPLEDISCS_IN_LEFTBIN
            $ErrorMsg = "Multiple discs were placed in the left bin.  Please manually move any extra discs to the right bin, keeping a single disc in place.  Then close the cover and press the left button."
        Case $SYSERR_CLR_EMPTY_FINAL
            $ErrorMsg = "WARNING:  The color cartridge is Empty.  To replace the cartridge, open the cover on the unit and press the left button.  Then install the new cartridge and close the cover.  To ignore the warning, press the left button."
        Case $SYSERR_BLK_EMPTY_FINAL
            $ErrorMsg = "WARNING:  The black cartridge is Empty.  To replace the cartridge, open the cover on the unit and press the left button.  Then install the new cartridge and close the cover.  To ignore the warning, press the left button."
        Case $SYSERR_BOTH_EMPTY_FINAL
            $ErrorMsg = "WARNING:  Both cartridges are Empty.  To replace the cartridge, open the cover on the unit and press the left button.  Then install the new cartridge and close the cover.  To ignore the warning, press the left button."
        Case $SYSERR_WAITING_FOR_PRINTER
            $ErrorMsg = "The system timed out waiting for the printer to finish.  The disc may not have been printed on."
        Case $SYSERR_NO_DISC_IN_PRINTER
            $ErrorMsg = "No disc was found in the printer."
        Case $SYSERR_BUSY
            $ErrorMsg = "System Busy."
        Case $SYSERR_PURGE
            $ErrorMsg = "Purge."
        Case $SYSERR_DOCK_SENSOR
            $ErrorMsg = "Dock Sensor."
        Case $SYSERR_ALREADY_PRINTED
            $ErrorMsg = "Already printed."
        Case $SYSERR_UNKNOWN_HARDWARE
            $ErrorMsg = "Unknown hardware."
        Case $PTROBOT_FEATURE_NOT_IMPLEMENTED
            $ErrorMsg = "This feature is not implemented."
        Case $CUSTOM_INVALID_DRIVE_LETTER
            $ErrorMsg = "Could not find valid drive letter for burner."
        Case Else
            $ErrorMsg = "UNKNOWN ERROR! " & $ErrorNum
    EndSwitch

    WriteStatusError("Error: " & $ErrorMsg & @CRLF)
    MsgBox(0, "Error", $ErrorMsg)
EndFunc   ;==>PTRobot_ErrorMsgBox

Func _ValidateImageFile($sFilename)
    Local Const $sSTDHeader = "4D5600FF0C001200"
    Local Const $sPNGHeader = "89504E470D0A1A0A"
    Local Const $sJPGHeader = "FFD8FFE000104A46"
    Local Const $sGIF87Header = "474946383961"
    Local Const $sGIF89Header = "474946383761"
    Local Const $sBMPHeader = "424D"
    Local $sFileType, $bReturn = False

    Local $hFileHandle = FileOpen($sFilename, 16) ; Open file read only
    Local $bFileContents = FileRead($hFileHandle, 8) ; Read first 8 bytes
    Local $sFileExt = StringLower(StringRight($sFilename, 4)) ; Determine file extension

    If StringMid($bFileContents, 3, StringLen($sJPGHeader)) = $sJPGHeader And $sFileExt = ".jpg" Then
        $sFileType = "JPEG"
        $bReturn = True
    ElseIf StringMid($bFileContents, 3, StringLen($sSTDHeader)) = $sSTDHeader And $sFileExt = ".std" Then
        $sFileType = "SureThing Label"
        $bReturn = True
    ElseIf StringMid($bFileContents, 3, StringLen($sPNGHeader)) = $sPNGHeader And $sFileExt = ".png" Then
        $sFileType = "PNG"
        $bReturn = True
    ElseIf StringMid($bFileContents, 3, StringLen($sBMPHeader)) = $sBMPHeader And $sFileExt = ".bmp" Then
        $sFileType = "BMP"
        $bReturn = True
        ;ElseIf StringMid($bFileContents, 3, StringLen($sGIF87Header)) = $sGIF87Header And $sFileExt = ".gif" Then
        ;  $sFileType = "GIF87"
        ;  $bReturn = True
        ;ElseIf StringMid($bFileContents, 3, StringLen($sGIF89Header)) = $sGIF89Header And $sFileExt = ".gif" Then
        ;  $sFileType = "GIF89"
        ;  $bReturn = True
    Else
        $sFileType = "Unknown"
    EndIf

    ;MsgBox(0, "", $sFileType)
    Return $bReturn
EndFunc   ;==>_ValidateImageFile

Func _NoHaltMsgBox($code = 0, $Title = "", $text = "", $timeout = 0)
    Run(@AutoItExe & ' /AutoIt3ExecuteLine  "MsgBox(' & $code & ', ''' & $Title & ''', ''' & $text & ''',' & $timeout & ')"')
EndFunc   ;==>_NoHaltMsgBox

Func OpenPrompt($message, $Queue)

    Local $answer

    ; Get number of sets from the command-line
    $answer = getNumSets()

    ; If copies were specified on command line, then end function without prompting
    If $answer > 0 Then
        $NumSets = $answer
        Return $Queue
    EndIf

    Local $QueueSize = UBound($Queue, 1)

    Local $Form_Duplicator_GUI = GUICreate("IMGBurn AutoIt Script", 404, 260, 192, 124)
    Local $Button_Start = GUICtrlCreateButton("Start", 72, 210, 87, 33)
    Local $NumCopies = GUICtrlCreateInput($NumSets, 220, 170, 49, 21, $ES_CENTER)
    Local $Updown_NumCopies = GUICtrlCreateUpdown($NumCopies)
    GUICtrlSetLimit(-1, $MAX_NUMSETS, 1)
    Local $Button_Cancel = GUICtrlCreateButton("Cancel", 232, 210, 91, 33)
    Local $Label_NumCopies = GUICtrlCreateLabel("How many copies?", 116, 170, 94, 17, BitOR($SS_RIGHT, $SS_CENTERIMAGE))
    Local $Label_Message = GUICtrlCreateLabel("This script will run the disc burning software for the job" & @LF & $message & @LF & "Run?", 2, 8, 400, 57, BitOR($SS_NOPREFIX, $SS_CENTER))
    Local $List_Queue = GUICtrlCreateList("", 2, 60, 400, 100, BitOR($LBS_MULTIPLESEL, $WS_HSCROLL, $WS_VSCROLL, $WS_BORDER))
    GUICtrlSetLimit(-1, 200) ; Limit horizontal scrolling
    Local $DiscTitle
    For $i = 0 To $QueueSize - 1
        $DiscTitle = StringRegExp($Queue[$i][0], '\\([^\\]*)\.std$', 1)
        GUICtrlSetData(-1, $DiscTitle[0])
        ;_GUICtrlListBox_SetSel($List_Queue, $i) ; Preselect entry
        GUICtrlSendMsg(-1, $LB_SETSEL, True, $i) ; Preselect entry
    Next
    GUICtrlSendMsg(-1, $LB_SETTOPINDEX, 0, 0) ; Send scrollbar to top of list
    GUISetState(@SW_SHOW)

    Local $NewQueue

    While 1
        $answer = GUIGetMsg()
        $NewQueue = $Queue ; Set/Reset NewQueue to Queue

        Switch $answer
            Case $Button_Start
                If GUICtrlRead($NumCopies) < 1 Or GUICtrlRead($NumCopies) > $MAX_NUMSETS Then
                    MsgBox(0, "Error", "Number of copies must be between 1 and " & $MAX_NUMSETS & ".")
                Else
                    For $i = $QueueSize - 1 To 0 Step -1 ; Process array in reverse to keep index aligned
                        If _GUICtrlListBox_GetSel($List_Queue, $i) == False Then
                            _ArrayDelete($NewQueue, $i)
                        EndIf
                    Next

                    If UBound($NewQueue, 1) = 0 Then
                        MsgBox(0, "Error", "No discs selected.")
                    Else
                        ExitLoop ; Success!
                    EndIf
                EndIf
            Case $Button_Cancel
                MsgBox(0, "IMGBurn AutoIt Script", "OK.  Bye!")
                Exit
            Case $GUI_EVENT_CLOSE
                Exit
        EndSwitch
    WEnd

    $NumSets = GUICtrlRead($NumCopies)

    GUISetState(@SW_HIDE)

    Return $NewQueue
EndFunc   ;==>OpenPrompt

Func CalcDupeTime($iTimestampDiff)
    Local $iSeconds = Int($iTimestampDiff / 1000)
    Local $iHours, $iMins, $iSecs

    $iHours = Int($iSeconds / 3600)
    $iSeconds = Mod($iSeconds, 3600)
    $iMins = Int($iSeconds / 60)
    $iSecs = Mod($iSeconds, 60)

    If StringLen($iHours) = 1 Then $iHours = "0" & $iHours
    If StringLen($iMins) = 1 Then $iMins = "0" & $iMins
    If StringLen($iSecs) = 1 Then $iSecs = "0" & $iSecs

    Return $iHours & ":" & $iMins & ":" & $iSecs
EndFunc   ;==>CalcDupeTime

Func sendEmail($Title, $Queue, $NumSets, $DupeTime)
    Local $QueueSize = UBound($Queue, 1)

    Local $s_SmtpServer = "10.100.52.30"
    Local $s_FromName = "IMGBurn Disc Duplicator"
    Local $s_FromAddress = "ConfigurationManagementDistribution@aaccorp.com"
    Local $s_ToAddress = "ConfigurationManagementDistribution@aaccorp.com"
    Local $s_Subject = "[DUPLICATOR] - " & $Title & " - " & $NumSets & " set(s) in " & $DupeTime

    ; Old _INetSmtpMail code
    ;Local $as_Body[$QueueSize + 1]
    ;$as_Body[0] = "The job took " & $DupeTime & " to complete." & @CRLF

    Local $s_Body = "<body><p style=""font-family:Calibri, Arial, Helvetica, sans-serif;font-size:11pt;"">The job took " & $DupeTime & " to complete.</p><p></p>"
    $s_Body &= "<p style=""font-family:Calibri, Arial, Helvetica, sans-serif;font-size:11pt;"">"

    Local $DiscTitle

    ; Old _INetSmtpMail code
    ;For $i = 0 To $QueueSize - 1
    ;   $DiscTitle = StringRegExp($Queue[$i][0], '\\([^\\]*)\.std$', 1)
    ;   $as_Body[$i+1] = $DiscTitle[0] & @TAB ; We add a TAB at the end to stop Outlook from concatenating lines >= 40 chars
    ;Next

    For $i = 0 To $QueueSize - 1
        $DiscTitle = StringRegExp($Queue[$i][0], '\\([^\\]*)\.std$', 1)
        _HtmlEntities_Encode($DiscTitle[0])
        $s_Body &= $DiscTitle[0] & "<br>"
    Next

    $s_Body &= "</p></body>"

    ; Old _INetSmtpMail code
    ;Local $Response = _INetSmtpMail($s_SmtpServer, $s_FromName, $s_FromAddress, $s_ToAddress, $s_Subject, $as_Body, 1, -1)
    ;Local $err = @error
    ;
    ;If $Response = 1 Then
    ;   MsgBox(0, "Success!", "Mail sent")
    ;Else
    ;   MsgBox(0, "Error!", "Mail failed with error code " & $err)
    ;EndIf

    Local $oMyRet[2]
    Local $oMyError = ObjEvent("AutoIt.Error", "MyErrFunc")
    Local $Response = _INetSmtpMailCom($s_SmtpServer, $s_FromName, $s_FromAddress, $s_ToAddress, $s_Subject, $s_Body)
    If @error Then
        MsgBox(0, "Error sending message", "Error code:" & @error & "  Description:" & $Response)
    EndIf

EndFunc   ;==>sendEmail

Func toggleScreenSaver()
    Local $key = "HKEY_CURRENT_USER\Control Panel\Desktop"
    Local $value = "ScreenSaveActive"
    If Number(RegRead($key, $value)) Then
        RegWrite($key, $value, "REG_SZ", 0)
    Else
        RegWrite($key, $value, "REG_SZ", 1)
    EndIf
EndFunc   ;==>toggleScreenSaver

Func disableScreenSaver()
    Local $key = "HKEY_CURRENT_USER\Control Panel\Desktop"
    Local $value = "ScreenSaveActive"
    If Number(RegRead($key, $value)) Then
        RegWrite($key, $value, "REG_SZ", 0)
    EndIf
EndFunc   ;==>disableScreenSaver

Func enableScreenSaver()
    Local $key = "HKEY_CURRENT_USER\Control Panel\Desktop"
    Local $value = "ScreenSaveActive"
    If Number(RegRead($key, $value)) = 0 Then
        RegWrite($key, $value, "REG_SZ", 1)
    EndIf
EndFunc   ;==>enableScreenSaver

Func WriteStatus($LogMessage)
    ConsoleWrite($LogMessage)
    GUICtrlSetData($Label_Status, $LogMessage)
EndFunc   ;==>WriteStatus

Func WriteStatusError($LogMessage)
    ConsoleWriteError($LogMessage)
    GUICtrlSetData($Label_Status, $LogMessage)
EndFunc   ;==>WriteStatusError

Func _INetSmtpMailCom($s_SmtpServer, $s_FromName, $s_FromAddress, $s_ToAddress, $s_Subject = "", $as_Body = "", $s_AttachFiles = "", $s_CcAddress = "", $s_BccAddress = "", $s_Importance = "Normal", $s_Username = "", $s_Password = "", $IPPort = 25, $ssl = 0)
    Local $objEmail = ObjCreate("CDO.Message")
    $objEmail.From = '"' & $s_FromName & '" <' & $s_FromAddress & '>'
    $objEmail.To = $s_ToAddress
    Local $i_Error = 0
    Local $i_Error_desciption = ""
    If $s_CcAddress <> "" Then $objEmail.Cc = $s_CcAddress
    If $s_BccAddress <> "" Then $objEmail.Bcc = $s_BccAddress
    $objEmail.Subject = $s_Subject
    If StringInStr($as_Body, "<") And StringInStr($as_Body, ">") Then
        $objEmail.HTMLBody = $as_Body
    Else
        $objEmail.Textbody = $as_Body & @CRLF
    EndIf
    If $s_AttachFiles <> "" Then
        Local $S_Files2Attach = StringSplit($s_AttachFiles, ";")
        For $x = 1 To $S_Files2Attach[0]
            $S_Files2Attach[$x] = _PathFull($S_Files2Attach[$x])
;~          ConsoleWrite('@@ Debug : $S_Files2Attach[$x] = ' & $S_Files2Attach[$x] & @LF & '>Error code: ' & @error & @LF) ;### Debug Console
            If FileExists($S_Files2Attach[$x]) Then
                ConsoleWrite('+> File attachment added: ' & $S_Files2Attach[$x] & @LF)
                $objEmail.AddAttachment($S_Files2Attach[$x])
            Else
                ConsoleWrite('!> File not found to attach: ' & $S_Files2Attach[$x] & @LF)
                SetError(1)
                Return 0
            EndIf
        Next
    EndIf
    $objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
    $objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = $s_SmtpServer
    If Number($IPPort) = 0 Then $IPPort = 25
    $objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = $IPPort
    ;Authenticated SMTP
    If $s_Username <> "" Then
        $objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1
        $objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusername") = $s_Username
        $objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendpassword") = $s_Password
    EndIf
    If $ssl Then
        $objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpusessl") = True
    EndIf
    ;Update settings
    $objEmail.Configuration.Fields.Update
    ; Set Email Importance
    Switch $s_Importance
        Case "High"
            $objEmail.Fields.Item("urn:schemas:mailheader:Importance") = "High"
        Case "Normal"
            $objEmail.Fields.Item("urn:schemas:mailheader:Importance") = "Normal"
        Case "Low"
            $objEmail.Fields.Item("urn:schemas:mailheader:Importance") = "Low"
    EndSwitch
    $objEmail.Fields.Update
    ; Sent the Message
    $objEmail.Send
    If @error Then
        SetError(2)
        Return $oMyRet[1]
    EndIf
    $objEmail = ""
EndFunc   ;==>_INetSmtpMailCom
;
;
; Com Error Handler
Func MyErrFunc()
    Local $oMyError = ObjEvent("AutoIt.Error", "MyErrFunc")
    $HexNumber = Hex($oMyError.number, 8)
    $oMyRet[0] = $HexNumber
    $oMyRet[1] = StringStripWS($oMyError.description, 3)
    ConsoleWrite("### COM Error !  Number: " & $HexNumber & "   ScriptLine: " & $oMyError.scriptline & "   Description:" & $oMyRet[1] & @LF)
    SetError(1); something to check for when this function returns
    Return
EndFunc   ;==>MyErrFunc

Func _HtmlEntities_Encode(ByRef $sTxt)
    For $i = 0 To 245
        $sTxt = StringReplace($sTxt, ChrW($aisEntities[$i][0]), '&' & $aisEntities[$i][1] & ';', 0, 1)
    Next
EndFunc   ;==>_HtmlEntities_Encode

Func _HtmlEntities_Decode(ByRef $sTxt)
    For $i = 0 To 245
        $sTxt = StringReplace($sTxt, '&' & $aisEntities[$i][1] & ';', ChrW($aisEntities[$i][0]), 0, 1)
    Next
EndFunc   ;==>_HtmlEntities_Decode

Lots of small improvements. It now autodetects the burner's drive letter. Added a queue in an array: first column is the labels and second column is the disc image files (e.g., .ISO). It's much more interactive when problems occur. Leaving the label file blank in the queue array will skip the printing process. More error checking done. If your duplicator doesn't have a printer, it will never attempt to print even if you specify labels. Added some more functions.

EDIT: Added console messages and error output.

DOUBLE EDIT: Eject disc on abort before asking if you want to close the program.

TRIPLE EDIT: Added validation of label files since the DLLs will crash if an invalid image file is passed. It's a very rudimentary check.

Edited by GPinzone

Gerard J. Pinzonegpinzone AT yahoo.com

Share this post


Link to post
Share on other sites

I am very interested in this code. I have never referenced a dll file. Is there any special way that the dll files must be registered? do the dll files need to be in the same directory as the autoit file? I have tried to use the code in this string and am getting an array errors. I suspect the dll call is not getting done.

Thanks for the hard work. I look forward to coding for my Primera Bravo II.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

I updated the above code once more with some minor tweaks:

  • Fixed speed of IMGBurn to 6X since the throughput of the USB connection isn't going to allow much more than that for writing anyway. Feel free to try other speeds (or none at all).
  • Open drive tray on error.
  • Close drive tray on retry (after error).
EDIT:
  • Set speed to AUTO which invokes AWS. Check out the IMGBurn form for more info on AWS.
  • Settings chosen by default in IMG burn could accidentally be set during commad-line run. I added switches to trun off test writing, deleting image, and ejecting the disc.
Edited by GPinzone

Gerard J. Pinzonegpinzone AT yahoo.com

Share this post


Link to post
Share on other sites

After all this time, I realized there was some erroneous code included. I updated the 3rd post with the correct code.


Gerard J. Pinzonegpinzone AT yahoo.com

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0