问题:
在对非托管函数进行托管调用时(在本例中为FtpFindFirstFile),我收到 PInvokeStackImbalance 异常。
我正在尝试做什么:
我试图检查FTP服务器上是否存在文件,这导致我使用FtpFindFirstFile作为实现此目的的方法。我成功使用了wininet.dll库的其他功能,但我对上述功能没有成功。
我迄今为止所做的一切:
更改托管呼叫的数据类型以匹配dll呼叫的数据类型。我也使用GetType()作为一种方法来确保我确实拥有我认为的数据类型,因为异常消息暗示我将数据错误地传递给函数的参数。看图像,所有这些布尔变量都返回true。
致电IsRemoteFileExist():
以下是对我正在进行的函数IsRemoteFileExist()的调用,这是调用FtpFindFirstFile()的函数。
\n
WinINet.DLL函数的定义
这是我的WinINet函数声明的粘贴。
WinINet Function Declarations
Public Function WindowsTransferFile(arr_sSourceFiles As String(),
sDirTarget As String,
Optional bUploadTransfer As Boolean = False) As Boolean
'TODO: check for file existence before upload or download
'TODO: This needs a logic cleanup to accommodate downloading
Dim bReturn As Boolean = False
Dim nINet As Long
Dim nINetConnection As Long
Dim sTargetFileName As String
Dim iFileTotalCount As Integer = arr_sSourceFiles.Count
Dim lstFilesFailed As List(Of String) = New List(Of String)
Try
nINet = WinINet.InternetOpen("ftp_sync", WinINet.INTERNET_OPEN_TYPE_DIRECT, vbNullString, vbNullString, 0)
nINetConnection = WinINet.InternetConnect(nINet,
Me._sHostname,
21,
Me._sUsername,
Me._sPassword,
WinINet.INTERNET_SERVICE_FTP,
WinINet.INTERNET_FLAG_PASSIVE,
0)
If nINetConnection = Nothing Then
Throw New Exception("Connection Failed.") 'TODO: Detailed exception message..
End If
ConsoleFeedback.OutputToConsole("Beginning FTP transfer of " & iFileTotalCount.ToString() & " files.")
For Each sFile As String In arr_sSourceFiles
If bUploadTransfer Then
sTargetFileName = sDirTarget & IO.Path.GetFileName(sFile)
IsRemoteFileExist(sTargetFileName, nINetConnection)
bReturn = UploadFile(nINetConnection, sFile, sTargetFileName, WinINet.INTERNET_FLAG_PASSIVE, 0)
If Not bReturn Then
lstFilesFailed.Add(sTargetFileName)
End If
Else
bReturn = DownloadFile(nINetConnection, sFile, sDirTarget, False, 0, WinINet.INTERNET_FLAG_PASSIVE, 0)
End If
Next
If lstFilesFailed.Count > 0 Then
Dim sErrorMsg As String = "Finished with failures: "
For Each sFileFailed As String In lstFilesFailed
sErrorMsg &= sFileFailed & vbCrLf
Next
ConsoleFeedback.OutputToConsole(sErrorMsg)
Else
ConsoleFeedback.OutputToConsole("Finished transferring files.")
End If
Catch ex As Exception
Throw New Exception(ex.Message, ex)
Finally
WinINet.InternetCloseHandle(CInt(nINet))
End Try
Return bReturn
End Function
不确定如何继续这个,所有其他WinINet功能对我有用,它就是我遇到问题的那个。
修改
刚注意到lib是" WinINet",我把它更改为" wininet.dll"为了一致性。
旧宣言:
Imports System.Runtime.InteropServices
Public Class WinINet
Public Const INTERNET_OPEN_TYPE_PRECONFIG = 0 ' // use registry configuration
Public Const INTERNET_OPEN_TYPE_DIRECT = 1 ' // direct to net
Public Const INTERNET_OPEN_TYPE_PROXY = 3 ' // via named proxy
Public Const INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY = 4 ' // prevent using java/script/INS
Public Const INTERNET_SERVICE_FTP = 1 '
Public Const INTERNET_SERVICE_GOPHER = 2 'Type of service to access.
Public Const INTERNET_SERVICE_HTTP = 3 '
Public Const INTERNET_OPTION_VERSION = 40 'Returns the version number of Wininet.dll.
Public Const INTERNET_DEFAULT_FTP_PORT = 21 'Number of the TCP/IP port on the server to connect to.
Public Const INTERNET_DEFAULT_GOPHER_PORT = 70
Public Const INTERNET_DEFAULT_HTTP_PORT = 80
Public Const INTERNET_DEFAULT_HTTPS_PORT = 443
Public Const INTERNET_DEFAULT_SOCKS_PORT = 1080
Public Const INTERNET_FLAG_PASSIVE As Long = &H8000000
Public Const INTERNET_FLAG_EXISITING_CONNECT As Long = &H20000000
Public Const INTERNET_FLAG_RELOAD As Long = &H80000000 'read from wire even if locally cached
Public Const INTERNET_FLAG_ASYNC As Long = &H10000000 'this request is asynchronous (where supported)
Public Structure FILETIME
Dim dwLowDateTime As Long
Dim dwHighDateTime As Long
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
Structure WIN32_FIND_DATA
Public dwFileAttributes As UInteger
Public ftCreationTime As ComTypes.FILETIME
Public ftLastAccessTime As ComTypes.FILETIME
Public ftLastWriteTime As ComTypes.FILETIME
Public nFileSizeHigh As UInteger
Public nFileSizeLow As UInteger
Public dwReserved0 As UInteger
Public dwReserved1 As UInteger
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> Public cFileName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)> Public cAlternateFileName As String
End Structure
Public Declare Function internetopen Lib "wininet.dll" Alias "InternetOpenA" (ByVal lpszAgent As String, ByVal dwAccessType As Long, ByVal lpszproxyName As String, ByVal lpszproxyBypass As String, ByVal dwflags As Long) As Long
Public Declare Function InternetCloseHandle Lib "wininet.dll" (ByVal HINet As Integer) As Integer
Public Declare Function InternetOpen Lib "wininet.dll" Alias "InternetOpenA" (ByVal sAgent As String, ByVal lAccessType As Integer, ByVal sProxyName As String, ByVal sProxyBypass As String, ByVal lFlags As Integer) As Integer
Public Declare Function InternetConnect Lib "wininet.dll" Alias "InternetConnectA" (ByVal hInternetSession As Integer, ByVal sServerName As String, ByVal nServerPort As Integer, ByVal sUsername As String, ByVal sPassword As String, ByVal lService As Integer, ByVal lFlags As Integer, ByVal lContext As Integer) As Integer
Public Declare Function FtpGetFile Lib "wininet.dll" Alias "FtpGetFileA" (ByVal hFtpSession As Integer, ByVal lpszRemoteFile As String, ByVal lpszNewFile As String, ByVal fFailIfExists As Boolean, ByVal dwFlagsAndAttributes As Integer, ByVal dwFlags As Integer, ByVal dwContext As Integer) As Boolean
Public Declare Function FtpPutFile Lib "wininet.dll" Alias "FtpPutFileA" (ByVal hFtpSession As Integer, ByVal lpszLocalFile As String, ByVal lpszRemoteFile As String, ByVal dwFlags As Integer, ByVal dwContext As Integer) As Boolean
Public Declare Function FtpFindFirstFile Lib "wininet.dll" Alias "FtpFindFirstFileA" (ByVal hFtpSession As IntPtr, ByVal lpszSearchFile As String, ByVal lpFindFileData As WIN32_FIND_DATA, ByVal dwFlags As Integer, ByVal dwContext As IntPtr) As IntPtr
Public Declare Function InternetFindNextFile Lib "wininet.dll" Alias "InternetFindNextFileA" (ByVal hFind As Long, ByVal lpFindFileData As WIN32_FIND_DATA) As Long
Public Declare Function FtpSetCurrentDirectory Lib "wininet.dll" Alias "FtpSetCurrentDirectoryA" (ByVal hFtpSession As Long, ByVal lpszDirectory As String) As Boolean
Public Declare Function FtpGetCurrentDirectory Lib "wininet.dll" Alias "FtpGetCurrentDirectoryA" (ByVal hFtpSession As Long, ByVal lpszCurrentDirectory As String, ByVal lpdwCurrentDirectory As Long) As Long
Public Declare Function FtpFindFirstFile Lib "WinInet" Alias "FtpFindFirstFileA" (ByVal hFtp As Long, ByVal lpszSearchFile As String, lpFindFileData As WIN32_FIND_DATA, ByVal dwFlags As Long, ByVal dwContext As Long) As Long
End Class
新声明:
Public Declare Function FtpFindFirstFile Lib "WinInet" Alias "FtpFindFirstFileA" (ByVal hFtp As Long, ByVal lpszSearchFile As String, lpFindFileData As WIN32_FIND_DATA, ByVal dwFlags As Long, ByVal dwContext As Long) As Long <br>
当然,这并没有解决我的问题。