14. 파일입출력 1 1. 파일입출력 BOOL ReadFile( HANDLE hfile, LPVOID lpbuffer, DWORD nnumberofbytestoread, LPDWORD lpnumberofbytesread, LPOVERLAPPED lpoverlapped ); hfile : 데이터를읽을대상파일의핸들 lpbuffer : 읽은데이터를저장할버퍼 nnumberofbytestoread : 읽고자하는양 lpnumberofbytesread : 실질적으로읽은바이트양 lpoverlapped : 비동기입출력을할때사용한다. BOOL CloseHandle( HANDLE hobject ); 파일핸들도메모리를차지하므로다사용하고난후에해제해주어야한다. 2
1. 파일입출력 HANDLE CreateFile( LPCTSTR lpfilename, DWORD dwdesiredaccess, DWORD dwsharemode, LPSECURITY_ATTRIBUTES lpsecurityattributes, DWORD dwcreationdisposition, DWORD dwflagsandattributes, HANDLE htemplatefile ); lpfilename : 열거나만들고자하는파일의완전경로 dwdesiredaccess : 파일의액세스타입, 즉파일로부터데이터를읽을것인지쓸것인지를지정한다. 파일로부터데이터를읽기만하면 GENERIC_READ 쓰기만하면 GENERIC_WRITE 읽기쓰기 : GENERIC_READ GENERIC_WRITE dwsharemode : 열려진파일의공유모드지정. 0 이면파일은공유되지않으며열려진파일을또열수없음. FILE_SHARE_DELETE : 삭제액세스에대해서만파일을열수있다. FILE_SHARE_READ : 읽기모드로열때만파일을열수있다. FILE_SHARE_WRITE : 쓰기모드로열때만파일을열수있다. 3 1. 파일입출력 lpsecurityattributes : 리턴핸들을차일드프로세스로상속할것인지를지정 SECURITY_ATTRIBUTES 구조체의핸들 dwcreationdisposition : 생성파일이이미존재, 또는오픈할파일이없을경우지정. CREATE_NEW : 새로운파일을만들되만약지정한파일이이미있으면만들지않는다. CREATE_ALWAYS : 새로운파일을만들되만약지정한파일이이미있으면기존파일을삭제하고다시만든다. OPEN_EXISTING : 이미있는파일을열되만약파일이없으면에러코드를되돌린다. OPEN_ALWAYS : 파일을열되만약없으면새로만든다. TRUNCATE_EXISTING : 파일을열되파일크기를 0으로만든다. 4
1. 파일입출력 dwflagsandattributes FILE_ATTRIBUTE_ARCHIVE FILE_ATTRIBUTE_HIDDEN FILE_ATTRIBUTE_NORMAL FILE_ATTRIBUTE_READONLY FILE_ATTRIBUTE_SYSTEM FILE_ATTRIBUTE_TEMPORARY 아카이브속성히든파일아무속성도가지지않은보통파일읽기전용운영체제가배타적으로사용하는파일임시저장소에저장되는파일. 이속성의파일은디스크에저장되지않고메모리에저장되므로입출력속도가빠르다. 사용후에는반드시지워주어야한다. FILE_FLAG_WRITE_THROUGH 데이터출력시캐시를통해곧바로디스크 로출력하도록한다. 플러쉬가더빨라진다. FILE_FLAG_OVERLAPPED 비동기입출력을행한다. FILE_FLAG_RANDOM_ACCESS 임의접근파일임을알린다. FILE_FLAG_SEQUENTIAL_SCAN 순차접근파일임을알린다. 이상의두플래 그는시스템이캐시를최적화하는데도움을 5 줄뿐이다. ( 임의접근가능 ) htemplatefile : 만들고자하는파일의추가속성을지원하는템플리트파일의핸들을지정. 일반적으로 NULL 지정 6
1. 파일입출력 리턴값 : 파일의핸들 어떤이유로파일열기에실패하면 INVALID_HANDLE_VALUE 를리턴한다. BOOL WriteFile( HANDLE hfile, LPCVOID lpbuffer, DWORD nnumberofbytestowrite, LPDWORD lpnumberofbyteswritten, LPOVERLAPPED lpoverlapped ); hfile : 대상파일의핸들 lpbuffer : 데이터가들어있는버퍼 nnumberofbytestowrite : 쓰고자하는바이트수 lpnumberofbyteswritten : 실제로쓰여진바이트수 lpoverlapped : 비동기입출력을할때사용한다. 7 2. 비동기입출력 ReadFile 이나 WriteFile 같은입출력함수는입출력이완전히끝날때까지리턴하지않는다. 비동기입출력을하려면 CreateFile 함수로파일을열때 FILE_FLAG_OVERLAPPED 플래그를주고 ReadFile, WriteFile 함수의마지막인수에 OVERLAPPED 구조체의포인터를전달해준다. 입출력함수는입출력이시작되는즉시리턴하여다른작업을계속할수있도록해준다. 입출력함수느데이터를완전히다입출력하지않았다는의미로 FALSE 를리턴하며 GetLastError 함수로에러코드를점검해보면 ERROR_IO_PENDING 이리턴된다. BOOL GetOverlappedResult( HANDLE hfile, LPOVERLAPPED lpoverlapped, LPDWORD lpnumberofbytestransferred, BOOL bwait ); 다음함수로입출력진행상태를언제든지확인할수있다. lpnumberofbytestransferred : 현재까지입출력한바이트수 bwait : 입출력이완료될때까지대기할것인가를지정 8
#include <windows.h> #include "resource.h" #include <process.h> #include <commctrl.h> BOOL CALLBACK DlgProc (HWND hdlg, UINT message, WPARAM wparam, LPARAM lparam); int WINAPI WinMain (HINSTANCE hinstance, HINSTANCE hprevinstance,pstr szcmdline, int icmdshow) DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc) ; return TRUE; typedef struct param HWND hbutton; HWND hprogress; PARAM; void DispErrorMessage() DWORD ErrorCode = GetLastError(); char errmsg[1024]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,ErrorCode,0,errMsg,1204,NULL); MessageBox(NULL,errMsg,"",MB_OK); BOOL GetFileName(char temp[]) strcpy(temp,"123.txt"); OPENFILENAME ofn; ZeroMemory(&ofn,sizeof(ofn)); ofn.lstructsize = sizeof(openfilename); ofn.hwndowner = NULL; ofn.lpstrfilter = " 모든파일 (*.*) 0*.* 0 텍스트파일 (*.txt) 0*.txt 0 0 0"; ofn.lpstrfile = temp; ofn.nfilterindex = 2; ofn.nmaxfile = 256; ofn.flags = OFN_EXPLORER OFN_ALLOWMULTISELECT OFN_ENABLESIZING ; if (GetOpenFileName(&ofn) == NULL) return TRUE; else return FALSE; 9 unsigned stdcall MyThreadProc( void * parguments ) PARAM * pparam = (PARAM *)parguments; EnableWindow(pParam->hButton,FALSE); char temp[256]; if (GetFileName(temp)) return FALSE; HANDLE hreadfile = CreateFile(temp,GENERIC_READ,NULL,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL); if (hreadfile == INVALID_HANDLE_VALUE) DispErrorMessage(); return FALSE; unsigned long dfilesize = 0; unsigned long dfilesizehigh = 0; dfilesize = GetFileSize(hReadFile,&dFileSizeHigh); BYTE * pdata = (BYTE *)malloc(dfilesize); BYTE * pbuffer = (BYTE *)malloc(1024*1024); SendMessage(pParam->hProgress,PBM_SETRANGE32,0,dFileSize); SendMessage(pParam->hProgress,PBM_SETPOS,0,0); DWORD ReadLen = 0; OVERLAPPED ov; memset(&ov,0,sizeof(overlapped)); ov.offset = 0; ov.offsethigh = 0 ; ov.hevent = NULL; int ntotalread = 0; do ReadLen = 0; if (ReadFile(hReadFile,pBuffer,1024*1024,&ReadLen,&ov) == FALSE) DispErrorMessage(); 10
WaitForSingleObject(hReadFile,INFINITE); GetOverlappedResult(hReadFile,&ov,&ReadLen,TRUE); SendMessage(pParam->hProgress,PBM_SETPOS,nTotalRead,0); CopyMemory(pData+nTotalRead,pBuffer,ReadLen); ntotalread += ReadLen; ov.offset += ReadLen; while( dfilesize!= ntotalread ); EnableWindow(pParam->hButton,TRUE); CloseHandle(hReadFile); //free(pdata); free(pbuffer); DWORD dwritelen; memset(&ov,0,sizeof(overlapped)); WriteFile(hWriteFile,pData,dFileSize,&dWriteLen,&ov); SendMessage(pParam->hProgress,PBM_SETPOS,0,0); DWORD ntotalwrite = 0; do DWORD WriteLen = 0; GetOverlappedResult(hWriteFile,&ov,&WriteLen,FALSE); ntotalwrite += WriteLen; SendMessage(pParam->hProgress,PBM_SETPOS,nTotalWrite,0); while(dfilesize!= ntotalwrite); CloseHandle(hWriteFile); free(pdata); _endthreadex( 0 ); return 0; 11 BOOL CALLBACK DlgProc (HWND hdlg, UINT message, WPARAM wparam, LPARAM lparam) static HWND hprogress,hbutton; static HANDLE hthread; static PARAM param; switch (message) case WM_INITDIALOG : hprogress = GetDlgItem(hDlg,IDC_PROGRESS1); hbutton = GetDlgItem(hDlg,IDC_BUTTON1); return TRUE ; case WM_COMMAND : switch (LOWORD (wparam)) case IDC_BUTTON1: param.hbutton = hbutton; param.hprogress = hprogress; hthread = (HANDLE)_beginthreadex(NULL,NULL,MyThreadProc,¶m,NULL,NULL); return TRUE; case IDOK : case IDCANCEL : EndDialog (hdlg, 0) ; return TRUE ; break ; return FALSE ; 12
3. 파일관리 BOOL CopyFile( LPCTSTR lpexistingfilename, LPCTSTR lpnewfilename, BOOL bfailifexists ); lpexistingfilename : 복사대상피일명 lpnewfilename : 새로만들어질파일명 bfailifexists : 새로만들어질파일이이미있을경우의처리 FALSE : 기존파일을지워버리고새로운파일을복사한다. TRUE : 기존파일이있을경우이함수는복사하지않고에러코드를리턴한다. BOOL CopyFileEx( LPCTSTR lpexistingfilename, LPCTSTR lpnewfilename, LPPROGRESS_ROUTINE lpprogressroutine, LPVOID lpdata, LPBOOL pbcancel, DWORD dwcopyflags ); 13 3. 파일관리 lpexistingfilename : 복사대상피일명 lpnewfilename : 새로만들어질파일명 lpprogressroutine : 이파라미터로전달한콜백함수를주기적으로호출해준다. lpdata : Argument to be passed to the callback function. pbcancel : 복사중에중지할수있는기능이있다. DWORD CALLBACK CopyProgressRoutine( LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred, DWORD dwstreamnumber, DWORD dwcallbackreason, HANDLE hsourcefile, HANDLE hdestinationfile, LPVOID lpdata ); 14
3. 파일관리 BOOL MoveFile( LPCTSTR lpexistingfilename, LPCTSTR lpnewfilename ); BOOL DeleteFile( LPCTSTR lpfilename ); DWORD GetFileSize( HANDLE hfile, LPDWORD lpfilesizehigh ); BOOL CreateDirectory( LPCTSTR lppathname, LPSECURITY_ATTRIBUTES lpsecurityattributes ); BOOL RemoveDirectory( LPCTSTR lppathname ); DWORD GetCurrentDirectory( DWORD nbufferlength, LPCTSTR lpbuffer ); DWORD GetSystemDirectory( LPTSTR lpbuffer, UINT usize ); DWORD GetWindowsDirectory( LPTSTR lpbuffer, UINT usize ); 15 3. 파일관리 int SHFileOperation(LPSHFILEOPSTRUCT lpfileop); 파일을관리하는함수로복사, 이동, 삭제, 이름변경등여러가지작업을하나의함수로처리 ( 탐색기에서이용하는파일관리함수 ) typedef struct _SHFILEOPSTRUCTA HWND hwnd; UINT wfunc; LPCSTR pfrom; LPCSTR pto; FILEOP_FLAGS fflags; BOOL fanyoperationsaborted; LPVOID hnamemappings; LPCSTR lpszprogresstitle; // only used if FOF_SIMPLEPROGRESS SHFILEOPSTRUCTA, FAR *LPSHFILEOPSTRUCTA; 16
3. 파일관리 wfunc flags 값 설명 FO_COPY pfrom 파일을 pto 파일로복사 FO_DELETE pfrom 파일을삭제 FO_MOVE pfrom 파일을 pto 파일로이동 FO_RENAME pfrom 파일을 pto로이름을변경 ( 파일만적용 ) 17 3. 파일관리 UINT GetDriveType( LPCTSTR lprootpathname ); 리턴값 lprootpathname 에조사대상디스크의루트디렉토리를지정하는문자열을준다. NULL 이면현재디렉토리가사용된다. 설명 DRIVE_UNKNOWN 알수없는타입이다. DRIVE_NO_ROOT_DIR 루트디렉토리가없다. DRIVE_REMOVABLE DRIVE_FIXED 이동식디스크이다. 플로피디스크 고정된디스트이며, 하드디스크 DRIVE_REMOTE 네트웍에연결된드라이브다. DRIVE_CDROM CD_ROM 드라이브이다. DRIVE_RAMDISK 램디스크이다. 18
#include <windows.h> #include "resource.h" BOOL CALLBACK DlgProc (HWND hdlg, UINT message, WPARAM wparam, LPARAM lparam); int WINAPI WinMain (HINSTANCE hinstance, HINSTANCE hprevinstance,pstr szcmdline, int icmdshow) DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc) ; return TRUE; BOOL CALLBACK DlgProc (HWND hdlg, UINT message, WPARAM wparam, LPARAM lparam) static HWND hlist,hbutton; switch (message) case WM_INITDIALOG : hlist = GetDlgItem(hDlg,IDC_LIST1); hbutton = GetDlgItem(hDlg,IDC_BUTTON1); return TRUE ; case WM_COMMAND : switch (LOWORD (wparam)) case IDC_BUTTON1: char temp[256]; for(char ch = 'a'; ch <= 'z';ch++) wsprintf(temp,"%c: ",ch); switch(getdrivetype(temp)) case DRIVE_UNKNOWN: strcat(temp," : 알수없는타입이다."); SendMessage(hList,LB_ADDSTRING,0,(LPARAM)temp); break; case DRIVE_NO_ROOT_DIR: //strcat(temp," : 루트디렉토리가없다."); //SendMessage(hList,LB_ADDSTRING,0,(LPARAM)temp); break; case DRIVE_REMOVABLE: strcat(temp," : 이동식디스크이다."); SendMessage(hList,LB_ADDSTRING,0,(LPARAM)temp); break; 19 case DRIVE_FIXED: strcat(temp," : 하드디스크 "); SendMessage(hList,LB_ADDSTRING,0,(LPARAM)temp); break; case DRIVE_REMOTE: strcat(temp," : 네트웍에연결된드라이브다."); SendMessage(hList,LB_ADDSTRING,0,(LPARAM)temp); break; case DRIVE_CDROM: strcat(temp," : CD_ROM 드라이브이다."); SendMessage(hList,LB_ADDSTRING,0,(LPARAM)temp); break; case DRIVE_RAMDISK: strcat(temp," : 램디스크이다."); SendMessage(hList,LB_ADDSTRING,0,(LPARAM)temp); break; return TRUE; case IDOK : case IDCANCEL : EndDialog (hdlg, 0) ; return TRUE ; break ; return FALSE ; 20
3. 파일관리 HANDLE FindFirstFile( LPCTSTR lpfilename, LPWIN32_FIND_DATA lpfindfiledata ); BOOL FindNextFile( HANDLE hfindfile, LPWIN32_FIND_DATA lpfindfiledata ); BOOL FindClose( HANDLE hfindfile ); lpfilename : 검색식을준다. 검색시작위치와검색대상파일을와일드카드식으로표현한다. (C: Windows *.exe) lpfindfiledata : 검색결과가구조체에담겨서넘어온다. WIN32_FIND_DATA FindData; HANDLE hfindfile = FindFirstFile("C: Windows *.*",&FindData); BOOL bresult = TRUE; while(bresult) bresult = FindNextFile(hFindFile,&FindData); SendMessage(hList,LB_ADDSTRING,0,(LPARAM)FindData.cFileName); FindClose(hFindFile); 21 3. 파일관리 HANDLE FindFirstChangeNotification( LPCTSTR lppathname, BOOL bwatchsubtree, DWORD dwnotifyfilter ); 윈도우는특정디렉토리의내용이변경될때통지를해줄수있으며응용프로그램은이통지를받았을때자신이가지고있는목록을갱신하거나특별한동작을할수있다. lppathname : 감시의대상이되는디렉토리경로 이객체는변화가생기면신호상태가되므로대기함수와함께사용하면변화의시점을정확하게통지받을수있다. bwatchsubtree : 서브디렉토리까지검사할것인지를지정한다. dwnotifyfilter : 어떤변화를감시할것인가를지정하며다음플래그들의조합으로지정한다. FILE_NAME : 파일명이변경되었다. 파일생성, 삭제 DIR_NAME : 디렉토리가변경되었다. 생성, 삭제 ATTRIBUTE : 속성중일부가변경되었다. SIZE : 파일의크기가변경되었다. LAST_WRITE : 파일의최후기록시간이변경되었다. 22
DLL 23 1. DLL (Dynamic Link Library) 동적연결라이브러리 (DLL) : (<-> 정적라이브러리, *.Lib) Microsoft Windows 의가장중요한구조적요소중하나이다. 라이브러리의기초 DLL 은직접실행될수없다. 메시지를받지않는다. 프로그램에서호출되는함수들을가진별도의파일이다. 프로그램이라이브러리내의함수들중하나를호출할때만동작한다. 확장자가 DLL 이면자동으로로드된다. DLL 의목적 다수의서로다른프로그램들에의해사용될수있는함수와자원을제공 DllMain DLL 이단순함수의집합이라면필요치않지만, 복잡한전역변수가있거나동적으로메모리를할당해사용할때초기화와종료처리를위해작성 DLL 이실행파일에의해요청되거나해제될때호출된다. DllMain(HINSTANCE hinstance, DWORD dwreason, LPVOID lpreserved) hinstance : 라이브러리의인스턴스핸들 dwreason : Windows 가 DllMain 을호출하는이유 DLL_PROCESS_ATTACH» 동적연결라이브러리가프로세스의주소공간으로매핑되어있음을나타낸다.» 프로세스가수행되는동안오직한번의호출된다. 24
1. DLL (Dynamic Link Library) DLL_PROCESS_DETACH» 해당프로세스에 DLL이더이상필요로하지않는다는것을의미» 라이브러리가자신을정리한다. DLL_THREAD_ATTACH» 추가된프로세스가새로운스레드를만든다. DLL_THREAD_DETACH» 스레드가종료될때 Window는호출한다. 우선함수를제공하는 DLL에서는자신이제공하는함수에대한정보를밖으로공개해놓아야한다. Export DLL을사용하는클라이언트에서는어떤 DLL에있는어떤함수를사용하겠다고선언해야한다. Import declspec ( extended-decl-modifier-seq ) 함수에대한정보를제공하는선언문이며엑스포트또는임포트하는함수앞에수식어로이문구가있어야한다. extern "C" declspec(dllexport) int InitHook( HINSTANCE hdll, HWND hwndhost ) extern "C" typedef declspec(dllimport) int (*PFNInitHook)( HINSTANCE hdll, HWND hwndhost ); extern "C" typedef declspec(dllimport) void (*PFNGetDeadWndTxt)( char *pszbuf, int nmaxbuf ); extern "C" typedef declspec(dllimport) void 25 (*PFNReleaseHook)(); 1. DLL (Dynamic Link Library) extern C mangled name 을만들지않도록지정함으로써 C 형식으로함수의정보를공개하도록한다. 명시적연결 m_hinstdll = ::LoadLibrary( "l3t_hook.dll" ); if(!m_hinstdll ) MessageBox( "l3t_hook.dll 을찾을수없습니다.", " 오류 " ); return FALSE; m_pfninithook = (PFNInitHook)::GetProcAddress( m_hinstdll, "InitHook" ); m_pfnreleasehook = (PFNReleaseHook)::GetProcAddress( m_hinstdll, "ReleaseHook" ); m_pfngetdeadwndtxt = (PFNGetDeadWndTxt)::GetProcAddress( m_hinstdll, "GetDeadWndTxt" ); if( (!m_pfninithook) (!m_pfnreleasehook) ) MessageBox( " 잘못된 dll입니다.", " 오류 " ); ::FreeLibrary( m_hinstdll ); m_hinstdll = 0; return FALSE; 26
DLL 컴파일시 dll, lib 자동복사 27 디버깅 DLL, EXE : 디버깅모드로컴파일되어야 각각프로젝트세팅에서패스지정해야 28