1 / 28

14.

14. 프로세스. 1. 프로세스와 스레드. 프로세스는 실행중인 프로그램의 한 인스턴스이다 . 운영체제는 실행된 프로그램을 프로세스 단위로 관리한다 . 프로세스는 각각 4GB 의 주소 공간과 파일 , 메모리 , 스레드 등의 객체들을 소유하며 프로세스가 종료될 때 프로세스가 소유한 자원은 운영체제에 의해 파괴된다 . 프로세스는 실행과 동시에 스레드를 하나 만들고 스레드를 호출함으로써 스레드에게 모든 작업을 맡긴다 . 프로세스는 최소한 한 개 이상의 스레드를 가진다 .

mauli
Download Presentation

14.

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 14. 프로세스

  2. 1. 프로세스와 스레드 • 프로세스는 실행중인 프로그램의 한 인스턴스이다. • 운영체제는 실행된 프로그램을 프로세스 단위로 관리한다. • 프로세스는 각각 4GB의 주소 공간과 파일, 메모리, 스레드 등의 객체들을 소유하며 프로세스가 종료될 때 프로세스가 소유한 자원은 운영체제에 의해 파괴된다. • 프로세스는 실행과 동시에 스레드를 하나 만들고 스레드를 호출함으로써 스레드에게 모든 작업을 맡긴다. • 프로세스는 최소한 한 개 이상의 스레드를 가진다. • 프로세스와 동시에 만들어지는 스레드를 주 스레드(Primary Thread)라고 한다. • 하나의 프로세스가 여러 개의 스레드를 만들 수 있다.

  3. 1. 프로세스와 스레드 BOOLCreateProcess( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); • lpApplicationName : • 실행하고자 프로그램의 이름을 준다. • 완전 경로를 주거나 파일명만 지정한 경우는 현재 디렉토리에서 파일을 찾으며 검색 경로는 사용하지 않는다. • 이 인수를 NULL로 주고 두 번째 인수에 실행 파일명을 줄 수도 있다.

  4. 1. 프로세스와 스레드 • lpCommandLine • 명령행 인수를 지정한다. • 첫 번째 인수가 NULL일 경우 실행 파일명을 가질 수도 있으며 실행 파일명과 명령행 인수를 동시에 지정하는 것도 가능하다. • lpStartupInfo • 새로 만든 프로세스의 메인 윈도우가 어떻게 초기화될지를 지정하는 구조체이다. • 이 구조체의 cb멤버에는 구조체의 크기가 반드시 대입되어야 한다. • lpProcessInformation • 생성된 프로세스의 정보를 대입 받기 위한 구조체이며 생략할 수 없다. case WM_LBUTTONDOWN: { STARTUPINFO si; memset(&si,0,sizeof(STARTUPINFO)); PROCESS_INFORMATION pi; CreateProcess(NULL,"Notepad.exe",NULL,NULL,FALSE,NULL,NULL,NULL,&si,&pi); } return 0;

  5. 1. 프로세스와 스레드 typedef struct _STARTUPINFO { DWORD cb; LPTSTR lpReserved; LPTSTR lpDesktop; LPTSTR lpTitle; DWORD dwX; DWORD dwY; DWORD dwXSize; DWORD dwYSize; DWORD dwXCountChars; DWORD dwYCountChars; DWORD dwFillAttribute; DWORD dwFlags; WORD wShowWindow; WORD cbReserved2; LPBYTE lpReserved2; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; } STARTUPINFO,*LPSTARTUPINFO;

  6. 1. 프로세스와 스레드 • cb : sizeof(STARTUPINFO)값을 대입한다. • dwFlags : 어떤 속성을 지정할 것인가에 따라 플래그를 설정한다. typedef struct _PROCESS_INFORMATION { HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId; } PROCESS_INFORMATION,*LPPROCESS_INFORMATION;

  7. 1. 프로세스와 스레드 • lpProcessAttributes • lpThreadAttributes • 프로세스와 주 스레드의 보안 속성을 지정한다. • bInheritHandles • 새로 생성되는 프로세스가 페이런트로부터 핸들을 상속받을 수 있는지를 지정한다. • dwCreationFlags • 새로 생성되는 프로세스의 우선 순위 클래스와 프로세스 생성 옵션을 지정한다. • REALTIME_PRIORITY_CLASS : 최상위 우선권 • HIGH_PRIORITY_CLASS : 상위 우선권 • ABOVE_PRIORITY_CLASS : 상위 우선권 • NORMAL_PRIORITY_CLASS : 보통 우선권 • BELOW_PRIORITY_CLASS : 하위 우선권 • IDLE_PRIORITY_CLASS : 최하위 우선권 • lpEnvironment • 새 프로세스의 환경 블록을 지정하는 포인터. 이 값이 NULL이면 페이런트의 환경 블록을 사용하며 보통 NULL이다. • lpCurrentDirectory, • lpStartupInfo, • lpProcessInformation

  8. 1. 프로세스와 스레드 • lpCurrentDirectory • 새 프로세스의 작업 디렉토리를 지정한다. • NULL일 경우 페이런트의 현재 디렉토리가 새 프로세스의 작업디렉토리가 된다. • DWORD WaitForInputIdle( HANDLE hProcess, DWORD dwMilliseconds); • 이 함수는 hProcess가 지정하는 프로세스가 사용자의 입력을 대기할 수 있을 때까지, 즉 초기화가 완료될 때까지 기다려준다. • LPTSTR GetCommandLine(VOID); • 이 함수는 현재 프로세스의 명령행 인수를 조사해 리턴해 준다. • CommandLineToArgvW() • 함수를 사용하여 토큰별로 분리 할 수도 있다.

  9. 1. 프로세스와 스레드 • VOID ExitProcess( UINT uExitCode ); • 이 함수가 호출되면 프로세스는 정리작업에 들어가 즉각 종료된다. • 1. 프로세스와 연결된 모든 DLL을 종료시키기 위해 각 DLL의 DllMain함수가 호출되며 DLL들은 스스로 정리 작업을 한다. • 2. 모든 열려진 핸들을 닫는다. • 3. 실행중인 모든 스레드는 종료한다. • 4. 프로세스 커널 객체와 스레드 객체는 신호상태가 되며 이 객체를 기다리는 다른 프로세스는 대기상태를 해제할 수 있다. • 5. 프로세스의 종료코드는 STILL_ACTIVE와 ExitProcess가 지정한 종료값이 된다. • BOOL TerminateProcess( HANDLE hProcess, UINT uExitCode); • 이 함수는 ExitProcess에 비해 종료 대상이 되는 프로세스의 핸들을 인수로 가지므로 다른 프로세스를 강제로 종료시킬 수도 있다. • 이 함수는 ExitProcess보다 훨씬 더 위험하다. • TerminateProcess함수가 호출될 때 ExitProcess와 동일한 정리작업이 수행되나 단 연결된 DLL에게 종료사실이 통지되지 않는다. • 어쩔 수 없이 강제로 종료해야 할 경우에만 사용한다.

  10. 2. 프로세스 핸들 • 커널 객체는 프로세스 한정적이다. • 커널 객체를 만드는 프로세스만이 자신의 핸들로 해당 객체를 액세스할 수 있다는 뜻이다. • 핸들은 프로세스 내에서 해당 객체를 액세스할 때 사용하는 한정적인 값이며 이 핸들을 사용하여 객체를 마음대로 조작할 수 있다. • ID는 시스템 전역적인 값이며 다른 프로세스 ID와 절대 중복되지 않는다. • 프로세스끼리 ID를 전달해 줌으로써 목적이 되는 프로세스 핸들을 다시 오픈할 수 있다. • HANDLE GetCurrentProcess(VOID); • HANDLE GetCurrentProcessId(VOID);

  11. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps ; static HINSTANCE hInst; static STARTUPINFO si; static PROCESS_INFORMATION pi; switch (message) { case WM_CREATE: hInst = ((LPCREATESTRUCT)lParam)->hInstance; return 0; case WM_LBUTTONDOWN: { memset(&si,0,sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USEPOSITION | STARTF_USESIZE; si.dwX = 200; si.dwY = 200; si.dwXSize = 100; si.dwYSize = 100; CreateProcess(NULL,"Notepad.exe",NULL,NULL,FALSE,NULL,NULL,NULL,&si,&pi); } return 0; case WM_RBUTTONDOWN: { HWND hProcessWnd = FindWindow(NULL,"Process"); MessageBox(NULL,"윈도우를 찾았습니다.","",MB_OK); PostMessage(hProcessWnd,WM_MYMSG,(WPARAM)pi.dwProcessId,NULL); } return 0; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }

  12. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps ; static HINSTANCE hInst; static DWORD pID; static HANDLE hProc; switch (message) { case WM_CREATE: hInst = ((LPCREATESTRUCT)lParam)->hInstance; return 0; case WM_MYMSG: { pID = (DWORD)wParam; hProc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pID); char temp[256]; wsprintf(temp,"Process ID : %x, Process Handle : %x",pID,hProc); MessageBox(NULL,temp,"",MB_OK); } return 0; case WM_LBUTTONDOWN: { DWORD ExitCode; GetExitCodeProcess(hProc,&ExitCode); if (ExitCode != STILL_ACTIVE) { MessageBox(NULL,"프로세스 핸들이 유효하지 않습니다.","",MB_OK); } else { TerminateProcess(hProc,NULL); pID = NULL; } } return 0; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }

  13. 3. Thread • Project/Settings c/c++탭의 Code Generation에서 Use run-time Library옵션을 선택

  14. 3. Thread uintptr_t _beginthreadex( void * security, unsigned stack_size, unsigned ( __stdcall *start_address )( void * ), void * arglist, unsigned initflag, unsigned * thrdaddr ); • security : SECURITY_ATTRIBUTES구조체의 주소, 대부분 NULL • stack_size : 0을 입력하면 기본 스텍사이즈를 사용한다. • unsigned ( __stdcall *start_address )( void * ) • arglist : 스레드 함수로 넘어가는 변수 • initflag : CREATE_SUSPENDED면 스레드만 만들고 실행은 하지 않는다. • thrdaddr : 스레드 ID

  15. typedef struct threadParam { HWND hwnd; BOOL bCont; }THREAD_PARAM; unsigned int WINAPI MyThreadFunc(LPVOID lpParameter) { THREAD_PARAM * pTp = (THREAD_PARAM *)lpParameter; HWND hwnd = pTp->hwnd; while(pTp->bCont) { HBRUSH hBrush = CreateSolidBrush(RGB(rand()%256,rand()%256,rand()%256)); RECT ClietRect,rect; GetClientRect(hwnd,&ClietRect); SetRect(&rect,rand()%ClietRect.right,rand()%ClietRect.bottom,rand()%ClietRect.right,rand()%ClietRect.bottom); HDC hdc = GetDC(hwnd); HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc,hBrush); Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom); SelectObject(hdc,hOldBrush); ReleaseDC(hwnd,hdc); Sleep(100); } return 0; } LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps ; static unsigned int ThreadID; static HANDLE hThread; static THREAD_PARAM tp;

  16. switch (message) { case WM_COMMAND: switch(LOWORD(wParam)) { case IDM_THREAD_START: if (hThread == NULL) { tp.hwnd = hwnd; tp.bCont = TRUE; hThread = (HANDLE)_beginthreadex(NULL,NULL,MyThreadFunc,(void *)&tp,NULL,&ThreadID); } else { DWORD ExitCode; GetExitCodeThread(hThread,&ExitCode); if (ExitCode == STILL_ACTIVE ) MessageBox(NULL,"현재 스레드는 살아있습니다.","",MB_OK); else MessageBox(NULL,"스레드는 죽었습니다.","",MB_OK); } break; case IDM_THREAD_QUIT: tp.bCont = FALSE; break; case IDM_THERAD_SUSPEND: SuspendThread(hThread); break; case IDM_THREAD_RESUME: ResumeThread(hThread); break; } return 0; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }

  17. CRITICAL_SECTION cs; int XPos; unsigned int WINAPI MyThreadFunc1(LPVOID lpParameter) { THREAD_PARAM * pTp = (THREAD_PARAM *)lpParameter; HWND hwnd = pTp->hwnd; while(pTp->bCont) { HBRUSH hBrush = CreateSolidBrush(RGB(rand()%256,rand()%256,rand()%256)); RECT ClietRect,rect; GetClientRect(hwnd,&ClietRect); SetRect(&rect,rand()%ClietRect.right,rand()%ClietRect.bottom,rand()%ClietRect.right,rand()%ClietRect.bottom); HDC hdc = GetDC(hwnd); EnterCriticalSection(&cs); XPos = 100; Sleep(10); TextOut(hdc,XPos,0,"1번 스레드 펑션",15); LeaveCriticalSection(&cs); HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc,hBrush); Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom); SelectObject(hdc,hOldBrush); ReleaseDC(hwnd,hdc); Sleep(120); } return 0; }

  18. unsigned int WINAPI MyThreadFunc2(LPVOID lpParameter) { THREAD_PARAM * pTp = (THREAD_PARAM *)lpParameter; HWND hwnd = pTp->hwnd; while(pTp->bCont) { HBRUSH hBrush = CreateSolidBrush(RGB(rand()%256,rand()%256,rand()%256)); RECT ClietRect,rect; GetClientRect(hwnd,&ClietRect); SetRect(&rect,rand()%ClietRect.right,rand()%ClietRect.bottom,rand()%ClietRect.right,rand()%ClietRect.bottom); HDC hdc = GetDC(hwnd); EnterCriticalSection(&cs); XPos = 400; Sleep(15); TextOut(hdc,XPos,0,"2번 스레드 펑션",15); LeaveCriticalSection(&cs); HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc,hBrush); Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom); SelectObject(hdc,hOldBrush); ReleaseDC(hwnd,hdc); Sleep(130); } return 0; }

  19. 3. 동기화 • 크리티컬 섹션 • voidInitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection ); • voidDeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection ); • 둘 다 CRITICAL_SECTON형의 포인터를 인수로 요구한다. • voidEnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection ); • voidLeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection ); • 보호될 코드를 다음과 같이 두 함수로 감싸준다. EnterCriticalSection(&cs); //이 사이에서 공유 자원을 안전하게 액세스한다. LeaveCriticalSection(&cs);

  20. 3. 동기화 case WM_CREATE: InitializeCriticalSection(&cs); return 0; case WM_DESTROY: DeleteCriticalSection(&cs); PostQuitMessage (0) ; return 0 ; • 교착 상태 EnterCriticalSection(&cs1); EnterCriticalSection(&cs2); //이 사이에서 공유 자원을 안전하게 액세스한다. LeaveCriticalSection(&cs2); LeaveCriticalSection(&cs1); EnterCriticalSection(&cs2); EnterCriticalSection(&cs1); //이 사이에서 공유 자원을 안전하게 액세스한다. LeaveCriticalSection(&cs1); LeaveCriticalSection(&cs2);

  21. 3. 동기화 • 동기화 객체 • 동기화에 사용되는 객체이다. • 프로세스,스레드처럼 커널 객체이며 프로세스 한정적인 핸들을 가진다. • 동기화 객체는 크리티컬 섹션보다 느리기는 하지만 여러 프로그램에서 동시에 동기화가 가능하다. • 신호 상태 : 스레드의 실행을 허가하는 상태. 신호상태의 동기화 객체를 가진 스레드는 계속 실행할 수 있다. • 비 신호 상태 : 스레드의 실행을 허가하지 않는 상태이며 신호 상태가 될 때까지 스레드는 블록 된다. • DWORDWaitForSingleObject(HANDLEhHandle, DWORDdwMilliseconds ); • dwMilliseconds : 1/1000초 단위로 지정한다. INFINITE로 지정하면 무한정 기다린다.

  22. 3. 동기화 • WAIT_OBJECT_0 : hHandle 객체가 신호 상태가 되었다. • WAIT_TIMEOUT : 타임 아웃 시간이 경과하였다. • WAIT_ABANDONED : 포기된 뮤텍스 • 뮤텍스 • 크리티컬 섹션과 유사하다. • 이름을 가질 수 있고 프로세스간에서도 사용이 가능하다. • HANDLECreateMutex(LPSECURITY_ATTRIBUTESlpMutexAttributes, BOOLbInitialOwner, LPCTSTRlpName ); • lpMutexAttributes : 보통 NULL • bInitialOwner :뮤텍스를 생성함과 동시에 소유할 것인지를 지정한다. TRUE이면 소유하며, 뮤텍스가 비 신호상태로 생성됨으로써 다른 스레드는 이 뮤텍스를 소요할 수 없게 된다. • 생성한 뮤텍스를 파괴할 때는 CloseHandle함수를 이용한다. • BOOLReleaseMutex(HANDLE hMutex ); • 뮤텍스 소유를 해제한다.

  23. #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 hEdit1,hEdit2; static HANDLE hFileMapping; static char * pMapView; static HANDLE hMutex; switch (message) { case WM_INITDIALOG : hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,1042,"MappingMutexSample"); pMapView = (char *)MapViewOfFile(hFileMapping,FILE_MAP_ALL_ACCESS,0,0,1024); hEdit1 = GetDlgItem(hDlg,IDC_EDIT1); hEdit2 = GetDlgItem(hDlg,IDC_EDIT2); hMutex = CreateMutex(NULL,FALSE,"MyMutexSample"); return TRUE ;

  24. case WM_COMMAND : switch (LOWORD (wParam)) { case IDC_BUTTON1: { WaitForSingleObject(hMutex,INFINITE); char temp[256]; GetWindowText(hEdit1,temp,256); SetWindowText(hEdit2,temp); strcpy(pMapView,temp); ReleaseMutex(hMutex); } return TRUE; case IDC_BUTTON2: { WaitForSingleObject(hMutex,INFINITE); SetWindowText(hEdit2,pMapView); ReleaseMutex(hMutex); } return TRUE; case IDOK : case IDCANCEL : EndDialog (hDlg, 0) ; return TRUE ; } break ; } return FALSE ; }

  25. 3. 동기화 • 이벤트 • 어떤 사건이 일어났음을 알려주는 동기화 객체이다. • 크리티컬 섹션, 뮤텍스, 세마포어는 주로 공유 자원을 보호하기 위해 사용되는 데 비해 이벤트는 그보다는 스레드간의 작업 순서나 시기를 조정하기 위해 사용한다. • 자동 리셋 • 대기 상태가 종료되면 자동으로 비신호상태가 된다. • 수동 리셋 • 스레드가 비신호상태로 만들어 줄 때까지 신호상태를 유지한다. HANDLECreateEvent( LPSECURITY_ATTRIBUTESlpEventAttributes, BOOLbManualReset, BOOLbInitialState, LPCTSTRlpName );

  26. 3. 동기화 • bManualReset : 이 이벤트가 수동 리셋 이벤트인지 자동 리셋 이벤트인지를 지정한다. • TRUE : 수종 리셋 이벤트, FALSE : 자동 리셋 이벤트 • bInitialState : 이벤트 생성과 동시에 신호상태로 만들어 이벤트를 기다리는 스레드가 곧바로 실행하도록 한다. • BOOL SetEvent( HANDLE hEvent ); • BOOL ResetEvent( HANDLE hEvent ); • BOOL PulseEvent(HANDLE hEvent );

  27. #include <windows.h> #include "resource.h" #include <process.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 hEdit2; BOOL bCont; HANDLE hEvent; char * pView; }PARAM; unsigned __stdcall MyThreadProc( void * pArguments ) { PARAM * pParam = (PARAM *)pArguments; while(pParam->bCont) { WaitForSingleObject(pParam->hEvent,INFINITE); SetWindowText(pParam->hEdit2,pParam->pView); } _endthreadex( 0 ); return 0; } BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hEdit1,hEdit2; static HANDLE hFileMapping; static char * pMapView; static HANDLE hMutex; static HANDLE hThread;

  28. static PARAM param; static HANDLE hEvent; switch (message) { case WM_INITDIALOG : hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,1042,"MappingMutexSample"); pMapView = (char *)MapViewOfFile(hFileMapping,FILE_MAP_ALL_ACCESS,0,0,1024); hEdit1 = GetDlgItem(hDlg,IDC_EDIT1); hEdit2 = GetDlgItem(hDlg,IDC_EDIT2); hMutex = CreateMutex(NULL,FALSE,"MyMutexSample"); hEvent = CreateEvent(NULL,TRUE,FALSE,"MyMutexSampleEvent"); param.bCont = TRUE; param.hEdit2 = hEdit2; param.hEvent = hEvent; param.pView = pMapView; hThread = (HANDLE)_beginthreadex(NULL,NULL,MyThreadProc,&param,NULL,NULL); return TRUE ; case WM_COMMAND : switch (LOWORD (wParam)) { case IDC_BUTTON1: { WaitForSingleObject(hMutex,INFINITE); char temp[256]; GetWindowText(hEdit1,temp,256); strcpy(pMapView,temp); PulseEvent(hEvent); ReleaseMutex(hMutex); } return TRUE; case IDOK : case IDCANCEL : EndDialog (hDlg, 0) ; return TRUE ; } break ; } return FALSE ; }

More Related