Attribute VB_Name = "Module1"
Option Explicit

Private Const m_cFRMNAME As String = "modCommon"
Global Const g_cAPP_NAME = "FOTA_ScreenSaver_Life_Running"


'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Background pasting API
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Declare Function GetDC Lib "USER32" (ByVal hwnd As Long) As Long
Declare Function GetDesktopWindow Lib "USER32" () As Long
Declare Function ReleaseDC Lib "USER32" (ByVal hwnd As Long, ByVal hdc As Long) As Long

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Screen saver stuff
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Public Const SWP_NOACTIVATE = &H10
Public Const SWP_NOZORDER = &H4
Public Const SWP_SHOWWINDOW = &H40

Public Const HWND_TOP = 0

Public Const WS_CHILD = &H40000000
Public Const GWL_HWNDPARENT = (-8)
Public Const GWL_STYLE = (-16)

Declare Function GetWindowLong Lib "USER32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Declare Function GetClientRect Lib "USER32" (ByVal hwnd As Long, lpRect As RECT) As Long
Declare Function SetWindowLong Lib "USER32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Declare Function SetParent Lib "USER32" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long
Declare Function SetWindowPos Lib "USER32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Declare Function ShowCursor Lib "USER32" (ByVal bShow As Long) As Long

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Set the priority of the thread
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Const HIGH_PRIORITY_CLASS = &H80
Public Const IDLE_PRIORITY_CLASS = &H40
Public Const NORMAL_PRIORITY_CLASS = &H20
Public Const REALTIME_PRIORITY_CLASS = &H100
Public Declare Function SetPriorityClass Lib "kernel32" (ByVal hProcess As Long, ByVal dwPriorityClass As Long) As Long
Public Declare Function GetCurrentProcess Lib "kernel32" () As Long
Public Declare Function GetPriorityClass Lib "kernel32" (ByVal hProcess As Long) As Long


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'The following constants are used to determine the mouse input on the
'the icon in the taskbar status area.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Left-click constants.
Public Const WM_LBUTTONDBLCLK = &H203   'Double-click
Public Const WM_LBUTTONDOWN = &H201     'Button down
Public Const WM_LBUTTONUP = &H202       'Button up

'Right-click constants.
Public Const WM_RBUTTONDBLCLK = &H206   'Double-click
Public Const WM_RBUTTONDOWN = &H204     'Button down
Public Const WM_RBUTTONUP = &H205       'Button up

'Declare the API function call.
Public Declare Function Shell_NotifyIcon Lib "shell32" Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, pnid As NOTIFYICONDATA) As Boolean

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'The following constant is the message sent when a mouse event occurs
'within the rectangular boundaries of the icon in the System Tray area.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Const WM_MOUSEMOVE = &H200

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'The following constants are the flags that indicate the valid
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'members of the NOTIFYICONDATA data type.
Public Const NIF_MESSAGE = &H1
Public Const NIF_ICON = &H2
Public Const NIF_TIP = &H4

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Declare a user-defined variable to pass to the Shell_NotifyIcon function.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Type NOTIFYICONDATA
   cbSize As Long
   hwnd As Long
   uId As Long
   uFlags As Long
   uCallBackMessage As Long
   hIcon As Long
   szTip As String * 64
End Type

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'The following constants are the messages sent to the
'Shell_NotifyIcon function to add, modify, or delete an icon from the System Tray
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Const NIM_ADD = &H0
Public Const NIM_MODIFY = &H1
Public Const NIM_DELETE = &H2

' ------------------------
' Bitmap Array Information
' ------------------------
Public Type RGBTriplet
    rgbBlue As Byte
    rgbGreen As Byte
    rgbRed As Byte
End Type

' ------------------
' Bitmap Information
' ------------------
Public Type BITMAP
    bmType As Long
    bmWidth As Long
    bmHeight As Long
    bmWidthBytes As Long
    bmPlanes As Integer
    bmBitsPixel As Integer
    bmBits As Long
End Type
Public Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Public Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Public Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long

Public Enum bmphErrors
    bmphInvalidBitmapBits = vbObjectError + 1001
    bmphPaletteError
End Enum

' -------------------
' Palette Information
' -------------------
Private Type PALETTEENTRY
    peRed As Byte
    peGreen As Byte
    peBlue As Byte
    peFlags As Byte
End Type
Private Declare Function GetNearestPaletteIndex Lib "gdi32" (ByVal hPalette As Long, ByVal crColor As Long) As Long
Private Declare Function GetPaletteEntries Lib "gdi32" (ByVal hPalette As Long, ByVal wStartIndex As Long, ByVal wNumEntries As Long, lpPaletteEntries As PALETTEENTRY) As Long
Private Declare Function RealizePalette Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function GetSystemPaletteEntries Lib "gdi32" (ByVal hdc As Long, ByVal wStartIndex As Long, ByVal wNumEntries As Long, lpPaletteEntries As PALETTEENTRY) As Long
Private Declare Function ResizePalette Lib "gdi32" (ByVal hPalette As Long, ByVal nNumEntries As Long) As Long
Private Declare Function SetPaletteEntries Lib "gdi32" (ByVal hPalette As Long, ByVal wStartIndex As Long, ByVal wNumEntries As Long, lpPaletteEntries As PALETTEENTRY) As Long
Private Const MAX_PALETTE_SIZE = 256
Private Const PC_NOCOLLAPSE = &H4    ' Do not match color existing entries.

' -------------------------------
' System Capabilities Information
' -------------------------------
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Const NUMRESERVED = 106  ' Number of reserved entries in system palette.
Private Const SIZEPALETTE = 104  ' Size of system palette.

' Copy memory quickly. Used for 24-bit images.
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

' Load the control's palette so it matches the
' system palette.
Private Sub MatchColorPalette(ByVal pic As PictureBox)
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    On Error GoTo ErrorHandler                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    Dim sRoutineName As String                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    sRoutineName = "Life." & m_cFRMNAME & ".MatchColorPalette"                                                           '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStart(sRoutineName)                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
Dim log_hpal As Long
Dim sys_pal(0 To MAX_PALETTE_SIZE - 1) As PALETTEENTRY
Dim orig_pal(0 To MAX_PALETTE_SIZE - 1) As PALETTEENTRY
Dim i As Integer
Dim sys_pal_size As Long
Dim num_static_colors As Long
Dim static_color_1 As Long
Dim static_color_2 As Long

    ' Make sure pic has the foreground palette.
    pic.ZOrder
    RealizePalette pic.hdc
    DoEvents

    ' Get system palette size and # static colors.
    sys_pal_size = GetDeviceCaps(pic.hdc, SIZEPALETTE)
    num_static_colors = GetDeviceCaps(pic.hdc, NUMRESERVED)
    static_color_1 = num_static_colors \ 2 - 1
    static_color_2 = sys_pal_size - num_static_colors \ 2

    ' Get the system palette entries.
    GetSystemPaletteEntries pic.hdc, 0, _
        sys_pal_size, sys_pal(0)

    ' Make the logical palette as big as possible.
    log_hpal = pic.Picture.hpal
    If ResizePalette(log_hpal, sys_pal_size) = 0 Then
        Err.Raise bmphPaletteError, _
            "DDBHelper.MatchColorPalette", _
            "Error matching bitmap palette"
    End If

    ' Blank the non-static colors.
    For i = 0 To static_color_1
        orig_pal(i) = sys_pal(i)
    Next i
    For i = static_color_1 + 1 To static_color_2 - 1
        With orig_pal(i)
            .peRed = 0
            .peGreen = 0
            .peBlue = 0
            .peFlags = PC_NOCOLLAPSE
        End With
    Next i
    For i = static_color_2 To 255
        orig_pal(i) = sys_pal(i)
    Next i
    SetPaletteEntries log_hpal, 0, sys_pal_size, orig_pal(0)

    ' Insert the non-static colors.
    For i = static_color_1 + 1 To static_color_2 - 1
        orig_pal(i) = sys_pal(i)
        orig_pal(i).peFlags = PC_NOCOLLAPSE
    Next i
    SetPaletteEntries log_hpal, static_color_1 + 1, static_color_2 - static_color_1 - 1, orig_pal(static_color_1 + 1)

    ' Realize the new palette.
    RealizePalette pic.hdc
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStop(sRoutineName)                                                                                    '<FOTA_ScreenSaver_Life_ADDER>
    Exit Sub                                                                                               '<FOTA_ScreenSaver_Life_ADDER>
ErrorHandler:                                                                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.HandleErrorWithSource(Err, sRoutineName)                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.DisplayErrorCount                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
End Sub
' Return a binary representation of the byte.
' This helper function is useful for understanding
' byte values.
Public Function BinaryByte(ByVal value As Byte) As String
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    On Error GoTo ErrorHandler                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    Dim sRoutineName As String                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    sRoutineName = "Life." & m_cFRMNAME & ".BinaryByte"                                                           '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStart(sRoutineName)                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
Dim i As Integer
Dim txt As String

    For i = 1 To 8
        If value And 1 Then
            txt = "1" & txt
        Else
            txt = "0" & txt
        End If
        value = value \ 2
    Next i

    BinaryByte = txt
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStop(sRoutineName)                                                                                    '<FOTA_ScreenSaver_Life_ADDER>
    Exit Function                                                                                               '<FOTA_ScreenSaver_Life_ADDER>
ErrorHandler:                                                                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.HandleErrorWithSource(Err, sRoutineName)                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.DisplayErrorCount                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
End Function

' Load the bits from this PictureBox into a
' two-dimensional array of RGB values. Set
' bits_per_pixel to be the number of bits per pixel.
Public Sub GetBitmapPixels(ByVal pic As PictureBox, ByRef pixels() As RGBTriplet, ByRef bits_per_pixel As Integer)
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    On Error GoTo ErrorHandler                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    Dim sRoutineName As String                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    sRoutineName = "Life." & m_cFRMNAME & ".GetBitmapPixels"                                                           '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStart(sRoutineName)                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
' Uncomment the following to make the routine
' display information about the bitmap.
' #Const DEBUG_PRINT_BITMAP = True

Dim hbm As Long
Dim bm As BITMAP
Dim l As Single
Dim t As Single
Dim old_color As Long
Dim bytes() As Byte
Dim num_pal_entries As Long
Dim pal_entries(0 To MAX_PALETTE_SIZE - 1) As PALETTEENTRY
Dim pal_index As Integer
Dim wid As Integer
Dim hgt As Integer
Dim x As Integer
Dim y As Integer
Dim two_bytes As Long

    ' Get the bitmap information.
    hbm = pic.Image
    GetObject hbm, Len(bm), bm
    bits_per_pixel = bm.bmBitsPixel

    ' If bits_per_pixel is 16, see if it's really
    ' 15 or 16 bits per pixel.
    If bits_per_pixel = 16 Then
        ' Make the upper left pixel white.
        l = pic.ScaleLeft
        t = pic.ScaleTop
        old_color = pic.Point(l, t)
        pic.PSet (l, t), vbWhite

        ' See what color was set.
        ReDim bytes(0 To 0, 0 To 0)
        GetBitmapBits hbm, 2, bytes(0, 0)
        If (bytes(0, 0) And &H80) = 0 Then
            ' It's really a 15-bit image.
            bits_per_pixel = 15
        End If

        ' Restore the pixel's original color.
        pic.PSet (l, t), old_color
    End If

    #If DEBUG_PRINT_BITMAP Then
        Debug.Print "*** BITMAP Data ***"
        Debug.Print "bmType       "; bm.bmType
        Debug.Print "bmWidth      "; bm.bmWidth
        Debug.Print "bmHeight     "; bm.bmHeight
        Debug.Print "bmWidthBytes "; bm.bmWidthBytes
        Debug.Print "bmPlanes     "; bm.bmPlanes
        Debug.Print "bmBitsPixel  "; bm.bmBitsPixel
        Debug.Print "BitsPerPixel "; bits_per_pixel
    #End If

    ' Get the bits.
    If (bits_per_pixel = 8) Or _
       (bits_per_pixel = 15) Or _
       (bits_per_pixel = 16) Or _
       (bits_per_pixel = 24) Or _
       (bits_per_pixel = 32) _
    Then
        ' Get the bits.
        ReDim bytes(0 To bm.bmWidthBytes - 1, 0 To bm.bmHeight - 1)
        GetBitmapBits hbm, bm.bmWidthBytes * bm.bmHeight, bytes(0, 0)
    Else
        ' We don't know how to read this format.
        Err.Raise bmphInvalidBitmapBits, _
            "DDBHelper.GetBitmapPixels", _
            "Invalid number of bits per pixel: " _
            & Format$(bits_per_pixel)
    End If

    ' Create the pixels array.
    wid = bm.bmWidth
    hgt = bm.bmHeight
    ReDim pixels(0 To wid - 1, 0 To hgt - 1)
    Select Case bits_per_pixel
        Case 8
            ' Match pic's palette to the system palette.
            MatchColorPalette pic

            ' Get the image's palette entries.
            num_pal_entries = GetPaletteEntries( _
                pic.Picture.hpal, 0, _
                MAX_PALETTE_SIZE, pal_entries(0))

            ' Get the RGB color components.
            For y = 0 To hgt - 1
                For x = 0 To wid - 1
                    With pixels(x, y)
                        pal_index = bytes(x, y)
                        .rgbRed = pal_entries(pal_index).peRed
                        .rgbGreen = pal_entries(pal_index).peGreen
                        .rgbBlue = pal_entries(pal_index).peBlue
                    End With
                Next x
            Next y

        Case 15
            For y = 0 To hgt - 1
                For x = 0 To wid - 1
                    With pixels(x, y)
                        ' Get the combined 2 bytes for this pixel.
                        two_bytes = bytes(x * 2, y) + bytes(x * 2 + 1, y) * 256&

                        ' Separate the pixel's components.
                        .rgbBlue = two_bytes Mod 32
                        two_bytes = two_bytes \ 32
                        .rgbGreen = two_bytes Mod 32
                        two_bytes = two_bytes \ 32
                        .rgbRed = two_bytes
                    End With
                Next x
            Next y

        Case 16
            For y = 0 To hgt - 1
                For x = 0 To wid - 1
                    With pixels(x, y)
                        ' Get the combined 2 bytes for this pixel.
                        two_bytes = bytes(x * 2, y) + bytes(x * 2 + 1, y) * 256&

                        ' Separate the pixel's components.
                        .rgbBlue = two_bytes Mod 32
                        two_bytes = two_bytes \ 32
                        .rgbGreen = two_bytes Mod 64
                        two_bytes = two_bytes \ 64
                        .rgbRed = two_bytes
                    End With
                Next x
            Next y

        Case 24
            ' Blast the data from the pixels array
            ' to the bytes array using CopyMemory.
            For y = 0 To hgt - 1
                CopyMemory pixels(0, y), bytes(0, y), wid * 3
            Next y

        Case 32
            For y = 0 To hgt - 1
                For x = 0 To wid - 1
                    With pixels(x, y)
                        .rgbBlue = bytes(x * 4, y)
                        .rgbGreen = bytes(x * 4 + 1, y)
                        .rgbRed = bytes(x * 4 + 2, y)
                    End With
                Next x
            Next y

    End Select
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStop(sRoutineName)                                                                                    '<FOTA_ScreenSaver_Life_ADDER>
    Exit Sub                                                                                               '<FOTA_ScreenSaver_Life_ADDER>
ErrorHandler:                                                                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.HandleErrorWithSource(Err, sRoutineName)                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.DisplayErrorCount                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
End Sub
' Set the bits in this PictureBox using a 0-based
' two-dimensional array of RGBTriplets. The pixels must
' have the right dimensions to match the picture.
Public Sub SetBitmapPixels(ByVal pic As PictureBox, ByVal bits_per_pixel As Integer, pixels() As RGBTriplet)
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    On Error GoTo ErrorHandler                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    Dim sRoutineName As String                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    sRoutineName = "Life." & m_cFRMNAME & ".SetBitmapPixels"                                                           '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStart(sRoutineName)                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
Dim wid_bytes As Long
Dim wid As Integer
Dim hgt As Integer
Dim x As Integer
Dim y As Integer
Dim bytes() As Byte
Dim hpal As Long
Dim two_bytes As Long

    ' See how big the image must be.
    wid = UBound(pixels, 1) + 1
    hgt = UBound(pixels, 2) + 1

    ' See how many bytes per row we need.
    Select Case bits_per_pixel
        Case 8
            wid_bytes = wid
        Case 15, 16
            wid_bytes = wid * 2
        Case 24
            wid_bytes = wid * 3
        Case 32
            wid_bytes = wid * 4
        Case Else
            ' We don't understand this format.
            Err.Raise bmphInvalidBitmapBits, _
                "DDBHelper.GetBitmapPixels", _
                "Invalid number of bits per pixel: " _
                & Format$(bits_per_pixel)
    End Select

    ' Make sure it's even.
    If wid_bytes Mod 2 = 1 Then wid_bytes = wid_bytes + 1

    ' Create the bitmap bytes array.
    ReDim bytes(0 To wid_bytes - 1, 0 To hgt - 1)

    ' Set the bitmap byte values.
    Select Case bits_per_pixel
        Case 8
            ' Use the nearest palette entries.
            hpal = pic.Picture.hpal

            ' Get the RGB color components.
            For y = 0 To hgt - 1
                For x = 0 To wid - 1
                    With pixels(x, y)
                        bytes(x, y) = (&HFF And _
                            GetNearestPaletteIndex(hpal, _
                                RGB(.rgbRed, .rgbGreen, .rgbBlue) _
                            + &H2000000))
                    End With
                Next x
            Next y

        Case 15
            For y = 0 To hgt - 1
                For x = 0 To wid - 1
                    With pixels(x, y)
                        ' Keep the values in bounds.
                        If .rgbRed > &H1F Then .rgbRed = &H1F
                        If .rgbGreen > &H1F Then .rgbGreen = &H1F
                        If .rgbBlue > &H1F Then .rgbBlue = &H1F

                        ' Combine the values in 2 bytes.
                        two_bytes = .rgbBlue + 32 * (.rgbGreen + CLng(.rgbRed) * 32)

                        ' Set the byte values.
                        bytes(x * 2, y) = (two_bytes Mod 256) And &HFF
                        bytes(x * 2 + 1, y) = (two_bytes \ 256) And &HFF
                    End With
                Next x
            Next y

        Case 16
            For y = 0 To hgt - 1
                For x = 0 To wid - 1
                    With pixels(x, y)
                        ' Keep the values in bounds.
                        If .rgbRed > &H1F Then .rgbRed = &H1F
                        If .rgbGreen > &H3F Then .rgbGreen = &H3F
                        If .rgbBlue > &H1F Then .rgbBlue = &H1F

                        ' Combine the values in 2 bytes.
                        two_bytes = .rgbBlue + 32 * (.rgbGreen + CLng(.rgbRed) * 64)

                        ' Set the byte values.
                        bytes(x * 2, y) = (two_bytes Mod 256) And &HFF
                        bytes(x * 2 + 1, y) = (two_bytes \ 256) And &HFF

                    End With
                Next x
            Next y

        Case 24
            ' Blast the data from the bytes array
            ' to the pixels array using CopyMemory.
            For y = 0 To hgt - 1
                CopyMemory bytes(0, y), pixels(0, y), wid * 3
            Next y

        Case 32
            For y = 0 To hgt - 1
                For x = 0 To wid - 1
                    With pixels(x, y)
                        bytes(x * 4, y) = .rgbBlue
                        bytes(x * 4 + 1, y) = .rgbGreen
                        bytes(x * 4 + 2, y) = .rgbRed
                    End With
                Next x
            Next y

    End Select

    ' Set the picture's bitmap bits.
    SetBitmapBits pic.Image, wid_bytes * hgt, _
        bytes(0, 0)
    pic.Refresh
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStop(sRoutineName)                                                                                    '<FOTA_ScreenSaver_Life_ADDER>
    Exit Sub                                                                                               '<FOTA_ScreenSaver_Life_ADDER>
ErrorHandler:                                                                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.HandleErrorWithSource(Err, sRoutineName)                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.DisplayErrorCount                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
End Sub

' Return the arctan of dy/dx.
Public Function ATan2(ByVal dy As Single, ByVal dX As Single) As Single
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    On Error GoTo ErrorHandler                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    Dim sRoutineName As String                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    sRoutineName = "Life." & m_cFRMNAME & ".ATan2"                                                           '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStart(sRoutineName)                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
Const PI = 3.14159265

Dim theta As Single

    If Abs(dX) < 0.01 Then
        If dy < 0 Then
            theta = -PI / 2
        Else
            theta = PI / 2
        End If
    Else
        theta = Atn(dy / dX)
        If dX < 0 Then theta = PI + theta
    End If

    ATan2 = theta
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStop(sRoutineName)                                                                                    '<FOTA_ScreenSaver_Life_ADDER>
    Exit Function                                                                                               '<FOTA_ScreenSaver_Life_ADDER>
ErrorHandler:                                                                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.HandleErrorWithSource(Err, sRoutineName)                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.DisplayErrorCount                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
End Function

' Rotate the image.
Public Sub MakeMask(ByVal pic_from As PictureBox, ByVal pic_to As PictureBox)
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    On Error GoTo ErrorHandler                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    Dim sRoutineName As String                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    sRoutineName = "Life." & m_cFRMNAME & ".MakeMask"                                                           '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStart(sRoutineName)                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>

    Dim white_pixel As RGBTriplet
    Dim black_pixel As RGBTriplet
    Dim input_pixels() As RGBTriplet
    Dim result_pixels() As RGBTriplet
    Dim bits_per_pixel As Integer
    Dim ix_out As Integer, iy_out As Integer

    white_pixel.rgbRed = 255
    white_pixel.rgbGreen = 255
    white_pixel.rgbBlue = 255
    
    black_pixel.rgbRed = 0
    black_pixel.rgbGreen = 0
    black_pixel.rgbBlue = 0

    'Get the pixels from pic_from.
    Call GetBitmapPixels(pic_from, input_pixels, bits_per_pixel)
    'Get the pixels from pic_to.
    Call GetBitmapPixels(pic_to, result_pixels, bits_per_pixel)

    ' Calculate the output pixel values.
    For iy_out = 0 To pic_from.ScaleHeight - 1
        For ix_out = 0 To pic_from.ScaleWidth - 1
            If input_pixels(ix_out, iy_out).rgbBlue = black_pixel.rgbBlue And _
               input_pixels(ix_out, iy_out).rgbGreen = black_pixel.rgbGreen And _
               input_pixels(ix_out, iy_out).rgbRed = black_pixel.rgbRed Then
                    result_pixels(ix_out, iy_out) = white_pixel
            Else
                    result_pixels(ix_out, iy_out) = black_pixel
            End If
        Next ix_out
    Next iy_out

    ' Set pic_to's pixels.
    Call SetBitmapPixels(pic_to, bits_per_pixel, result_pixels)
    pic_to.Picture = pic_to.Image
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStop(sRoutineName)                                                                                    '<FOTA_ScreenSaver_Life_ADDER>
    Exit Sub                                                                                               '<FOTA_ScreenSaver_Life_ADDER>
ErrorHandler:                                                                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.HandleErrorWithSource(Err, sRoutineName)                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.DisplayErrorCount                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
End Sub

' Rotate the image.
Public Sub RotateImage(ByVal pic_from As PictureBox, ByVal pic_to As PictureBox, ByVal angle As Single, Optional nRGBNullColor As Long = -1)
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    On Error GoTo ErrorHandler                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    Dim sRoutineName As String                                                                                          '<FOTA_ScreenSaver_Life_ADDER>
    sRoutineName = "Life." & m_cFRMNAME & ".RotateImage"                                                           '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStart(sRoutineName)                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>

    Dim white_pixel As RGBTriplet
    Dim input_pixels() As RGBTriplet
    Dim result_pixels() As RGBTriplet
    Dim bits_per_pixel As Integer
    Dim xmax_in As Integer, ymax_in As Integer
    Dim CxIn As Single, CyIn As Single
    Dim CxOut As Single, CyOut As Single
    Dim x_in As Single, y_in As Single
    Dim ix_in As Integer, iy_in As Integer
    Dim ix_out As Integer, iy_out As Integer
    Dim dX As Single, dy As Single
    Dim radius As Single
    Dim theta As Single
    Dim dx1 As Single, dx2 As Single
    Dim dy1 As Single, dy2 As Single
    Dim v11 As Integer, v12 As Integer
    Dim v21 As Integer, v22 As Integer
    Dim nRed As Long, nBlue As Long, nGreen As Long

    With white_pixel
        If nRGBNullColor = -1 Then
            'Set the white pixel's value.
            .rgbRed = 255
            .rgbGreen = 255
            .rgbBlue = 255
        Else
            Call clsFunctions.RGBToRedGreenBlue(nRGBNullColor, nRed, nGreen, nBlue)
            .rgbRed = nRed
            .rgbBlue = nBlue
            .rgbGreen = nGreen
        End If
    End With

    ' Get the pixels from pic_from.
    GetBitmapPixels pic_from, input_pixels, bits_per_pixel

    ' Get the pixels from pic_to.
    GetBitmapPixels pic_to, result_pixels, bits_per_pixel

    ' Get the centers of both images.
    CxIn = pic_from.ScaleWidth / 2
    CyIn = pic_from.ScaleHeight / 2
    CxOut = pic_to.ScaleWidth / 2
    CyOut = pic_to.ScaleHeight / 2

    ' Get the size of the original image.
    xmax_in = pic_from.ScaleWidth - 1
    ymax_in = pic_from.ScaleHeight - 1

    ' Calculate the output pixel values.
    For iy_out = 0 To pic_to.ScaleHeight - 1
        For ix_out = 0 To pic_to.ScaleWidth - 1
            ' Map the pixel value from
            ' (ix_out, iy_out) to (x_in, y_in).
            dX = ix_out - CxOut
            dy = iy_out - CyOut
            radius = Sqr(dX * dX + dy * dy)
            theta = ATan2(dy, dX)
            x_in = CxIn + radius * Cos(theta + angle)
            y_in = CyIn + radius * Sin(theta + angle)

            ' Find the nearest integral position.
            ix_in = Int(x_in)
            iy_in = Int(y_in)

            ' See if this is in bounds.
            If (ix_in >= 0) And (ix_in < xmax_in) And _
               (iy_in >= 0) And (iy_in < ymax_in) _
            Then
                ' The point lies within the image.
                ' Calculate its value.
                dx1 = x_in - ix_in
                dy1 = y_in - iy_in
                dx2 = 1# - dx1
                dy2 = 1# - dy1

                With result_pixels(ix_out, iy_out)
                    ' Calculate the red value.
                    v11 = input_pixels(ix_in, iy_in).rgbRed
                    v12 = input_pixels(ix_in, iy_in + 1).rgbRed
                    v21 = input_pixels(ix_in + 1, iy_in).rgbRed
                    v22 = input_pixels(ix_in + 1, iy_in + 1).rgbRed

                    .rgbRed = _
                        v11 * dx2 * dy2 + v12 * dx2 * dy1 + _
                        v21 * dx1 * dy2 + v22 * dx1 * dy1

                    ' Calculate the green value.
                    v11 = input_pixels(ix_in, iy_in).rgbGreen
                    v12 = input_pixels(ix_in, iy_in + 1).rgbGreen
                    v21 = input_pixels(ix_in + 1, iy_in).rgbGreen
                    v22 = input_pixels(ix_in + 1, iy_in + 1).rgbGreen
                    .rgbGreen = _
                        v11 * dx2 * dy2 + v12 * dx2 * dy1 + _
                        v21 * dx1 * dy2 + v22 * dx1 * dy1

                    ' Calculate the blue value.
                    v11 = input_pixels(ix_in, iy_in).rgbBlue
                    v12 = input_pixels(ix_in, iy_in + 1).rgbBlue
                    v21 = input_pixels(ix_in + 1, iy_in).rgbBlue
                    v22 = input_pixels(ix_in + 1, iy_in + 1).rgbBlue
                    .rgbBlue = _
                        v11 * dx2 * dy2 + v12 * dx2 * dy1 + _
                        v21 * dx1 * dy2 + v22 * dx1 * dy1
                End With
            Else
                ' The point is outside the image.
                ' Use white.
                result_pixels(ix_out, iy_out) = white_pixel
            End If
        Next ix_out
    Next iy_out

    ' Set pic_to's pixels.
    SetBitmapPixels pic_to, bits_per_pixel, result_pixels
    pic_to.Picture = pic_to.Image
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
    Call WriteProcStop(sRoutineName)                                                                                    '<FOTA_ScreenSaver_Life_ADDER>
    Exit Sub                                                                                               '<FOTA_ScreenSaver_Life_ADDER>
ErrorHandler:                                                                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.HandleErrorWithSource(Err, sRoutineName)                                                           '<FOTA_ScreenSaver_Life_ADDER>
     Call g_oErrors.DisplayErrorCount                                                                                   '<FOTA_ScreenSaver_Life_ADDER>
                                                                                                                        '<FOTA_ScreenSaver_Life_ADDER>
End Sub
