Posts from 2008

Statyczne składowe i takież konstruktory

2008-06-04 23:30

Wiadomo, że konstruktor to specjalna metoda, która jest wywoływana przy tworzeniu nowego obiektu i ma za zadanie go zainicjalizować. Okazuje się, że w innej wersji “konstruktor” (albo coś, co go przypomina) może służyć do inicjalizacji nie obiektu, lecz samej klasy. A co takiego ma klasa, że należy czasem zadbać o jej prawidłową inicjalizację? Ano chociażby składowe statyczne – wspólne dla wszystkich obiektów.
W C# możemy sobie zdefiniować statyczny konstruktor, który może się tym zająć – jak również (niemal) czymkolwiek innym. Taki konstruktor, podobnie jak zwykły ma postać metody o tej samej co klasa nazwie, lecz jest opatrzony modyfikatorem static. Zostaje on wywołany przed stworzeniem pierwszego obiektu klasy lub próbą dostępu do jakiejkolwiek składowej statycznej. Całkiem praktyczne, prawda?
Coś podobnego ma również Java, a zwie się to oryginalnie ‘statycznym inicjalizatorem’. W odróżnieniu od wariantu z C#, inicjalizator ten jest wywoływany wcześniej – już w momencie załadowania klasy przez maszynę wirtualną. Właściwie jednak nie ma to wielkiego znaczenia, bo efekt jest analogiczny: jeśli ów inicjalizator ma zrobić coś przed pierwszym użyciem klasy, na pewno zostanie to zrobione. Jego kod pisze się w definicji klasy, w bloku otoczonym nawiasami klamrowymi i opatrzonym – a jakże – słówkiem static.

A jak pod tym względem wypada C++? No cóż, jak zwykle blado :) Kruczkiem standardu jest fakt, że wszelkie składowe statyczne klas mają niezdefiniowaną kolejność inicjalizacji, jeśli są przypisane do odrębnych modułów (plików .cpp). Jeśli więc takie składowe zależą od siebie, to wynikiem mogą być tylko kłopoty.
Poradzić na to można dwojako – zależnie od tego, którą zaletę statycznych konstruktorów chcemy wykorzystać. Jeżeli na przykład chcemy, aby jakaś zmienna statyczna lub globalna była zainicjowana niezależnie od tego, gdzie i kiedy chcemy ją użyć, najlepiej uczynić ją lokalną statyczną zmienną w funkcji:

  1. Foo& GetFoo() { static Foo foo; return foo; }

Jeśli z kolei musimy mieć pewność, że przed stworzeniem obiektu naszej klasy zostaną wykonane jakieś dodatkowe czynności, to możemy to częściowo osiągnąć za pomocą statycznej flagi:

  1. class Foo
  2. {
  3.     public:
  4.         Foo()
  5.         {
  6.             if (!ms_bInitialized)
  7.             {
  8.                   // (czynności konieczne przed użyciem klasy)
  9.                   ms_bInitialized = true;
  10.             }
  11.         }
  12. };
  13. Foo::ms_bInitialized = false;

Niezależnie jednak od tego, co jest nam akurat potrzebne, nie powinniśmy nigdy zapominać o rozważeniu zależności między składowymi statycznymi klas i/lub zmiennymi globalnymi w naszym kodzie, jeśli chcemy uniknąć niezdefiniowanego zachowania. Bo wtedy po prostu wszystko się zdarzyć może :]

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

Triki z PowerShellem #3 – PowerGUI

2008-06-03 20:29

Logo PowerGUIW Windows większość czynności administracyjnych można wykonać przy pomocy interfejsu graficznego. Wraz z wprowadzeniem PowerShella częściowo się to zmieniło, bo – jak to już kilka razy pokazywałem – stanowi on bardzo ciekawą tekstową alternatywę. Istnieje jednak narzędzie, które zamyka to kółeczko i powraca do interfejsu graficznego – to PowerGUI.
Screen z PowerGUIPomysł wydawać się może dziwny, bo przecież GUI nigdy nie osiągnie tego, co jest największą zaletą dobrej konsolki i powłoki tekstowej – ogromnej elastyczności. PowerGUI radzi sobie jednak całkiem nieźle, oferując spore możliwości dostosowywania tego, jakie informacje chcemy przeglądać i jakie dodatkowe akcje możemy na nich wykonać. Obie te rzeczy koduje się po prostu za pomocą poleceń PowerShella; mamy tu elementy zwane script nodes, które wyświetlane są w formie drzewka i po wybraniu prezentują rezultaty jakiejś komendy, np. listę wszystkich uruchomionych procesów (Get-Process). Dodatkowo możemy przypisać im też akcje wykonywane na zwróconych elementach lub odwołania do innych kolekcji obiektów (np. usług zależnych od danej).
Ogólnie pomysł wydaje się całkiem zgrabny i ma potencjał oszczędzania czasu – zwłaszcza że klepanie dość rozwlekłych komend PowerShella może być raczej męczące.

Screen z PowerGUi Script EditorWedług mnie znacznie przydatniejszą częścią PowerGUI jest dołączony edytor skryptów. To nic innego, jak (niemal) pełnowartościowe IDE do skryptów .ps1. Oprócz kolorowania składni oferuje ono debugowanie przy pomocy pracy krokowej i breakpointów oraz podglądanie wartości zmiennych – czyli prawie wszystko, co programiście do szczęścia potrzebne :)
I właśnie ten edytor jest, jak sądzę, najważniejszych powodem, dla którego powinniśmy rzucić okiem na PowerGUI, jeśli przynajmniej od czasu do czasu używamy PowerShella. Nie od rzeczy jest też argument, że cały ten pakiet licencjonowany jest jako freeware, więc możemy go używać bez ograniczeń do dowolnych celów. Zanim więc druga wersja PowerShella (która ma oferować między innymi środowisko graficzne) wyjdzie w świat, jest to całkiem rozsądna propozycja.

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

Kopiowanie do katalogu wyjściowego w VS

2008-06-02 19:02

Kiedy program korzysta z zewnętrznych plików (np. obrazków, dźwięków, itp.), które docelowo mają się znaleźć razem z nim w tym samym katalogu, w Visual Studio pojawia się pewien problem. Otóż nie bardzo wiadomo, gdzie dokładnie pliki te należy umieścić, by aplikacja miała do nich dostęp. Zazwyczaj najwygodniej byłoby wrzucić je do katalogu głównego z projektem i/lub całym solution. Tyle że wersje skompilowane trafiają zwykle do katalogów w rodzaju Debug czy Release, czyli folderów pod- lub równorzędnych. Skutek jest często taki, że aplikacja nie potrafi znaleźć potrzebnych plików, gdyż nie znajdują się one we wspomnianych katalogach ze skompilowanymi wersjami programu.

Można je oczywiście ręcznie tam skopiować, ale to niezbyt dobre rozwiązanie – zwłaszcza, jeśli ręcznie musielibyśmy te pliki aktualizować przy każdej zmianie (i to w dwóch miejscach!). Alternatywą jest ustawienie w opcjach projektu odpowiedniego katalogu roboczego (working directory), dzięki czemu moglibyśmy otwierać nasze niezbędne pliki posługując się ścieżkami względnymi. W finalnej wersji programu należałoby jednak pozbyć się tej zależności od katalogu roboczego. Jej pozostawanie sprawiłoby bowiem, że nasz program nie odszukałby potrzebnych plików, jeśli tylko zostałby uruchomiony z innym katalogiem roboczym (np. z poziomu wiersza poleceń lub przy pomocy odpowiednio przygotowanego skrótu). Byłby to ewidentny błąd.
Dlatego też lepiej, aby wszystkie pliki “towarzyszące” otwierać przy pomocy ich pełnych ścieżek, złożonych przy pomocy ścieżki do katalogu z plikiem EXE. Ją zaś można pobrać na wiele sposobów, w zależności od języka i platformy. W Windows API można na przykład użyć funkcji GetModuleFileName (do uzyskania pełnej ścieżki do pliku wykonywalnego) oraz PathRemoveFileSpec (do wyrzucenia z niej nazwy pliku). W .NET będzie to pole System.Windows.Forms.Application.ExecutablePath w połączeniu np. z metodą System.IO.Path.GetDirectoryName.

Wówczas jednak dochodzimy do punktu wyjścia, jako że podczas uruchamiania w debuggerze program będzie szukał swoich plików w katalogach Debug/Release. Można temu w prosty sposób zaradzić. Wystarczy mianowicie:

  1. Dodać potrzebne pliki do projektu w Visual Studio – zupełnie tak samo, jak pliki z kodem źródłowym.
  2. Odpowiednio ustawić dla nich właściwość Copy to Output Directory.

Właściwość Copy to Output DirectoryDomyślną wartością dla tej właściwości jest Do not copy. Wybranie wariantu Copy always sprawi, że zawsze po kompilacji Visual Studio skopiuje wskazany plik do katalogu z plikami wykonywalnymi (np. Debug). Możemy też wybrać Copy if newer, przez co kopiowanie zostanie wykonane tylko wtedy, jeśli od ostatniego zbudowania projektu nasz plik uległ zmianie. Ten wariant jest zwykle najrozsądniejszy, bo oszczędza niepotrzebnego kopiowania tych samych wersji plików.

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

Struktury danych nieobecne w .NET

2008-05-31 16:00

Programując z użyciem platformy .NET można niekiedy mieć wrażenie, że jest w niej niemal wszystko. Oczywiście takie przekonanie jest nietrwałe: wystarczy bowiem znaleźć coś, co być w niej mogłoby (a zwłaszcza coś, co występuje w innych, podobnych bibliotekach), a czego jednak nie ma. Nietrudno zauważyć, że takich rzeczy jest mimo wszystko większość – bo w sumie nie może być przecież inaczej :)
Niektóre braki są aczkolwiek bardziej dotkliwe niż inne. Należą do nich chociażby luki w systemie kolekcji obiektów, czyli – mówiąc ogólniej – wszelkiego rodzaju struktur danych. W .NET brakuje bowiem takich rzeczy jak:

Niektóre pojemniki w .NET 2.0
Niedużo tego…
  • Zbiory. Wprawdzie niemal każdy pojemnik zawiera metodę Contains o wiadomym przeznaczeniu, jednak tylko kontenery słownikowe sprawdzają unikalność umieszczanych w nich obiektów. Te zaś zasadniczo służą do czegoś innego: mapowania jednych obiektów na inne. Brakuje więc zwykłej, prostej klasy Set z operacjami dodawania, usuwania i wyszukiwania elementów – odpowiednika std::set z STL.
  • Kolejki priorytetowe (priority queues). Tutaj znowu można je symulować przy pomocy klas typu SortedDictionary, które jednak nie są zasadniczo do tego przeznaczone. Kolejka priorytetowa powinna mieć przecież niemal identyczny interfejs do zwykłej kolejki FIFO (czyli głównie metody Push i Pop), bo różnica polega wyłącznie na porządku zwracanych elementów, określonym przez ich porównania.
  • Kolekcje zbiorów rozłącznych (disjoint sets). Te dość specyficzne struktury danych są przydatne wtedy, gdy musimy szybko zorganizować kolekcję obiektów w osobne podgrupy wedle jakichś kryteriów. Można to oczywiście zrobić za pomocą dowolnych pojemników, tyle że będzie to nieefektywne. Dedykowana implementacja z użyciem wydajnych algorytmów (tzw. łączenia według rangi i kompresji ścieżek) byłaby znacznie bardziej na miejscu.
  • Grafy. Wprawdzie grafy nie są aż tak często wykorzystywane, ale nie da się ukryć, że czasami ich użycie jest konieczne. Na pewno nie zaszkodziłoby posiadanie ich jako wbudowanego feature‘a w każdej bibliotece struktur danych. Zwłaszcza z gotowym zestawem podstawowych algorytmów grafowych.

Tę listę można by oczywiście ciągnąć bardzo długo, ale zdecydowałem się ograniczyć do tych czterech rzeczy z dwóch powodów. Po pierwsze, przynajmniej raz zdarzyło się, że potrzebowałem którejś z wymienionych tutaj struktur w .NET i byłem zmuszony poradzić sobie we własnym zakresie. Po drugie, bez problemu można podać przykłady innych bibliotek, języków czy środowisk, gdzie jedna z nich, większość lub nawet wszystkie są obecne. Najlepszym przykładem jest C++ (z STL) uzupełniony o bibliotekę Boost, który pod względem struktur danych prezentuje się w tej postaci naprawdę potężnie.
Nie widzę więc specjalnych usprawiedliwień dla faktu, że w .NET lista standardowych struktur prezentuje się nadzwyczaj skromnie. Może więc zamiast dodawać w nowych wersjach platformy kolejne wątpliwej jakości “usprawnienia” – jak wyrażenia lambda wbudowane w C# czy zabawki typu LINQ – programiści Microsoftu zajęliby się raczej zaniedbanymi dotąd podstawami?…

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

Tej funkcji brakuje ‘n’

2008-05-29 15:01

W dzisiejszych niebezpiecznych czasach niemal każdy program może stać się przedmiotem ataku, za pomocą którego można – jak to się zwykło mówić w żargonie speców od bezpieczeństwa – “wykonać dowolny kod” (execute arbitrary code). Chyba najbardziej znanym exploitem tego typu jest przepełnienie bufora (buffer overflow), które w najprostszym wypadku może dotyczyć na przykład takiej sytuacji jak poniższa:

  1. int some_function()
  2. {
  3.     char buf[BUF_SIZE];
  4.     do_something_and_give_results (buf, ...);
  5. }

Gdy bowiem bufor rezyduje na stosie, a jakaś funkcja przypadkowo “wyjedzie” poza jego zakres, możliwe jest nadpisanie innej części stosu. Jedną z nich może być odkładany przy wywołaniu każdej funkcji adres powrotu. Po zakończeniu działania kodu funkcji, adres ten jest zdejmowany ze stosu i program skacze pod uzyskane w ten sposób miejsce w pamięci. Dzięki temu wykonanie programu może wrócić do miejsca tuż za wywołaniem funkcji i kontynuować działanie. Jeśli jednak ów adres zostanie nadpisany przez exploit, możemy w rezultacie skoczyć pod zupełnie inny adres i wykonać dowolny – potencjalnie szkodliwy – kod.

Dlatego też nie należy nigdy ślepo zakładać, że przekazywane nam tablice będą zawsze wystarczająco duże na pomieszczenie rezultatów funkcji. Powinniśmy na to zwrócić baczną uwagę zwłaszcza wtedy, gdy mamy zapisać w buforze dane pochodzące z zewnątrz – z pliku, sieci, od użytkownika, itd. Pisząc funkcje operujące na buforach będących tablicami w C, powinniśmy więc zawsze dodawać do nich jeszcze jeden parametr: rozmiar przekazywanego bufora. Oczywiście nalezy potem dbać, aby go nie przekroczyć.
A co z już istniejącymi funkcjami C, jak sprintf, strcpy, gets?… Wszystkie aktualne dokumentacje do kompilatorów, w których funkcje te występują (MSDN, linuksowy man, itp.), solidnie przestrzegają przed potencjalnym przepełnieniem bufora, które może być skutkiem ich używania. Zwykle też podawane są bezpieczne alternatywy, do których przekazuje się rozmiar bufora: w Visual C++ są one oznaczone końcówką _s (np. sprintf_s), a w GNU GCC dodatkową literką n w nazwie (np. snprintf). To ich właśnie należy używać, jeśli występuje potencjalna możliwość przepełnienia bufora.

Wyjątkiem jest gets, której to… nie powinniśmy w ogóle używać :) Co ciekawe, tylko MSDN wspomina o jej bezpiecznym odpowiedniku (gets_s). Pod GCC funkcji gets po prostu permanentnie brakuje n ;-]

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

Wyjątki mają warstwy

2008-05-27 19:31

Kiedy w kodzie zdarza się coś niedobrego, na co nie mamy natychmiastowego rozwiązania, zwykle rzucamy wyjątek. To nam odwija stos, wychodząc po kolei z głęboko zagnieżdżonych funkcji – aż w końcu natrafimy na handler, który potrafi rzeczony błąd obsłużyć. Odwiecznym problemem wyjątków jest to, gdzie należy tak naprawdę je łapać; zwykle bardzo łatwo jest umieścić kod ich obsługi na zbyt wysokim poziomie, tłumacząc się, że przecież “niżej” nic na ten błąd nie można było poradzić.
Faktycznie zaradzić wyjątkowi często nie można, ale prawie zawsze można w tym pomóc już na wczesnym etapie jego obsługi. Błąd gdzieś “w środku” powoduje bowiem niepowodzenie wywołania wszystkich funkcji po drodze, a każda z takich porażek jest specyficzna dla czynności, która dana funkcja wykonuje. Jeśli przykładowo chcemy odczytać jakiś parametr konfiguracyjny programu, który wymaga załadowania z pliku, to może się okazać, że tego pliku nie da się otworzyć. Wówczas odczytywanie konfiguracji nie powiedzie się – co samo w sobie jest błędem, ale także powoduje, że niemożliwe jest uzyskanie wartości żądanego parametru – kolejny błąd. Widać więc, że błędy-wyjątki mogą być dla siebie kolejno przyczyną i skutkiem.
Taka szczegółowa “historia błędów” jest przydatna, bo pozwala oddzielić informacje ważniejsze od mniej ważnych. Nasza aplikacja może na przykład w ogóle nie wiedzieć, że jej konfiguracja jest zapisywana w pliku (a nie np. Rejestrze) i dlatego wyjątek ‘Nie znaleziono pliku konfiguracyjnego’ powinien być przed nią ukryty. Trzeba go opakować w błąd wyższego rzędu.

Nazywa się to wewnętrznymi wyjątkami (inner exceptions) i jako wbudowany mechanizm występuje chociażby w .NET i Javie. Idea jest prosta: kiedy złapiemy wyjątek “z dołu”, którego nie możemy do końca obsłużyć, zapakowujemy go w nowy obiekt, sygnalizujący niepowodzenie na “naszym” poziomie kodu. Ten nowy wyjątek wyrzucamy dalej; może on potem podlegać bardzo podobnemu procesowi.
I tak w przykładzie z ładowaniem konfiguracji, próba odczytania nieistniejącego pliku skończy się w .NET wyjątkiem IOException, który zostanie pewnie natychmiast opakowany w FileNotFoundException. Funkcja odczytująca dane konfiguracyjne z pliku najpewniej sama wsadzi ten wyjątek w nowy, np. ArgumentException, co mówi wywołującemu, że przekazany argument – tu: nazwa pliku z konfiguracją – jest nieprawidłowy. W końcu, ponieważ nie będzie można odczytać żądanej wartości, funkcja która miała ją zwrócić może nas ostatecznie uraczyć wyjątkiem InvalidOperationException, zawierającym w środku wszystkie wymienione wcześniej błędy. Których było zresztą całkiem sporo :)
Gdy w końcu złapiemy cały ten wielokrotnie zapakowany wyjątek w innym miejscu, możemy dostać się do całego łańcucha przyczynowo-skutkowego, który powstał podczas odwijania stosu. W tym celu korzysta się z właściwości InnerException w .NET lub metody getCause w Javie – na przykład tak:

  1. public void PrintException(Exception exception)
  2. {
  3.    int i = 0;
  4.    Console.WriteLine ("Exception (!)");
  5.    for (Exception e = exception; e != null; e = e.InnerException, ++i)
  6.       Console.WriteLine (new String(' ', i) + " at level {0}: {1}", i, e.Message);
  7. }

Zapewne jednak rzadko będziemy sięgali aż do samego dna – zwykle tylko w celach logowania. Dzięki odpowiedniemu opakowaniu możemy bowiem zająć się od razu sytuacją wyjątkową “najwyższego rzędu” – adekwatną do czynności, którą chcieliśmy wykonać (a nie tą pochodzącą z głębokich czeluści kodu niższego poziomu, od której wszystko się zaczęło).

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

Triki z PowerShellem #2 – Szybki upload

2008-05-24 12:52

Oto zadanie: mamy plik, który chcemy komuś przesłać przez Internet i mieć przy tym jak najmniej zawracania głowy. Jest oczywiście e-mail, są komunikatory, podprotokół IRC-a o nazwie DCC serwisy typu RapidShare, itd. Każdy z tych sposobów wymaga jednak albo wymiany jakichś informacji typu adres czy numer identyfikacyjny, albo nie zawsze chce działać w różnych konfiguracjach sieci (zwłaszcza gdy jedna ze stron jest ukryta za NAT-em), albo… wymaga wpatrywania się w literki celem odróżnienia psów od kotów :)
Jeśli jednak dysponujemy serwerem FTP z zawartością dostępną przez HTTP (czyli po prostu hostingiem strony WWW), to możemy dzielić się plikami w prostszy i szybszy sposób. W tym celu posłużyć się można odpowiednim skryptem w PowerShellu, który potrafi samodzielnie połączyć się z serwerem FTP i wgrać na niego podany plik, a potem zwrócić jego URL. Następnie możemy przekazać go osobie, której chcemy przekazać plik.

  1. # Send.ps1 - wysyła podany plik na serwer FTP i zwraca jego adres HTTP
  2. # Parametr: nazwa pliku lokalnego
  3. param([string]$file = $(throw "File not specified"))
  4. $filename = (New-Object IO.FileInfo @($file)).Name
  5.  
  6. # Stałe
  7. $SERVER = "moj.server.pl"
  8. $FTP_LOGIN = "loginFtp"
  9. $FTP_PASS = "hasłoFtp"
  10. $FTP_PATH = "/public_html/pub/upload/" # Ścieżka FTP do katalogu z uploadami
  11. $HTTP_PATH = "/pub/upload/" # Ścieżka HTTP do tego samego katalogu
  12.  
  13. # Odczytujemy plik
  14. $stream = New-Object IO.FileStream @($file, [IO.FileMode]::Open,
  15.     [IO.FileAccess]::Read, [IO.FileShare]::Read)
  16. $content = New-Object byte[] @($stream.Length)
  17. $stream.Read($content, 0, $content.Length) | Out-Null
  18. $stream.Close()
  19.  
  20. # Uploadujemy na FTP
  21. $url = "ftp://" + $SERVER + $FTP_PATH + $filename
  22. $ftp = [Net.FtpWebRequest]::Create($url)
  23. $ftp.Credentials = New-Object Net.NetworkCredential @($FTP_LOGIN, $FTP_PASS)
  24. $ftp.Method = [Net.WebRequestMethods+Ftp]::UploadFile
  25. $ftp.ContentLength = $content.Length
  26. $req = $ftp.GetRequestStream()
  27. $req.Write($content, 0, $content.Length)
  28. $req.Close()
  29.  
  30. # Kopiujemy URL do schowka
  31. # (działa w Windows Vista i 2003 Server; niżej opis alternatywy dla XP)
  32. "http://" + $SERVER + $HTTP_PATH + $filename | clip

Całkiem zmyślnie, prawda? Wystarczy jedynie odczytać lokalny plik, a następnie użyć .NET-owej klasy System.Net.FtpWebRequest w celu wykonania “żądania FTP” w postaci uploadu tegoż pliku na serwer.

Co jednak zrobić z takim skryptem, aby był użyteczny?… Jako że jego parametrem jest ścieżka do lokalnego pliku, który chcemy załadować, możemy użyć następującej komendy:

  1. powershell -Command . 'C:\Sciezka\Do\Skryptu\Send.ps1' '%1'

w celu jego wywołania – o ile potrafimy sprawić, by system Windows zamienił nam symbol zastępczy %1 na rzeczoną ścieżkę. Jest to możliwe przynajmniej na dwa sposoby:

  1. Menu Wyślij do z dodaną komendę uploadu FTPMożemy dodać nowe polecenie do podmenu kontekstowego Wyślij do, wyświetlanego dla każdego pliku w Eksploratorze Windows. W tym celu wystarczy stworzyć plik wsadowy (.bat) w katalogu SendTo, zawierający powyższą komendę, i nazwać go odpowiednio intuicyjnie. Po odświeżeniu Eksploratora, we wspomnianym menu pojawi się nowa pozycja, której wybór uruchomi nam nasz skrypt dla wybranego pliku.
  2. Innym wyjściem jest po prostu dodać nową akcję dla każdego typu plików, przez co będzie ona wyświetlania w głównym menu kontekstowym, obok innych: Otwórz, Edytuj, Drukuj, itd. Aby tego dokonać, najwygodniej jest po prostu otworzyć Edytor Rejestru i przejść do klucza HKEY_CLASSES_ROOT/*/shell. Tworzymy tam nowy podklucz, nazywając go jakoś odpowiednio (np. upload) i wpisując jako wartość domyślną tekst polecenia, który chcemy zobaczyć w menu (np. Upload). Następnie tworzymy tam podklucz command, ustawiając jego wartość domyślną na polecenia uruchomienia skryptu. Odświeżamy Eksplorator i mamy już nowe polecenie w menu kontekstowym.

Dodawanie akcji uploadu dla wszystkich plików w RejestrzeSprytne i wygodne. I kto teraz powie, że tylko w systemach linuksowych można bezustannie kombinować, by dostosowywać je do swoich potrzeb ;-)

PS. Użyty w skrypcie program clip jest bardzo prosty: kopiuje on po prostu swoje wejście do Schowka. Niestety, to malutkie narzędzie nie jest obecne w Windows XP. Nie ma tam więc prostego sposobu na wpisanie tekstu do Schowka z poziomu PowerShella. Alternatywą jest wypisanie URLa- do załadowanego pliku bezpośrednio w oknie konsoli PSh. Wystarczy po prostu zmienić clip na Out-Host, a także zmienić wywołanie skryptu, dodając parametr -NoExit:

  1. powershell -NoExit -Command . 'C:\Sciezka\Do\Skryptu\Send.ps1' '%1'

To sprawi, że o wykonaniu operacji konsola PowerShella pozostanie otwarta wraz z wypisanym w niej URL-em, który można z niej skopiować.

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


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