Shell – aneb zástupci, speciální složky, souborové operace a pod.

V tomto článku si ukážeme, jak pracovat s některými položkami shellu. Naučíme se jak zjistit skutečnou cestu k speciálním složkám, jako je například nabídka start, dále si ukážeme jak vytvářet zástupce, jak je přidat třeba na plochu či do nabídky „po spuštění“.
Speciální složky

Nejprve si řekněme, jak zjistit skutečnou cestu k tzv. speciálním složkám Windows, jako jsou například Dokumenty, Plocha, složka „Windows“ a pod. Jde samozřejmě o to, že skutečná cesta k těmto složkám se liší v závislosti na verzi Windows a samozřejmě na logické jednotce, na kterou byl systém nainstalován.

Cesty ke speciálním složkám bychom mohli získat načtením příslušných klíčů v registrační databázi, nicméně máme k disposici jednodušší a preferovaný způsob – použití funkce SHGetFolderPath:

HRESULT SHGetFolderPath(
HWND hwndOwner,
int nFolder,
HANDLE hToken,
DWORD dwFlags,
LPTSTR pszPath
);

Parametr hwndOwner se v běžných případech nastaví na NULL, důležitý je parametr nFolder, jenž určuje, která ze speciálních složek nás zajímá. Hodnoty, kterých může nabývat, i s vysvětlujícími texty uvidíte o pár řádků dále ve výpisu konkrétního použití této funkce. Parametr hToken je typicky NULL, nebudeme jej zde podrobně rozebírat. Musíme si však říci o parametru dwFlags, který určuje, zda chceme získat skutečnou cestu k uvedené složce na tomto počítači, nebo zda nás zajímá její výchozí (default) hodnota pro daný operační systém. Možné hodnoty jsou tyto:

  • SHGFP_TYPE_CURRENT – skutečná, aktuální složka
  • SHGFP_TYPE_DEFAULT – výchozí umístění složky na dané verzi Windows.
Jako příklad si naplníme list-box (jako ukázku použijeme jednoduchou, i když ne zrovna „cool“ implementaci) zjištěnými cestami včetně popisů. Vytvoříme si následující funkci:

void CSpecialFolders::GetFolder(int nFolder, LPCTSTR lpText)
{
TCHAR chText[_MAX_PATH+50];
TCHAR chFolder[_MAX_PATH];
SHGetFolderPath(NULL, nFolder, NULL, SHGFP_TYPE_CURRENT, chFolder);
SendDlgItemMessage(IDC_LIST_FOLDERS, LB_ADDSTRING, 0, (LPARAM)lpText);
strcpy(chText, TEXT("    - "));
strcat(chText, chFolder);
SendDlgItemMessage(IDC_LIST_FOLDERS, LB_ADDSTRING, 0, (LPARAM)chText);
}

Zde budeme dosazovat příslušný identifikátor a popisující text třeba takto:

void CSpecialFolders::ShowSpecialFolders()
{
SendDlgItemMessage(IDC_LIST_FOLDERS, LB_ADDSTRING,
(LPARAM)"Speciální složky");
SendDlgItemMessage(IDC_LIST_FOLDERS, LB_ADDSTRING, 0, (LPARAM)"");
GetFolder(CSIDL_WINDOWS, "Windows: ");
GetFolder(CSIDL_ADMINTOOLS, "Admin tools: ");
GetFolder(CSIDL_COMMON_ADMINTOOLS, "Nástroje pro správu: ");
GetFolder(CSIDL_APPDATA, "Data aplikací: ");
GetFolder(CSIDL_COMMON_APPDATA, "Společná data aplikací: ");
GetFolder(CSIDL_COMMON_DOCUMENTS, "Společné dokumenty: ");
GetFolder(CSIDL_COOKIES, "Cookies: ");
GetFolder(CSIDL_HISTORY, "Historie: ");
GetFolder(CSIDL_INTERNET_CACHE, "Dočasné soubory Internetu: ");
GetFolder(CSIDL_LOCAL_APPDATA, "Lokální data aplikací: ");
GetFolder(CSIDL_MYPICTURES, "Obrázky: ");
GetFolder(CSIDL_PERSONAL, "Osobní dokumenty: ");
GetFolder(CSIDL_PROGRAM_FILES, "Program Files: ");
GetFolder(CSIDL_PROGRAM_FILES_COMMON, "Program Files (společné soubory): ");
GetFolder(CSIDL_SYSTEM, "Systém: ");
GetFolder(CSIDL_STARTMENU, "Nabídka Start: ");
GetFolder(CSIDL_STARTUP, "Startup: ");
GetFolder(CSIDL_DESKTOPDIRECTORY, "Plocha: ");
GetFolder(CSIDL_BITBUCKET, "Koš: ");
GetFolder(CSIDL_FAVORITES, "Oblíbené: ");
GetFolder(CSIDL_FONTS, "Písma: ");
}

Zástupci

Přejděme nyní k zástupcům. K jejich vytvoření potřebujeme získat interface IShellLink a IPersistFile. Pomocí jejich metod pak můžeme zástupce vytvořit. Nebudeme se zde zabývat rozborem COM objektů, neboť to by bylo nad rámec tohoto článku. Řekněme si jen tolik, že musíme inicializovat COM knihovnu a poté můžeme pracovat s příslušnými interface. Uvedu zde ukázku funkce, kterou budeme používat pro vytvoření zástupců v různých místech.

BOOL shell_CreateShortcut(LPCTSTR lpPathObj, LPCTSTR lpLinkFile, LPCTSTR  lpDescription)
{
HRESULT hres;
IShellLink* psl;
CoInitialize(NULL);
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
IID_IShellLink, (LPVOID>&psl);
if ( hres != S_OK )
{
return FALSE;
}
IPersistFile* ppf;
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID>&ppf);
if ( hres != S_OK )
{
return FALSE;
}
WORD wsz[MAX_PATH];
hres = psl->SetPath(lpPathObj);
if ( !SUCCEEDED(hres) ) return FALSE;
hres = psl->SetDescription(lpDescription);
if ( !SUCCEEDED(hres) )
{
return FALSE;
}
MultiByteToWideChar(CP_ACP, 0, lpLinkFile, -1, (LPWSTR)wsz, MAX_PATH);
hres = ppf->Save((LPWSTR)wsz, TRUE);
ppf->Release();
psl->Release();
CoUninitialize();
return ( SUCCEEDED(hres));
}

Parametr lpPathObj je plná cesta k objektu (souboru) jehož zástupce chceme vytvořit. Parametr lpLinkFile bude plná cesta souboru se zástupcem. Jako text u ikony zástupce systém použije název souboru bez cesty a přípony. Parametr lpDescription je pak popis zástupce, konkrétně text, který se objeví jako „tool-tip“ po najetí myší na zástupce (pokud je například na ploše).

Ukažme si jako příklad vytvoření zástupce poznámkového bloku (notepad.exe) na ploše. Co musíme udělat? Již zmíněným způsobem zjistit umístění 2 složek: plochy a systémové složky Windows, ve které je soubor notepad.exe. Nakonec už jen zavoláme uvedenou vlastní funkci shell_CreateShortcut:

// přidání zástupce notepadu na plochu:

void CUkazkaDlg::OnDesktopLink()
{
TCHAR chPath[_MAX_PATH];
CHAR chDesktop[_MAX_PATH];
SHGetFolderPath(NULL, CSIDL_WINDOWS, NULL, SHGFP_TYPE_CURRENT, chPath);
SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, chDesktop);
lstrcat(chPath, "\\notepad.exe");
lstrcat(chDesktop, "\\");
lstrcat(chDesktop, "Žákovská knížka");
lstrcat(chDesktop, ".lnk");
shell_CreateShortcut(chPath, chDesktop,
"Žádný strach, jde o obyčejný poznámkový blok, neboli notepad ...");
}

Podobným způsobem přidáme položku (konkrétně třeba program „kalkulačka“ do programů spouštěných při startu Windows, přesněji při přihlášení konkrétního uživatele):

// přidání kalkulačky do start-up menu

void CUkazkaDlg::OnAddStartmenu()
{
TCHAR chPath[_MAX_PATH];
CHAR chStartUp[_MAX_PATH];
SHGetFolderPath(NULL, CSIDL_SYSTEM, NULL, SHGFP_TYPE_CURRENT, chPath);
SHGetFolderPath(NULL, CSIDL_STARTUP, NULL, SHGFP_TYPE_CURRENT, chStartUp);

lstrcat(chPath, "\\calc.exe");
strcat(chStartUp, "\\");
strcat(chStartUp, "Počítadlo");
strcat(chStartUp, ".lnk");
shell_CreateShortcut(chPath, chStartUp,
"Nemůžete-li usnout, zkuste počítat ovečky ....");
}

Souborové operace

Nyní si řekneme něco o souborových operacích, jako je kopírování, přesun, umístění do koše a odstranění. Vzhledem k tomu, že se zabýváme „shellem“, budeme se zabývat metodami používajícími právě funkce shellu. (O funkcích CopyFile, CopyFileEx, DeleteFile apod. se zmíníme třeba někdy příště.) Budeme tedy používat stejné funkce, které používá Průzkumník Windows. Jednou z nejběžnějších funkcí tohoto typu je funkce SHFileOperation:

int SHFileOperation(
LPSHFILEOPSTRUCT lpFileOp
);

kde parametr lpFileOp je adresa následující struktury:

typedef struct _SHFILEOPSTRUCT{
HWND hwnd;
UINT wFunc;
LPCTSTR pFrom;
LPCTSTR pTo;
FILEOP_FLAGS fFlags;
BOOL fAnyOperationsAborted;
LPVOID hNameMappings;
LPCSTR lpszProgressTitle;
} SHFILEOPSTRUCT, *LPSHFILEOPSTRUCT;

Když se podíváme na parametr wFunc, zjistíme, že může nabývat následujících hodnot podle typu operace, kterou chceme provést:

  • FO_COPY – zkopíruje soubor(-y) pFrom do souboru pTo(-y)
  • FO_DELETE – smaže soubor(-y) specifikovaný(-é) pFrom
  • FO_MOVE - přesune soubor(-y) pFrom do souboru pTo(-y)
  • FO_RENAME – přejmenuje soubor pFrom (nelze použít pro více souborů najednou).
Parametr hwnd je handle dialogu zobrazujícího informace o stavu operace. Parametr fAnyOperationAborted je naplněn hodnotou TRUE, pokud uživatel během tuto operaci během jejího průběhu stornoval. Parametr hNameMappings se používá pouze ojediněle a nebudeme jej zde podrobně rozebírat (pro zájemce je zde samozřejmě MSDN). Parametr lpszProgressTitle je text, který se objeví v titulku dialogu průběhu operace. A nakonec se podívejme na parametr fFlags. Zde máme poměrně bohatý výběr nejrůznějších upřesnění; zmíním se o těch nejdůležitějších:
  • FOF_ALLOWUNDO – umožňuje vzít operaci zpět (např. přesun do koše)
  • FOF_NOCONFIRMATION – od uživatele není vyžadováno žádné potvrzení operace, jako přepsání cílového souboru apod.
  • FOF_NONCONFIRMMKDIR – od uživatele není vyžadováno povolení k vytvoření složky, pokud je třeba vytvořit v cíli novou složku.
  • FOF_SILENT – nezobrazuje během operace stav průběhu
  • FOF_SIMPLEPROGRESS – zobrazí dialog průběhu operace, ale bez zobrazování zpracovávaných souborů
Ukážeme si příklad kopírováni souboru, třeba s volbou bez potvrzení přepsání cílového souboru:

// kopírování souboru

void CUkazkaDlg::OnCopyFile()
{
SHFILEOPSTRUCT op;
ZeroMemory(&op, sizeof(op));
op.hwnd  = m_hWnd;
op.wFunc = FO_COPY;
op.pFrom = "d:\\data\\zdroj.avi";
op.pTo  = "d:\\data\\zaloha.avi";
op.fFlags = FOF_NOCONFIRMATION;
SHFileOperation( &op);
}
Ještě uvedu příklad odstranění souboru. Nejprve jeho přesun do koše:

// přesun souboru do koše

void CUkazkaDlg::OnToRecycle()
{
SHFILEOPSTRUCT op;
ZeroMemory(&op, sizeof(op));
op.hwnd = m_hWnd;
op.wFunc = FO_DELETE;
op.pFrom = "d:\\data\\zaloha.avi";
op.fFlags= FOF_ALLOWUNDO;
SHFileOperation( &op);
}

Jak vidíte, je zde použit příznak FOF_ALLOWUNDO na operaci FO_DELETE.

Pro úplnost úplné odstranění souboru (bez umístění do koše):

void CUkazkaDlg::OnDelete()
{
SHFILEOPSTRUCT op;
ZeroMemory(&op, sizeof(op));
op.hwnd = m_hWnd;
op.wFunc = FO_DELETE;
op.pFrom = "d:\\data\\zaloha.avi";
SHFileOperation( &op);
}

Nyní, když jsem u koše, ukažme si, jak programově vysypat koš. K tomu požijeme funkci SHEmptyRecycleBin:

HRESULT SHEmptyRecycleBin(
HWND hwnd,
LPCTSTR pszRootPath,
DWORD dwFlags
);

  • hwnd je obdobně jako u funkce SHFileOperation handle rodičovského okna dialogů, které mohou být během operace zobrazovány.
  • pszRootPath je adresa textového řetězce obsahujícího ke kořenovému adresáři příslušného disku
  • dwFlags – další upřesnění operace, můžeme uvést jednu nebo více z těchto hodnot:
    • SHERB_NOCONFIRMATION – nezobrazí se dialog vyžadující potvrzení odstranění položek z koše
    • SHERB_NOPROGRESSUI – nezobrazí se dialog informující o průběhu operace
    • SHERB_NOSOUND – nebude přehrán žádný zvukový doprovod
    Konkrétní příklad vysypání koše může vypadat třeba takto:

    // vysypání koše

    void CUkazkaDlg::OnVysypatKos()
    {
    SHEmptyRecycleBin(m_hWnd, "d:\\", SHERB_NOCONFIRMATION);
    }

    Pokud by nás zajímaly informace o obsahu koše, můžeme k jejich získání použít funkci SHQueryRecycleBin:

    HRESULT SHQueryRecycleBin(
    LPCTSTR pszRootPath,
    LPSHQUERYRBINFO pSHQueryRBInfo
    );

    kde parametr pSHQueryRBInfo je adresa struktury

    typedef struct _SHQUERYRBINFO {
    DWORD cbSize;
    __int64 i64Size;
    __int64 i64NumItems;
    } SHQUERYRBINFO, *LPSHQUERYRBINFO;

    Jak již napovídají názvy položek této struktury, můžeme takto získat informace o počtu položek v koši (i64NumItems) a o celkové velikosti položek v koši (i64Size). Uveďme si opět příklad použití:

    void CUkazkaDlg::OnRecycleInfo()
    {
    SHQUERYRBINFO shqrb;
    shqrb.cbSize = sizeof(SHQUERYRBINFO);
    SHQueryRecycleBin("f:\\", &shqrb);
    SetDlgItemInt(IDC_RB_SIZE, shqrb.i64Size, FALSE);
    SetDlgItemInt(IDC_RB_ITEMS, shqrb.i64NumItems, FALSE);
    }

    Na závěr tohoto článku je nutné si říci o pravidlech slušného chování. Pokud provedeme nějakou z operací, která nějak mění prostředí souborového sytému, obecně shellu, mělo by být pravidlem o tom informovat systém. K tomu složí funkce SHChangeNotify:

    VOID SHChangeNotify(
    LONG wEventId,
    UINT uFlags,
    LPCVOID dwItem1,
    LPCVOID dwItem2
    );

    Parametr wEventId označuje událost, resp. změnu, která nastala. Úplný výčet parametrů naleznete v MSDN, uvedu zde jen některé z těch běžných:

    • SHCNE_MKDIR – byla vytvořena nová složka
    • SHCNE_CREATE – byla vytvořena položka, např. soubor
    • SHCNE_DELETE – položka byla odstraněna
    Nyní si uveďme příklad, jak doplnit výše uvedenou funkci pro kopírování souboru o toto oznámení:

    void CUkazkaDlg::OnCopyFile()
    {
    SHFILEOPSTRUCT op;
    ZeroMemory(&op, sizeof(op));
    op.hwnd  = m_hWnd;
    op.wFunc = FO_COPY;
    op.pFrom = "d:\\data\\zdroj.avi";
    op.pTo  = "d:\\data\\zaloha.avi";
    op.fFlags = FOF_NOCONFIRMATION;
    SHFileOperation( &op);
    SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, (LPCVOID) "d:\\data", 0);
    }

    Tolik pro dnešek o shellu a v příštím článku se k němu ještě vrátíme.

    Zde si můžete stáhnout ukázkový projekt shell.zip.

Diskuze (12) Další článek: Service Pack 2 pro Corel Draw 10

Témata článku: Software, Windows, Programování, Soubor, Opera, Nová složka, Úplné odstranění, Bohatý výčet, SHF, Code, Složka, Cesta, Běžný případ, Osobní dokument, Speciální systém, Speciál, SPEC, PSH, Dialog


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

10 míst na mapách Googlu, která nesmíte vidět. Nahradily je čtverečky

10 míst na mapách Googlu, která nesmíte vidět. Nahradily je čtverečky

** Deset míst, které nesmíte vidět ve webových mapách ** Jsou to letiště, základny i elektrárny ** Nejvíce míst tají Francie

Jakub Čížek | 21

Jakub Čížek
Mapy GoogleMapy
Vyšel Windows 10 October 2020 Update. Poradíme, jak je stáhnout a co je nového
Vladislav Kluska
October 2020 UpdateWindows 10
Teď už Chromium ovládne Windows 10 úplně. Microsoft dokončil WebView2

Teď už Chromium ovládne Windows 10 úplně. Microsoft dokončil WebView2

** Před dvěma lety se Microsoft zasnoubil s Chromem ** Nový Edge není zdaleka jejich jediné dítě ** Ještě důležitější je komponenta WebView2

Jakub Čížek | 53

Jakub Čížek
Windows 10ChromeSoftware
Testy procesorů Ryzen 5000: AMD překonalo Intel ve všech směrech

Testy procesorů Ryzen 5000: AMD překonalo Intel ve všech směrech

** AMD začalo prodávat nové procesory Ryzen 5000 s architekturou Zen 3 ** K dispozici jsou nezávislé testy z celého světa ** AMD překonává Intel ve všech směrech

Karel Javůrek | 69

Karel Javůrek
ProcesoryTestyAMD
Jak v prohlížeči vypnout oznámení zasílaná webovými stránkami

Jak v prohlížeči vypnout oznámení zasílaná webovými stránkami

** Obtěžují vás neustálé dotazy webů, zda chcete zobrazovat oznámení? ** Můžete je zakázat, a to jak kompletně, tak i pro jednotlivé stránky ** Připravili jsme návody pro Chrome, Firefox, Edge a Operu

Karel Kilián | 11

Karel Kilián
Jak na InternetTipyProhlížeče
Zapomeňte na destičky. Raspberry Pi 400 je nový počítač zabudovaný do klávesnice
Lukáš Václavík
Raspberry PiPočítače
Apple Macbook Air M1: testujeme výkon, výdrž, a hlavně kompatibilitu aplikací [průběžně aktualizováno]

Apple Macbook Air M1: testujeme výkon, výdrž, a hlavně kompatibilitu aplikací [průběžně aktualizováno]

** Testujeme Apple Macbook Air s procesorem M1 ** Zajímá nás nejen výkon, ale zejména kompatibilita aplikací ** Článek je průběžně doplňován na základě vašich dotazů

Jiří Kuruc | 205

Jiří Kuruc
Apple
Vodafonu se zhroutila kabelovka. Síť bývalého UPC má výpadky
Lukáš Václavík
VodafoneUPC
Vážně dnes ještě někdo krade Adobe? Video můžete stříhat zdarma v Resolve a fotky i vektory zvládne Affinity

Vážně dnes ještě někdo krade Adobe? Video můžete stříhat zdarma v Resolve a fotky i vektory zvládne Affinity

** Kde jsou ty doby, kdy měl skoro každý doma Photoshop ** Photoshop a Premiere Pro od kamaráda nebo z warezu ** Dnes už to nemá smysl, existuje totiž hromada laciných alternativ

Jakub Čížek | 90

Jakub Čížek
Grafický editorStřih videa
Google chystá funkci, která z chytrého Gmailu udělá hloupý Gmail
Lukáš Václavík
SoukromíGmailGoogle

Aktuální číslo časopisu Computer

Jak prodloužit výdrž notebooku

Velké testy: gamepady a inkoustové tiskárny

Důkladný test Sony Playstation 5