22.1.2002
V tomto pokračování si ukážeme něco málo ze základů práce se soubory. Naučíme se použít standardní dialog pro otevření souboru a dále si ukážeme ten nejjednodušší způsob načtení souboru (textu) například do víceřádkového editačního pole. Výsledek dnešního ukázkového příkladu vidíte na obrázku:
K vyvolání standardního systémového dialogu pro otevření (nebo uložení) souboru složí funkce GetOpenFileName:
BOOL GetOpenFileName( LPOPENFILENAME lpofn // inicializační data );
Jak je vidět, veškeré parametry funkce jsou ve struktuře OPENFILENAME:
typedef struct tagOFN { DWORD lStructSize; HWND hwndOwner; HINSTANCE hInstance; LPCTSTR lpstrFilter; LPTSTR lpstrCustomFilter; DWORD nMaxCustFilter; DWORD nFilterIndex; LPTSTR lpstrFile; DWORD nMaxFile; LPTSTR lpstrFileTitle; DWORD nMaxFileTitle; LPCTSTR lpstrInitialDir; LPCTSTR lpstrTitle; DWORD Flags; WORD nFileOffset; WORD nFileExtension; LPCTSTR lpstrDefExt; LPARAM lCustData; LPOFNHOOKPROC lpfnHook; LPCTSTR lpTemplateName; #if (_WIN32_WINNT >= 0x0500) void * pvReserved; DWORD dwReserved; DWORD FlagsEx; #endif // (_WIN32_WINNT >= 0x0500) } OPENFILENAME, *LPOPENFILENAME;
Prozatím se nebudeme zabývat podrobnějším vysvětlením všech prvků této struktury. Nejlépe si ukázat jednoduchý příklad. Důležité je pamatovat na "vynulování" struktury před plněním jednotlivých prvků, abychom ty které nás nezajímají, mohli ignorovat a měli jistotu, že jsou "nulové". Dále je nutné runě naplnit prvek lStructSize na velikost struktury (pomocí sizeof). Nyní již k příkladu. V dnešní ukázce je aplikace založená na dialogu se 2 edit-boxy, z nichž do jednoho vypíšeme plný název vybraného souboru, do druhého (víceřádkového) pak obsah tohoto (textového) souboru. Dialog otevření souboru vyvoláme na talčítko "Vybrat soubor" (IDC_OPEN_FILE). Pro vybrání souboru si vytvoříme následující funkci:
BOOL OpenDialog(LPTSTR lpFile, HWND hwndOwner) { OPENFILENAME ofn; TCHAR chFile[_MAX_PATH]; lstrcpy(chFile, ""); ZeroMemory(&ofn, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.lpstrFile = chFile; ofn.hwndOwner = hwndOwner; ofn.nMaxFile = sizeof(chFile); ofn.lpstrFilter = TEXT("Textové soubory (*.txt)\0*.txt\0Všechny soubory (*.*)\0*.*\0"); ofn.nFilterIndex = 1; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; if ( !GetOpenFileName(&ofn) ) return FALSE; lstrcpy(lpFile, chFile); return TRUE; }
Pokud uživatel stiskne tlačítko "OK", funkce zkopíruje plný název vybraného souboru do parametru lpFile.
Nyní tedy máme jméno souboru a můžeme přistoupit k jeho otevření a načtení. Pro otevření (nebo vytvoření nového) souboru se používá funkce CreateFile:
HANDLE CreateFile( LPCTSTR lpFileName, // jméno souboru DWORD dwDesiredAccess, // přístup DWORD dwShareMode, // sdílení LPSECURITY_ATTRIBUTES lpSecurityAttributes, // atributy zabezpečení DWORD dwCreationDisposition, // způsob vytvoření DWORD dwFlagsAndAttributes, // atributy souboru HANDLE hTemplateFile // soubor "šablony" );
Podrobněji se k této funkci a jejím možnostem vrátíme později, zde si ukážeme ten nejjednodušší způsob použití pro otevření existujícího souboru. Funkce vrátí handle otevřeného souboru nebo v případě neúspěchu hodnotu INVALID_HANDLE_VALUE. Podívejme se nyní na celou vlastní funkci, která načte zadaný soubor a jeho obsah nastaví jako text okna zadaného jako parametr:
BOOL LoadFile(LPCTSTR lpFileName, HWND hWndTo) { HANDLE hFile; DWORD dwSize; DWORD dw; LPBYTE lpBuffer = NULL; hFile = CreateFile(lpFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); if ( hFile == INVALID_HANDLE_VALUE ) return FALSE; dwSize = GetFileSize(hFile, NULL); lpBuffer = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, dwSize+1); if ( !ReadFile(hFile, lpBuffer, dwSize, &dw, NULL) ) { CloseHandle(hFile); HeapFree(GetProcessHeap(), 0, lpBuffer); return FALSE; } CloseHandle(hFile); lpBuffer[dwSize] = 0; SetWindowText(hWndTo, (LPCTSTR)lpBuffer); if ( !HeapFree(GetProcessHeap(), 0, lpBuffer) ) return FALSE; return TRUE; }
Jak je zřejmé, celý obsah souboru načítáme v jednom čtení. Musíme tedy nejprve zjistit velikost souboru pomocí funkce GetFileSize. Buffer si naalokujeme na tuto velikost plus jeden byte navíc pro uložení nulového znaku ukončujícího řetězec, neboť k tomuto bufferu budeme přistupovat jako k céčkovskému řetězci, použijeme ho jako parametr funkce SetWindowText. Pro alokaci bufferu by samozřejmě bylo možné použít standardní céčkovské funkce malloc/free. Na tomto příkladě jsem ale také ukázal jednoduchý způsob alokace paměti pomocí Win32 funkcí, konkrétně HeapAlloc/HeapFree. Vlastní načtení souboru pak provádíme funkcí ReadFile:
BOOL ReadFile( HANDLE hFile, // handle otevřeného souboru LPVOID lpBuffer, // datový buffer DWORD nNumberOfBytesToRead, // počet bytů k načtení LPDWORD lpNumberOfBytesRead, // počet načtených bytů LPOVERLAPPED lpOverlapped // "overlapped" buffer );
Tato funkce nám vrátí logickou hodnotu indikující úspěch načtení a současně naplní parametr lpNumberOfBytesRead počtem skutečně načtených bytů, který může být menší než počet bytů požadovaných, pokud například narazíme na konec souboru.
Doprovodný projekt je ke stažení zde: win_api_22.zip
Školení
Kontakt
739 219 991
live:radekchalupa_1
Nové články