10.5(금) 실습-1

2007/10/13 17:04

1. 프로세스 생성과 CloseHandle의 이유 ( 자식을 정말 죽이자~!! )
[ more.. | less.. ]
// 프로세스를 생성하는 간단한 방법들
int main()
{
    //system( "calc.exe" );   // 자식 프로세스가 종료 될때 까지 Blocking 된다.

    WinExec( "calc.exe", SW_SHOW ); // non - Blocking

    cout << "프로그램 계속 실행" << endl;
}

int
main()
{
    PROCESS_INFORMATION pi;

    STARTUPINFO si = { 0 };
    si.cb = sizeof(si);

    // 버퍼가 아니라 "calc.exe"(문자열은 const) 로 넘기면
    // 유니코드 환경(내부적으로변경)에서 상수변경 에러 뜬다.

    char name[256] = _T("C:\\windows\\system32\\calc.exe");    // 실행할 프로세스

    BOOL b = CreateProcess(
        0,      // App Name - 절대경로
        name,   // Command Line Arg..
        0,0,    // PKO, TKO 보안
        FALSE// Object Table 상속여부
        NORMAL_PRIORITY_CLASS,  // 우선순위 | Flag
        0, 0,   // 환경변수, 현재 디렉토리
        &si,    // 시작정보구조체
        &pi     // 자식 프로세스의 ID와 핸들을 담을 변수
        );

    // 이때 자식프로세스의 참조계수는 2이다.
    cout << "자식프로세스에 접근하기 위한 핸들" << (void*)pi.hProcess << endl;
    cout << "자식프로세스의 스레드에 접근하기 위한 핸들" << (void*)pi.hThread << endl;
   
    // 자식의 핸들을 닫는 것이 중요한다.
    // 닫지 않으면 자식이 종료된 후에도 계속 메모리에 PKO, TKO가 남아 있다.
    // 핸들이 필요 없다면 즉시 닫아라.
    //if ( b )
    //{
    //    // 자식의 핸들을 닫는것이 중요한다.
    //    CloseHandle( pi.hProcess );
          CloseHandle( pi.hThread );
    //}
    // 이때 자식프로세스의 참조계수는 1이다.

    //////////////////////////////////////////////////////////////////////////
    int cmd;
    while( 1 )
    {
        cin >> cmd;

        if ( cmd == 2 )
        {
            // 자식 프로세스를 강제로 종료되게 한다. - 그리고 종료 코드를 채운다.
            TerminateProcess( pi.hProcess, 100 );

            // TermainateProcee는 비동기 함수 이다. 아직 자식이 죽었다고 장담못한다.
            // 모든 프로세스는 죽을때 KO가 signal 된다.
            // 특정 KO가 signal 될 때 까지 대기한다.
            WaitForSingleObject( pi.hProcess, INFINITE );
            // 이제 자식은 정말 죽었다.

            cmd = 1; // 자식이 정말 죽었는지 확인한다.!!!
        }

        if ( cmd == 1 )
        {
            // 자식 프로세스의 종료 코드를 구한다.
            DWORD code;
            GetExitCodeProcess( pi.hProcess, &code );

            if( code == STILL_ACTIVE ) // 0x103
                cout << "아직 자식이 살아 있습니다." << endl;
            else
            {
                cout << "자식 종료 : " << code << endl;
                CloseHandle( pi.hProcess ); // 더이상 핸들이 필요 없으면..
            }
        }
    }

    return 0;
}

2. 다른 프로세스의 오브젝트 테이블을 복사 해 오기~!! ( a.txt에 B프로세스가 hello를 쓴다. )
[ more.. | less.. ]
int main()
{
    HANDLE hFile = CreateFile(
        "a.txt", GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        0,  // 보안속성
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        0
        );

    cout << "생성된 파일의 핸들 : " << (void*)hFile << endl;

    // 다른 프로세스에 전달한다.
    HWND hwnd = FindWindow( 0, "B" );

    // 윈도우 핸들로 프로세스 ID를 구한다.
    DWORD pid;
    DWORD tid = GetWindowThreadProcessId( hwnd, &pid );

    // 프로세스 ID를 가지고 프로세스 핸들을 얻는다.
    HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, 0, pid );

    // Object Table의 항목을 복사 해준다.
    HANDLE hDest;
    DuplicateHandle(
        GetCurrentProcess(), hFile,  // source
        hProcess,            &hDest, // Target
        0, 0, DUPLICATE_SAME_ACCESS // option
        ); 

    cout << "복사된 항목의 핸들 : " << (void*)hDest << endl;

    /////////////////////////////////////////////////////////
    SendMessage( hwnd, WM_USER+100, 0, (LPARAM)hDest );

    CloseHandle( hFile );   // 1. if (--(fFile.참조개수) == 0 ) Delete KO
                            // 2. Object Table에서 항목을 제거한다.
}

// 윈도우 캡션이 "B"인 윈도우App 하나 만들기
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   
switch( msg )
    {

   
case WM_USER+100:
        {
           
char s1[256] = "hello";
           
char s2[256];
           
HANDLE hFile = (HANDLE)lParam;
           
DWORD len;
           
BOOL b = WriteFile( hFile, s1, 256, &len, 0 );

           
if( b )
                MessageBox( 0,
"성공", "", MB_OK );
           
else
            {
               
// 에러의 원인을 알아낸다.
                wsprintf( s2, "실패 : %d", GetLastError() );
                MessageBox( 0, s2,
"", MB_OK );
            }
        }
       
return 0;
       
// B을 먼저 실행하세요. 그리고 A을 실행 하세요.
    case WM_DESTROY:
        PostQuitMessage(0);
       
return 0;
    }
   
return DefWindowProc( hwnd, msg, wParam, lParam);
}


3. 마우스 캡쳐한곳의 윈도우창을 강제종료 시키기( pid를 얻어오는것이 관건 )
[ more.. | less.. ]
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch( msg )
    {
    case WM_LBUTTONDOWN:
        SetCapture( hwnd );
        return 0;

    case WM_LBUTTONUP:
        if( GetCapture() == hwnd )
        {
            ReleaseCapture();

            POINT pt;
            GetCursorPos( &pt ); // 커서의 좌표를 스크린 좌표로 구한다.

            HWND h = WindowFromPoint( pt );

            // 해당 윈도우를 만든 프로세스ID, 스레드 ID를 구한다.
            DWORD pid;
            DWORD tid = GetWindowThreadProcessId( h, &pid );

            // 프로세스 ID를 가지고 해당 프로세스에 접근하기 위한 핸들을 얻는다.
            // (Table에 항목을 만드는 것이다. ************)

            // HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, 0, pid );
            // ALL은 너무 많은 권한

            // 최소 요구의 원칙 - 필요한 권한만 요구하자.****꼭 필요한것만 요구하자.
            HANDLE hProcess = OpenProcess(
                PROCESS_TERMINATE | SYNCHRONIZE,    // 죽이고 | wait 할수 있는 권한
                0,
                pid
                );

            // 이제 핸들을 사용한다.
            TerminateProcess( hProcess, INFINITE );
            DWORD ret = WaitForSingleObject( hProcess, 5000 );

            if( ret == WAIT_OBJECT_0 )  // 숫자 0
            {
                // 강제종료 성공 - KO가 signal 되었다.
            }
            else if( ret == WAIT_TIMEOUT )
            {
                MessageBox( 0, "프로세스를 죽일 수 없습니다.", "", MB_OK );
            }
            else if( ret == WAIT_FAILED )
            {
                // 핸들이 잘못된 경우
            }
            CloseHandle( hProcess );
        }
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc( hwnd, msg, wParam, lParam);
}

Tags

API, 실습