ShellApi

michal_lot
Ten artykuł wymaga dopracowania!

Jeżeli możesz popraw ten artykuł według zaleceń, które możesz znaleźć na stronie [[Artykuły do poprawy]]. Po dopracowaniu tego tekstu można usunąć ten komunikat.
1 Krótki opis
2 Zestawienie wybranych procedur i funkcji modułu ShellAPI
3 Przykład z ShellExecute
4 Aplikacja w tray'u (na pasku zadań, obok zegara)

Krótki opis

Moduł jest podstawową biblioteką Delphi, służy do komunikowania się programu z otoczeniem Windows. Na przykład, dzięki procedurze ShellExecute możemy otworzyć dany plik. Poniżej zestaw funkcji i procedur:

Zestawienie wybranych procedur i funkcji modułu ShellAPI

function DragQueryFile(Drop: HDROP; FileIndex: UINT; FileName: PChar; cb: UINT): UINT; stdcall;

function DragQueryFileA(Drop: HDROP; FileIndex: UINT; FileName: PAnsiChar; cb: UINT): UINT; stdcall;

function DragQueryFileW(Drop: HDROP; FileIndex: UINT; FileName: PWideChar; cb: UINT): UINT; stdcall;

function DragQueryPoint(Drop: HDROP; var Point: TPoint): BOOL; stdcall;

procedure DragFinish(Drop: HDROP); stdcall;

procedure DragAcceptFiles(Wnd: HWND; Accept: BOOL); stdcall;

function ShellExecute(hWnd: HWND; Operation, FileName, Parameters,
  Directory: PChar; ShowCmd: Integer): HINST; stdcall;

function ShellExecuteA(hWnd: HWND; Operation, FileName, Parameters,
  Directory: PAnsiChar; ShowCmd: Integer): HINST; stdcall;

function ShellExecuteW(hWnd: HWND; Operation, FileName, Parameters,
  Directory: PWideChar; ShowCmd: Integer): HINST; stdcall;

function FindExecutable(FileName, Directory: PChar; Result: PChar): HINST; stdcall;

function FindExecutableA(FileName, Directory: PAnsiChar; Result: PAnsiChar): HINST; stdcall;

function FindExecutableW(FileName, Directory: PWideChar; Result: PWideChar): HINST; stdcall;

function CommandLineToArgvW(lpCmdLine: LPCWSTR; var pNumArgs: Integer): PPWideChar; stdcall;

function ShellAbout(Wnd: HWND; szApp, szOtherStuff: PChar; Icon: HICON): Integer; stdcall;

function ShellAboutA(Wnd: HWND; szApp, szOtherStuff: PAnsiChar; Icon: HICON): Integer; stdcall;

function ShellAboutW(Wnd: HWND; szApp, szOtherStuff: PWideChar; Icon: HICON): Integer; stdcall;

function DuplicateIcon(hInst: HINST; Icon: HICON): HICON; stdcall;

function ExtractAssociatedIcon(hInst: HINST; lpIconPath: PChar;
  var lpiIcon: Word): HICON; stdcall;

function ExtractAssociatedIconA(hInst: HINST; lpIconPath: PAnsiChar;
  var lpiIcon: Word): HICON; stdcall;

function ExtractAssociatedIconW(hInst: HINST; lpIconPath: PWideChar;
  var lpiIcon: Word): HICON; stdcall;

function ExtractIcon(hInst: HINST; lpszExeFileName: PChar;
  nIconIndex: UINT): HICON; stdcall;

function ExtractIconA(hInst: HINST; lpszExeFileName: PAnsiChar;
  nIconIndex: UINT): HICON; stdcall;

function ExtractIconW(hInst: HINST; lpszExeFileName: PWideChar;
  nIconIndex: UINT): HICON; stdcall;

Przykład z ShellExecute

Teraz pokaże użycie najczęściej używanych procedur:

...
uses
   ..., ShellAPI;
...

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShellExecute(Handle, 'Open', 'C:\Test.txt', nil, nil, SW_NORMAL);
end;
Nazwa argumentu Podana wartość Opis
hWnd Handle uchwyt
Operation Open otwiera plik
FileName C:\Text.txt nazwa pliku do otwarcia
Parameters nil parametry otwarcia
Directory nil ścieżka katalogu
ShowCmd SW_NORMAL typ pokazania okna (tu: standardowe)
SW_MINIMALIZED zminimalizowane
SW_MAXIMIZED zmaksymalizowane

Aplikacja w tray'u (na pasku zadań, obok zegara)

Są dwie rzeczy, które trzeba wziąć pod uwagę tworząc aplikację do tray'a. Pierwsza to "ukrycie" aplikacji przed Windows. Mimo, że aplikacje takie wyglądają i zachowują się jak zwykłe aplikacje Windows, nie można się na nie przełączyć przy użyciu Alt+Tab ani nie mają swojego przycisku na pasku zadań. Tym zajmiemy się najpierw.

Każde okno posiadające styl WS_EX_TOOLWINDOW ani nie ma przycisku na pasku zadań ani nie można się na nie przełączyć. Z początku może wydawać się właściwym ustawienie tego stylu przy użyciu CreateParams. Niestety nie zadziała to dla formy. Tu mała dygresja. Główna forma aplikacji nie jest oknem (w terminologii Windows) aplikacji. Obiekt aplikacji ma swoje własne okno - nie można go zobaczyć ale ono "tam" jest. To jest właśnie to okno, do którego należy przypisać styl WS_EX_TOOLWINDOW. Gdzie więc należy wstawić kod? Oczywiście w źródle projektu. Po wybraniu View->Project Source należy skopiować poniższy kod:

program Project1;
uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  { To jest wymagane aby znana była stała WS_EX_TOOLWINDOW i pozostałe }
  Windows;

{$R *.RES}

var
  { Deklaracja zmiennej do przyjęcia informacji o stylu okna }
  ExtendedStyle: Integer;
begin
  Application.Initialize;
  { Pobranie informacji o oknie aplikacji przy użyciu GetWindowLong }
  ExtendedStyle := GetWindowLong(Application.HandlApplication.Handle, GWL_EXSTYLE);

  { Teraz ustawiamy styl rozszerzony przy użyciu operacji na bitach
    Przekształca to okno z okna-aplikacji do okna-narzędzia }
  SetWindowLong(Application.Handle, GWL_EXSTYLE,
                ExtendedStyle or WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW);
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

A teraz aby utworzyć właściwy efekt aplikacji w tray'u będziemy potrzebowali przede wszystkim głównej formy aplikacji. Połóż na formie komponent z klasy TPopupMenu. Będzie to główny interfejs do naszej aplikacji. Popatrz na poniższy kod:

unit Unit1;

  { Poniższe umieszcza aplikację w trayu.

    Jest to główna forma aplikacji. Posiada ona menu popup używane do
    wyświetlenia formy i zamknięcia aplikacji.

    Używając modułu ShellAPI w prosty sposób pokażemy ikonę aplikacji w tray'u
    i spowodujemy aby reagowała na kliknięcia myszą }

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
  ShellAPI, ExtCtrls, Menus;

type
  TForm1 = class(TForm)
    PopupMenu1: TPopupMenu;
    ShowMainForm1: TMenuItem;
    N1: TMenuItem;
    ExitApplication1: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure ShowMainForm1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ExitApplication1Click(Sender: TObject);
  private
    procedure WndProc(var Msg : TMessage); override;
  public
    IconNotifyData : TNotifyIconData;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  { Zostawiamy tylko przycisk zamykający okno }
  BorderIcons := [biSystemMenu];

  { Teraz wypełniamy rekord IconNotifyData tak aby przyjmował
    komunikaty wysyłane do aplikacji i pokazywał "dymki" podpowiedzi. }
  with IconNotifyData do
    begin
      hIcon := Application.Icon.Handle;
      uCallbackMessage := WM_USER + 1;
      cbSize := SizeOf(IconNotifyData);
      Wnd := Handle;
      uID := 100;
      uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
    end;

  { Kopiujemy tytuł aplikacji jako "dymek" }
  StrPCopy(IconNotifyData.szTip, Application.Title);
  { Dodajemy ikonę do tray'a }
  Shell_NotifyIcon(NIM_ADD, @IconNotifyData);
end;

procedure TForm1.WndProc(var Msg: TMessage);
var
  P: TPoint;
begin
  if (Msg.Msg = WM_USER + 1) and (Msg.lParam = WM_RBUTTONDOWN) then
   begin
     GetCursorPos(P);
     PopupMenu1.Popup(P.X, P.Y);
   end;

  inherited;
end;

{ To jedna z procedur obsługi elementów menu }
procedure TForm1.ShowMainForm1Click(Sender: TObject);
begin
  Form1.Show;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caNone;
  Form1.Hide;
end;

procedure TForm1.ExitApplication1Click(Sender: TObject);
begin
  Shell_NotifyIcon(NIM_DELETE, @IconNotifyData);
  Application.ProcessMessages;
  Application.Terminate;
end;

end.

Jak widać nie ma wiele do zrobienia. Ale ważne jest aby rozumieć co zrobiliśmy w metodzie OnCreate i jakie znaczenie ma rekord IconNotifyData. Jest to rekord zdefiniowany w module ShellAPI, który przechowuje informację o ikonie w tray'u. Zauważ flagi, których użyliśmy: NIF_MESSAGE + NIF_ICON + NIF_TIP. Oznaczają one kolejno: obsługę komunikatów dla aplikacji, pokazywanie ikony aplikacji i pokazywanie "dymku" z podpowiedzią.

Następna sprawa to nadpisanie procedury WndProc (skrót od WindowProcedure). Dostaje ona wszystkie komunikaty przesyłane do okna i zachowuje się jak centralna rozdzielnia komunikatów. Można przejąć obsługę komunikatu pisząc własną jego obsługę i wywołując odziedziczoną procedurę. Przy obsłudze komunikatu sprawdzamy czy jest to nasz własny (WM_USER + 1) zdefiniowany w zmiennej IconNotifyData oraz czy nastąpiło kliknięcie prawym przyciskiem myszy. Pozostałe komunikaty przesyłamy bez zmian. [...]

michal_lot

3 komentarzy

A ja orty już naprawiłem. Naliczyłem ich 666.

michal_lot, Ty się lepiej naucz pisać po polsku analfabeto. Ktos, nieźle z tymi polskimi literkami zauważyłeś :)
Ten artykuł jak i kody znalazłem na http://www.murphy.website.pl/faq.php?action=dzial&id=3. O dziwo, tam też są problemy z polskimi literkami :P Plagiat?

angielskom klawiature i nie mam polskich liter

To sobie zainstaluj polską. A dlaczego w dalszej części artykułu są polskie litery? Przepisane (skopiowane) skąś? A dlaczego są dwa tragiczne błędy ortograficzne w pierwszych zdaniach, to już nie jest wina klawiatury.

Do poprawy.