home *** CD-ROM | disk | FTP | other *** search
/ Planet Source Code Jumbo …e CD Visual Basic 1 to 7 / 1_2002.ISO / Data / Zips / CODE_UPLOAD170663142001.psc / basFileFunction.bas next >
Encoding:
BASIC Source File  |  2001-03-15  |  18.2 KB  |  474 lines

  1. Attribute VB_Name = "basFileFunctions"
  2. '----------------------------------------------------------------------------------------'
  3. '
  4. ' Multi Downloader using multithreadings
  5. ' Created by Suk Yong Kim, 03/14/2001
  6. '
  7. ' This project is my first project to upload to the PSC.
  8. ' Many persons contribute to create this project
  9. ' I really appreicate their efforts and codes and the great server PSC.
  10. '
  11. ' if any question, mail to : techtrans@dreamwiz.com
  12. '----------------------------------------------------------------------------------------'
  13.  
  14.  
  15. Option Explicit
  16.  
  17. Private Declare Function GetLogicalDriveStrings _
  18.      Lib "kernel32" Alias "GetLogicalDriveStringsA" _
  19.     (ByVal nBufferLength As Long, _
  20.      ByVal lpBuffer As String) As Long
  21.  
  22. Private Declare Function GetDriveType _
  23.      Lib "kernel32" Alias "GetDriveTypeA" _
  24.     (ByVal nDrive As String) As Long
  25.     
  26. Private Const DRIVE_REMOVABLE = 2
  27. Private Const DRIVE_FIXED = 3
  28. Private Const DRIVE_REMOTE = 4
  29. Private Const DRIVE_CDROM = 5
  30. Private Const DRIVE_RAMDISK = 6
  31.  
  32. ' Structures
  33. Private Type SHFILEOPSTRUCT
  34.     hwnd As Long
  35.     wFunc As Long
  36.     pFrom As String
  37.     pTo As String
  38.     fFlags As Integer
  39.     fAnyOperationsAborted As Long
  40.     hNameMappings As Long
  41.     lpszProgressTitle As Long
  42. End Type
  43.  
  44. ' API
  45. Private Declare Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As Long
  46.  
  47. ' Contants
  48. Private Const FO_DELETE = &H3
  49. Private Const FOF_ALLOWUNDO = &H40
  50. Private Const FOF_NOCONFIRMATION = &H10 ' Responds with "yes to all" for any dialog box that is displayed.
  51. Private Const FOF_SILENT = &H4
  52.  
  53. Public Type BROWSEINFOTYPE
  54.     hOwner As Long
  55.     pidlRoot As Long
  56.     pszDisplayName As String
  57.     lpszTitle As String
  58.     ulFlags As Long
  59.     lpfn As Long
  60.     lParam As Long
  61.     iImage As Long
  62. End Type
  63.  
  64. Private Declare Function SHBrowseForFolder Lib "shell32.dll" Alias "SHBrowseForFolderA" (lpBROWSEINFOTYPE As BROWSEINFOTYPE) As Long
  65. Private Declare Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" (ByVal pidl As Long, ByVal pszPath As String) As Long
  66. Private Declare Sub CoTaskMemFree Lib "ole32.dll" (ByVal pv As Long)
  67. Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
  68. Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal dwLength As Long)
  69.  
  70. Private Const WM_USER = &H400
  71.  
  72. Private Const BFFM_SETSELECTIONA As Long = (WM_USER + 102)
  73. Private Const BFFM_SETSELECTIONW As Long = (WM_USER + 103)
  74. Private Declare Function LocalAlloc Lib "kernel32" (ByVal uFlags As Long, ByVal uBytes As Long) As Long
  75. Private Declare Function LocalFree Lib "kernel32" (ByVal hMem As Long) As Long
  76. Private Const LPTR = (&H0 Or &H40)
  77. Declare Function ShellExecute Lib "shell32.dll" _
  78.     Alias "ShellExecuteA" (ByVal hwnd As Long, _
  79.     ByVal lpOperation As String, _
  80.     ByVal lpFile As String, _
  81.     ByVal lpParameters As String, _
  82.     ByVal lpDirectory As String, _
  83.     ByVal nShowCmd As Long) As Long
  84.     
  85. Function ftnRunAnyFile(strFilePathName As String) As Long
  86.     On Error Resume Next
  87.     ftnRunAnyFile = ShellExecute(0, "open", strFilePathName, vbNullString, vbNullString, 1)
  88. End Function
  89.  
  90. Private Function BrowseCallbackProcStr(ByVal hwnd As Long, ByVal uMsg As Long, ByVal lParam As Long, ByVal lpData As Long) As Long
  91. If uMsg = 1 Then
  92.     Call SendMessage(hwnd, BFFM_SETSELECTIONA, True, ByVal lpData)
  93. End If
  94. End Function
  95.  
  96. Private Function FunctionPointer(FunctionAddress As Long) As Long
  97. FunctionPointer = FunctionAddress
  98. End Function
  99.  
  100. Public Function BrowseForFolder(startPath As String, Optional ByVal strTitle As String) As String
  101. Dim Browse_for_folder As BROWSEINFOTYPE
  102. Dim itemID As Long
  103. Dim selectedPathPointer As Long
  104. Dim tmpPath As String * 256
  105. Dim selectedPath As String
  106.  
  107. selectedPath = startPath ' Take the selected path from startPath
  108. If Len(selectedPath) > 0 Then
  109.     If Not Right$(selectedPath, 1) <> "\" Then selectedPath = Left$(selectedPath, Len(selectedPath) - 1) ' Remove "\" if the user added
  110. End If
  111.  
  112. With Browse_for_folder
  113.     .hOwner = 0 ' Window Handle
  114.     If Len(strTitle) > 0 Then
  115.         .lpszTitle = strTitle ' Dialog Title
  116.     Else
  117.         .lpszTitle = "Please, Select a folder."
  118.     End If
  119.     .lpfn = FunctionPointer(AddressOf BrowseCallbackProcStr) ' Dialog callback function that preselectes the folder specified
  120.     selectedPathPointer = LocalAlloc(LPTR, Len(selectedPath) + 1) ' Allocate a string
  121.     CopyMemory ByVal selectedPathPointer, ByVal selectedPath, Len(selectedPath) + 1 ' Copy the path to the string
  122.     .lParam = selectedPathPointer ' The folder to preselect
  123. End With
  124. itemID = SHBrowseForFolder(Browse_for_folder) ' Execute the BrowseForFolder API
  125. If itemID Then
  126.     If SHGetPathFromIDList(itemID, tmpPath) Then ' Get the path for the selected folder in the dialog
  127.         BrowseForFolder = Left$(tmpPath, InStr(tmpPath, vbNullChar) - 1) ' Take only the path without the nulls
  128.     End If
  129.     Call CoTaskMemFree(itemID) ' Free the itemID
  130. End If
  131. Call LocalFree(selectedPathPointer) ' Free the string from the memory
  132. End Function
  133.  
  134. Public Sub fnMoveToRecycleBin(FileName As String, _
  135.     Optional Confirm As Boolean = False, Optional Silent As Boolean = True)
  136.     If Not fnFileExists(FileName) Then Exit Sub 'if file not exists exit sub
  137.     Dim FileOp As SHFILEOPSTRUCT
  138.     On Error GoTo bye
  139.     'fills the file operation structure
  140.     With FileOp
  141.         .wFunc = FO_DELETE
  142.         .pFrom = FileName
  143.         .fFlags = FOF_ALLOWUNDO
  144.         If Not Confirm Then .fFlags = .fFlags + FOF_NOCONFIRMATION
  145.         If Silent Then .fFlags = .fFlags + FOF_SILENT
  146.     End With
  147.     SHFileOperation FileOp
  148. bye:
  149. End Sub
  150.  
  151. Function fnFolderExists(ByVal strFolderFullName As String) As Boolean
  152.     Dim FSO As Object
  153.     Dim ThisFolder As Object
  154.     Set FSO = CreateObject("Scripting.FileSystemObject")
  155.     fnFolderExists = FSO.folderexists(strFolderFullName)
  156.     
  157.     Set FSO = Nothing
  158.     Set ThisFolder = Nothing
  159. End Function
  160.  
  161. Function fnCreateSubFolder(ByVal strParentFolder As String, ByVal strFolderToCreate As String) As Boolean
  162.     Dim FSO As Object
  163.     Dim ThisFolder As Object
  164.     On Error GoTo bye
  165.     strParentFolder = fnGetPathRemoveEndDelimeter(strParentFolder)
  166.     Set FSO = CreateObject("Scripting.FileSystemObject")
  167.     If fnFolderExists(strParentFolder) Then
  168.         If fnFolderExists(strParentFolder & "\" & strFolderToCreate) = False Then
  169.             Set ThisFolder = FSO.CreateFolder(strParentFolder & "\" & strFolderToCreate)
  170.         End If
  171.         fnCreateSubFolder = True
  172.     Else
  173.         fnCreateSubFolder = False
  174.     End If
  175.     Set FSO = Nothing
  176.     Set ThisFolder = Nothing
  177.     
  178.     Exit Function
  179. bye:
  180.     Set FSO = Nothing
  181.     Set ThisFolder = Nothing
  182. End Function
  183. Function fnCreateFolder(ByVal strFolderToCreate As String) As Boolean
  184.     strFolderToCreate = fnGetPathRemoveEndDelimeter(strFolderToCreate)
  185.     If fnFolderExists(strFolderToCreate) Then fnCreateFolder = True: Exit Function
  186.     Dim vFolder As Variant
  187.     Dim vFolders As Variant
  188.     Dim i As Integer
  189.     vFolders = Split(strFolderToCreate, "\")
  190.     Dim sParentFolder As String
  191.     On Error GoTo Error_Drive
  192.     For Each vFolder In vFolders
  193.         If i = 0 Then
  194.             sParentFolder = CStr(vFolder)
  195.         ElseIf Len(CStr(vFolder)) Then
  196.             fnCreateFolder = fnCreateSubFolder(sParentFolder, CStr(vFolder))
  197.             sParentFolder = sParentFolder & "\" & CStr(vFolder)
  198.         End If
  199.         i = i + 1
  200.     Next
  201. bye:
  202.     Exit Function
  203. Error_Drive:
  204.     fnCreateFolder = False
  205.     MsgBox "No Drive! Creating folder is aborted!"
  206. End Function
  207.  
  208. Function fnGetParentFolder(strFolder As String, Optional IsAttachDelimeter As Boolean) As String
  209.     Dim Delimeter As String
  210.     Delimeter = IIf(InExists(strFolder, "\"), "\", "/")
  211.     fnGetParentFolder = BeforeRev(fnGetPathRemoveEndDelimeter(strFolder), Delimeter)
  212.     If IsAttachDelimeter Then fnGetParentFolder = fnGetParentFolder & Delimeter
  213. End Function
  214. Function fnGetNetPath(ByVal strPath As String, Optional IsAttachPathDelimeter As Boolean) As String
  215.     Dim tmpParent  As String
  216.     fnGetNetPath = fnGetPathRemoveEndDelimeter(strPath)
  217.     fnGetNetPath = fnGetParentFolder(fnGetNetPath, True)
  218.     fnGetNetPath = Replace(strPath, fnGetNetPath, "")
  219.     If Not IsAttachPathDelimeter Then fnGetNetPath = mID(fnGetNetPath, 1, Len(fnGetNetPath) - 1)
  220. End Function
  221.  
  222.  
  223. Function fnFileExists(strURL As String) As Boolean
  224.     Dim IsWebURL As Boolean
  225. '    If fnIsURL(strURL, , , IsWebURL) Then
  226.             Dim FSO As Object
  227.             Dim ThisFile As Object
  228.             Set FSO = CreateObject("Scripting.FileSystemObject")
  229.             fnFileExists = FSO.FileExists(strURL)
  230.             Set FSO = Nothing
  231.             Set ThisFile = Nothing
  232. '    End If
  233. End Function
  234.  
  235.  
  236. Public Function fnIsURL(strURL As String, _
  237.         Optional strRtnNetURL As String, Optional IsRootPath As Boolean, _
  238.         Optional IsWebURL As Boolean, Optional Protocol As String, _
  239.         Optional IsConvertPathDelimeter As Boolean, _
  240.         Optional PathDelimeter As String) As Boolean
  241.         
  242.     Dim pos As Long
  243.     
  244.     fnIsURL = True
  245.     
  246.     If InExists(strURL, "http:///", 1, pos) Then
  247.         Protocol = "http:///"
  248.         IsWebURL = False
  249.         fnIsURL = False
  250.     ElseIf InExists(strURL, "http://", 1, pos) Then
  251.         Protocol = "http://"
  252.         IsWebURL = IIf(pos = 1, True, False)
  253.         If IsWebURL Then strRtnNetURL = mID(strURL, pos + 7)
  254.     ElseIf InExists(strURL, "ftp://", 1, pos) Then
  255.         Protocol = "ftp://"
  256.         IsWebURL = IIf(pos = 1, True, False)
  257.         If IsWebURL Then strRtnNetURL = mID(strURL, pos + 6)
  258.     ElseIf InExists(strURL, "pnm://", 1, pos) Then
  259.         Protocol = "pnm://"
  260.         IsWebURL = IIf(pos = 1, True, False)
  261.         If IsWebURL Then strRtnNetURL = mID(strURL, pos + 6)
  262.     ElseIf InExists(strURL, "mms://", 1, pos) Then
  263.         Protocol = "mms://"
  264.         IsWebURL = IIf(pos = 1, True, False)
  265.         If IsWebURL Then strRtnNetURL = mID(strURL, pos + 6)
  266.     ElseIf InExists(strURL, "rtsp://", 1, pos) Then
  267.         Protocol = "rtsp://"
  268.         IsWebURL = IIf(pos = 1, True, False)
  269.         If IsWebURL Then strRtnNetURL = mID(strURL, pos + 7)
  270.     ElseIf InExists(strURL, "file:///", 1, pos) Then
  271. '        Protocol = "file:///"
  272.         IsWebURL = IIf(pos = 1, False, True)
  273.         If Not IsWebURL Then strRtnNetURL = mID(strURL, pos + 8)
  274.     ElseIf InExists(strURL, "file://", 1, pos) Then
  275. '        Protocol = "file://"
  276.         IsWebURL = IIf(pos = 1, False, True)
  277.         If Not IsWebURL Then strRtnNetURL = mID(strURL, pos + 7)
  278.     ElseIf InExists(strURL, "file:", 1, pos) Then
  279. '        Protocol = "file:"
  280.         IsWebURL = IIf(pos = 1, False, True)
  281.         If Not IsWebURL Then strRtnNetURL = mID(strURL, pos + 5)
  282.     ElseIf Len(strURL) >= 3 Then
  283.         IsWebURL = False
  284.         If InExists(fnGetDriveString, Left(strURL, 3)) Then
  285.             strRtnNetURL = strURL
  286.         Else
  287.             fnIsURL = False
  288.         End If
  289.     Else
  290.         IsWebURL = False
  291.         fnIsURL = False
  292.     End If
  293.     
  294.     If fnIsURL Then
  295.         If Len(PathDelimeter) = 0 Then PathDelimeter = IIf(IsWebURL, "/", "\")
  296.         strRtnNetURL = Replace(strRtnNetURL, "?", PathDelimeter)
  297.         strRtnNetURL = ReplaceSCharsInURL(strRtnNetURL)
  298.         If IsConvertPathDelimeter Then
  299.             strRtnNetURL = Replace(strRtnNetURL, "/", PathDelimeter)
  300.             strRtnNetURL = Replace(strRtnNetURL, "\", PathDelimeter)
  301.         ElseIf Not IsWebURL Then
  302.             strRtnNetURL = Replace(strRtnNetURL, "/", PathDelimeter)
  303.         End If
  304.         
  305.         If InCount(strRtnNetURL, PathDelimeter) = 0 Then
  306.             IsRootPath = True
  307.         ElseIf InCount(strRtnNetURL, PathDelimeter) = 1 Then
  308.             If Right(strRtnNetURL, 1) = PathDelimeter Then IsRootPath = True
  309.         End If
  310.     End If
  311.     
  312. End Function
  313. Private Function ReplaceSCharsInURL(ByVal strURL As String) As String
  314.     strURL = Replace(strURL, "&", "&")
  315.     strURL = Replace(strURL, "%20", Space(1))
  316.     ReplaceSCharsInURL = strURL
  317. End Function
  318.  
  319. Function fnIsRootPath(strURL As String, Optional strRtnRootPath As String, _
  320.     Optional NetURL As String, Optional IsAttachProtocol As Boolean = True, Optional Protocol As String, _
  321.     Optional IsAttachPathDelimeter As Boolean, Optional PathDelimeter As String) As Boolean
  322.     
  323.     Dim IsRootPath As Boolean
  324.     strRtnRootPath = fnGetRootPath(strURL, NetURL, IsAttachProtocol, Protocol, IsAttachPathDelimeter, PathDelimeter, IsRootPath)
  325.     fnIsRootPath = IsRootPath
  326. End Function
  327.  
  328. Function fnGetRootPath(strURL As String, Optional NetURL As String, _
  329.     Optional IsAttachProtocol As Boolean = True, Optional Protocol As String, _
  330.     Optional IsAttachPathDelimeter As Boolean, Optional PathDelimeter As String, _
  331.     Optional IsRootPath As Boolean) As String
  332.     
  333.     Dim IsWebURL As Boolean
  334.  
  335.     If fnIsURL(strURL, NetURL, IsRootPath, IsWebURL, Protocol, IsAttachPathDelimeter, PathDelimeter) Then
  336.         Dim pos As Long
  337.         If InExists(NetURL, PathDelimeter, , pos) Then
  338.             fnGetRootPath = mID(NetURL, 1, pos - 1)
  339.         Else
  340.             fnGetRootPath = NetURL
  341.         End If
  342.         If IsAttachProtocol Then fnGetRootPath = Protocol & fnGetRootPath
  343.         If IsAttachPathDelimeter Then fnGetRootPath = fnGetRootPath & PathDelimeter
  344.     End If
  345. End Function
  346. Function fnGetPath(strURL As String, Optional IsAttachPathDelimeter As Boolean, _
  347.     Optional IsAttachProtocol As Boolean = True, _
  348.     Optional IsRootPath As Boolean, _
  349.     Optional strRtnRootPath As String) As String
  350.     
  351.     Dim NetURL As String
  352.     Dim Protocol As String
  353.     Dim PathDelimeter As String
  354.     
  355.     IsRootPath = fnIsRootPath(strURL, strRtnRootPath, NetURL, IsAttachProtocol, Protocol, IsAttachPathDelimeter, PathDelimeter)
  356.     If IsRootPath Then
  357.         fnGetPath = strRtnRootPath
  358.     Else
  359.         Dim pos As Long
  360.         If InExistsRev(NetURL, PathDelimeter, , pos) Then
  361.             fnGetPath = mID(NetURL, 1, pos - 1)
  362.         End If
  363.         If IsAttachProtocol Then fnGetPath = Protocol & fnGetPath
  364.         If IsAttachPathDelimeter Then fnGetPath = fnGetPath & PathDelimeter
  365.     End If
  366. End Function
  367.  
  368.  
  369. Function fnGetFileName(strURL As String, Optional IsReturnIndexHtmlIfRootPath As Boolean) As String
  370.     If fnIsRootPath(strURL) Then
  371.          If IsReturnIndexHtmlIfRootPath Then fnGetFileName = "index.html"
  372.     Else
  373.         Dim ii As Integer
  374.         Dim pos As Integer
  375.         For ii = Len(strURL) To 1 Step -1
  376.             If mID(strURL, ii, 1) = "/" Or mID(strURL, ii, 1) = "?" Or mID(strURL, ii, 1) = "\" Then
  377.                 fnGetFileName = Right(strURL, Len(strURL) - ii)
  378.                 Exit For
  379.             End If
  380.         Next ii
  381.         If Len(fnGetFileName) = 0 And IsReturnIndexHtmlIfRootPath Then
  382.             fnGetFileName = "index.html"
  383.         ElseIf Not InExistsRev(fnGetFileName, ".") And IsReturnIndexHtmlIfRootPath Then
  384.             fnGetFileName = fnGetFileName & ".html"
  385.         End If
  386.     End If
  387. End Function
  388.  
  389.  
  390. Function fnGetNetFileName(strURL As String, Optional Prefix As String, Optional IsReturnIndexHtmlIfRootPath As Boolean) As String
  391.     Dim pos As Long
  392.     If fnIsURL(strURL) Then
  393.         fnGetNetFileName = fnGetFileName(strURL, IsReturnIndexHtmlIfRootPath)
  394.         If InExistsRev(fnGetNetFileName, ".", , pos) Then
  395.             fnGetNetFileName = Prefix & mID(fnGetNetFileName, 1, pos - 1)
  396.         End If
  397.     Else
  398.         If InExistsRev(strURL, ".", , pos) Then
  399.             fnGetNetFileName = Prefix & mID(strURL, 1, pos - 1)
  400.         Else
  401.             fnGetNetFileName = Prefix & strURL
  402.         End If
  403.     End If
  404. End Function
  405. Function fnGetExtension(strURL As String, Optional PrefixBeforeDot As String, _
  406.             Optional IsReturnIndexHtmlIfRootPath As Boolean) As String
  407.     Dim pos As Long
  408.     If fnIsURL(strURL) Then
  409.          fnGetExtension = fnGetFileName(strURL, IsReturnIndexHtmlIfRootPath)
  410.     Else
  411.         fnGetExtension = strURL
  412.     End If
  413.     If InExistsRev(fnGetExtension, ".", , pos) Then
  414.         fnGetExtension = mID(fnGetExtension, pos + 1)
  415.     Else
  416.         fnGetExtension = "html"
  417.     End If
  418.     If Len(PrefixBeforeDot) Then fnGetExtension = PrefixBeforeDot & "." & fnGetExtension
  419. End Function
  420.  
  421. Function fnGetPathRemoveEndDelimeter(strPath As String) As String
  422.     If Len(strPath) Then
  423.         If Right(strPath, 1) = "/" Or Right(strPath, 1) = "?" Or Right(strPath, 1) = "\" Then
  424.             fnGetPathRemoveEndDelimeter = mID(strPath, 1, Len(strPath) - 1)
  425.         Else
  426.             fnGetPathRemoveEndDelimeter = strPath
  427.         End If
  428.     End If
  429. End Function
  430. Function fnGetPortNum(ByVal strURL As String) As String
  431.     fnGetPortNum = After(fnGetRootPath(strURL, , False), ":")
  432. End Function
  433.  
  434. Public Function fnGetDriveString() As String
  435.   'returns string of available
  436.   'drives each separated by a null
  437.    Dim sBuffer As String
  438.   'possible 26 drives, three characters each
  439.    sBuffer = Space$(26 * 3)
  440.   If GetLogicalDriveStrings(Len(sBuffer), sBuffer) Then
  441.      'do not trim off trailing null!
  442.       fnGetDriveString = Trim$(sBuffer)
  443.    End If
  444. End Function
  445.  
  446. Function fnGetShortName(sFilePathName As String, Optional MaxLen As Integer = 80) As String
  447.     Dim Path As String
  448.     Dim RootPath As String
  449.     Dim Delimeter As String
  450.     Dim tmpName As String
  451.     Dim FileName As String
  452.     Dim Extension As String
  453.     Dim strNetURL As String
  454.     
  455.     If Len(sFilePathName) <= MaxLen Then
  456.         fnGetShortName = sFilePathName: Exit Function
  457.     End If
  458.     
  459.     Delimeter = IIf(InExists(sFilePathName, "\"), "\", "/")
  460.     Call fnIsRootPath(sFilePathName, RootPath, strNetURL)
  461.     If InCount(strNetURL, Delimeter) <= 2 Then fnGetShortName = sFilePathName: Exit Function
  462.     FileName = fnGetFileName(sFilePathName)
  463.     If Len(FileName) Then ' is file
  464.         Path = Delimeter & fnGetNetPath(fnGetPath(sFilePathName, True), True) & FileName
  465.     Else 'is folder
  466.         Path = Delimeter & fnGetNetPath(fnGetParentFolder(Path, True), True) & fnGetNetPath(sFilePathName, True)
  467.     End If
  468.     If Len(Path) > 50 Then
  469.         fnGetShortName = RootPath & Delimeter & "..." & Right(Path, 50)
  470.     Else
  471.         fnGetShortName = RootPath & Delimeter & "..." & Path
  472.     End If
  473. End Function
  474.