Страница: 1 | 2 |
Вопрос: О поиске логических дисков
Добавлено: 02.09.07 03:22
Автор вопроса: Winand | Web-сайт:
Public Function FirstMuVoDrive() As String
Dim i As Long
For i = 67 To 90 ' От 'C:\' до 'Z:\'
If GetDriveType(Chr$(i) & ":\") = 2 Then
FirstMuVoDrive = Chr$(i) & ":\"
Exit Function
End If
Next i
FirstMuVoDrive = "C:\"
End Function
Вот такой был код.
Тогда я придумал вот такой способ
Private Declare Function GetLogicalDriveStrings Lib "kernel32" Alias "GetLogicalDriveStringsA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare Function GetDriveType Lib "kernel32.dll" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long
Public remDriveLetters() As String
Public Sub GetRemDriveLetters()
Dim sDrives As String * 255, arDrives() As String
Dim POS As Long
Call GetLogicalDriveStrings(255, sDrives)
POS = InStr(1, sDrives, vbNullChar & vbNullChar)
sDrives = Left(sDrives, POS - 1)
arDrives = Split(sDrives, vbNullChar)
Dim i As Long
For i = 0 To UBound(arDrives)
If GetDriveType(arDrives(i)) = 2 Then
ReDim Preserve remDriveLetters(UUBound + 1)
remDriveLetters(UUBound) = arDrives(i)
End If
Next i
End Sub
Private Function UUBound() As Long
On Error GoTo X:
UUBound = UBound(remDriveLetters)
Exit Function
X: UUBound = -1
End Function
Как обычно мне интересно: есть ли варианты лучше? ))
Ответы
Всего ответов: 16
Номер ответа: 1
Автор ответа:
Winand
Вопросов: 87
Ответов: 2795
Web-сайт:
Профиль | | #1
Добавлено: 02.09.07 03:24
Собственно поиск СЪёМНЫХ дисков происходит
Номер ответа: 2
Автор ответа:
sne
Разработчик Offline Client
ICQ: 233286456
Вопросов: 34
Ответов: 5445
Web-сайт:
Профиль | | #2
Добавлено: 02.09.07 11:18
1. лучше способа не предусмотрено
2. ты не учитываешь что буфер может потребоваться большей длинны чем ты его задаешь. Так что сделал бы ты лучше динамическое выделение памяти, а размер узнавал бы вызовом GetLogicalDriveStrings(0, vbNullString)
Номер ответа: 3
Автор ответа:
Winand
Вопросов: 87
Ответов: 2795
Web-сайт:
Профиль | | #3
Добавлено: 02.09.07 12:08
Private Declare Function GetLogicalDriveStrings Lib "kernel32" Alias "GetLogicalDriveStringsA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare Function GetDriveType Lib "kernel32.dll" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long
Public remDriveLetters() As String
Public Sub GetRemDriveLetters()
Dim sDrives As String, arDrives() As String
Dim LNG As Long
LNG = GetLogicalDriveStrings(0, vbNullString)
sDrives = Space(LNG - 2) 'String ends with double chr$(0),so we need "-2"
Call GetLogicalDriveStrings(LNG, sDrives)
arDrives = Split(sDrives, vbNullChar)
Dim i As Long
For i = 0 To UBound(arDrives)
If GetDriveType(arDrives(i)) = 2 Then
ReDim Preserve remDriveLetters(UUBound + 1)
remDriveLetters(UUBound) = arDrives(i)
End If
Next i
End Sub
Private Function UUBound() As Long
On Error GoTo X:
UUBound = UBound(remDriveLetters)
Exit Function
X: UUBound = -1
End Function
ВО!
Номер ответа: 4
Автор ответа:
udpn
Вопросов: 2
Ответов: 45
Профиль | | #4
Добавлено: 02.09.07 22:12
DriveLetters никогда не будет больше 26. К чему этот гемор с динамическим массивом? Времени жрет до хрена, а выиграть 100 байт памяти - это смешно ))) Отпадает необходимость в медленном вызове UUBound (засунуть в стек все регистры и перейти! + отлов ошибок + без того медленный убаунд)
В любом случае вместо UBound можно использовать переменную верхней границы (Split - единственное место где без него не обойтись).
sDrives = Space(LNG - 2) опять же, зачем? разводишь перспективу для багов? да и вариант без минуса будет в итоге быстрее
наконец, что если объявлять remDriveLetters типом As String * 1? попробуй оба варианта в твоем контексте, они равновероятно оказываются то быстрее, то медленнее.
GetDriveType(arDrives(i)) = 2 в норме, но неплохо бы дать Const. Это будет хорошим стилем программирования.
Номер ответа: 5
Автор ответа:
udpn
Вопросов: 2
Ответов: 45
Профиль | | #5
Добавлено: 02.09.07 22:15
да, еще. отступ необходим для любой открывающей конструкции, будь то Do, For, While, With или Function.
Номер ответа: 6
Автор ответа:
Winand
Вопросов: 87
Ответов: 2795
Web-сайт:
Профиль | | #6
Добавлено: 03.09.07 01:50
Хмм... Здесь всего 1 вызов UBound
и 2 - ReDim Preserve
Посчитал, если 26 лог.дисков, то буфер нужен длиной 103 (в функции длину нужно указывать на 2 больше - 105)
Добавил константы, remDriveLetters - фиксированной длины (as string * 3)
Private Declare Function GetLogicalDriveStrings Lib "kernel32" Alias "GetLogicalDriveStringsA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare Function GetDriveType Lib "kernel32.dll" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long
Private Const DRIVE_UNKNOWN As Long = 0
Private Const DRIVE_NO_ROOT_DIR As Long = 1
Private Const DRIVE_REMOVABLE As Long = 2
Private Const DRIVE_FIXED As Long = 3
Private Const DRIVE_REMOTE As Long = 4
Private Const DRIVE_CDROM As Long = 5
Private Const DRIVE_RAMDISK As Long = 6
Public remDriveLetters() As String * 3
Public Sub GetRemDriveLetters()
Dim sDrives As String * 103, arDrives() As String
Dim LNG As Long
LNG = GetLogicalDriveStrings(0, vbNullString)
Call GetLogicalDriveStrings(103 + 2, sDrives)
arDrives = Split(sDrives, vbNullChar)
Dim i As Long, uuBound As Long, topIndex As Long, driveType As Long
topIndex = -1
uuBound = UBound(arDrives)
ReDim Preserve remDriveLetters(uuBound)
For i = 0 To uuBound
driveType = GetDriveType(arDrives(i))
If driveType = DRIVE_REMOVABLE Then
topIndex = topIndex + 1
remDriveLetters(topIndex) = arDrives(i)
ElseIf driveType = DRIVE_NO_ROOT_DIR Then
Exit For
End If
Next i
ReDim Preserve remDriveLetters(topIndex)
End Sub
Номер ответа: 7
Автор ответа:
Winand
Вопросов: 87
Ответов: 2795
Web-сайт:
Профиль | | #7
Добавлено: 03.09.07 01:52
LNG = GetLogicalDriveStrings(0, vbNullString)
Это забыл удалить
Номер ответа: 8
Автор ответа:
Winand
Вопросов: 87
Ответов: 2795
Web-сайт:
Профиль | | #8
Добавлено: 03.09.07 02:10
Осенило))ЮБаунд вообще не нужен оказывается
Private Declare Function GetLogicalDriveStrings Lib "kernel32" Alias "GetLogicalDriveStringsA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare Function GetDriveType Lib "kernel32.dll" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long
Private Const DRIVE_NO_ROOT_DIR As Long = 1
Private Const DRIVE_REMOVABLE As Long = 2
Public remDriveLetters() As String * 3
Public Sub GetRemDriveLetters()
Dim sDrives As String * 103, arDrives() As String
Call GetLogicalDriveStrings(103 + 2, sDrives)
arDrives = Split(sDrives, vbNullChar)
Dim i As Long, topIndex As Long, driveType As Long
topIndex = -1
ReDim Preserve remDriveLetters(25)
For i = 0 To 25
driveType = GetDriveType(arDrives(i))
If driveType = DRIVE_REMOVABLE Then
topIndex = topIndex + 1
remDriveLetters(topIndex) = arDrives(i)
ElseIf driveType = DRIVE_NO_ROOT_DIR Then
Exit For
End If
Next i
ReDim Preserve remDriveLetters(topIndex)
End Sub
Номер ответа: 9
Автор ответа:
udpn
Вопросов: 2
Ответов: 45
Профиль | | #9
Добавлено: 03.09.07 15:42
молодец, сделал именно то о чем я говорил. а теперь попробуй заменить звезданутые стринги на обычные и сравни производительность в контексте. результат непредсказуем, но по-моему без активной работы со строковыми функциями (Mid, Left, Right) звездочки быстрее
есть одно большое но, только сейчас заметил. прога вылетит к чертям если зареганы все диски. подумай почему. короче, говорить бесполезно, надо писать все самому )
Option Explicit
Private Declare Function GetLogicalDriveStrings Lib "kernel32" Alias "GetLogicalDriveStringsA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare Function GetDriveType Lib "kernel32.dll" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long
' Никогда не удаляем ненужные константы. Комментируем "на случай если кому..." (c) Беляев или кто там так подписывается
'Private Const DRIVE_UNKNOWN As Long = 0
'Private Const DRIVE_NO_ROOT_DIR As Long = 1
Private Const DRIVE_REMOVABLE As Long = 2
'Private Const DRIVE_FIXED As Long = 3
'Private Const DRIVE_REMOTE As Long = 4
Private Const DRIVE_CDROM As Long = 5
'Private Const DRIVE_RAMDISK As Long = 6
Private mLetters(25) As String * 1 ' * 3 если надо "A:\" вместо "A". Обрезается оно автоматически и времени не занимет, так что оба варианта хороши.
Private mCount As Long
Public Sub GetRemDriveLetters()
Dim DrivesStr As String
Dim DrivesArr() As String
Dim i As Long
Dim DrivesStrLen As Long
mCount = 0
 rivesStrLen = GetLogicalDriveStrings(0, vbNullString)
 rivesStr = Space(DrivesStrLen)
Call GetLogicalDriveStrings(DrivesStrLen, DrivesStr)
 rivesArr = Split(DrivesStr, vbNullChar)
For i = 0 To UBound(DrivesArr)
Select Case GetDriveType(DrivesArr(i))
Case DRIVE_REMOVABLE, DRIVE_CDROM
'CDROM тоже в некотоом смысле сменный... Ну да тебе виднее
mLetters(mCount) = DrivesArr(i)
mCount = mCount + 1
End If
Next
End Sub
Номер ответа: 10
Автор ответа:
Winand
Вопросов: 87
Ответов: 2795
Web-сайт:
Профиль | | #10
Добавлено: 03.09.07 19:41
Попробовал запихнуть в sDrives все букавы от A до Z. Не вылетела.
А разве Select Case хорошая (всмысле скорости) функция?
Номер ответа: 11
Автор ответа:
Winand
Вопросов: 87
Ответов: 2795
Web-сайт:
Профиль | | #11
Добавлено: 03.09.07 20:08
константы это я именно в том коде удалил - чтоб меньше код был, а так и правда лучше знать все возможные варианты))
Private Declare Function GetLogicalDriveStrings Lib "kernel32" Alias "GetLogicalDriveStringsA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare Function GetDriveType Lib "kernel32.dll" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long
'Private Const DRIVE_UNKNOWN As Long = 0
'Private Const DRIVE_NO_ROOT_DIR As Long = 1
Private Const DRIVE_REMOVABLE As Long = 2
'Private Const DRIVE_FIXED As Long = 3
'Private Const DRIVE_REMOTE As Long = 4
Private Const DRIVE_CDROM As Long = 5
'Private Const DRIVE_RAMDISK As Long = 6
Public mLetters(25) As String * 3
Public mCount As Long
Public Sub GetRemDriveLetters()
Dim DrivesStr As String 'lpBuffer
Dim DrivesStrLen As Long 'nBufferLength
Dim DrivesArr() As String 'ALL Drives Array
Dim drvType As Long '= GetDriveType
Dim i As Long
mCount = 0
 rivesStrLen = GetLogicalDriveStrings(0, vbNullString)
 rivesStr = Space(DrivesStrLen - 2)
Call GetLogicalDriveStrings(DrivesStrLen, DrivesStr)
 rivesArr = Split(DrivesStr, vbNullChar)
For i = 0 To UBound(DrivesArr)
drvType = GetDriveType(DrivesArr(i))
If drvType = DRIVE_REMOVABLE Then
mLetters(mCount) = DrivesArr(i)
mCount = mCount + 1
ElseIf drvType = DRIVE_CDROM Then
mLetters(mCount) = DrivesArr(i)
mCount = mCount + 1
End If
Next
End Sub
Все таки настаиваю на DrivesStr = Space(DrivesStrLen - 2)
Иначе массив после split получается с 2 лишними пустыми значениями. Тут нужно оставить комментарий, шоб понятно было
Номер ответа: 12
Автор ответа:
udpn
Вопросов: 2
Ответов: 45
Профиль | | #12
Добавлено: 03.09.07 20:21
да ну ) а по-моему, если заняты все диски, ему не хватает буфера, происходит излияние в чужое пространство и порча либо соседних переменных либо едреный вылет с кодом 5 Программа выполнила... У меня происходит именно второе. Писать надо
Select Case БЫВАЕТ быстрее. этот случай - как раз тот самый. Только End Select надо поставить
Номер ответа: 13
Автор ответа:
Winand
Вопросов: 87
Ответов: 2795
Web-сайт:
Профиль | | #13
Добавлено: 03.09.07 22:21
Ясно. Спасибо)
Еще вопрос под конец
Если сделать так:
Можно ли вместо
использовать саму функцию?
Номер ответа: 14
Автор ответа:
udpn
Вопросов: 2
Ответов: 45
Профиль | | #14
Добавлено: 03.09.07 23:04
можно. но не нужно.
а еще лучше объявить mCount и mLetters как Private и использовать ReadOnly свойства
Номер ответа: 15
Автор ответа:
Winand
Вопросов: 87
Ответов: 2795
Web-сайт:
Профиль | | #15
Добавлено: 04.09.07 00:48
Так это ж всё в модуле. Как я буду обращаться к mCount и mLetters, если они Private.
Про ReadOnly ничего не знаю (вру: в UserControl это достигается вызовом ошибки при Property Let)