Tom Shelton
MVP [Visual Basic]
Just as an update, I rewrote the class based off of some research. I know
am running into this problem which only happens on the second iteration
through code.
Imports System
Tibby,
I am looking over the code and will see what I can do with it. I do
have some ftp code that I wrote that uses the WinInet API. It is in C#,
but it should be fairly straight forward to either convert to VB.NET or
just compile it into a separate dll. Might work as quick and dirty
temporary solution (that's why I wrote it
// wininet.cs
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace FireAnt.Net.Ftp
{
/// <summary>
/// WinInet API declarations.
/// </summary>
internal sealed class WinInet
{
public const int INTERNET_OPEN_TYPE_PRECONFIG = 0;
public const int INTERNET_OPEN_TYPE_DIRECT = 1;
public const int INTERNET_OPEN_TYPE_PROXY = 3;
public const short INTERNET_DEFAULT_FTP_PORT = 21;
public const int INTERNET_SERVICE_FTP = 1;
public const int FTP_TRANSFER_TYPE_ASCII = 0x01;
public const int FTP_TRANSFER_TYPE_BINARY = 0x02;
public const int GENERIC_WRITE = 0x40000000;
public const int GENERIC_READ = unchecked((int)0x80000000);
public const int MAX_PATH = 260;
[DllImport("wininet.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern IntPtr InternetOpen(
string lpszAgent,
int dwAcessType,
string lpszProxyName,
string lpszProxyBypass,
int dwFlags);
[DllImport("wininet.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern IntPtr InternetConnect(
IntPtr hInternet,
string lpszServerName,
short nServerPort,
string lpszUserName,
string lpszPassword,
int dwService,
int dwFlags,
ref int dwContext);
[DllImport("wininet.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool FtpGetCurrentDirectory(
IntPtr hConnect,
StringBuilder lpszCurrentDirectory,
ref int lpdwCurrentDirectory);
[DllImport("wininet.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool FtpSetCurrentDirectory(
IntPtr hConnect,
string lpszCurrentDirectory);
[DllImport("wininet.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern IntPtr FtpOpenFile(
IntPtr hConnect,
string lpszFileName,
int dwAccess,
int dwFlags,
out int dwContext);
[DllImport("wininet.dll", SetLastError=true)]
public static extern bool InternetWriteFile(
IntPtr hFile,
[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,
int dwNumberOfBytesToWrite,
out int lpdwNumberOfBytesWritten);
[DllImport("wininet.dll", SetLastError=true)]
public static extern bool InternetReadFile(
IntPtr hFile,
[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,
int dwNumberOfBytesToRead,
out int lpdwNumberOfBytesRead
);
[DllImport("wininet.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool InternetCloseHandle(IntPtr hInternet);
private WinInet()
{
}
}
}
// SimpleFTP.cs
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
namespace FireAnt.Net.Ftp
{
[Flags()]
public enum AccessMode
{
Read = WinInet.GENERIC_READ,
Write = WinInet.GENERIC_WRITE,
}
public enum TransferMode
{
Ascii = WinInet.FTP_TRANSFER_TYPE_ASCII,
Binary = WinInet.FTP_TRANSFER_TYPE_BINARY,
}
/// <summary>
/// SimpleFTP class using the WinInet API.
/// </summary>
public sealed class SimpleFtp : IDisposable
{
private IntPtr internet;
private IntPtr connection;
private IntPtr fileHandle;
private int context;
private const int BUFFER_SIZE = 2048;
public SimpleFtp(string host, string userName, string password)
{
internet = WinInet.InternetOpen(
null,
WinInet.INTERNET_OPEN_TYPE_DIRECT,
null,
null,
0);
if (internet == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
connection = WinInet.InternetConnect(
this.internet,
host,
WinInet.INTERNET_DEFAULT_FTP_PORT,
userName,
password,
WinInet.INTERNET_SERVICE_FTP,
0,
ref this.context);
if (connection == IntPtr.Zero)
{
WinInet.InternetCloseHandle(this.internet);
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
~SimpleFtp()
{
this.CleanUp();
}
void IDisposable.Dispose()
{
this.CleanUp();
GC.SuppressFinalize(this);
}
public string CurrentDirectory
{
get
{
StringBuilder path = new StringBuilder(260);
int bufferSize = path.Capacity;
if (!WinInet.FtpGetCurrentDirectory(this.connection, path, ref bufferSize))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return path.ToString();
}
set
{
if (!WinInet.FtpSetCurrentDirectory(this.connection, value))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
public void Close()
{
((IDisposable)this).Dispose();
}
public void OpenFile(string fileName, AccessMode access, TransferMode mode)
{
this.fileHandle = WinInet.FtpOpenFile(this.connection, fileName, (int) access, (int) mode, out this.context);
if (this.fileHandle == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
public void CloseFile()
{
if (this.fileHandle != IntPtr.Zero)
{
if (WinInet.InternetCloseHandle(this.fileHandle))
{
this.fileHandle = IntPtr.Zero;
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
public int WriteFile(string buffer)
{
byte[] bytes = new ASCIIEncoding().GetBytes(buffer);
return this.WriteFile(bytes);
}
public int WriteFile(byte[] buffer)
{
int byteCount;
if (!WinInet.InternetWriteFile(this.fileHandle, buffer, buffer.Length, out byteCount))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return byteCount;
}
public bool ReadFile(out string buffer)
{
// clear the buffer...
buffer = string.Empty;
// read from the file
int bytesRead;
byte[] readBuffer = new byte[SimpleFtp.BUFFER_SIZE];
bool success = WinInet.InternetReadFile(this.fileHandle, readBuffer, readBuffer.Length, out bytesRead);
// the call failed!
if (!success)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
// we got some data, so convert it for the return...
if (bytesRead != 0)
{
buffer = Encoding.ASCII.GetString(readBuffer, 0, bytesRead);
}
return (bytesRead != 0) ? true : false;
}
public bool ReadFile(byte[] buffer)
{
int bytesRead;
bool success = WinInet.InternetReadFile(this.fileHandle, buffer, buffer.Length, out bytesRead);
if (!success)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return (bytesRead != 0) ? true : false;
}
private void CleanUp()
{
if (this.fileHandle != IntPtr.Zero)
{
WinInet.InternetCloseHandle(this.fileHandle);
}
if (this.connection != IntPtr.Zero)
{
WinInet.InternetCloseHandle(this.connection);
}
if (this.internet != IntPtr.Zero)
{
WinInet.InternetCloseHandle(this.internet);
}
}
}
}
Anyway, should do most of the basic stuff... here is a quick little
snippit of code for using it...
SimpleFTP ftp = new SimpleFTP("myserver.mydomain.com", "myuser",
"mypassword");
if (ftp.CurrentDirectory != "my directory")
{
ftp.CurrentDirectory = "my directory";
}
string data;
ftp.OpenFile("myfile.txt", AccessMode.Read, TransferMode.Ascii);
while (ftp.ReadFile(out data))
// you can of course write the
// data to your local file here
Console.WriteLine(data);
}
// If your not done with the object, and
// are going to transfer more files, then
// call .CloseFile() instead to just close
// the current file handle.
ftp.Close();
Anyway, sorry for the C# - but you should be able to use this pretty
much the way it is. At least until we get this VB code worked out