I'm writing a filecopier using APIs. I've gotten everything working, but I
want to set the destination file's date stamps match the source file's. I
can get the info using GetFileInformationByHandle, but I'm stumped on the
SetFileInformationByHandle. I'm using the Unicode versions because we often
encounter very long paths here. Here's the MSDN page:
http://msdn.microsoft.com/en-us/library/aa365539(VS.85).aspx
(..Declarations)
Private Declare Function SetFileInformationByHanlde Lib "kernel32" ( _
hFile As Long, FileInformationClass As FILE_INFO_BY_HANDLE_CLASS, _
lpFileInformation As Long, dwBufferSize As Long) As Long
Private Declare Function GetFileInformationByHandle Lib "kernel32" ( _
ByVal hFile As Long, lpFileInformation As BY_HANDLE_FILE_INFORMATION)
As Long
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileW"
(ByVal lpFileName As Long, ByVal dwDesiredAccess As Long, ByVal dwShareMode
As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As
Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As
Long
Private Type BY_HANDLE_FILE_INFORMATION
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
dwVolumeSerialNumber As Long
nFileSizeHigh As Long
nFileSizeLow As Long
nNumberOfLinks As Long
nFileIndexHigh As Long
nFileIndexLow As Long
End Type
Private Type FILE_BASIC_INFO
CreationTime As Long
LastAccessTime As Long
LastWriteTime As Long
ChangeTime As Long
FileAttributes As String
End Type
Private Enum FILE_INFO_BY_HANDLE_CLASS
FileBasicInfo
FileStandardInfo
FileNameInfo
FileRenameInfo
FileDispositionInfo
FileAllocationInfo
FileEndOfFileInfo
FileStreamInfo
FileCompressionInfo
FileAttributeTagInfo
FileIdBothDirectoryInfo
FileIdBothDirectoryRestartInfo
FileIoPriorityHintInfo
MaximumFileInfoByHandlesClass
End Enum
Private Const GENERIC_WRITE = &H40000000
Private Const OPEN_EXISTING = 3
(Code)
Dim srcHand as Long, destHand as Long, lngCopy as Long, lngSetInfo as
Long
dim srcHFI As BY_HANDLE_FILE_INFORMATION
If InStr(srcPath, "\\") = 1 Then 'Prepends
"\\?\" to alert the API to use UNICODE names
srcPath= "\\?\UNC\" & Mid$(srcPath, 3)
Else
srcPath= "\\?\" & srcPath
End If
If InStr(destPath, "\\") = 1 Then 'Prepends
"\\?\" to alert the API to use UNICODE names
destPath= "\\?\UNC\" & Mid$(destPath, 3)
Else
destPath= "\\?\" & destPath
End If
srcHand = CreateFile(StrPtr(srcPath), GENERIC_READ, 0, ByVal 0&,
OPEN_EXISTING, 0, 0) ' get the handle of the source file
srcHand = GetFileInformationByHandle(srcHand, srcHFI)
' get the File's info
lngCopy = CopyFile(StrPtr(srcPath), StrPtr(destPath), nFailFlag)
destHand = CreateFile(StrPtr(destPath), GENERIC_READ, 0, ByVal 0&,
OPEN_EXISTING, 0, 0)
lngSetInfo = SetFileInformationByHandle(destHand,FileBasicInfo, srcHFI,
len(srcHFI)) '
<-THIS IS WHERE I GET STUCK! The third parameter is Long, but
' how to pass? Am I even passing
the right object? TIA!!
Stuart McCall - 03 Sep 2008 20:12 GMT
> I'm writing a filecopier using APIs. I've gotten everything working, but
> I want to set the destination file's date stamps match the source file's.
[quoted text clipped - 87 lines]
>
> ' how to pass? Am I even passing the right object? TIA!!
You're going to kick yourself. You have a typo in the first declaration
(which also just happens to be the function you're having trouble with).
SetFileInformationByHanlde
should be:
SetFileInformationByHandle
Thorsten Albers - 03 Sep 2008 20:33 GMT
Mike <nospam@whitehouse.gov> schrieb im Beitrag
<ugHf$heDJHA.232@TK2MSFTNGP04.phx.gbl>...
> Private Declare Function SetFileInformationByHanlde Lib "kernel32" ( _
> hFile As Long, FileInformationClass As FILE_INFO_BY_HANDLE_CLASS, _
> lpFileInformation As Long, dwBufferSize As Long) As Long
- 'hFile As Long' has to be 'ByVal hFile As Long'
- 'dwBufferSize As Long' has to be 'ByVal dwBufferSize As Long'
- In order to be able to pass different structure types to this procedure
a) add one declare statement for every type or b) use 'lpFileInformation As
Any'.
a)
Private Declare Function SetFileInformationByHandleBasic _
Lib "kernel32" _
Alias "SetFileInformationByHandle"
( _
ByVal hFile As Long, _
FileInformationClass As
FILE_INFO_BY_HANDLE_CLASS, _
lpFileInformation As FILE_BASIC_INFO, _
ByVal dwBufferSize As Long _
) As Long
b)
Private Declare Function SetFileInformationByHandleBasic _
Lib "kernel32" _
Alias "SetFileInformationByHandle"
( _
ByVal hFile As Long, _
FileInformationClass As
FILE_INFO_BY_HANDLE_CLASS, _
lpFileInformation As Any, _
ByVal dwBufferSize As Long _
) As Long
> Private Type FILE_BASIC_INFO
> CreationTime As Long
[quoted text clipped - 3 lines]
> FileAttributes As String
> End Type
- 'FileAttributes As String' has to be 'FileAttributes As Long'
- All other structure members have to be '... As LARGE_INTEGER'
Private Type LARGE_INTEGER
lowpart As Long
highpart As Long
End Type
> srcHand = CreateFile(StrPtr(srcPath), GENERIC_READ, 0, ByVal 0&,
> OPEN_EXISTING, 0, 0)
> srcHand = GetFileInformationByHandle(srcHand, srcHFI)
- Don't overwrite the contents of 'srcHand' because you need the handle
later to close the file by a call to CloseHandle()
- The return value of GetFileInformationByHandle() is 0 (failure) or <> 0
(success)
> lngCopy = CopyFile(StrPtr(srcPath), StrPtr(destPath), nFailFlag)
- Remember, that as the third parameter you have to pass either 1 (TRUE) or
0 (FALSE)
- The return value of CopyFile() is 0 (failure) or <> 0 (success)
> destHand = CreateFile(StrPtr(destPath), GENERIC_READ, 0, ByVal 0&,
> OPEN_EXISTING, 0, 0)
If you want to manipulate a file somehow you need GENERIC_WRITE access.
> lngSetInfo = SetFileInformationByHandle(destHand,FileBasicInfo, srcHFI,
> len(srcHFI)) '
- You can't pass 'srcHFI' to SetFileInformationByHandle(); if you want to
pass FILE_BASIC_INFO structure data to this procedure, you have to set the
data of that structure from the data of the 'srcHFI' structure and pass it
to the procedure.
- You have to close any handle retrieved from a call to CreateFile() by a
call to CloseHandle()!
- Be aware of the fact that SetFileInformationByHandle() is currently
available only on Windows Vista and Windows Server 2003.
You should read the MSDN documentation on each of the procedures again -
and carefully!

Signature
----------------------------------------------------------------------
Thorsten Albers albers(a)uni-freiburg.de
----------------------------------------------------------------------
expvb - 03 Sep 2008 21:36 GMT
> I'm writing a filecopier using APIs. I've gotten everything working, but
> I want to set the destination file's date stamps match the source file's.
> I can get the info using GetFileInformationByHandle, but I'm stumped on
> the SetFileInformationByHandle. I'm using the Unicode versions because we
> often encounter very long paths here. Here's the MSDN page:
> http://msdn.microsoft.com/en-us/library/aa365539(VS.85).aspx
That function requires Vista+, you can use it on XP/2003 if you install some
DLL, but why not use GetFileTime/SetFileTime? They run on Windows 95+. Also,
you can use CopyFileW to copy files with long file names on NT, instead of
making your own. Example:
Option Explicit
Private Declare Function CopyFileW Lib "kernel32" ( _
ByVal lpExistingFileName As Long, ByVal lpNewFileName As Long, _
ByVal bFailIfExists As Long) As Long
Private Sub Form_Load()
Dim fn1 As String
Dim fn2 As String
' Set fn1 and fn2 here
Debug.Print "CopyFileW returned " & CopyFileW(ByVal StrPtr(fn1), _
ByVal StrPtr(fn2), 0)
End Sub
Karl E. Peterson - 03 Sep 2008 23:03 GMT
>> http://msdn.microsoft.com/en-us/library/aa365539(VS.85).aspx
>
> That function requires Vista+, you can use it on XP/2003 if you install some
> DLL, but why not use GetFileTime/SetFileTime? They run on Windows 95+.
Agreed!
> you can use CopyFileW to copy files with long file names on NT, instead of
> making your own.
Main reason I'd suggest would be to track the progress.

Signature
.NET: It's About Trust!
http://vfred.mvps.org
expvb - 03 Sep 2008 23:09 GMT
>>> http://msdn.microsoft.com/en-us/library/aa365539(VS.85).aspx
>>
[quoted text clipped - 9 lines]
>
> Main reason I'd suggest would be to track the progress.
CopyFileExW can do that, but it requires Windows 98+.
Karl E. Peterson - 03 Sep 2008 23:43 GMT
>>> you can use CopyFileW to copy files with long file names on NT, instead
>>> of making your own.
>>
>> Main reason I'd suggest would be to track the progress.
>
> CopyFileExW can do that, but it requires Windows 98+.
Seems to not be a totally unreasonable requirement anymore. <g>

Signature
.NET: It's About Trust!
http://vfred.mvps.org
Thorsten Albers - 04 Sep 2008 04:25 GMT
expvb <nobody@cox.net> schrieb im Beitrag
<OAh4NHhDJHA.5316@TK2MSFTNGP04.phx.gbl>...
> CopyFileExW can do that, but it requires Windows 98+.
In fact in requires Windows NT >= 3.51 - because on Windows 9x the "W"
versions of these procedures aren't available (as well as the special file
path parsing with "\\?\"). CopyFileExA() works on Windows 98/ME.

Signature
----------------------------------------------------------------------
Thorsten Albers albers(a)uni-freiburg.de
----------------------------------------------------------------------