Centrum skryptów - Systemy operacyjne

Jak dynamicznie wyświetlić dostępne litery dysków w polu listy?

Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

Cześć Skrypciarze!

Witamy w rubryce TechNet, w której Skrypciarze z firmy Microsoft odpowiadają na częste pytania dotyczące używania skryptów w administracji systemu. Jeśli macie jakieś pytania z tej dziedziny, zachęcamy do wysłania e-maila na adres: scripter@microsoft.com. Nie możemy zagwarantować odpowiedzi na każde otrzymane pytanie, ale staramy się jak możemy.

Jak dynamicznie wyświetlić dostępne litery dysków w polu listy?

Cześć Skrypciarze! Pytanie

Cześć, Skrypciarze! Używam aplikacji HTA do mapowania dysków. Chcę, żeby dostępne litery dysków pojawiały się w polu listy. Jak dynamicznie wyświetlić wszystkie litery dysku dostępne na komputerze?

-- JT

Cześć Skrypciarze! Pytanie

Cześć, JT. Chciałbym dzisiaj na powitanie powiedzieć coś błyskotliwego, opowiedzieć jakąś fajną anegdotę, ale mam umysł zajęty tym, co nas czeka. Chodzi mianowicie o to, że przed nami dużo pracy, pytanie JT wymaga kompleksowego spojrzenia i mam zamiar przedstawić odpowiedź w formie wielowątkowej. Zamiar zamiarem, zobaczymy, czy mi się uda, ale obiecuję, że będziecie zadowoleni z efektu. Czeka nas tylko trochę pracy, więc nie będę przedłużał i zajmę się od razu konkretami.

Oto skrypt wyświetlający dostępne litery dysków w polu listy:

<SCRIPT Language="VBScript">

    Sub Window_onLoad

        strComputer = "."



        Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")



        Set colDisks = objWMIService.ExecQuery("Select * from Win32_LogicalDisk")



        Set objDictionary = CreateObject("Scripting.Dictionary")



        For Each objDisk in colDisks

            objDictionary.Add objDisk.DeviceID, objDisk.DeviceID

        Next



        For i = 67 to 90

            strDrive = Chr(i) & ":"

            If objDictionary.Exists(strDrive) Then

            Else

                strDrives = strDrives & strDrive & vbCrLf

            End If

        Next



        arrDrives = Split(strDrives, vbCrlf)



        For Each strDrive In arrDrives

            Set objOption = Document.createElement("OPTION")

            objOption.Text = strDrive

            objOption.Value = strDrive

            AvailableDrives.Add(objOption)

        Next

    End Sub

</SCRIPT>



<body>

    <select size="5" name="AvailableDrives" style="width:100">

    </select>

</body>

Zanim przejdę do opisu skryptu i jego działania chcę zauważyć, że nie jest to kompletne rozwiązanie do mapowania napędu dysku; skrypt ten pokazuje tylko, jak pobrać dostępne litery dysku i dodać te litery do pola listy. Czy przedstawię jeszcze dzisiaj kompletne rozwiązanie? Być może, ale jeszcze nic nie powiem. Gdybym to zrobił, moglibyście od razu przejść do tej części artykułu, co oznacza, że przegapilibyście to, co mam do powiedzenia w pozostałych jego częściach.

Aplikacja HTA jest bardzo prosta: składa się jedynie z pola listy o nazwie AvailableDrives, które wyświetla pięć elementów jednorazowo (do tego służy właściwość Size) i ma 100 pikseli szerokości. Oto tagowanie HTML wyświetlające pole listy:

<select size="5" name="AvailableDrives" style="width:100">

</select>

Macie rację: ta lista nie zawiera żadnych opcji, nieprawdaż? (Tak samo, jak Skrypciarze jeżeli chodzi o wybór ścieżki kariery.) Ale nie martwmy się; jak wiecie, w aplikacji HTA chodzi o to, żeby dodać te opcje programistycznie. I tak też zrobimy we właściwym czasie.

Uwaga. Jeżeli nie do końca wiecie, co to aplikacja HTA, pola listy oraz instrukcja <SELECT>, zajrzyjcie do centrum HTA Developer’s Center (j.ang.), aby poszerzyć swoją wiedzę.

No dobrze, tyle na temat wyświetlania pola na ekranie. Zajmijmy się teraz tym, o co nam naprawdę chodzi: dynamicznym dodawaniem dostępnych liter dysków do tego pola listy.

Chcemy, aby nasza aplikacja HTA automatycznie ładowała te litery dysków przy każdym otwarciu lub odświeżeniu aplikacji. Jak to zrobić? To proste: umieszczamy kod aktualizujący pole listy w podprocedurze o nazwie Window_onLoad:

<SCRIPT Language="VBScript">

    Sub Window_onLoad

Jeżeli znacie się na programowaniu HTML, wiecie, że podprocedura Window_onLoad jest wykonywana automatycznie przy każdym załadowaniu lub odświeżaniu witryny internetowej (lub aplikacji HTA). A co, jeżeli nie wiecie zbyt wiele na temat programowania HTML? Żaden problem: teraz wiecie, że podprocedura Window_onLoad jest wykonywana przy każdym załadowaniu lub odświeżaniu witryny internetowej (lub aplikacji HTA).

Wewnątrz podprocedury zaczynamy od połączenia się z usługą WMI na lokalnym komputerze. Czy aplikacja HTA może współpracować ze zdalnym komputerem? No cóż, tak jakby. Nie stanowi problemu pobranie informacji na temat litery dysku ze zdalnego komputera; jednak mapowanie dysków na zdalnym komputerze to poważniejsza sprawa, którą nie możemy się dzisiaj zająć. (Wskazówki dotyczące tego, jak to zrobić, znajdują się w tym archiwalnym artykule Cześć Skrypciarze).

Po połączeniu się z usługą WMI stosujemy metodę ExecQuery w celu pobrania informacji o wszystkich używanych dyskach na komputerze, zarówno tych lokalnych, jak i zmapowanych dysków sieciowych:

Set colDisks = objWMIService.ExecQuery("Select * from Win32_LogicalDisk")

A cóż to? Jedyne, co do tej pory zrobiliśmy, to pobranie kolekcji niedostępnych liter dysków (czyli tych, które są już używane). Ale czy nie chcieliśmy się dowiedzieć, które litery są dostępne? No tak, tu się sprawa trochę komplikuje. Ale przecież sobie z tym poradzimy.

O tym jednak też wam nie powiem, przynajmniej nie teraz. Zanim będę mógł to zrobić, musimy utworzyć wystąpienie obiektu Scripting.Dictionary. Kiedy już utworzymy wystąpienie obiektu Dictionary, wykonujemy poniższy wiersz kodu:

For Each objDisk in colDisks

    objDictionary.Add objDisk.DeviceID, objDisk.DeviceID

Next

Co się tutaj dzieje? Uruchamiamy pętlę, która przejdzie przez kolekcję napędów dysku i dla każdego dysku w kolekcji dodajemy literę dysku (DeviceID) do obiektu Dictionary, używając litery dysku jako zarówno klucza, jak i elementu Dictionary.

Uwaga. Wiem, wiem. Ale wszystko, czego można się dowiedzieć na temat obiektu Dictionary znajduje się w rubryce Sesame Script (j.ang.) .

Teraz mamy obiekt Dictionary zawierający klucze podobne do poniższych, przy czym każdy klucz reprezentuje używaną literę dysku:

  • C:
  • D:
  • E:
  • M:
  • X:

Macie racje: w dalszym ciągu nie mamy listy dostępnych liter dysku, nieprawdaż? Ale to się zaraz zmieni dzięki zastosowaniu następującego fragmentu kodu:

For i = 67 to 90

    strDrive = Chr(i) & ":"

    If objDictionary.Exists(strDrive) Then

    Else

        strDrives = strDrives & strDrive & vbCrLf

    End If

Next

Bez obawy, zaraz wyjaśnimy, jak to działa. Na początek uruchamiamy pętlę For Next, która przejdzie przez elementy od 67 do 90. Dlaczego od 67 do 90? No cóż, litery dysków są ograniczone do liter od C do Z (litery A oraz B są zarezerwowane dla napędów dyskietek). Jak się okazuje, wartość ASCII (j.ang.) dla litery C to 67, a wartość ASCII dla litery Z to 90. Ustawienie pętli For Next, która przejdzie przez elementy od 67 do 90 pozwoli nam w sprytny sposób przejść przez litery z zakresu od C do Z.

Wewnątrz pętli For Next, używamy funkcji Chr w celu przekonwertowania wartości ASCII zmiennej pętli (i) na bieżący znak; na przykład, przy pierwszym przejściu pętli, i ma wartość 67 co oznacza, że funkcja Chr przekaże nam literę C. Po przekonwertowaniu wartości ASCII dodajemy na końcu dwukropek. Do tego posłuży nam ten oto wiersz kodu:

strDrive = Chr(i) & ":"

To z kolei oznacza, że – przy pierwszym przejściu pętli - zmienna strDrive będzie miała wartość: C:.

Co, teraz jak o tym myślę, do złudzenia przypomina literę dysku, nieprawdaż?

Teraz przechodzimy do następującego wiersza kodu:

If objDictionary.Exists(strDrive) Then

Używamy tutaj metody Exists w celu określenia, czy ta pierwsza litera pojawia się w obiekcie Dictionary. Przypuśćmy, że tak jest. Oznacza to, że dana litera dysku jest już używana i dlatego też nie jest dostępna do zmapowania. Wskutek tego nie robimy absolutnie nic. (Cóż, nic oprócz krążenia w kółko i powtarzania procesu dla następnej wartości w pętli.)

Teraz przypuśćmy, że litera nie pojawia się w obiekcie Dictionary. (czyli, zakładamy, że metoda Exists daje wynik False.) To może oznaczać tylko jedno: ta litera nie jest używana i dlatego też jest dostępna do zmapowania dysku. Wskutek tego, stosujemy poniższy wiersz kodu w celu dodania litery dysku (oraz znaku powrotu karetki) do zmiennej o nazwie strDrives:

strDrives = strDrives & strDrive & vbCrLf

Macie to? Zanim opuścimy pętlę, wszystkie dostępne litery dysku zostaną bezpiecznie zachowane w zmiennej o nazwie strDrives.

Teraz wystarczy tylko zastanowić się, w jaki sposób umieścić te litery dysku w naszym polu listy. Aby tego dokonać, następnym naszym krokiem jest zastosowanie funkcji Split w celu utworzenia tablicy o nazwie arrDrives; jak widać robimy to rozdzielając zmienną strDrive używając znaku powrotu karetki jako delimitera (vbCrLf):

arrDrives = Split(strDrives, vbCrlf)

To z kolei daje nam tablicę składającą się z następujących elementów (na naszym komputerze testowym), które odpowiadają dostępnym literom dysku na komputerze:

  • F:
  • G:
  • H:
  • I:
  • J:
  • K:
  • L:
  • N:
  • O:
  • P:
  • Q:
  • R:
  • S:
  • T:
  • U:
  • V:
  • W:
  • Y:
  • Z:

A teraz – na koniec – dodajemy dostępne litery dysku do pola listy (nie martwcie się, działanie skryptu kończy się szybciej niż moje wyjaśnienia na jego temat):

For Each strDrive In arrDrives

    Set objOption = Document.createElement("OPTION")

    objOption.Text = strDrive

    objOption.Value = strDrive

    AvailableDrives.Add(objOption)

Next

Ustawiliśmy tylko pętlę For Each, która przejdzie przez kolekcję dostępnych liter dysków. Dla każdego elementu w kolekcji tworzymy wystąpienie obiektu HTML Option; każdy obiekt Option jest ekwiwalentem elementu znajdującego się w polu listy. Do tego służy następujący wiersz kodu:

Set objOption = Document.createElement("OPTION")

Teraz używamy poniższych dwóch wierszy kodu w celu konfiguracji właściwości Text oraz Value dla elementu:

objOption.Text = strDrive

objOption.Value = strDrive

W razie, gdybyście nie wiedzieli, na czym polega praca z HTML, właściwość Text to po prostu tekst pojawiający się w polu listy. Właściwość Value, natomiast, to dane raportowane do podprocedury podczas wyboru określonej opcji. Właściwości Text oraz Value danej opcji nie muszą być identyczne. Sprawiliśmy, że tutaj są identyczne ponieważ ma to sens: chcemy, aby litera dysku pojawiała się w polu listy i chcemy ponadto, aby ta sama litera dysku została użyta w podprocedurze.

Po skonfigurowaniu obiektu Option dodajemy nowy element do pola listy w ten oto sposób:

AvailableDrives.Add(objOption)

Jak widać, odnosimy się tylko do pola listy (AvailableDrives) i wywołujemy metodę Add. Przy tym, przekazujemy metodzie Add jeden parametr: odniesienie do obiektu do naszego obiektu Option. Następnie kontynuujemy działanie pętli i powtarzamy proces dla następnego elementu w tablicy. Kiedy to zakończymy, wszystkie dostępne litery dysków pojawią się w polu listy, które powinno wyglądać jak to poniżej:

Co powiecie na pełniejsze rozwiązanie, takie, które w zasadzie mapuje dysk za nas? No cóż, bez żadnych dodatkowych wyjaśnień, przedstawię Wam pewien sposób. Aby zastosować tę HTA, należy wybrać literę dysku, a następnie kliknąć przycisk Map Drive. Kiedy pojawi się okno dialogowe , należy wpisać ścieżkę UNC do napędu dysku (np. \\atl-fs-01\public). Kliknąć OK i czekać, aż staną się dwie rzeczy:

  • Dysk zostanie zmapowany
  • Odświeży się pole listy (ponieważ poprzednio dostępna litera dysku nie jest już dostępna)

Oto obiecany kod:

<SCRIPT Language="VBScript">

    Sub Window_onLoad

        Set objDictionary = CreateObject("Scripting.Dictionary")



        strComputer = "."



        Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")



        Set colDisks = objWMIService.ExecQuery("Select * from Win32_LogicalDisk")



        For Each objDisk in colDisks

            objDictionary.Add objDisk.DeviceID, objDisk.DeviceID

        Next



        For i = 67 to 90

            strDrive = Chr(i) & ":"

            If objDictionary.Exists(strDrive) Then

            Else

                strDrives = strDrives & strDrive & vbCrLf

            End If

        Next



        arrDrives = Split(strDrives, vbCrlf)



        For Each strDrive In arrDrives

            Set objOption = Document.createElement("OPTION")

            objOption.Text = strDrive

            objOption.Value = strDrive

            AvailableDrives.Add(objOption)

        Next

    End Sub



    Sub MapDrive

        If AvailableDrives.Value = "" Then

            Msgbox "Please select a drive letter."

            Exit Sub

        End If

        strDrive = AvailableDrives.Value

        strPath = InputBox("Please enter the network path:")

        If strPath = "" Then

            Exit Sub

        End If

        Set objNetwork = CreateObject("Wscript.Network")

        objNetwork.MapNetworkDrive strDrive, strPath

        Location.Reload(True)

     End Sub

</SCRIPT>



<body>

    <select size="5" name="AvailableDrives" style="width:100px"></select><p>

    <input type="button" value="Map Drive" onClick="MapDrive">

</body>

I to już na szczęście koniec.

Sami przyznacie, że trochę się dziś napracowaliśmy.

 Do początku strony Do początku strony

Centrum skryptów - Systemy operacyjne