artykuły

Delphi - Potęga możliwości ShellExecute()

21:03
nie, 23 czerwiec 2002
Tekst opisuje funkcję ShellExecute() zawartą w module ShellAPI. Czytelnik znajdzie w nim również kilka sztuczek dotyczących tej metody, jak: otwieranie za jej pomocą okna programu pocztowego z wpisanym adresem e-mail oraz treścią listu, otwieranie stron internetowych w przeglądarkach systemowych itp...

Wprowadzenie

Bardzo często spotykamy się z programami, które pozwalają wysyłać do autora mejla, czy otwierać jego WWW. Zapewne kiedyś zastanawialiście się jak to zrobić przy pomocy Delphiego. W tym artykule opiszę krótko jak zastosować dostosowaną do tego typu operacji funkcję. ShellExecute - bo o niej mowa, potrafi wykonywać rozmaite operacje - od otwierania pliku, programu do drukowania jego treści. Jeśli chcesz jej użyć - pamiętaj o dodaniu słówka ShellAPI do listy modułów -uses. Będzie to wyglądać nieco podobnie:
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ShellAPI;

Budowa funkcji ShellExecute

... przedstawia się następująco:
ShellExecute(1, 2, 3, 4, 5, 6);Gdzie poszczególne parametry oznaczają:

  • 1 - Handle (od ang. uchwyt) - uchwyt okna. W większości wypadków piszemy Handle, czyli uchwyt naszej aplikacji.
  • 2 - Typ operacji, zależny od rodzaju wykonywanej pracy, może to być: open, print czy expore - Jednak uwaga! Ten parametr należy wpisywać w apostrofach gdyż jest to typ PChar.
  • 3 - FileName - Ścieżka do pliku lub jego nazwa. Jednak w wypadku wpisania samej nazwy należy uzupełnić ścieżkę w parametrze Directory.
  • 4 - Parameters - Parametr aktualnie uruchamianego programu - wyjaśnię później
  • 5 - Directory - Katalog w którym znajduję się uruchamiany program. Jeśli katalog podałeś już wcześniej (w FileName) możesz to pole zostawić puste (nil)
  • 6 - Sposób uruchomienia aplikacji. Dostępne są: SW_HIDE - aplikacja, zostanie ukryta - nie pojawi się.
    SW_SHOW - pokazanie aplikacji.
    SW_MINIZE - tryp zminimalizowany.
    SW_MAXIMIZED - tryb zmaksymilizowany.
    SW_SHOWNORMAL - otwarcie okna w domyślnych rozmiarach, przypisanych przez programistę.

Przykład z zastosowaniem FileName i Directory: ShellExecute(Handle, 'open', 'NetSpeak.exe', nil, 'C:\Dokumenty\Programy\Delphi\NetSpeak', SW_NORMAL); Takie polecenie uruchomi program NetSpeak z podanego w parametrze Directory katalogu. Można także inaczej, bez Directory: ShellExecute(Handle,'open','C:\Dokumenty\Programy\Delphi\NetSpeak\NetSpeak.exe', nil, nil, SW_NORMAL); Tym sposobem także uruchomimy program.

Przykład zastosowania parametrów (parameters):
Chcesz na przykład aby program (np. zwykły notatnik systemowy) uruchomił się i wczytał jakiś plik. Można to uczynić w ten sposób: ShellExecute(Handle, 'open', 'Notepad.exe', 'C:\MsDos.sys', 'C:\Windows', SW_SHOWNORMAL); Wpisaliście? Działa? Z pewnością - przecież musi! :) Tak teraz do tłumaczenia. Pierwszy i drugi parametr pozostawiam na mocy wcześniejszego tekstu, natomiast trzeci, jak już mówiłem wskazuje nazwę pliku programu, który chcemy otworzyć. Następny parametr to właśnie... parametr :) W naszym wypadku określa plik do otworzenia. Kolejny, już piąty z rzędu to Directory, określa położenie programu z FileName. ...A okno ma pojawić się normalne...

Parametry w grach

Często, zamiast tradycyjnego kodu, w grach, aby uruchomić konsolę do ich wpisywania należy uruchomić grę z parametrem. Parametr ten dopisujemy najczęściej w skrócie do naszej gierki, możemy również uruchomić taką aplikację korzystając z opcji Uruchom z Menu Start lub... przez ShellExecute. Napiszemy teraz prostą komendę uruchamiającą grę Half-Life Blue Shift z parametrem -console. ShellExecute(Handle, 'open','bshift.exe', 'console', 'C:\Gry\Half-Life Blue Shift\', 0); Miłej zabawy ! ;)

Drukowanie dokumentu

Droga ku oświeceniu jest długa ... ;) ale chcąc wydrukować dokument możemy także użyć naszej funkcji. Otóż w miejsce drugiego parametru podstawiamy 'print', a ostatni parametr modyfikujemy do SW_HIDE. W ten sposób dokument zostanie wydrukowany, a program notatnik nie pokaże się nawet na ekranie. jednak musimy pamiętać, iż drukując przez Notatnik musimy używać formatów jakie ten program otwiera, np. *.txt, *.htm, *.php, *.log itp. Nie mogą to być natomiast dokumenty przedstawiające różne formy formatowania tekstu np. *.rtf, *.doc itp. Przykład prosty do zastosowania a zarazem skuteczny:ShellExecute(Handle, 'print', 'MsDos.sys', nil, 'C:\', SW_HIDE);Teraz możecie już wypróbować polecenie, powinno ono wydrukować zawartość pliku MsDos.sys. Nie zapomnijcie jednak o dodaniu do listy uses modułu ShellAPI. Jest to bardzo ważne gdyż inaczej - program się nie skompiluje.

Dodatkowo, czyli jak wysłać do kogoś mejla lub otworzyć WWW?

Jest to szalenie proste, wystarczy pod parametrem ścieżki do pliku podać adres e-mail adresata w postaci: 'mailto: lukas.home.page@gmail.com'.
Oto przykład: ShellExecute(Handle, 'open', 'mailto:', nil, nil, SW_SHOW); lub z wpisanym tematem... ShellExecute(Handle, 'open', 'mailto:?Subject=Temat', nil, nil, SW_SHOW); ...i treścią: ShellExecute(Handle, 'open', 'mailto:?Subject=Temat&Body=Treść', nil, nil, SW_SHOW); Możemy wykorzystać powyższy sposób aby otworzyć przykładowe okno nowej wiadomości e-mail z wpisanym imieniem i nazwiskiem nadawcy (jeśli je posiadamy): ShellExecute(Handle, 'open', 'mailto:?Subject=Temat&Body=%0d%0a%0d%0aImię%20Nazwisko%0d%0amejl@nadawcy.pl', nil, nil, SW_SHOW); Przy czym należy zaznaczyć, że ciągi %xx służą wstawianiu znaków specjalnych. Po znaku procentu określamy szesnastkowy identyfikator znaku w tabeli ASCII (np. literę A możemy równie dobrze zapisać jako %41 [ponieważ litera dużego A ma w tablicy ASCII kod dziesiętny 65, który po konwersji na szesnastkowy (np. za pomocą Windowsowego kalkulatora) zmienia się w 41], %0D%0A - znak nowego wiersza, a właściwie - w systemie Windows - dwa znaki [znak powrotu karetki do początku wiersza i znak nowego wiersza] (w systemach Unixowych występuje tylko jeden znak %0A oznaczający to samo co w Windowsie %0D%0A).

Otworzenie, wczytanie strony WWW też nie jest wyjątkowo trudne! Patrz niżej v: ShellExecute(Handle, 'open', http://www.at.g.pl', nil, nil, SW_SHOW); Jedynie tyle!

Czy istnieje możliwość wysyłania załączników?

Nie ma takiej możliwości poprzez funkcję ShellExecute - nie działają parametry „Attach”, ani nic podobnego.
Rozwiązanie tego problemu podpowiadają na StackOverflow (poprzez bibliotekę JCLMapi, która nie jest dostępna jednak w starszych wersjach Delphi):
How can a Delphi Program send an Email with Attachments via the DEFAULT E-mail Client?

Inne funkcje

Do innych funkcji należy przede wszystkim WinExec. Jest ona dużo prostsza w budowie - posiada tylko dwa parametry, gdzie pierwszy z nich to FileName (Ścieżka do pliku), a drugi ShowCmd - jak ma się pokazać okienko. Do drugiego parametru funkcji WinExec używamy tych samych "słówek" co w ShellExecute: SW_SHOW, SW_HIDE, SW_MINIZE, SW_MAXIMIZED, SW_SHOWNORMAL. Używamy jej następująco: WinExec('C:\Command.com', SW_SHOW);

Jak uruchomić program bezpośrednio z zasobów?

Odpowiedź na to pytanie znajdziecie w moim artykule z cyklu "Delphi - strumienie" dotyczącym strumienia TResourceStream.

Zakończenie

Wielkie dzięki wszystkim, którzy dotrwali do końca. Tylko parę słów: "Mam nadzieję, że przyda się wam to w przyszłości." Jeśli czegoś nierozumiesz, może coś źle tłumaczyłem - napisz: lukas.home.page@gmail.com .

12345
Delphi - Potęga możliwości ShellExecute() Autor opinii: Czytelnicy, data przesłania: 5

Podobne artykuly:

Skomentuj

Aby zamieścić komentarz, proszę włączyć JavaScript - niestety roboty spamujące dają mi niezmiernie popalić.






Komentarze czytelników

    • StarStableLeni
    • pią, 22 maj 2015, 9:10
    • A co jeśli pokazuje się Shellexecute i nie ma żadnej cyfry?.Bo ja tak mam...
    • Grabiecu
    • wto, 24 lipiec 2012, 8:43
    • Prosto, jasno z przykładami. Tego mi było trzeba ;)
    • TomRiddle
    • pon, 12 wrzesień 2011, 22:07
    • Do wysyłania maili się to nie nadaje. Co jeżeli ktoś nie ma skonfugurowanego programu pocztowego i używa tylko np. onet/interia?

      Ja do maili polecam Indy.
    • Gustaw
    • pon, 29 sierpień 2011, 12:22
    • Jak wysłać maila automatycznie?


      Funkcja:

      ShellExecute(Handle, 'open', 'mailto:lukas.home.page@gmail.com?Subject=Temat&Body=%0d%0a%0d%0aImię%20Nazwisko%0d%0amejl@nadawcy.pl', nil, nil, SW_SHOW);



      otwiera tylko program pocztowy z wpisanym adresatem, tematem i terścią, ale go nie wysyła. Co zrobić, żeby wysłało




      Odp: Opisywana funkcja ShellExecute nie służy do wysyłania e-maila bezpośrednio z poziomu programu. Służy jedynie do otwarcia okna domyślnego programu pocztowego z uzupełnionymi polami adresata, tematu i treści.

      Aby wysłać e-mail bezpośrednio z poziomu naszego programu należy pójść inną drogą. Są dwie metody (jak zwykle): trudniejsza, dająca więcej kontroli i prostsza. Trudniejsza metoda polega na wykorzystaniu gniazdek sieciowych (tzw. socket'ów) lub pełniącego obiektowy odpowiednik komponentu ClientSocket z zakładki Internet i posłużeniu się nim w celu ręcznej obsługi protokołu SMTP (jak wygląda komunikacja z serwerem SMTP i wysyłanie listu e-mail na najniższym poziomie, można sprawdzić np. w Wikipedii pod hasłem SMTP).

      Druga metoda jest łatwiejsza i polega na użyciu komponentu idSMTP z bardzo popularnej paczki komponentów sieciowych o nazwie Indy. Przykład jak wykorzystać komponent idSMTP to wysłania mejla z poziomu programu można znaleźć tutaj:

      http://delphi.about.com/od/indy/a/email-send-indy.htm




      Należy jednak wspomnieć, że oba sposoby wymagają podania adresu serwera pocztowego służącego do wysyłki mejli (serwera SMTP). Na dzień dzisiejszy jest jedynie garstka serwerów nie wymagających autoryzacji przy wysyłaniu e-maili (jeszcze pamiętam w roku 2000 każdy mógł wysyłać mejle z serwera SMTP nie mając na nim konta). Tak więc, dzisiaj, aby skorzystać z usług takiego serwera, należy się zarejestrować (np. założyć odpowiednie konto na poczcie Onetu). Zdobyte dane (login i hasło) oraz adres i port serwera należy podać w ustawieniach komponentu idSMTP. Tyle.
    • Marcin
    • śro, 9 luty 2011, 14:36
    • Witaj, świetny poradnik. Mam problem ze swoim programem (ShellExecute) i szukam pomocy.

      Otóż mam na formie ListBox'a i Button

      W listboxie znajdują się linki do stron np: www.google.pl. Po wciśnięciu na przycisk program ma otworzyć domyślną przeglądarkę z zaznaczoną stroną internetową(ListBox).

      ShellExecute(self.WindowHandle,'open', www.google.pl', nil, nil, SW_SHOWNORMAL);

      mam tutaj kod, który umożliwia otwarcie strony internetowej przy domyślnej przeglądarce, jednak strona internetowa jest już podana w kodzie.

      Moje pytanie brzmi: Jak zmienić powyższą linijkę kodu aby móc po wciśnięciu buttona otworzyć stronę internetową z listbox'a.

      Proszę o pomoc...

      Pozdrawiam




      Odp: Należy wyciągnąć tekst aktualnie zaznaczonej pozycji komponentu ListBox, w ten sposób:

      ListBox1.Items[ListBox1.ItemIndex]

      (zwróci tekst aktualnego zaznaczenia w ListBox)


      Można by w takim razie pomyśleć, że wystarczy to podstawić pod odpowiedni parametr funkcji ShellExecute(), jednak taka instrukcja...:

      ShellExecute(Handle,'open',ListBox1.Items[ListBox1.ItemIndex],nil,nil,SW_NORMAL);

      ...spowoduje błąd. To dlatego, że funkcja ShellExecute wymaga parametru w formacie PChar (wskaźnik na łańcuch tekstowy zakończony znakiem o kodzie 0), natomiast nasz tekst (aktualne zaznaczenie ListBox) jest w formacie String. Należy więc przekonwertować format String na format PChar przy użyciu funkcji PChar():

      ShellExecute(Handle,'open',PChar(ListBox1.Items[ListBox1.ItemIndex]),nil,nil,SW_NORMAL);

      Powyższa instrukcja spowoduje uruchomienie domyślnej przeglądarki i wczytanie strony, której adres jest aktualnie zaznaczoną pozycją ListBox'a.
      Pozdrawiam!
    • Halkatla
    • śro, 29 grudzień 2010, 16:13
    • Mam pytanie,bo wpisałeś formułę jak zrobić by notatnik otwierał określony plik. A jeśli my w Delphi w Memo mięliśmy plik tekstowy i zapisaliśmy go poleceniem SaveDialog1.Filename to jak potem automatycznie ten plik otworzyć?Bo nie mozemy wpisać ścieżki. Póbowałam ShellExecute(Handle, 'open', 'Notepad.exe', SaveDialog1.Filename , 'C:WindowsSystem32Notepad.exe', SW_SHOW); ale wyskakują mi błędy własnie przy tym SaveDialogu i nie wiem,co z tym zrobić.




      Odp: I bardzo dobrze próbowałaś. Do pełnego sukcesu zabrakło tylko przekonwertowania zmiennej typu String (SaveDialog1.FileName jest typu String) na zmienną typu PChar. To, jakiego typu parametry przyjmuje funkcja zawsze jest opisane w dokumentacji, w tzw. prototypie funkcji. Zawsze trzeba podawać jako parametry zmienne dokładnie żądanego typu. Jeśli zmienne są innego typu należy je przekonwertować (tutaj akurat wystarczyło przkonwertować typ String na starszy typ tekstowy PChar, znany z języka C). Czyli prawidłowy kod jest następujący:

      ShellExecute(Handle, 'open', 'Notepad.exe', PChar(SaveDialog1.Filename) , 'C:WindowsSystem32Notepad.exe', SW_SHOW);


      Pozdrawiam serdecznie!
    • TomRiddle
    • pią, 24 wrzesień 2010, 13:18
    • A jak można podpisać nadawcę?
    • Disip
    • pią, 23 kwiecień 2010, 17:21
    • Hmmm... A jak w ten sposób można otworzyć program z zasobów?



      Odp: Witam! Poddałeś mi pomysł na poszerzenie artykułu. Odpowiedź na swoje pytanie znajdziesz w artykule TResourceStream z cyklu "Delphi - strumienie"
    • mietpas
    • wto, 23 luty 2010, 13:09
    • Przydało się, zwłaszcza uwaga dot. Uses. Dziekuje.
    • Vesim
    • pią, 5 luty 2010, 9:42
    • Ja mam takie pytanie a jak zrobic ze w Dictory bedze to co w edit1?



      Odp: Robi się to następująco:


      ShellExecute(Handle,'open','','',PChar(Edit1.Text),SW_NORMAL);


      Wyjaśnienie: Parametr Directory funkcji ShellExecute jest typu PChar, natomiast właściwość Text komponentu TEdit jest typu TCaption. Z pomocy Delphi możemy się dowiedzieć, że (cytuje):

      type TCaption = type string;

      Czyli innymi słowy typ TCaption to nic innego jak zwykły String. Możemy więc użyć funkcji PChar() aby przekonwertować Edit1.Text na typ PChar, który wymagany jest przez funkcję ShellExecute.
    • Paweł
    • czw, 31 grudzień 2009, 16:32
    • Witam, mam dziwny problem z tą procedurą. Po wywołaniu w celu otwarcia strony www/wysłania maila otwiera jak należy, ale od tego momentu aplikacja choć działa dalej, nie reaguje na próbę zamknięcia (krzyżykiem, czy przy pomocy close). Jeżeli procedura wywołana została z innej formatki otwartej przez showmodal, nie można zamknąć tej formatki (jeżeli przez show, można zamknąć, ale głównego okna już nie). Problem występuje z jednym konkretnym programem, w innych wszystko jest ok (dotąd stosowałem tą procedurę bez problemu). Do tego nie działają zdarzenia OnMouseEnter i OnMouseLeave w TLabel (po prostu nic się nie dzieje - tak samo tylko w tym programie, może ma to jakiś związek). Czym to może być spowodowane?
      Pozdrawiam
    • Rav
    • nie, 10 maj 2009, 12:22
    • Witam. Jak można przy pomocy tej funkcji otworzyć stronke www i uzupełnić pola login i hasło na stronce www potrzebuje to konkretnie do serwisu SynDns.
      Pozdrawiam




      Odp: Witam. Za pomocą funkcji ShellExecute jest możliwe nie tyle "uzupełnienie pól" co wywołanie strony z określonymi parametrami. Zadziała to tylko w przypadku w którym zmienne z formularza przesyłane są za pomocą metody GET (czyli jako takie dziwne parametry w pasku adresu). W przypadku drugiego sposobu (meotdy POST - dziwnych parametrow w pasku adresu w tej metodzie nie widać, zmienne przesyłane są inaczej - w nagłówku HTTP) nie jest możliwe wysłanie danych do strony internetowej za pomocą omawianej funkcji ShellExecute.
      Jeśli zatem Twój formularz jest wysyłany za pomocą metody GET i w pasku adresu widzisz coś takiego:


      gdzie parametry "Temat", "Komentarz" oraz "Nick" są nazwami pól formularza to jedynym co musisz zrobić w wywołaniu adresu przez funkcję ShellExecute jest wywołanie właśnie tego adresu. I tyle.
      Natomiast w przypadku metody POST... nie ma zmiłuj - albo posłużyć się zewnętrznym programem, albo skorzystać z komponentów Indy (dość łatwo jest to zrobić za ich pomocą - jakieś 10 linijek kodu), albo posłużyć się WinAPI i biblioteką WinSock (trudne).
Dexter