更换FTP服务器后VB6代码无法上传文件求助(FtpOpenFile返回0)
Let's break down your issue and walk through the most likely fixes based on your code and the working ExtraFTP log.
First, the key observation: your code creates an empty file on the new server but can't get a valid handle via FtpOpenFile—this suggests the initial file creation works, but the data connection or write permissions are failing. Let's compare your code to the successful ExtraFTP session and fix the gaps.
Step 1: Capture the Exact Error Code
First, let's get specific details on why FtpOpenFile is returning 0. Add the GetLastError declaration and capture the error when it fails—this will give us concrete clues:
Private Declare Function GetLastError Lib "kernel32" () As Long ' Inside your UploadFile function, after checking hFile = 0: If hFile = 0 Then Dim errCode As Long errCode = GetLastError() MsgBox "FtpOpenFile failed. Error code: " & errCode & vbCrLf & _ "Check WinINet error codes for details." Exit Function End If
Common error codes here might point to connection issues (like 12031 = connection reset) or mode mismatches.
Step 2: Enable Passive FTP Mode
Looking at your ExtraFTP log, it explicitly uses PASV mode, but WinINet's default is active (PORT) mode. Many modern FTP servers block active mode due to firewall restrictions. Let's enable passive mode for your connection:
First, add the InternetSetOption declaration:
Private Declare Function InternetSetOption Lib "wininet.dll" Alias "InternetSetOptionA" ( _ ByVal hInternet As Long, _ ByVal dwOption As Long, _ lpBuffer As Any, _ ByVal dwBufferLength As Long _ ) As Long Const INTERNET_OPTION_USE_PASSIVE_FTP = &H20000
Then, right after calling InternetConnect, enable passive mode:
hConnection = InternetConnect(hInternet, sServerName, INTERNET_INVALID_PORT_NUMBER, _ sUserName, sPassword, INTERNET_SERVICE_FTP, 0, 0) ' Enable passive FTP Dim enablePassive As Long enablePassive = 1 ' 1 = enable, 0 = disable If InternetSetOption(hConnection, INTERNET_OPTION_USE_PASSIVE_FTP, enablePassive, 4) = 0 Then MsgBox "Failed to set passive mode." Exit Function End If
Step 3: Match Working Directory & UTF8 Settings
Your ExtraFTP log does two critical things your code doesn't:
- Switches to the correct working directory (
CWD /michlol/HomeMI) - Enables UTF8 encoding (
OPTS UTF8 ON)
Let's add both to your code:
Add Directory Change
First, declare FtpSetCurrentDirectory:
Private Declare Function FtpSetCurrentDirectory Lib "wininet.dll" Alias "FtpSetCurrentDirectoryA" ( _ ByVal hFtpSession As Long, _ ByVal lpszDirectory As String _ ) As Boolean
Then, after enabling passive mode, switch to the target directory:
If Not FtpSetCurrentDirectory(hConnection, "/michlol/HomeMI") Then MsgBox "Failed to switch to target directory." Exit Function End If
Enable UTF8 Encoding
Some servers require UTF8 for filename handling (even if your filenames are ASCII). Add the FtpCommand declaration to send the OPTS UTF8 ON command:
Private Declare Function FtpCommand Lib "wininet.dll" Alias "FtpCommandA" ( _ ByVal hFtpSession As Long, _ ByVal fExpectResponse As Boolean, _ ByVal dwFlags As Long, _ ByVal lpszCommand As String, _ dwContext As Long, _ phFtpCommand As Long _ ) As Boolean Const FTP_TRANSFER_TYPE_ASCII = &H1
Send the command after logging in:
' Send OPTS UTF8 ON to match ExtraFTP's behavior If Not FtpCommand(hConnection, True, FTP_TRANSFER_TYPE_ASCII, "OPTS UTF8 ON", 0, 0) Then MsgBox "Warning: Failed to set UTF8 mode (server may not require this, but try anyway)." End If
Step 4: Double-Check FtpOpenFile Parameters
Your current FtpOpenFile call uses &H40000000 (which is GENERIC_WRITE)—that's correct, but ensure RemoteFile is just the filename (like Be072222.mdb) now that we've switched directories, not a full path. Also, trim any hidden spaces from the filename:
RemoteFile = Trim(RemoteFile) hFile = FtpOpenFile(hConnection, RemoteFile, &H40000000, FTP_TRANSFER_TYPE_BINARY, 0)
Full Modified Code Snippet
Putting it all together, your UploadFile function would look like this:
Private Declare Function InternetOpen Lib "wininet.dll" Alias "InternetOpenA" (ByVal sAgent As String, ByVal lAccessType As Long, ByVal sProxyName As String, ByVal sProxyBypass As String, ByVal lFlags As Long) As Long Private Declare Function InternetConnect Lib "wininet.dll" Alias "InternetConnectA" (ByVal hInternetSession As Long, ByVal sServerName As String, ByVal nServerPort As Integer, ByVal sUserName As String, ByVal sPassword As String, ByVal lService As Long, ByVal lFlags As Long, ByVal lContext As Long) As Long Private Declare Function FtpOpenFile Lib "wininet.dll" Alias "FtpOpenFileA" (ByVal hFtpSession As Long, ByVal sBuff As String, ByVal Access As Long, ByVal flags As Long, ByVal Context As Long) As Long Private Declare Function InternetSetOption Lib "wininet.dll" Alias "InternetSetOptionA" (ByVal hInternet As Long, ByVal dwOption As Long, lpBuffer As Any, ByVal dwBufferLength As Long) As Long Private Declare Function FtpSetCurrentDirectory Lib "wininet.dll" Alias "FtpSetCurrentDirectoryA" (ByVal hFtpSession As Long, ByVal lpszDirectory As String) As Boolean Private Declare Function FtpCommand Lib "wininet.dll" Alias "FtpCommandA" (ByVal hFtpSession As Long, ByVal fExpectResponse As Boolean, ByVal dwFlags As Long, ByVal lpszCommand As String, dwContext As Long, phFtpCommand As Long) As Boolean Private Declare Function GetLastError Lib "kernel32" () As Long Private Declare Function InternetCloseHandle Lib "wininet.dll" (ByVal hInternet As Long) As Long Const INTERNET_OPEN_TYPE_PRECONFIG = 0 Const INTERNET_INVALID_PORT_NUMBER = 0 Const INTERNET_SERVICE_FTP = 1 Public Const FTP_TRANSFER_TYPE_BINARY = &H2 Const INTERNET_OPTION_USE_PASSIVE_FTP = &H20000 Const FTP_TRANSFER_TYPE_ASCII = &H1 Const scUserAgent As String = "VB6 FTP Client" Public Function UploadFile(sServerName As String, sUserName As String, sPassword As String, RemoteFile As String) As Boolean Dim hInternet As Long Dim hConnection As Long Dim hFile As Long Dim errCode As Long hInternet = InternetOpen(scUserAgent, INTERNET_OPEN_TYPE_PRECONFIG, vbNullString, vbNullString, 0) If hInternet = 0 Then MsgBox "InternetOpen failed. Error: " & GetLastError() UploadFile = False Exit Function End If hConnection = InternetConnect(hInternet, sServerName, INTERNET_INVALID_PORT_NUMBER, sUserName, sPassword, INTERNET_SERVICE_FTP, 0, 0) If hConnection = 0 Then errCode = GetLastError() MsgBox "InternetConnect failed. Error: " & errCode InternetCloseHandle hInternet UploadFile = False Exit Function End If ' Enable passive FTP mode Dim enablePassive As Long enablePassive = 1 If InternetSetOption(hConnection, INTERNET_OPTION_USE_PASSIVE_FTP, enablePassive, 4) = 0 Then MsgBox "Warning: Failed to enable passive mode (may cause issues)." End If ' Set UTF8 mode (matches ExtraFTP) If Not FtpCommand(hConnection, True, FTP_TRANSFER_TYPE_ASCII, "OPTS UTF8 ON", 0, 0) Then MsgBox "Warning: Failed to set UTF8 mode (server may not require this)." End If ' Switch to target directory If Not FtpSetCurrentDirectory(hConnection, "/michlol/HomeMI") Then errCode = GetLastError() MsgBox "Failed to change directory. Error: " & errCode InternetCloseHandle hConnection InternetCloseHandle hInternet UploadFile = False Exit Function End If ' Trim remote filename to avoid hidden spaces RemoteFile = Trim(RemoteFile) hFile = FtpOpenFile(hConnection, RemoteFile, &H40000000, FTP_TRANSFER_TYPE_BINARY, 0) If hFile = 0 Then errCode = GetLastError() MsgBox "Unable to create the remote file. Error code: " & errCode InternetCloseHandle hConnection InternetCloseHandle hInternet UploadFile = False Exit Function End If ' Add your file writing logic here (using InternetWriteFile) ' Cleanup InternetCloseHandle hFile InternetCloseHandle hConnection InternetCloseHandle hInternet UploadFile = True End Function
Key Notes
- Passive mode is the most likely fix here—most modern servers block active mode due to firewall rules.
- Matching the working directory ensures your file is written to the correct location.
- UTF8 encoding is a safeguard, even for ASCII filenames, since some servers enforce it.
If these steps don't resolve the issue, share the error code you get—this will help narrow down the remaining problems.
内容的提问来源于stack exchange,提问作者yoram

