[C#] 자동 시작하는 프로그램

이것저것 응용해서

프로그래밍을 하는 분들은 이정도의 기능을 만드는것은 기본중에 기본이라고 생각한다. 그래서 나 같은 사람은 인터넷 검색으로 만드는 경우가 대부분이다보니 이것저것 응용해서 만드는 방법을 직접 해보려고 생각했고, 그래서 내가 만드는 프로그램들 중 요구사항이 '자동 시작해야 한다.' 라고 한다면 이 글에서 얘기할 방법으로 만든다. 어려운 방법은 아니다. 생각해보면 간단한게, 1. 먼저 Windows가 부팅되면 프로그램이 자동으로 켜지도록 할 수 있게 해야하고, 2. 동작이 필요한 경우 이전 상태에 따라서 자동으로 해당 동작이 되도록 해야 한다. 3. 혹시나 모를 상황에 대비해 동작을 중지할 경우 Windows 부팅시 프로그램이 자동으로 켜지도록 하는 부분을 없애 줄 수 도 있어야 한다. 정도...

이를 위해서 필요한 것은 레지스트리를 다룰 수 있어야 하고, 현재 상태를 저장할 수 있어야 한다. 자동으로 켜지도록 하는 방법은 대표적으로 두가지가 있는데 시작 프로그램에 프로그램 바로가기를 넣는 방법과, 레지스트리에 시작 프로그램을 등록하는 방법이 있다. 나는 레지스트리를 건드는 방법을 아주아주 싫어하기 때문에 첫번째 방법을 쓰고 싶었지만, 쉽지 않으니 그냥 간단하게 레지스트리를 사용하는 방법을 쓴다. 그리고 현재 상태를 저장하는 방법도 몇가지가 있는데, 제일 간단한 프로그램 내부 프로퍼티에 저장하는 방법을 사용한다.


시작 프로그램 등록을 위한 레지스트리 등록

Windows가 부팅되면 시스템 권한 레지스트리의 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run' 경로에 등록되어 있는 값들을 확인하고 이 값들이 가리키는 프로그램들을 실행시킨다. 그리고 나서 유저 권한 레지스트리의 같은 경로에서 같은 동작을 한다. 시스템 권한 레지스트리는 관리자 권한이 필요하기 때문에 생략, 우리는 유저 권한 레지스트리에 시작 프로그램으로 등록한다. 나는 이 코드를 메소드로 만들어 필요할때마다 쓴다.

    private void registrySet()
    {
        var rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
        rkApp.SetValue("name", System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName));
    }


코드에서 안에 name에는 상황에 맞춰 적당히 수정해주면 된다. 보통은 프로그램 이름이 들어갈테니 그냥 네임스페이스 값을 바로 넣어도 된다. 물론 나는 해보지 않았으니 확인 필요. 프로그램 경로와 파일 이름까지 정확히 써줘야 하는데, 디버그와 릴리즈 프로그램간 차이와 WPF프로그램을 만들다보니 통상적인 프로그램의 경로를 파악하는 코드의 결과값이 간혹 다르게 나왔다. 그래서 아주 확실하게 현제 프로세스의 매인모듈이 있는 프로그램 파일의 이름과 경로를 가져오도록 System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName 를 썼다. 혹시나 마음에 들지 않는다면 통상적인 방법으로 써도 괜찮을 것 같지만, 나는 이미 그 방법의 신뢰를 잃어버렸으니 이렇게 쓴다.


자동 동작을 위한 코드 수정

시작 프로그램이 띄워지기만 하고 동작을 하지 않으면 소용 없다. 동작도 되어야 하는데, 이럴때 설정값이 저장되고 불러오는 기능이 필요하다. XML로 저장하거나, TXT로 저장하거나, ini로 저장하거나 방법은 많지만 굳이 자동 동작 하나를 위해 파일을 읽고 쓰는 기능을 만들 필요는 없다고 생각한다. 그래서 프로퍼티의 설정값을 추가해서 그값을 이용하기로 한다. 나는 보통 autoStart라는 bool 변수로 저장하고 기본값은 False로 한다. 그리고 동작이 시작하는 부분에 해당 값을 true로 만들고 저장. 마찬가지로 동작이 종료되는 부분에 해당 값을 false로 만들고 저장. 이렇게 하면 이전에 프로그램이 종료되었을때 어떻게 종료되었는지를 확인할 수 있다.

설정값만 저장하면 의미가 없다. autoStart가 true가 될 때 시작프로그램을 등록해주는 레지스트리를 써주면 이제는 동작을 시작한 다음 PC를 껐거나 예기치 못한 상황으로 PC가 꺼졌을때 다음에 다시 켜면 프로그램이 띄워진다. 여기다가 프로그램이 열렸을때 autoStart가 true라면 해당 동작 이벤트가 자동으로 시작되도록만 해주면, 자동 동작 부분은 끝. 아래 코드는 간단하게 버튼이 눌러지면 레지스트리를 등록하고, autoStart를 true로 변경해주고 설정값을 저장하도록 되어 있다. 그리고 프로그램이 시작되고 Form_Load 이벤트가 불려지면 autoStart 값을 확인하고 동작 이벤트를 발생시키도록 한다.


  • 동작 이벤트

    connect = false;
    private void btnConnect_Click(object sender, EventArgs e)
    {
        if(!connect){
            ...
            connect = true;
    
            registrySet();
            Properties.Settings.Default.autoStart = true;
            Properties.Settings.Default.Save();
        }
        else{
        ...
        }
    }
    
  • 시작 이벤트

    private void Form1_Load(object sender, EventArgs e)
    {
        if (Properties.Settings.Default.autoStart)
        {
            btnConnect_Click(null, null);
        }
    }
    


시작 프로그램 등록 해지를 위한 레지스트리 삭제와 자동 동작 해제

이렇게까지 만들면, 동작 시작 후 PC를 껐다 다시 켜면 자동으로 시작하는 모습을 볼 수 있다. 문제는 동작을 종료했을때도 다음에 PC가 켜질때 자동으로 켜지고 동작도 시작될 것이다. 즉, 자동 동작도 해제해 줘야 하고 자동 시작도 해제해 줘야 한다. 생각해보면 당연하겠지만, 이건 위의 코드에서 동작 이벤트 안에 else부분에 들어가면 되는데 autoStart를 false로 바꿔주고 저장한 다음, 마찬가지로 아까 등록했던 레지스트리를 삭제해 주는 코드를 만들어 동작시키면 된다. 레지스트리의 이름은 위에 레지스트리 등록했을때의 이름으로 맞춰줘야 한다. 또한 추가로 레지스트리 값 이름은 통상적으로 쓰는 이름보다는 프로그램이 구분될 수 있도록 하자. 잘못하다간 엄한 프로그램을 건들 수 도 있다.


  • 레지스트리 삭제

    private void registryDel()
    {
        var rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
        rkApp.DeleteValue("name");
    }
    
  • 자동 시작 해제까지 포함한 동작 이벤트

    connect = false;
    private void btnConnect_Click(object sender, EventArgs e)
    {
        if(!connect){
            ...
            connect = true;
    
            registrySet();
            Properties.Settings.Default.autoStart = true;
            Properties.Settings.Default.Save();
        }
        else{
        ...
        connect = false;
    
        registryDel();
        Properties.Settings.Default.autoStart = false;
        Properties.Settings.Default.Save(); 
        }
    }
    


Minny_

,