Shell v C++ 2.díl

V tomto článku ještě zůstaneme u Shellu. Ukážeme si jak spustit jiný program, jak získat informace o jeho návratovém kódu a jak detekovat, zda program byl ukončen. Ukážeme si také jak získat některé informace o běžícím procesu.
Spuštění jiného programu pomocí ShellExecuteEx

Nejprve si ukažme první způsob zpuštění jiného programu pomocí funkce ShellExecuteEx:

BOOL ShellExecuteEx(
  LPSHELLEXECUTEINFO lpExecInfo
);

Tato funkce rozšiřuje možnosti jednodušší funkce ShellExecute. Nyní se sice zabýváme spuštěním programu, ale tato funkce má mnohem širší použití. Můžeme její pomocí otevírat libovolné (registrované samozřejmě) soubory, vyvolat dialog vlastností souborů a složek apod. Nyní ale ke spuštění programu. Ukážeme si příklad, jak spustit třeba poznámkový blok (notepad.exe) a následně hlídat jeho ukončení a zjistit jeho ukončovací kód. Ukončovací kód je návratová hodnota funkce WinMain, což je „hlavní“ funkce každého běžného programu ve Windows.

Jak detekovat ukončení programu, který spustíme?

Proměnou typu SHELLEXECUTEINFO si deklarujeme mimo „spouštěcí funkci“, neboť jedním jejím prvkem je handle na spuštěný proces, který budeme dále potřebovat. Cestu k souboru notepad.exe si najdeme pomocí funkce SHGetFolderPath, kterou jsme se podrobněji zabývali v minulém článku. Dále už musíme pouze vhodně naplnit některé prvky struktury SHELLEXECUTEINFO a její adresu použít jako parametr funkce ShellExecuteEx. Nakonec si spustíme timer (s intervalem třeba půl sekundy), na který budeme testovat stav takto spuštěného programu.

SHELLEXECUTEINFO sei;

void CMainFrame::OnLaunchNotepad()
{
  TCHAR chPath[_MAX_PATH];
  SHGetFolderPath(NULL, CSIDL_WINDOWS, NULL, SHGFP_TYPE_CURRENT, chPath);
  lstrcat(chPath, "\\notepad.exe");
  ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
  sei.cbSize =  sizeof(SHELLEXECUTEINFO);
  sei.fMask = SEE_MASK_NOCLOSEPROCESS;
  sei.hwnd = m_hWnd;
  sei.nShow = SW_SHOWNORMAL;
  sei.lpFile = chPath;
  sei.lpVerb = "open";
  ShellExecuteEx(&sei);
  SetTimer(1, 500, NULL);
}

Pro zjištění ukončovacího kódu programu použijeme funkci GetExitCodeProcess:

BOOL GetExitCodeProcess(
  HANDLE hProcess,  // handle procesu
  LPDWORD lpExitCode  // ukončovací kód
);

Touto funkcí samozřejmě také zjistíme, zda proces ještě běží. V takovém případě je hodnota lpExitCode rovna definované hodnotě STILL_ACTIVE. Nyní se tedy podívejme, jak může vypadat handler timeru, ve kterém testujeme „stav“ procesu:

void CMainFrame::OnTimer(UINT nIDEvent)
{
  DWORD dwExitCode;
  GetExitCodeProcess(sei.hProcess, &dwExitCode);
  if ( dwExitCode == STILL_ACTIVE )
  {
    CFrameWnd::OnTimer(nIDEvent);
    return;
  }
  KillTimer(1);
  ShowWindow(SW_SHOWNORMAL);
  SetForegroundWindow();
  TCHAR chText[30];
  sprintf(chText, "Notepad ukončen kódem: %d", dwExitCode);
  MessageBox(chText, "Proces ukončen", MB_OK | MB_ICONINFORMATION);
}

Jak ukončit proces „zvenku“

Pokud je proces spuštěn a máme k disposici jeho handle, můžeme snadno proces „natvrdo“ ukončit pomočí funkce TerminateProcess:

BOOL TerminateProcess(
  HANDLE hProcess,  // handle procesu
  UINT uExitCode  // ukončovací kód procesu
);

Konkrétní příklad použití této funkce může vypadat třeba takhle:

void CMainFrame::OnKillprocess()
{
  TerminateProcess(sei.hProcess, 0); 
}

Spuštění programu pomocí funkce CreateProcess

Nyní si ukažme další způsob spuštění jiného programu, tentokrát pomocí funkce CreateProcess:

BOOL CreateProcess(
  LPCTSTR lpApplicationName,    // jméno spustitelného souboru
  LPTSTR lpCommandLine,    // příkazový řádek
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL bInheritHandles,    // volba zdědění handle
  DWORD dwCreationFlags,    // volby vytvoření
  LPVOID lpEnvironment,
  LPCTSTR lpCurrentDirectory,    // adresář spuštění
  LPSTARTUPINFO lpStartupInfo,    // startovací informace
  LPPROCESS_INFORMATION lpProcessInformation // informace o procesu
);

V tomto případě je důležitě správně naplnit prvek, sui, tedy strukturu STARTUPINFO a po úspěšném vykonání této funkce máme v prvku lpProcessInformation uloženy informace o spuštěném procesu, včetně jeho handle, což nás většinou zajímá nejvíce. Další přístup k takto spuštěnému procesu by pak byl stejný jako když jsme jej spustili pomocí funkce ShellExecuteEx, tedy přes jeho handle. V tomto případě máme handle procesu v prvku hProcess struktury PROCESS_INFORMATION:

typedef struct _PROCESS_INFORMATION {
  HANDLE hProcess;
  HANDLE hThread;
  DWORD dwProcessId;
  DWORD dwThreadId;
} PROCESS_INFORMATION;

Jak jsem se zmínil na začátku, pomocí funkce ShellExecuteEx lze pracovat nejen se spustitelnými soubory (.exe) ale s jakýmkoli souborem. Pokud tento patří mezi registrované tipy, lze soubor touto funkcí otevřít, nechat vytisknout apod. Vraťme se ještě k parametru této funkce, kterým je adresa struktury SHELLEXECUTEINFO:

typedef struct _SHELLEXECUTEINFO{
  DWORD cbSize;
  ULONG fMask;
  HWND hwnd;
  LPCTSTR lpVerb;
  LPCTSTR lpFile;
  LPCTSTR lpParameters;
  LPCTSTR lpDirectory;
  int nShow;
  HINSTANCE hInstApp;
  // Volitelné prvky
  LPVOID lpIDList;
  LPCSTR lpClass;
  HKEY hkeyClass;
  DWORD dwHotKey;
  union {
    HANDLE hIcon;
    HANDLE hMonitor;
  };
  HANDLE hProcess;
} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;

Parametr fMask je kombinace hodnot, určující které prvky struktury obsahují platná data a popřípadě jaký mají tato data konkrétní význam. Důležitým parametrem je lpVerb, což je adresa textu určujícího, jaká akce se má se souborem nebo složkou provést. Může mít tento obsah:

  • „edit“ – otevře soubor (určený parametrem lpFile) pro editaci přidruženým editorem
  • „explore“ – otevře složku určenou parametrem lpFile Průzkumníkem Windows
  • „find“ – spustí panel vyhledávání s tím, že jako počátek vyhledávání je složka lpDirectory
  • „open“ – otevře soubor přidruženým programem.
  • „print“ – spustí tisk dokumentu lpFile
  • „properties“ – zobrazí vlastnosti souboru nebo složky
Jako příklad si ukažme jak zobrazit vlastnosti souboru:

void CMainFrame::OnFileProperties()
{
  SHELLEXECUTEINFO sei;
  ZeroMemory(&sei,sizeof(sei));
  sei.cbSize = sizeof(sei);
  sei.lpFile = "d:\\data\\list_url.txt";
  sei.lpVerb = "properties";
  sei.fMask  = SEE_MASK_INVOKEIDLIST;
  ShellExecuteEx(&sei); 
}

Diskuze (8) Další článek: Nejvyhledávanější slova Internetu 2001

Témata článku: Software, Windows, Programování, Úspěšný editor, Timer, Struktura, CFR, Hicon, Spustitelný soubor, Funkce, Union, Explore


Určitě si přečtěte


Aktuální číslo časopisu Computer

Megatest 20 procesorů

Srovnání 15 True Wireless sluchátek

Vyplatí se tisknout fotografie doma?

Vybíráme nejlepší základní desky