티스토리 뷰

190701-2 - 핸들, 동기, 신호/비신호

(1일차) 교육을 받으면서 노트필기 했던 내용을 날것 그대로 업로드합니다.


 
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
 
 
void main()
{
    //const char* s = "Hello!"; // 상수 메모리 문자열
    ////s[0] = 'a'; // 변경할 수 업
    //printf("%s\n", s);
 
    char cur[MAX_PATH];
    char sys[MAX_PATH];
    char win[MAX_PATH];
 
    // 현재 작업 디렉토리
    GetCurrentDirectory(MAX_PATH, cur); //● 작업 디렉토리 : 프로세스는 자기만의 작업디렉토리가 있다.
    //SetCurrentDirectory("C:\\Temp");
    //GetCurrentDirectory(MAX_PATH, cur);
 
    // 시스템 디렉토리
    GetSystemDirectory(sys, MAX_PATH);
 
    // 윈도우즈 디렉토리
    GetWindowsDirectory(win, MAX_PATH);
 
    printf("현재 작업 디렉토리: %s\n", cur);
    printf("시스템 디렉토리: %s\n", sys);
    printf("윈도우즈 디렉토리: %s\n", win);
 
}
 
● 클래스의 이름으로 윈도우를 찾을 수 있다.
 
●윈도우는 프로세스가 뜨면 자동적으로 프라이머리 쓰레드가 하나 뜬다. 무조건 프로세스의 ID가하나있고 쓰레드의 ID가 하나 있다. 프로세스 커널오브젝트와 쓰레드 커널오브젝트가 서로 다르다.
 
● 여태 만들었었던 윈도우들은 쓰레드가 소유하게된다.
● UI쓰레드도 하나씩 돌고있다.
 
● ID만 있으면 핸들을 얻을 수 있다.
 
● 이름으로 윈도우 핸들을 받아온다 -> 윈도우 핸들로 프로세스 아이디를 받는다.(쓰레드 아이디도 받는다.) -> 프로세스 아이디로 프로세스 핸들을 얻어온다. -> 얻은 권한을 사용한다.
 
● 윈도우 핸들 : 윈도우 최대화 등 윈도우를 컨트롤할 수 있다.
● 프로세스 핸들 : 종료 등을 할 수 있다.
#include <stdio.h>
#include <windows.h>
void main()
{
    //HWND hWnd = FindWindow(
// 0, // 윈도우 클래스 이름
// "제목 없음 - 메모장" // 윈도우 이름(윈도우 타이틀 이름)
// );
    HWND hWnd = FindWindow( "notepad", 0); // ● 클래스이름 으로 윈도우를 찾아서 핸들을 반환한다. (윈도우의 핸들)
    if( hWnd == NULL)
    {
        printf("메모장을 실행하시오!\n");
        return;
    }
 
    DWORD processID;
    DWORD threadID;
    threadID = GetWindowThreadProcessId( hWnd, &processID );
    // ●윈도우의 핸들로 프로세스의 아이디를 찾는다.
    //● 반환으로는 쓰레드의 아이디를 찾는다. (파라미터로 프로세스의 아이디 또한 건져온다.)
 
    // ID로 프로세스 핸들 얻기
    // PROCESS_TERMINATE : TerminateProcess() 호출 위한 권한 설정
    HANDLE hProcess;
    hProcess = OpenProcess( //● 프로세스의 핸들을 얻어옴
        PROCESS_TERMINATE|PROCESS_QUERY_LIMITED_INFORMATION, //● 종료시킬 수 있는 권한의 핸들을 얻겠다.
        0, processID); // ● 메모장 프로세스핸들을 사용하여 종료가능
    printf("메모장의 윈도우 핸들 %d\n", hWnd);
    printf("메모장의 프로세스 ID %d\n", processID);
    printf("메모장의 프로세스 핸들 %d\n", hProcess);
 
    //프로세스의 커널오브젝트 종료 코드 값을 받음.
    DWORD exitCode;
    GetExitCodeProcess(hProcess, &exitCode);
    if(exitCode == STILL_ACTIVE)
        printf("메모장 프로세스가 사용 중~\n");
 
    printf("메모장을 종료하려면 '엔터'키 치시오\n");
    getchar();
 
    //메모장 프로세스 핸들을 이용하여 종료 시킴.
    TerminateProcess(hProcess, 100); // ● 비정상 종료를 강제로 만들어냄.
    // ● 비정상 종료가 바로 보장되지는 않는다.(싱크)
 
    GetExitCodeProcess(hProcess, &exitCode);
    if(exitCode == STILL_ACTIVE)
        printf("메모장 프로세스가 사용 중~\n");
    else
        printf("메모장의 종료 코드: %d\n", exitCode);
}
 

 
#include <stdio.h>
#include <windows.h>
//● 싱크로나이제이션 (동기, 순서를 제어) 를 알아보는 예제
void main()
{
    DWORD processID;
    printf("확인할 프로세스 ID 입력: ");
    scanf_s("%d", &processID); // ● 1.정수값을 입력받아서
    //● 보안 문제로 _s 추가되었다. 스택오버플로우 어택
    //● 문자열을 기록하는 곳은 모두다 그 문자열의 크기를 지정하게 되어있다.
 
 
    HANDLE hProcess;
    hProcess = OpenProcess( //● 2. 프로세스 핸들을 찾는다.
        SYNCHRONIZE, // wait functions 사용 권한 부여
        //● ↑ 동기화(순서제어) wait하는 핸들. wait로 시작하는 함수를 호출할 수 있는 권한
        0, processID);
    if(hProcess == NULL)
    {
        printf("프로세스 ID : %d의 프로세스가 없습니다.\n");
        return;
    }
    printf("프로세스 ID %d\n", processID);
    printf("프로세스 핸들 %d\n\n", hProcess);
    
 
    printf("프로세스 ID %d가 종료하기를 기다립니다~!\n", processID);
    
    WaitForSingleObject(hProcess, INFINITE); // ● 중요한함수. (현재 프로세스가 wait를 한다.)
    //● 3.가리키고있는 핸들의 커널오브젝트가 신호상태가 되기를 대기한다.
    //● INFINITE : 무한정 기다리겠다
    printf("프로세스 ID %d가 종료했습니다.\n", processID);
}
 
 
●커널오브젝트는 신호, 비신호를 가지고있다. 신호상태/비신호상태.
쓰레드와 프로세스는 종료될 때 신호상태가 된다. 실행되고 있을 때는 비신호 상태이다.
 
● 윈도우즈 에서는 쓰레드
 
● 구조체의 첫 변수는 자신 구조체의 크기를 나타내는 경우가 많다.
향후 멤버 추가를 할 때 문제가 발생하는 것을 막기 위해서 사용한다.
DWORD cb; 라는 카운트 바이트를 주어서 무조건 자신의 구조체의 사이즈를 명시하도록한다.
 
● 내가 얻은 핸들은 사용하지 않을 거면 무조건 닫아야한다.
 
● CreateProcess
 

 
● 파일찾기 (cmd 창에서의 실행)
  1. 실행 위치
  2. 작업 위치 (DLL)
  3. 윈도우즈 디렉토리
  4. 시스템 디렉토리
  5. path 설정
 
#include <stdio.h>
#include <windows.h>
void main() //● 프로세스와 윈도우의 관계 예제
{
    STARTUPINFO si={sizeof(STARTUPINFO),}; //● 사이즈를 꼭 명시하게 되어있다. !!
    PROCESS_INFORMATION pi; // ● 4개정보를 가져오는 아웃파라미터로 사용(프로세스,스레드 의 핸들과 아이디)
 
    
 
    CreateProcess(
        NULL, //프로그램 이름 ●중요
        "notepad.exe", //프로그램 명령행 인자(프로그램이름이 NULL경우 프로그램 이름까지 포함할 수 있음) ●중요
        NULL, // 프로세스 보안속성
        NULL, // 쓰레드 보안속성
        FALSE, // 상속여부 ●중요 (FALSE는 상속안함) (커널 오브젝트, 자식오브젝트에 테이블을 물려줄 것인가)
        0, //생성 플래그 우선 순위 지정(HIGH_PRIORITY_CLASS 등) 0: 기본 우선 순위 및 새 콘솔 창 실행(CREATE_NEW_CONSOLE) ●중요
        NULL, //환경변수 설정 NULL이면 부모의 환경 변수 사용
        NULL, // 현재 디렉토리 설정
        &si, // 메인 윈도우가 어떻게 보일지 초기화 구조체 ●중요
        &pi // 생성한 프로세스의 정보 구조체 out param ●중요
        );
    
    ////
 
    CreateProcess(NULL, "notepad.exe",NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
 
    //● 절대 경로를 표시하는 코드
    TCHAR Path[MAX_PATH];
    GetWindowsDirectory(Path, MAX_PATH);
    lstrcat(Path, "\\notepad.exe"); //● 결합
    CreateProcess(Path, NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi); //● 첫 번째 경로 써서 프로그램 실행
 
 
    CreateProcess(NULL, "notepad.exe c:\\Setup.log",NULL,NULL,
        FALSE,0,NULL,NULL,&si,&pi);
 
 
//STARTUPINFO 구조체(윈도우 옵션은 아래 세 가지.
    si.dwFlags = STARTF_USEPOSITION | STARTF_USESIZE; //● 사용자가 지정한 위치에 지정한 크기로 자리를 잡을 수 있다.
    si.dwX = 50; // 위치, 크기가 CW_USEDEFAULT 로 설정된 윈도우만 가능
    si.dwY = 50;
    si.dwXSize = 200;
    si.dwYSize = 200;
 
    //CreateProcess(NULL, "TestWindow.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
 
    getchar();
    // 핸들은 닫아야 한다.
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}
 

● 메인 함수의 표준 타입
#include <stdio.h>
int main(int argc, char** argv)
{
    printf("명령행 인자 개수: %d\n", argc);
    for(int i = 0 ; i < argc ; ++i)
        printf("argv[%d]: %s\n", i, argv[i]);
}
  1. int main(void){}
  2. int main(int, char**){} : 프로그램인수의 개수, 프로그램인수의 문자열 테이블 주소
  • 첫 번째 문자열은 프로그램이름
 
● 명령행 인자 불러서 대화상자(다이얼로그) 출력하기
#include <windows.h>
 
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass=TEXT("CmdLine");
//●명령행 인수2
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
     ,LPSTR lpszCmdParam,int nCmdShow)
{
    //●첫 번째
    MessageBox(NULL, lpszCmdParam, "명령행 인수-lpszCmdParam", MB_OK);
    
    //●두 번째
    for (int i = 0; i < __argc; i++)
        MessageBox(NULL, __argv[i], "명령행 인수-argv", MB_OK);
        
    //●세 번째 // ● 유니코드 에서만 가능
    LPSTR cmd = GetCommandLine();
    MessageBox(NULL, cmd, "명령행 인수-GetCommandLine", MB_OK);
 
 
    ////●네 번째
    int nArg;
    LPWSTR *p=CommandLineToArgvW(GetCommandLineW(),&nArg);//● 명령행 인자 얻어오기
    //●GetCommandLineW() 토큰 별로 잘라주는 역할 (인자 구분해줌)
    for (int i = 0; i < nArg; ++i) {
        MessageBoxW(NULL, p[i], NULL, MB_OK);
    }
    LocalFree(p);
 
    return 0;
}
댓글
댓글쓰기 폼