Hi.
I was reading the article:
.NET 2.0 Workaround for PathTooLongException
for a solution to the too long path name problem. In that article it states that there is a long, "W" version of the CreateFile() function. Now, the class he developed seems to support opening, reading and writing of files but not looking at the contents of a directory. I have two questions:
1. Is there an "easy" way to expand his class to include other functions such as listing directory contents? If so, what other functions would be required to pull this off? I have found such functions such as FindFirstFile(), but the documentation and Googling do not suggest that there are any "W" versions of these.
UPDATE: According to MSDN, FindFirstFileEx() does not carry the MAX_PATH limitation, so in theory, it should work.
2. In his code, he does not include declarations for his API functions, although he does import namespaces. Is this because he is working in C# (which I am only partly familiar with)? I have converted his code from C# to vb.Net, but the online converter cannot necessarily know that declarations need to be added to the converted code, if in fact they DO need to be. My experience says, "Yes", it definitely does, but then again, why wouldn't those same Import lines work just as well in vb.Net? If that is where these functions are located, then why does vb.Net require explicit declarations? Is this so an entire library does not need to be loaded into memory all at once?
Many thanks for any help!
Below is his original code and usage, followed by my online conversion from C# to vb.Net:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.IO;
namespace System.IO
{
class Win32File
{
const int ERROR_ALREADY_EXISTS = 183;
const uint FILE_BEGIN = 0x0;
const uint FILE_CURRENT = 0x1;
const uint FILE_END = 0x2;
const uint GENERIC_READ = 0x80000000;
const uint GENERIC_WRITE = 0x40000000;
const uint GENERIC_EXECUTE = 0x20000000;
const uint GENERIC_ALL = 0x10000000;
const uint FILE_APPEND_DATA = 0x00000004;
const uint FILE_ATTRIBUTE_NORMAL = 0x80;
const uint FILE_SHARE_DELETE = 0x00000004;
const uint FILE_SHARE_READ = 0x00000001;
const uint FILE_SHARE_WRITE = 0x00000002;
const uint CREATE_NEW = 1;
const uint CREATE_ALWAYS = 2;
const uint OPEN_EXISTING = 3;
const uint OPEN_ALWAYS = 4;
const uint TRUNCATE_EXISTING = 5;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFileW(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern uint SetFilePointer(SafeFileHandle hFile, long lDistanceToMove, IntPtr lpDistanceToMoveHigh, uint dwMoveMethod);
#region GetMode
private static uint GetMode(FileMode mode)
{
uint umode = 0;
switch (mode)
{
case FileMode.CreateNew:
umode = CREATE_NEW;
break;
case FileMode.Create:
umode = CREATE_ALWAYS;
break;
case FileMode.Append:
umode = OPEN_ALWAYS;
break;
case FileMode.Open:
umode = OPEN_EXISTING;
break;
case FileMode.OpenOrCreate:
umode = OPEN_ALWAYS;
break;
case FileMode.Truncate:
umode = TRUNCATE_EXISTING;
break;
}
return umode;
}
#endregion
#region GetAccess
private static uint GetAccess(FileAccess access)
{
uint uaccess = 0;
switch (access)
{
case FileAccess.Read:
uaccess = GENERIC_READ;
break;
case FileAccess.ReadWrite:
uaccess = GENERIC_READ | GENERIC_WRITE;
break;
case FileAccess.Write:
uaccess = GENERIC_WRITE;
break;
}
return uaccess;
}
#endregion
#region GetShare
private static uint GetShare(FileShare share)
{
uint ushare = 0;
switch (share)
{
case FileShare.Read:
ushare = FILE_SHARE_READ;
break;
case FileShare.ReadWrite:
ushare = FILE_SHARE_READ | FILE_SHARE_WRITE;
break;
case FileShare.Write:
ushare = FILE_SHARE_WRITE;
break;
case FileShare.Delete:
ushare = FILE_SHARE_DELETE;
break;
case FileShare.None:
ushare = 0;
break;
}
return ushare;
}
#endregion
public static FileStream Open(string filepath, FileMode mode)
{
FileStream fs = null;
uint umode = GetMode(mode);
uint uaccess = GENERIC_READ | GENERIC_WRITE;
uint ushare = 0;
if (mode == FileMode.Append)
uaccess = FILE_APPEND_DATA;
if (filepath.StartsWith(@"\\"))
{
filepath = @"\\?\UNC\" + filepath.Substring(2, filepath.Length - 2);
}
else
filepath = @"\\?\" + filepath;
SafeFileHandle sh = CreateFileW(filepath, uaccess, ushare, IntPtr.Zero, umode, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
int iError = Marshal.GetLastWin32Error();
if ((iError > 0 && !(mode == FileMode.Append && iError == ERROR_ALREADY_EXISTS)) || sh.IsInvalid)
{
throw new Exception("Error opening file Win32 Error:" + iError);
}
else
{
fs = new FileStream(sh, FileAccess.ReadWrite);
}
if (mode == FileMode.Append)
{
if (!sh.IsInvalid)
{
SetFilePointer(sh, 0, IntPtr.Zero, FILE_END);
}
}
return fs;
}
public static FileStream Open(string filepath, FileMode mode, FileAccess access)
{
FileStream fs = null;
uint umode = GetMode(mode);
uint uaccess = GetAccess(access);
uint ushare = 0;
if (mode == FileMode.Append)
uaccess = FILE_APPEND_DATA;
if (filepath.StartsWith(@"\\"))
{
filepath = @"\\?\UNC\" + filepath.Substring(2, filepath.Length - 2);
}
else
filepath = @"\\?\" + filepath;
SafeFileHandle sh = CreateFileW(filepath, uaccess, ushare, IntPtr.Zero, umode, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
int iError = Marshal.GetLastWin32Error();
if ((iError > 0 && !(mode == FileMode.Append && iError != ERROR_ALREADY_EXISTS)) || sh.IsInvalid)
{
throw new Exception("Error opening file Win32 Error:" + iError);
}
else
{
fs = new FileStream(sh, access);
}
if (mode == FileMode.Append)
{
if (!sh.IsInvalid)
{
SetFilePointer(sh, 0, IntPtr.Zero, FILE_END);
}
}
return fs;
}
public static FileStream Open(string filepath, FileMode mode, FileAccess access, FileShare share)
{
FileStream fs = null;
uint umode = GetMode(mode);
uint uaccess = GetAccess(access);
uint ushare = GetShare(share);
if (mode == FileMode.Append)
uaccess = FILE_APPEND_DATA;
if (filepath.StartsWith(@"\\"))
{
filepath = @"\\?\UNC\" + filepath.Substring(2, filepath.Length - 2);
}
else
filepath = @"\\?\" + filepath;
SafeFileHandle sh = CreateFileW(filepath, uaccess, ushare, IntPtr.Zero, umode, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
int iError = Marshal.GetLastWin32Error();
if ((iError > 0 && !(mode == FileMode.Append && iError != ERROR_ALREADY_EXISTS)) || sh.IsInvalid)
{
throw new Exception("Error opening file Win32 Error:" + iError);
}
else
{
fs = new FileStream(sh, access);
}
if (mode == FileMode.Append)
{
if (!sh.IsInvalid)
{
SetFilePointer(sh, 0, IntPtr.Zero, FILE_END);
}
}
return fs;
}
public static FileStream OpenRead(string filepath)
{
return Open(filepath, FileMode.Open, FileAccess.Read, FileShare.Read);
}
public static FileStream OpenWrite(string filepath)
{
return Open(filepath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
}
}
}
And an example of its usage:
FileStream fs1= Win32File.Open( "Long file name of greater " +
"than 260 char length", FileMode.Open);
StreamWriter sw = new StreamWriter(fs1);
sw.WriteLine("Hello world");
sw.Close();
sw.Dispose();
Finally, the conversion from C# to vb.Net:
:cool:Imports System.Text
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices
Imports System.IO
Namespace System.IO
Class Win32File
Const ERROR_ALREADY_EXISTS As Integer = 183
Const FILE_BEGIN As UInteger = &H0
Const FILE_CURRENT As UInteger = &H1
Const FILE_END As UInteger = &H2
Const GENERIC_READ As UInteger = &H80000000UI
Const GENERIC_WRITE As UInteger = &H40000000
Const GENERIC_EXECUTE As UInteger = &H20000000
Const GENERIC_ALL As UInteger = &H10000000
Const FILE_APPEND_DATA As UInteger = &H4
Const FILE_ATTRIBUTE_NORMAL As UInteger = &H80
Const FILE_SHARE_DELETE As UInteger = &H4
Const FILE_SHARE_READ As UInteger = &H1
Const FILE_SHARE_WRITE As UInteger = &H2
Const CREATE_NEW As UInteger = 1
Const CREATE_ALWAYS As UInteger = 2
Const OPEN_EXISTING As UInteger = 3
Const OPEN_ALWAYS As UInteger = 4
Const TRUNCATE_EXISTING As UInteger = 5
<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
Private Shared Function CreateFileW(ByVal lpFileName As String, ByVal dwDesiredAccess As UInteger, ByVal dwShareMode As UInteger, ByVal lpSecurityAttributes As IntPtr, ByVal dwCreationDisposition As UInteger, ByVal dwFlagsAndAttributes As UInteger, _
ByVal hTemplateFile As IntPtr) As SafeFileHandle
End Function
<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
Private Shared Function SetFilePointer(ByVal hFile As SafeFileHandle, ByVal lDistanceToMove As Long, ByVal lpDistanceToMoveHigh As IntPtr, ByVal dwMoveMethod As UInteger) As UInteger
End Function
#Region "GetMode"
Private Shared Function GetMode(ByVal mode As FileMode) As UInteger
Dim umode As UInteger = 0
Select Case mode
Case FileMode.CreateNew
umode = CREATE_NEW
Exit Select
Case FileMode.Create
umode = CREATE_ALWAYS
Exit Select
Case FileMode.Append
umode = OPEN_ALWAYS
Exit Select
Case FileMode.Open
umode = OPEN_EXISTING
Exit Select
Case FileMode.OpenOrCreate
umode = OPEN_ALWAYS
Exit Select
Case FileMode.Truncate
umode = TRUNCATE_EXISTING
Exit Select
End Select
Return umode
End Function
#End Region
#Region "GetAccess"
Private Shared Function GetAccess(ByVal access As FileAccess) As UInteger
Dim uaccess As UInteger = 0
Select Case access
Case FileAccess.Read
uaccess = GENERIC_READ
Exit Select
Case FileAccess.ReadWrite
uaccess = GENERIC_READ Or GENERIC_WRITE
Exit Select
Case FileAccess.Write
uaccess = GENERIC_WRITE
Exit Select
End Select
Return uaccess
End Function
#End Region
#Region "GetShare"
Private Shared Function GetShare(ByVal share As FileShare) As UInteger
Dim ushare As UInteger = 0
Select Case share
Case FileShare.Read
ushare = FILE_SHARE_READ
Exit Select
Case FileShare.ReadWrite
ushare = FILE_SHARE_READ Or FILE_SHARE_WRITE
Exit Select
Case FileShare.Write
ushare = FILE_SHARE_WRITE
Exit Select
Case FileShare.Delete
ushare = FILE_SHARE_DELETE
Exit Select
Case FileShare.None
ushare = 0
Exit Select
End Select
Return ushare
End Function
#End Region
Public Shared Function Open(ByVal filepath As String, ByVal mode As FileMode) As FileStream
Dim fs As FileStream = Nothing
Dim umode As UInteger = GetMode(mode)
Dim uaccess As UInteger = GENERIC_READ Or GENERIC_WRITE
Dim ushare As UInteger = 0
If mode = FileMode.Append Then
uaccess = FILE_APPEND_DATA
End If
If filepath.StartsWith("\\") Then
filepath = "\\?\UNC\" & filepath.Substring(2, filepath.Length - 2)
Else
filepath = "\\?\" & filepath
End If
Dim sh As SafeFileHandle = CreateFileW(filepath, uaccess, ushare, IntPtr.Zero, umode, FILE_ATTRIBUTE_NORMAL, _
IntPtr.Zero)
Dim iError As Integer = Marshal.GetLastWin32Error()
If (iError > 0 AndAlso Not (mode = FileMode.Append AndAlso iError = ERROR_ALREADY_EXISTS)) OrElse sh.IsInvalid Then
Throw New Exception("Error opening file Win32 Error:" & iError)
Else
fs = New FileStream(sh, FileAccess.ReadWrite)
End If
If mode = FileMode.Append Then
If Not sh.IsInvalid Then
SetFilePointer(sh, 0, IntPtr.Zero, FILE_END)
End If
End If
Return fs
End Function
Public Shared Function Open(ByVal filepath As String, ByVal mode As FileMode, ByVal access As FileAccess) As FileStream
Dim fs As FileStream = Nothing
Dim umode As UInteger = GetMode(mode)
Dim uaccess As UInteger = GetAccess(access)
Dim ushare As UInteger = 0
If mode = FileMode.Append Then
uaccess = FILE_APPEND_DATA
End If
If filepath.StartsWith("\\") Then
filepath = "\\?\UNC\" & filepath.Substring(2, filepath.Length - 2)
Else
filepath = "\\?\" & filepath
End If
Dim sh As SafeFileHandle = CreateFileW(filepath, uaccess, ushare, IntPtr.Zero, umode, FILE_ATTRIBUTE_NORMAL, _
IntPtr.Zero)
Dim iError As Integer = Marshal.GetLastWin32Error()
If (iError > 0 AndAlso Not (mode = FileMode.Append AndAlso iError <> ERROR_ALREADY_EXISTS)) OrElse sh.IsInvalid Then
Throw New Exception("Error opening file Win32 Error:" & iError)
Else
fs = New FileStream(sh, access)
End If
If mode = FileMode.Append Then
If Not sh.IsInvalid Then
SetFilePointer(sh, 0, IntPtr.Zero, FILE_END)
End If
End If
Return fs
End Function
Public Shared Function Open(ByVal filepath As String, ByVal mode As FileMode, ByVal access As FileAccess, ByVal share As FileShare) As FileStream
Dim fs As FileStream = Nothing
Dim umode As UInteger = GetMode(mode)
Dim uaccess As UInteger = GetAccess(access)
Dim ushare As UInteger = GetShare(share)
If mode = FileMode.Append Then
uaccess = FILE_APPEND_DATA
End If
If filepath.StartsWith("\\") Then
filepath = "\\?\UNC\" & filepath.Substring(2, filepath.Length - 2)
Else
filepath = "\\?\" & filepath
End If
Dim sh As SafeFileHandle = CreateFileW(filepath, uaccess, ushare, IntPtr.Zero, umode, FILE_ATTRIBUTE_NORMAL, _
IntPtr.Zero)
Dim iError As Integer = Marshal.GetLastWin32Error()
If (iError > 0 AndAlso Not (mode = FileMode.Append AndAlso iError <> ERROR_ALREADY_EXISTS)) OrElse sh.IsInvalid Then
Throw New Exception("Error opening file Win32 Error:" & iError)
Else
fs = New FileStream(sh, access)
End If
If mode = FileMode.Append Then
If Not sh.IsInvalid Then
SetFilePointer(sh, 0, IntPtr.Zero, FILE_END)
End If
End If
Return fs
End Function
Public Shared Function OpenRead(ByVal filepath As String) As FileStream
Return Open(filepath, FileMode.Open, FileAccess.Read, FileShare.Read)
End Function
Public Shared Function OpenWrite(ByVal filepath As String) As FileStream
Return Open(filepath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)
End Function
End Class
End Namespace
modified 3-May-13 15:52pm.
|