I have an Access app that allows a user to click a button to FTP a file from the network out to one of our Unix servers. What I need is a way to make sure the FTP process was successful. I was able to find this ShellAnd Wait function but it doesn't seem to be working. I've tested it by intentionally giving the incorrect server for the FTP process and I expected it to fail and give me an error. It is instead returning a code = 0 which is wrong.

Code:
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function IsWindow Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long

Private Const STILL_ACTIVE = &H103
Private Const PROCESS_QUERY_INFORMATION = &H400
Private Const SYNCHRONIZE = &H100000

Public Const WAIT_FAILED = -1&        'Error on call
Public Const WAIT_OBJECT_0 = 0        'Normal completion
Public Const WAIT_ABANDONED = &H80&   '
Public Const WAIT_TIMEOUT = &H102&    'Timeout period elapsed
Public Const IGNORE = 0               'Ignore signal
Public Const INFINITE = -1&           'Infinite timeout

Public Const SW_HIDE = 0
Public Const SW_SHOWNORMAL = 1
Public Const SW_SHOWMINIMIZED = 2
Public Const SW_SHOWMAXIMIZED = 3
Public Const SW_SHOWNOACTIVATE = 4
Public Const SW_SHOW = 5
Public Const SW_MINIMIZE = 6
Public Const SW_SHOWMINNOACTIVE = 7
Public Const SW_SHOWNA = 8
Public Const SW_RESTORE = 9

Private Const WM_CLOSE = &H10
Private Const GW_HWNDNEXT = 2
Private Const GW_OWNER = 4

Public Function ShellAndWait(ByVal JobToDo As String, Optional ExecMode, Optional TimeOut) As Long
   '
   ' Shells a new process and waits for it to complete.
   ' Calling application is totally non-responsive while
   ' new process executes.
   '
   Dim ProcessID As Long
   Dim hProcess As Long
   Dim nRet As Long
   Const fdwAccess = SYNCHRONIZE

   If IsMissing(ExecMode) Then
      ExecMode = vbMinimizedNoFocus
   Else
      If ExecMode < vbHide Or ExecMode > vbMinimizedNoFocus Then
         ExecMode = vbMinimizedNoFocus
      End If
   End If

   On Error Resume Next
      ProcessID = Shell(JobToDo, CLng(ExecMode))
      If Err Then
         ShellAndWait = vbObjectError + Err.Number
         Exit Function
      End If
   On Error GoTo 0

   If IsMissing(TimeOut) Then
      TimeOut = INFINITE
   End If

   hProcess = OpenProcess(fdwAccess, False, ProcessID)
   nRet = WaitForSingleObject(hProcess, CLng(TimeOut))
   MsgBox (nRet)
   Call CloseHandle(hProcess)

   Select Case nRet
      Case WAIT_TIMEOUT: Debug.Print "Timed out!"
      Case WAIT_OBJECT_0: Debug.Print "Normal completion."
      Case WAIT_ABANDONED: Debug.Print "Wait Abandoned!"
      Case WAIT_FAILED: Debug.Print "Wait Error:"; Err.LastDllError
   End Select
   ShellAndWait = nRet
End Function
And here's my code, and the code I use to call it:

Call UploadFTPFile("\\serverAAA\Access\Batch\test\steve .dat", "serverxyz", "\\Projects\NATS Project\Working Documents\Access\Batch\test\", "/opt/manu/natt1/scripts/Users", "/opt/manu/natt1/scripts/Users/steve.dat", "manuftp", "passwd")
Code:
Public Function UploadFTPFile(ByVal sFile As String, _
                                      sSVR As String, _
                                      sFLD As String, _
                                      sDEST As String, _
                                      sTARGET As String, _
                                      sUID As String, _
                                      sPWD As String) As String
   Dim sLocalFLD As String
   Dim sScrFile As String
   Dim iFile As Integer
   Dim sExe As String
   Const q As String = """"
   On Error GoTo Err_Handler
   
   ' The scr file will contain the FTP commands
   ' (If it exists from previous run, delete it)
   sScrFile = sFLD & "ftpfile.scr"

   If dir(sScrFile) <> "" Then Kill sScrFile
   
   iFile = FreeFile
   
   Open sScrFile For Output As iFile
   Print #iFile, "open " & sSVR
   Print #iFile, sUID
   Print #iFile, sPWD
   Print #iFile, "cd " & sDEST
   Print #iFile, "binary"
   Print #iFile, "put " & sFile & " " & sTARGET
   Print #iFile, "bye"
   Close #iFile
   sExe = Environ$("COMSPEC")
   sExe = Left$(sExe, Len(sExe) - Len(dir(sExe)))
   'sExe = sExe & "ftp.exe -s:" & q & sScrFile & q
    
   Dim nRet As Long
   
   nRet = ShellAndWait(sExe & "ftp.exe -s:" & q & sScrFile & q, vbNormalFocus)
   MsgBox ("The FTP has completed and the return code = " & nRet)

   DoEvents
  
Exit_Here:
   Exit Function
Err_Handler:
   MsgBox Err.Description, vbExclamation, "E R R O R"
   Resume Exit_Here
End Function