Posts tagged ‘Windows’

Triki z PowerShellem #12 – Rozpakowywanie

2009-12-07 23:18

Powtarzające się katalogiWiele programów z sieci wciąż jeszcze ściąga się w postaci archiwów do samodzielnego wypakowania, jak choćby w formacie .zip. Ma to swoje zalety i wady – do tych drugich należy fakt, że nie bardzo wiadomo, jak wygląda wewnętrzna struktura katalogów takiej paczki. Używając opcji typu Wypakuj tutaj ryzykujemy zaśmiecenie folderu Downloads plikami programu. Dlatego osobiście zawsze stosuję polecenie Wypakuj do nowego katalogu.
I tu czasem jest mały zonk, gdy twórca archiwum zdecydował się na spakowanie całego folderu, a nie tylko zawartych w nim plików. Powstają wtedy nadmiarowe katalogi, wydłużające ścieżki do plików (co widać obok – w wersji trochę przesadzonej ;)).

Ponieważ podobne sytuacje zdarzają mi się dość często, postanowiłem im zaradzić przy pomocy najlepszego narzędzia na takie okazje, czyli PowerShella rzecz jasna :) Wynikiem jest poniższy skrypt do sprytniejszego rozpakowywania archiwów:

  1. # unpack.ps1
  2. # Sprytne rozpakowywanie archiwów
  3. param ([string]$archive = $(throw "No archive specified"))
  4.  
  5. # Bierzemy nazwę archiwum i tworzymy odpowiadający mu katalog
  6. $name = [IO.Path]::GetFileNameWithoutExtension($archive)
  7. Set-Location -Path (New-Object IO.FileInfo @($name)).DirectoryName
  8. $dir = [IO.Directory]::CreateDirectory($name)
  9.  
  10. # Rozpakowujemy archiwum do tego katalogu
  11. $shell = New-Object -ComObject Shell.Application
  12. $src = $shell.Namespace($archive)
  13. $dest = $shell.Namespace($name)
  14. $dest.CopyHere($src.items())
  15.  
  16. # Rekurencyjnie badamy zawartość rozpakowanego archiwum
  17. while (($items = $dir.GetFileSystemInfos()) -eq 1)
  18. {
  19.     # Sprawdzamy, czy jego pierwszy i jedyny element jest katalogiem
  20.     $fsi = $items[0]
  21.     if (($fsi.Attributes -band [IO.FileAttributes]::Directory) -eq 0)
  22.         { break }
  23.    
  24.     # Jest - dokonujemy skrócenia ścieżki
  25.     $fsi.MoveTo([IO.Path]::GetRandomFileName())
  26.     $dir.Delete()
  27.     $dir = $fsi
  28.     $dir.MoveTo($name)
  29. }

Jego działanie polega wpierw na zwykłej dekompresji archiwum. Jak można zauważyć, używa do tego obiektu COM-owskiego Shell.Application. To sprawia, że skrypt ma pod tym względem te same możliwości co zwykły windowsowy Eksplorator (dla większych plików pokaże nawet pasek postępu ;]).
Później wypakowana zawartość jest poddawana operacji, którą nazywam tutaj ‘skróceniem ścieżki’. Polega ona wyrzuceniu jednego poziomu drzewa folderów, o ile tylko pewien katalog jest jedynym elementem swojego katalogu nadrzędnego. Takie właśnie sytuacje powstają przy dekompresji do nowego folderu archiwów źle zapakowanych (przynajmniej z mojego punktu widzenia ;P). Wynikiem działania skryptu będzie więc w sumie jeden nowy podkatalog zawierający bezpośrednio całą interesującą zawartość archiwum.

Oczywiście używanie powyższego skryptu tylko z poziomu linii komend PowerShella nie jest specjalnie wygodne; lepiej jest dodać go do menu kontekstowego archiwów, czyli np. plików .. O tym, jak można tego dokonać, napisałem dość obszernie przy okazji prezentacji skryptu do wysyłania przez FTP.

Tags: , ,
Author: Xion, posted under Applications, Internet, Programming » 5 comments

Listy skoków w Windows 7

2009-11-30 22:44

Przykładowa lista skokówJednym z bardziej zauważalnych składników Windows 7, które odróżniają ten system od Visty, jest nowy wygląd paska zadań. Jest szerszy, wyświetla duże ikony i przesunięcie go z dołu na bok ekranu w końcu ma sens (hurra dla monitorów wide-screen). Ale nowy wygląd to w tym przypadku nie wszystko, bo pasek ten zyskał też trochę na funkcjonalnościach.
Wśród nich mamy tzw. listy skoków (Jump Lists), zastępujące tradycyjne menu sterowania. Listy te pojawiają się po kliknięciu prawym przyciskiem na ikonkę na pasku zadań.

Co zawierają takie listy? Jak widać z boku, ich elementami mogą być skróty do ostatnio otwartych w programie dokumentów. Żeby było zabawniej, będzie ona wygenerowana automatycznie nawet dla tych aplikacji, których twórcy w momencie ich pisania nie mieli bladego pojęcia o tym, że kiedyś będziemy mieli taki system jak Windows 7 :) W tej wersji bowiem sam Windows zarządza listami MRU (Most Recenty Used) dla poszczególnych programów, o ile tylko wywołują one funkcję ShAddToRecentDocs przy otwieraniu poszczególnych plików.
A to wbrew pozorom nie jest takie duże wymaganie, gdyż jest automatycznie ono spełnione, jeśli zachodzi jedna z poniższych sytuacji:

  • aplikacja ma zarejestrowane skojarzenie rozszerzenia plików i użytkownik otwiera przypisany jej plik przy pomocy Eksploratora Windows (np. dwukrotnie klikając)
  • program używa standardowych okienek dialogowych do otwierania plików (np. funkcji GetOpenFileName z WinAPI albo OpenFileDialog z .NET)

Na listę skoków możemy też dodawać własne pozycje w postaci tak zwanych zadań (tasks), działających jak zwykłe systemowe skróty i tworzonych w ten sam sposób (interfejs IShellLink). Szczegóły i przykładowy kod można znaleźć na przykład w tym artykule na CodeProject.

Tags: , ,
Author: Xion, posted under Applications, Programming » Comments Off on Listy skoków w Windows 7

Dwie uwagi o śpiących wątkach

2009-11-29 14:46

Wszyscy znamy doskonale funkcję Sleep, która w Windows API służy do zawieszania działania wątku na określony czas (podawany w milisekundach). Wydawałoby się, że musi to być najprostsza funkcja z tego API, jaką tylko można sobie wyobrazić – bo co może być skomplikowanego w “zwykłej pauzie”? A okazuje się, że jak najbardziej może :)

Używając Sleep – zwłaszcza w swej zwykłej wersji – musimy bowiem pamiętać przynajmniej o dwóch sprawach:

  1. Wątek, w którym wywołamy tę funkcję, zostanie zawieszony całkowicie aż do momentu, gdy podany interwał czasowy się skończy . W szczególności Sleep(INFINITE); sprawi, że właściwie możemy ów wątek wyrzucić do kosza, gdyż nie da się już go odwiesić (funkcja ResumeThread wywołana z innego wątku nic tu nie pomoże).
    Również przyjście komunikatu okna w czasie, gdy nasz wątek smacznie śpi, nic nie zmienia. Wiadomości takie będą nieobsłużone aż do odwieszenia się wątku. Wynika stąd fakt, że uśpienie na dłuższy czas wątku, w którym obsługujemy UI, będzie dla użytkownika natychmiast zauważalne jako zawieszenie się programu. Jeśli chcemy, by w czasie przerwy aplikacja odpowiadała na komunikaty, należy zastosować inną funkcję (np. MsgWaitForMultipleObjectsEx albo po prostu GetTickCount wraz z wewnętrzną pętlą komunikatów).
    Istnieje też wariant Ex funkcji Sleep. Różni się on od oryginału tym, że rozpoczęte przez niego oczekiwanie można przerwać, jeśli sobie tego zażyczymy. Wątek uśpiony przez SleepEx może być przedwcześnie obudzony, gdy otrzyma informacje o zakończeniu asynchronicznej operacji I/O lub asynchronicznego wywołania procedury (APC).
  2. Czas, na jaki faktycznie uśpimy nasz wątek, będzie prawie na pewno dłuższy niż ten, który podamy jako parametr funkcji Sleep. Jest on bowiem determinowany przez długość tzw. kwantów czasu (time slices), jakie system operacyjny przydziela kolejnym wątkom, by zapewnić złudzenie ich jednoczesnego wykonania. Działanie Sleep polega w rzeczywistości na oddaniu systemowi reszty kwantu czasu, który został przydzielony wątkowi; przestawienie wątku w stan “nieuruchamialności” na podaną ilość milisekund; a następnie na wznowieniu jego pracy, gdy ponownie otrzyma czas procesora od systemowego schedulera. W sumie więc czas uśpienia będzie równy:

    PozostałyKwantCzasu + ParametrSleep + CzasDoUaktywnieniaWątku

    Stąd wynikają dwa wnioski. Po pierwsze, nie powinniśmy nigdy używać Sleep jako sposobu na mierzenie czasu – już poczciwy GetTickCount sprawi się tu znacznie lepiej. Po drugie, wywołanie Sleep(0); jest jak najbardziej dopuszczalne i oznacza przedwczesne zrzeczenie się kwantu czasu, jaki wątek dostał od systemu. W czasach 16-bitowych wersji Windows i wielowątkowości bez wywłaszczała była od tego specjalna funkcja Yield, którą należało często wywoływać, aby przełączanie wątków w ogóle było możliwe. Teraz rzecz jasna nie jest to konieczne, ale nadal może być przydatne dla zasygnalizowania, że nasz wątek nie robi nic pożytecznego, a tylko w brzydki sposób na coś czeka (tzw. busy waiting).

O tych dwóch szczegółach odnośnie funkcji Sleep dobrze jest pamiętać, jeśli nasze wątki chcemy usypiać. Jako programiści Windows możemy się aczkolwiek podbudować tym, że nie mamy przy tym takich problemów jak koderzy piszący pod Linuksem. Tam sleep może być potencjalnie zaimplementowany na sygnałach, co wymaga ostrożności przy stosowaniu go razem z funkcjami alarm i signal.

Tags: ,
Author: Xion, posted under Programming » Comments Off on Dwie uwagi o śpiących wątkach

Bogata ikonografia

2009-11-10 13:25

Zajmę się dzisiaj pewnym rodzajem aplikacji, którą przeciętny programista wykorzystuje rzadko, ale którą mimo tego powinien mieć. Mam tu na myśli program graficzny służący do edycji ikon, czyli tych małych (a od niedawna i większych) obrazków, które w Windows (i nie tylko) pojawiają się na każdym kroku – zwłaszcza na pulpicie czy w menu Start. Może nieczęsto zdarza się konieczność stworzenia ikonki dla własnej aplikacji, lecz kiedy już trzeba to zrobić, warto posłużyć się w tym celu odpowiednim narzędziem (a nie Paintem na przykład :]).
Znalezienie dobrej i darmowej aplikacji do edycji ikon nie jest jednak takie łatwe, jako że najlepsze i najpopularniejsze z nich są licencjonowane jako shareware. Istnieje jednak przynajmniej jeden darmowy i wart polecenia program tego typu; sam dowiedziałem się o nim od Rega.

Logo programu IcoFXNazywa się on IcoFX i ze względu na swą niepozorną wielkość (1.5 MB) ma chyba jedną z lepszych proporcji użyteczności do rozmiaru. Zawiera on bowiem zdecydowaną większość funkcji (jeśli nie wszystkie), jakie można wymagać od tego rodzaju aplikacji.
Program ten obsługuje oczywiście wszystkie używane obecnie rozmiary (od 16×16 do 256×256), głębie kolorów (od 1 do 32 bitów z kanałem alfa) i formaty ikon (łącznie z PNG wykorzystywanym od Visty wzwyż). Oprócz całego wachlarza typowych narzędzi graficznych oferuje też wiele predefiniowanych filtrów (rozmycie, detekcja krawędzi itp.) wraz z możliwością definiowania własnych. Generalnie część “graficzna” programu jest bez zarzutu. Jedynym mankamentem, na jaki się zdołałem dotąd natknąć, jest brak możliwości określania tolerancji kolorów dla wypełniania typu flood fill.

Screen z programu IcoFX Screen z programu IcoFX Screen z programu IcoFX

Część “narzędziowa” też prezentuje się dobrze. Przy pomocy programu możemy nie tylko ekstrahować ikony z plików .exe i .dll (w razie potrzeby masowo przy pomocy batch processing), ale także edytować takie pliki (w zakresie ikon, rzecz jasna). Taka edycja mogłaby być wprawdzie nieco lepiej pomyślana (dodanie nowej ikony do pliku .exe/.dll jest możliwe tylko poprzez import z .ico), ale w sumie da się z nią wytrzymać.

Tak więc na te niezbyt częste okazje, gdy musimy/chcemy pobawić z ikonami, IcoFX wydaje się ogólnie całkiem dobrym rozwiązaniem. Zwłaszcza ze tę cenę :)

Tags: , , ,
Author: Xion, posted under Applications » 5 comments

Jak naprawić GRUB-a

2009-10-24 23:38

"Logo" GRUB-aJeśli oprócz systemu okienkowego rodem z Microsoftu mamy też jakiegoś *niksa, to reinstalacja Windows będzie dla nas miała jeden nieprzyjemny efekt uboczny. Otóż instalatory Okienek radośnie nadpisują sektor startowy dysku (czyli MBR – Master Boot Sector), przez co Windows staje się jedynym systemem dającym się uruchomić w zwykły sposób. Ot, zwyczajowe MS-owe praktyki monopolistyczne ;-)

Jak temu zaradzić? Trzeba oczywiście przywrócić boot sector do właściwego stanu, co oznacza ponowne zainstalowanie używanego przez nas wcześniej bootloadera. W większości przypadków (jeśli mówimy o Linuksie jako drugim systemie) jest nim GRUB; w takim wypadku jego ponowne zainstalowanie wymaga:

  1. Uruchomienia Linuksa przy użyciu płytki typu LiveCD, dystrybucji uruchamianej z pendrive‘a, itp. Graficzny interfejs jest niepotrzebny, bo jak to zwykle w Linuksie, wszystko można zrobić z konsoli.
  2. Następnie należy uruchomić GRUB-a – koniecznie z prawami roota, a więc np. poprzez sudo grub.
  3. Z poziomu jego wiersza poleceń należy najpierw ustawić partycję, w której znajdują się pliki z danymi bootloadera. Jeśli nie wiemy, która to, najlepiej użyć polecenia find /boot/grub/stage1. Potem rezultat przekazujemy do komendy root, np. root (hd0,5).
  4. Na koniec komendą setup instalujemy GRUB-a na wybranym dysku fizycznym – zazwyczaj jest to setup (hd0).

Tyle powinno wystarczyć, by po ponownym uruchomieniu komputera z tego dysku pojawiło się nam menu bootowania GRUB-a. Przy odrobinie szczęścia oba systemy będą więc uruchamiały się normalnie ;)

Tags: , , , ,
Author: Xion, posted under Applications » 10 comments

Operacja reinstalacja

2009-10-23 19:02

Wczorajsza premiera Windows 7 to dobry pretekst, żeby nowy system w końcu przetestować – zwłaszcza, że większość opinii, których o nim słyszałem, była zdecydowanie przychylna. W połączeniu z faktem, iż system operacyjny na moim laptopie już od dobrych paru miesięcy domaga się skrócenia swoich cierpień, otrzymujemy tylko jeden logiczny wniosek: czas zakasać rękawy i zabrać się za reinstalację!

Ktokolwiek choć raz zajmował się ponownym stawianiem systemu od zera wie, że czynność ta nie należy do relaksujących. Chociaż drobne komplikacje są praktycznie gwarantowane: a to zapomnimy o jakimś sterowniku, a to zapodziejemy gdzieś numer seryjny systemu, i tak dalej. Posiadanie komputera “zapasowego” (w moim przypadku tradycyjnego – stacjonarnego) znacznie redukuje dolegliwość takich problemów, ale nawet i w tej sytuacji warto się do całej operacji dobrze przygotować.
I właśnie dlatego sporządziłem poniższą listę kontrolną czynności, które dobrze jest wykonać przed rozpoczęciem zabawy w reinstalację systemu. Nie gwarantuję oczywiście, że da się przy jej użyciu uniknąć wszelkich kłopotów. Powinna być ona jednak w dużym stopniu pomocna. A wygląda ona następująco:

  1. Zrób kopie zapasowe. Jest to oczywiste, a jednocześnie na tyle ważne, że warto o tym wspomnieć na początku. Niestety we współczesnych systemach dane, które chciałoby się zachować, prawie nigdy nie znajdują się w jednym miejscu. Dlatego właśnie można niemal zagwarantować, że przy robieniu przedinstalacyjnego backupu uda nam się coś pominąć.
    Żeby zminimalizować prawdopodobieństwo tego zdarzenia, warto do robienia kopii podejść dwojako:

    • Najpierw pomyślmy, co chcemy zachować. Edytowane dokumenty czy pisane programy są pewnie najważniejsze, ale to zdecydowanie nie wszystko. Co z ustawieniami używanych przez nas programów? Ulubionymi łączami w przeglądarce? Ciastkami (cookies)? Zapisanymi stanami gier (save‘ami)? Co z wszelkiego rodzaju przydatnymi materiałami, które kiedyś ściągnęliśmy nie wiadomo skąd i które jeszcze mogą się przydać? O różnego typu multimediach (muzyka, filmy) też nie wypadałoby zapomnieć. W sumie więc lista robi się całkiem pokaźna i pewnie każdy jeszcze mógłby coś na nią wpisać.
    • Następnie upewnijmy się, że o niczym nie zapomnieliśmy, przeglądając typowe miejsca, w których mogły się ukryć przydatne pliki. Moje dokumenty czy katalog /home będą pierwszym przystankiem. Potem warto odwiedzić Program Files (tudzież /usr/bin itp.) w poszukiwaniu aplikacji, których katalogi mogą zawierać ustawienia do skopiowania. W końcu warto spojrzeć do głównego katalogu dysku, do folderu z plikami ściąganymi z sieci, a w końcu na… Pulpit. Zwłaszcza jeśli tego ostatniego dawno nie sprzątaliśmy ;)
  2. Sprawdź, czy masz pod ręką odpowiednie płyty z systemami operacyjnymi. Celowo użyłem tu liczby mnogiej, bowiem nierzadko w grę wchodzi tutaj więcej niż jeden system. W szczególności chodzi więc tutaj o:
    • dysk z systemem, który będziemy instalować – dość oczywiste :)
    • dysk z systemem, którego aktualnie używamy – jeśli jest on inny niż ten instalowany, dobrze jest mieć na wszelki wypadek możliwość powrotu, gdyby up/downgrade okazał się porażką
    • dyski od pozostałych systemów, których używamy – jak chociażby LiveCD jakiegoś Linuksa, jeśli zdarza nam się mieć takowego

    Pamiętaj też o wszelkich kluczach produktów czy numerach seryjnych, jeśli któryś z systemów ich wymaga.

  3. Wyciągnij na wierzch dyski ze sterownikami do urządzeń, których używa twój komputer. Większość z nich pewnie będzie działała od razu, ale i tak warto mieć płytki pod ręką. Alternatywnie możemy zaufać sieci i stamtąd zaopatrzyć się w drivery – upewnijmy się jednak wpierw, że posiadamy sterowniki do modemu :)
  4. Przygotuj też wersje instalacyjne dużych programów, których używasz do pracy. Chodzi tu o takie rzeczy jak pakiet biurowy, środowisko programistyczne (wraz z wszystkimi SDK-ami!), program graficzny, itp. Nawet jeśli można się w nie zaopatrzyć poprzez sieć, dobrze jest mieć je nagrane na nośnikach DVD/CD.
  5. Nie zapomnij o programie antywirusowym i firewallu. Nie ma co, rzecz jasna, wierzyć przeróżnym badaniom stwierdzającym, że niezabezpieczony komputer podłączony do Internetu już po kilku minutach złapie megabajty wszelkiego rodzaju złośliwych programów. Nawet w przypadku Windows standardowy Windows Defender na początek w zupełności wystarczy. Tym niemniej warto w miarę szybko wyposażyć nowy system w aplikacje zabezpieczające.
  6. Zaopatrz się w listę małych programów, których używasz. Zachowywanie ich wersji instalacyjnej zwykle nie ma sensu, ale dobrze jest mieć przynajmniej ich nazwy, aby dało się je szybko odnaleźć w sieci i zainstalować na nowym systemie.
  7. Znajdź sobie jakieś zajęcie na czas instalacji systemu i większych programów; to może długo potrwać. Niewątpliwym utrudnieniem będzie tu oczywiście fakt, że zajęcie to nie może wymagać komputera ;-) (No, chyba że masz zapasowy :]). Tym niemniej przez te parę godzin warto skupić się na czymś bardziej produktywnym niż obserwowanie paska postępu.

Uff, spora ta lista. Jej rygorystyczne przestrzeganie może nie zawsze jest konieczne, ale nie wydaje mi się, żeby mogło komukolwiek zaszkodzić :) Akurat w przypadku tej nieczęsto (i coraz rzadziej) wykonywanej czynności, jaką jest reinstalacja systemu, zbytnia przezorność na pewno nie zawadzi.

Ciągnięcie okna za wnętrze

2009-10-06 21:14

System Windows pozwala tworzyć okna o różnych niestandardowych właściwościach – między innymi takich, które nie zawierają żadnego standardowego elementu, jak pasek tytułu czy przycisk zamknięcia. Kiedy zechcemy umożliwić przesuwanie takiego okna, to natrafimy na klasyczny problem Windows API, który posiada kilka rozwiązań. I jak to często bywa, mało które jest dobre ;)

Najkrótszym jest obsłużenie komunikatu WM_NCHITTEST. Przy jego pomocy system pyta okno, w jaką jego część “trafia” (stąd nazwa hit test) podany punkt. Trik polega na oszustwie poprzez udawanie, że prawie całe nasze okno (a przynajmniej jego obszar klienta) jest paskiem tytułu:

  1. case WM_NCHITTEST:
  2.     LRESULT hit = DefWindowProc(hWnd, uMsg, wParam, lParam);
  3.     return hit == HTCLIENT ? HTCAPTION : hit;

Jest to jednak na tyle skuteczne, że wówczas nasze okno naprawdę zacznie składać z samego paska tytułu. Najpoważniejszym (acz wcale nie jedynym) skutkiem ubocznym tego faktu jest niemożność jakiejkolwiek interakcji z kontrolkami zawartymi w oknie. Jeśli więc mamy takowe, to mamy też kłopot :)

Można oczywiście załatwić wszystko ręcznie: wykryć przeciąganie (WM_LBUTTONDOWN), “złapać” myszkę (SetCapture), odpowiednio przesuwać okno (np. SetWindowPos) o różnicę początkowej oraz aktualnej pozycji kursora (w WM_MOUSEMOVE), a na koniec zwolnić gryzonia (ReleaseCapture) w odpowiedzi na koniec przeciągania (WM_LBUTTONUP). Uff… Sporo roboty, nieprawdaż? Tak to jest, kiedy oszustwo nie popłaca :)
A może jednak?… Pomysł z podszyciem się pod pasek tytułu wydawał się dobry, lecz sęk w tym, że nie potrzebujemy (wręcz nie chcemy) całej jego funkcjonalności. Dlatego zamiast dużego przekrętu posłużmy się małym: symulujmy tylko i wyłącznie wciśnięcia lewego przycisku myszy:

  1. case WM_LBUTTONDOWN:
  2.     SendMessage (hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
  3.     break;

Wciśnięcia kierowane w pasek tytułu, rzecz jasna. W ten sposób “wywołamy” niejako tę część jego możliwości, która nas interesuje – czyli przesuwanie okna. Jednocześnie, ponieważ robimy to dopiero w WM_LBUTTONDOWN, nie przeszkadzamy innym kontrolkom w odpowiadaniu na zdarzenia myszy.

To rozwiązanie ma jeszcze jedną zaletę: daje się je zastosować także w środowiskach, które nie dają łatwego dostępu do procedury zdarzeniowej okna – jak np. Windows Forms. W nich wystarczy wywołać SendMessage wewnątrz zdarzenia w rodzaju OnMouseDown (wciśnięcie przycisku myszy nad oknem).

Tags: , ,
Author: Xion, posted under Programming » 4 comments
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.