|
-
Jul 6th, 2013, 01:46 AM
#1
Thread Starter
Junior Member
Re: Classic VB - How can I check if a file exists?
 Originally Posted by dee-u
We can also utilize the API's FindFirstFile and FindNextFile to determine the existence of a file or a folder, it can also support wildcard searches which I demonstrate here.
vb Code:
'In a standard Module
Option Explicit
Public Const MAX_PATH As Long = 260
Private Const ERROR_NO_MORE_FILES As Long = 18&
Private Const FILE_ATTRIBUTE_NORMAL As Long = &H80
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
Private Type WIN32_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName As String * MAX_PATH
cAlternate As String * 14
End Type
Private Declare Function FindFirstFile Lib "kernel32" Alias "FindFirstFileA" ( _
ByVal lpFileName As String, _
lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindClose Lib "kernel32" ( _
ByVal hFindFile As Long) As Long
Private Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileA" ( _
ByVal hFindFile As Long, _
lpFindFileData As WIN32_FIND_DATA) As Long
Public Function FileExists(ByVal sFile As String) As Boolean
Dim lpFindFileData As WIN32_FIND_DATA
Dim lFileHandle As Long
Dim lRet As Long
Dim sTemp As String
Dim sFileExtension As String
Dim sFileName As String
Dim sFileData() As String
Dim sFileToCompare As String
If IsDirectory(sFile) = True Then
sFile = AddSlash(sFile) & "*.*"
End If
If InStr(sFile, ".") > 0 Then
sFileToCompare = GetFileTitle(sFile)
sFileData = Split(sFileToCompare, ".")
sFileName = sFileData(0)
sFileExtension = sFileData(1)
Else
Exit Function
End If
' get a file handle
lFileHandle = FindFirstFile(sFile, lpFindFileData)
If lFileHandle <> -1 Then
If sFileName = "*" Or sFileExtension = "*" Then
FileExists = True
Else
Do Until lRet = ERROR_NO_MORE_FILES
' if it is a file
If (lpFindFileData.dwFileAttributes And FILE_ATTRIBUTE_NORMAL) = vbNormal Then
sTemp = StrConv(RemoveNull(lpFindFileData.cFileName), vbProperCase)
'remove LCase$ if you want the search to be case sensitive
If LCase$(sTemp) = LCase$(sFileToCompare) Then
FileExists = True ' file found
Exit Do
End If
End If
'based on the file handle iterate through all files and dirs
lRet = FindNextFile(lFileHandle, lpFindFileData)
If lRet = 0 Then Exit Do
Loop
End If
End If
' close the file handle
lRet = FindClose(lFileHandle)
End Function
Private Function IsDirectory(ByVal sFile As String) As Boolean
On Error Resume Next
IsDirectory = ((GetAttr(sFile) And vbDirectory) = vbDirectory)
End Function
Private Function RemoveNull(ByVal strString As String) As String
Dim intZeroPos As Integer
intZeroPos = InStr(strString, Chr$(0))
If intZeroPos > 0 Then
RemoveNull = Left$(strString, intZeroPos - 1)
Else
RemoveNull = strString
End If
End Function
Public Function GetFileTitle(ByVal sFileName As String) As String
GetFileTitle = Right$(sFileName, Len(sFileName) - InStrRev(sFileName, "\"))
End Function
Public Function AddSlash(ByVal strDirectory As String) As String
If InStrRev(strDirectory, "\") <> Len(strDirectory) Then
strDirectory = strDirectory + "\"
End If
AddSlash = strDirectory
End Function
Sample Usage:
VB Code:
'specific file
If FileExists("C:\WINDOWS\system32\progman.exe") Then
MsgBox "Existing!"
Else
MsgBox "Not Existing!"
End If
'check existence of folder
If FileExists("C:\Program Files") Then
MsgBox "Existing!"
Else
MsgBox "Not Existing!"
End If
'wildcard search1
If FileExists("C:\WINDOWS\system32\pschdprf.*") Then
MsgBox "Existing!"
Else
MsgBox "Not Existing!"
End If
'wildcard search2
If FileExists("C:\WINDOWS\system32\*.dll") Then
MsgBox "Existing!"
Else
MsgBox "Not Existing!"
End If
'wildcard search3
If FileExists("C:\WINDOWS\*.*") Then
MsgBox "Existing!"
Else
MsgBox "Not Existing!"
End If
Will it work if you put.
If FileExists(App.Path & "\filename.txt") Then
MsgBox "Existing!"
Else
MsgBox "Not Existing!"
End If
-
Jul 6th, 2013, 11:00 AM
#2
Re: Classic VB - How can I check if a file exists?
Thread moved from this thread in the FAQ forum, as the FAQ forum is not the place to post your questions.
The answer to your question is basically yes... but it depends on the value of App.Path because if the path is the root of a drive (eg: "C:\") then App.Path gets confused with the \ , so you need to deal with that.
-
Jul 6th, 2013, 12:37 PM
#3
Re: Classic VB - How can I check if a file exists?
 Originally Posted by si_the_geek
... but it depends on the value of App.Path because if the path is the root of a drive (eg: "C:\") then App.Path gets confused with the \ , so you need to deal with that.
Using this version of the FileExists function ...
Code:
Public Function FileExists(ByRef sFileName As String) As Boolean
On Error Resume Next
FileExists = (GetAttr(sFileName) And vbDirectory) <> vbDirectory
End Function
... the following code seems to work correctly ...
Code:
Private Sub Main()
If FileExists(App.Path & "\\\\\/////filename.txt") Then
MsgBox "Existing!", vbInformation
Else
MsgBox "Not Existing!", vbInformation
End If
End Sub
... even when the exe and text file were placed in any drive's root directory.
It appears that the GetFileAttributes API function sanitizes the supplied path first. I've noticed this behavior in other File System APIs too, although I can't recall whether FindFirstFile behaves the same.
@ PSXGamerPro1
You might also want to check out The Optimum FileExists Function.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)
-
Jul 6th, 2013, 06:53 PM
#4
Re: Classic VB - How can I check if a file exists?
IMO, the best and easiest way is to simply use the API function.
Code:
Public Declare Function PathFileExists Lib "shlwapi" Alias "PathFileExistsA" (ByVal pszPath As String) As Long
If PathFileExists("C:\whatever.wtv") Then
It returns 0 if the file/folder doesn't exist. There's also PathFileExistsW if you're dealing with Unicode. I use this function extensively, it works fine in VB. Just pass the full directory info.
Last edited by fafalone; Jul 6th, 2013 at 06:57 PM.
-
Jul 7th, 2013, 01:55 AM
#5
Re: Classic VB - How can I check if a file exists?
 Originally Posted by fafalone
IMO, the best and easiest way is to simply use the API function.
Code:
Public Declare Function PathFileExists Lib "shlwapi" Alias "PathFileExistsA" (ByVal pszPath As String) As Long
If PathFileExists("C:\whatever.wtv") Then
It returns 0 if the file/folder doesn't exist. There's also PathFileExistsW if you're dealing with Unicode. I use this function extensively, it works fine in VB. Just pass the full directory info.
From Visual C++ in Short: Determining whether a path refers to a file system object:
 Originally Posted by Kenny Kerr
The shell provides the PathFileExists function which is simpler than the approaches mentioned thus far but is limited in that it does not distinguish between files and directories.
. . .
Incidentally, the PathFileExists function I mentioned above uses GetFileAttributes internally if it determines that you’re running on a supported version of Windows.
From Superstition: Why is GetFileAttributes the way old-timers test file existence?:
 Originally Posted by Raymond Chen
If you ask an old-timer how to test for file existence, they'll say, "Use GetFileAttributes." This is still probably the quickest way to test for file existence, since it requires only a single call. Other methods such as FindFirstFile or CreateFile require a separate FindClose or CloseHandle call, which triggers another network round-trip, which adds to the cost.
Through extensive research and experimentation, I believe I've found The Optimum FileExists Function.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)
-
Jul 7th, 2013, 05:00 AM
#6
Re: Classic VB - How can I check if a file exists?
I'm always amazed by the number of VB coders who think using API calls makes their code whizzy and 'leet.
Lots of things built into VB like GetAttr() are very thin wrappers on API calls.
Worse yet using the Declare Function... syntax wraps even more overhead around the API call than you have by using the built-in function! Not only does this resolve the entrypoint interpretively at runtime by scanning the DLL's export table, anything passed ByVal... As String entails two copy operations that convert from Unicode to ANSI and back, and extra GetLastError API calls get made.
You can improve on that by creating a type library and using wide-character entrypoints, avoiding copy/convert and resolving entrypoints at compile time. But hardly anyone does that anymore.
-
Jul 7th, 2013, 08:31 AM
#7
Re: Classic VB - How can I check if a file exists?
What are you talking about, dilettante?
Wrappers are usually slower than direct calls to windows api. Although I may agree that using api isn't always necessary it's often much faster approach.
You may discuss unicode/ansi conversion for as long as you want however in the end the fastest time wins. Try doing recursive search without FindFirst using perhaps Dir function which is nothing more than a wrapper...
Regardless how thin is the wrapper it's still a wrapper.
-
Jul 7th, 2013, 10:43 AM
#8
Re: Classic VB - How can I check if a file exists?
When you use Declare Function your calls are anything but direct, and this imposes the performance penalties I described above. As a result it is often quite a bit slower than using native operations in VB.
I have no idea why you think converting strings back and forth between character sets might be free. Or for that matter why you don't realize that calls to a "Declared" entrypoint are "wrapped."
I'm not sure where you get the notion that the Dir$() function is particularly slow.
-
Jul 7th, 2013, 11:03 AM
#9
Re: Classic VB - How can I check if a file exists?
 Originally Posted by dilettante
Lots of things built into VB like GetAttr() are very thin wrappers on API calls.
Worse yet using the Declare Function... syntax wraps even more overhead around the API call than you have by using the built-in function!
Well, according to my tests, the following FileExists function:
Code:
Public Function FileExists(ByRef sFileName As String) As Boolean
On Error Resume Next
FileExists = (GetAttr(sFileName) And vbDirectory) <> vbDirectory
End Function
was slower than this one:
Code:
Private Declare Function GetFileAttributesW Lib "kernel32.dll" (ByVal lpFileName As Long) As Long
Public Function FileExists(ByRef sFileName As String) As Boolean
Const ERROR_SHARING_VIOLATION = 32&
Select Case (GetFileAttributesW(StrPtr(sFileName)) And vbDirectory) = 0&
Case True: FileExists = True
Case Else: FileExists = Err.LastDllError = ERROR_SHARING_VIOLATION
End Select
End Function
by about one second after 100,000 iterations (with both existing and non-existent files).
I think an unbiased benchmark should be able to settle this API vs intrinsic function debate once and for all.
EDIT
GetAttr probably lost due to ANSI-Unicode conversion on the OS side. As mentioned in Unicode and ANSI Functions:
 Originally Posted by MSDN
The ANSI versions are also less efficient, because the operating system must convert the ANSI strings to Unicode at run time.
Last edited by Bonnie West; Jul 7th, 2013 at 01:47 PM.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)
-
Jul 7th, 2013, 12:44 PM
#10
Re: Classic VB - How can I check if a file exists?
Thanks Bonnie for posting your test. Here is another great example of wrapper vs api comparison (sorry but I don't have tool to write my own right now).
Paraphrasing what Bonnie said it's pointless to debate this matter any further.
edit: was able to run some tests so below are the results from reading System32 folder:
api 1 (using code posted here) - 2.9 sec
api 2 (using code posted here) - 0.51 sec
fso (using code posted here) - 8.1 sec
dir wrapper (using code posted here) - a whooping 26.9 sec
Last edited by RhinoBull; Jul 7th, 2013 at 05:15 PM.
-
Jul 8th, 2013, 04:04 AM
#11
Re: Classic VB - How can I check if a file exists?
Code:
Option Explicit
Private Type WIN32_FIND_DATA 'Modified UDT
dwFileAttributes As Long
ftCreationTime As Currency
ftLastAccessTime As Currency
ftLastWriteTime As Currency
nFileSize As Currency
dwReserved As Currency
cFileName(519) As Byte
cAlternate(27) As Byte
End Type
Private Declare Function FindClose Lib "kernel32.dll" (ByVal hFindFile As Long) As Long
Private Declare Function FindFirstFileW Lib "kernel32.dll" (ByVal lpFileName As Long, ByRef lpFindFileData As Any) As Long
Private Declare Function QueryPerformanceCounter Lib "kernel32.dll" (ByRef lpPerformanceCount As Currency) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32.dll" (ByRef lpFrequency As Currency) As Long
Private Declare Sub Sleep Lib "kernel32.dll" (Optional ByVal dwMilliseconds As Long)
Private Sub Main()
Const FILE1 = "C:\\\\\Windows\/\/\System32/////msvbvm60.dll"
Const FILE2 = "C:\\\\\Windows\/\/\System32/////msvbvm70.dll"
Dim RV As Boolean, i As Long, Iterations As Long, sRetVal As String
Dim StartAPI As Currency, StopAPI As Currency, Freq As Currency
Dim StartDIR As Currency, StopDIR As Currency
MsgBox "FILE1 = """ & FILE1 & """" & vbNewLine & _
"FileExistsAPI(FILE1) = " & FileExistsAPI(FILE1) & vbNewLine & _
"FileExistsDIR(FILE1) = " & FileExistsDIR(FILE1) & vbNewLine & vbNewLine & _
"FILE2 = """ & FILE2 & """" & vbNewLine & _
"FileExistsAPI(FILE2) = " & FileExistsAPI(FILE2) & vbNewLine & _
"FileExistsDIR(FILE2) = " & FileExistsDIR(FILE2), vbInformation, "FileExists"
Do: sRetVal = InputBox("Loop how many times?", "FileExistsAPI vs FileExistsDIR", "500,000")
If StrPtr(sRetVal) = 0& Then Exit Sub ' Abort benchmark if canceled
On Error Resume Next
Iterations = CLng(sRetVal) - 1&
Loop While Err
If QueryPerformanceFrequency(Freq) Then
Sleep
QueryPerformanceCounter StartAPI
For i = 0& To Iterations
RV = FileExistsAPI(FILE1) 'Existing
RV = FileExistsAPI(FILE2) 'Missing
Next
QueryPerformanceCounter StopAPI
Sleep
QueryPerformanceCounter StartDIR
For i = 0& To Iterations
RV = FileExistsDIR(FILE1) 'Existing
RV = FileExistsDIR(FILE2) 'Missing
Next
QueryPerformanceCounter StopDIR
MsgBox FormatNumber(Iterations + 1&, 0&) & " Iterations" & vbNewLine & vbNewLine & _
"API = " & Round((StopAPI - StartAPI) / Freq, 3&) & " secs" & vbNewLine & _
"DIR = " & Round((StopDIR - StartDIR) / Freq, 3&) & " secs", vbInformation, _
"FileExistsAPI vs FileExistsDIR"
End If
End Sub
Public Function FileExistsAPI(ByRef sFileName As String) As Boolean
Dim WFD As WIN32_FIND_DATA
If LenB(sFileName) Then _
If FindClose(FindFirstFileW(StrPtr(sFileName), WFD)) Then _
FileExistsAPI = (WFD.dwFileAttributes And vbDirectory) <> vbDirectory
End Function
Public Function FileExistsDIR(ByRef sFileName As String) As Boolean
Const FILE_ATTRIBS = vbArchive Or vbHidden Or vbReadOnly Or vbSystem
If LenB(sFileName) Then FileExistsDIR = LenB(Dir(sFileName, FILE_ATTRIBS)) <> 0&
End Function
Code:
Vista 500,000x
-----------------
API = 75.787 secs
DIR = 88.540 secs
Win 7 500,000x
-----------------
API = 86.682 secs
DIR = 99.917 secs
Verdict: API rules! 
Exe optimized for Fast Code with all Advanced Optimizations on. Both benchmarks performed in Safe Mode with Command Prompt. Process boosted to Realtime priority. Tested with both Vista and Win 7 on the same machine.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)
-
Jul 8th, 2013, 05:35 AM
#12
Thread Starter
Junior Member
Re: Classic VB - How can I check if a file exists?
 Originally Posted by Bonnie West
Code:
Option Explicit
Private Type WIN32_FIND_DATA 'Modified UDT
dwFileAttributes As Long
ftCreationTime As Currency
ftLastAccessTime As Currency
ftLastWriteTime As Currency
nFileSize As Currency
dwReserved As Currency
cFileName(519) As Byte
cAlternate(27) As Byte
End Type
Private Declare Function FindClose Lib "kernel32.dll" (ByVal hFindFile As Long) As Long
Private Declare Function FindFirstFileW Lib "kernel32.dll" (ByVal lpFileName As Long, ByRef lpFindFileData As Any) As Long
Private Declare Function QueryPerformanceCounter Lib "kernel32.dll" (ByRef lpPerformanceCount As Currency) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32.dll" (ByRef lpFrequency As Currency) As Long
Private Declare Sub Sleep Lib "kernel32.dll" (Optional ByVal dwMilliseconds As Long)
Private Sub Main()
Const FILE1 = "C:\\\\\Windows\/\/\System32/////msvbvm60.dll"
Const FILE2 = "C:\\\\\Windows\/\/\System32/////msvbvm70.dll"
Dim RV As Boolean, i As Long, Iterations As Long, sRetVal As String
Dim StartAPI As Currency, StopAPI As Currency, Freq As Currency
Dim StartDIR As Currency, StopDIR As Currency
MsgBox "FILE1 = """ & FILE1 & """" & vbNewLine & _
"FileExistsAPI(FILE1) = " & FileExistsAPI(FILE1) & vbNewLine & _
"FileExistsDIR(FILE1) = " & FileExistsDIR(FILE1) & vbNewLine & vbNewLine & _
"FILE2 = """ & FILE2 & """" & vbNewLine & _
"FileExistsAPI(FILE2) = " & FileExistsAPI(FILE2) & vbNewLine & _
"FileExistsDIR(FILE2) = " & FileExistsDIR(FILE2), vbInformation, "FileExists"
Do: sRetVal = InputBox("Loop how many times?", "FileExistsAPI vs FileExistsDIR", "500,000")
If StrPtr(sRetVal) = 0& Then Exit Sub ' Abort benchmark if canceled
On Error Resume Next
Iterations = CLng(sRetVal) - 1&
Loop While Err
If QueryPerformanceFrequency(Freq) Then
Sleep
QueryPerformanceCounter StartAPI
For i = 0& To Iterations
RV = FileExistsAPI(FILE1) 'Existing
RV = FileExistsAPI(FILE2) 'Missing
Next
QueryPerformanceCounter StopAPI
Sleep
QueryPerformanceCounter StartDIR
For i = 0& To Iterations
RV = FileExistsDIR(FILE1) 'Existing
RV = FileExistsDIR(FILE2) 'Missing
Next
QueryPerformanceCounter StopDIR
MsgBox FormatNumber(Iterations + 1&, 0&) & " Iterations" & vbNewLine & vbNewLine & _
"API = " & Round((StopAPI - StartAPI) / Freq, 3&) & " secs" & vbNewLine & _
"DIR = " & Round((StopDIR - StartDIR) / Freq, 3&) & " secs", vbInformation, _
"FileExistsAPI vs FileExistsDIR"
End If
End Sub
Public Function FileExistsAPI(ByRef sFileName As String) As Boolean
Dim WFD As WIN32_FIND_DATA
If LenB(sFileName) Then _
If FindClose(FindFirstFileW(StrPtr(sFileName), WFD)) Then _
FileExistsAPI = (WFD.dwFileAttributes And vbDirectory) <> vbDirectory
End Function
Public Function FileExistsDIR(ByRef sFileName As String) As Boolean
Const FILE_ATTRIBS = vbArchive Or vbHidden Or vbReadOnly Or vbSystem
If LenB(sFileName) Then FileExistsDIR = LenB(Dir(sFileName, FILE_ATTRIBS)) <> 0&
End Function
Code:
Vista 500,000x
-----------------
API = 75.787 secs
DIR = 88.540 secs
Win 7 500,000x
-----------------
API = 86.682 secs
DIR = 99.917 secs
Verdict: API rules!
Exe optimized for Fast Code with all Advanced Optimizations on. Both benchmarks performed in Safe Mode with Command Prompt. Process boosted to Realtime priority. Tested with both Vista and Win 7 on the same machine.
Yes! API is awesome and Quicker. I should use API for anything I might want to get my projects to do.
Last edited by PSXGamerPro1; Jul 8th, 2013 at 08:11 AM.
-
Jul 8th, 2013, 09:48 AM
#13
Re: Classic VB - How can I check if a file exists?
Personally I would just use the DIR$() function. A while back we did some testing on the various methods of searching for files and DIR$() was right there with the API calls in terms of speed. In our test we were looping through around 40,000 files and found that the time taken with API and DIR$() was almost identical with one being about 1 second + or - of the other on each run and the one that gave the fastest time was not always the API. We also tested with the FSO which was much much slower than the other two options.
Of course the old faithful Dos Dir was faster than anything we tested but if you add code to call it and get the results then it can take longer than the API on a listign of files that is not very long or is not scanning bunch of folders. On really large requests the Dos method seems to be the fastest and on short requests API or DIR$() are about the same.
Last edited by DataMiser; Jul 8th, 2013 at 09:52 AM.
-
Jul 8th, 2013, 10:02 AM
#14
Re: Classic VB - How can I check if a file exists?
@ DataMiser
In your tests, which version of the API did your team use? Is it the A (ANSI) or the W (Unicode) entrypoint? Also, on which OS did your team ran the tests? The reason I'm asking is because, ANSI-Unicode conversion may be a factor in the timing results. See my edit in post #9.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)
-
Jul 8th, 2013, 08:54 PM
#15
Re: Classic VB - How can I check if a file exists?
 Originally Posted by DataMiser
Personally I would just use the DIR$() function. A while back we did some testing on the various methods of searching for files and DIR$() was right there with the API calls in terms of speed. In our test we were looping through around 40,000 files and found that the time taken with API and DIR$() was almost identical with one being about 1 second + or - of the other on each run and the one that gave the fastest time was not always the API. We also tested with the FSO which was much much slower than the other two options.
Of course the old faithful Dos Dir was faster than anything we tested but if you add code to call it and get the results then it can take longer than the API on a listing of files that is not very long or is not scanning bunch of folders. On really large requests the Dos method seems to be the fastest and on short requests API or DIR$() are about the same.
Agreed. You also have to write code that checks all possible drive letters for the file. The same file name can exist on several drives. Thus, the files(s) could be anywhere on the system. It can be done and you should count and/or list them all along with their location.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|