윈도우 서비스의 복구 동작 옵션 변경

 

윈도우 서비스는 프로그램 동작중에 예외가 발생하여 프로그램이 죽게 된 경우, 아래와 같은 Recovery 옵션이 있어 프로그램을 다시 시작하거나 (restart), 또는 전체 시스템을 리부팅하는 등의 대처를 자동으로 수행해 주는 옵션이 있다. 이 Recovery 옵션은 서비스 속성에서 설정 할 수 있는데, 속성에서 제공하는 것들을 잠깐 살펴보면 아래와 같다.

 

 

1. 다음기간 이후에 실패 횟수 다시설정

 

서비스는 에러가 발생하게 되면 이놈이 몇 번 째 에러인지 에러카운트를 올리는데, 여기에 설정 된 시간만큼 에러가 없으면 에러 카운트는 다시 0이 되어 새로운 에러가 발생하면 그 에러를 1번째 에러로 간주하여 첫째 실패에 대한 액션을 취하게 되는 식이다. 예를 들어 이 값이 30초로 (물론 속성창에서는 일 단위로만 가능하지만, 다른 방법을 통해 30초 설정이 가능함)설정되어 있다면, 아래와 같이 에러가 몇번 째 에러인지 세어 나가게 된다.

 

(error cnt : 0) - 에러 (error cnt : 1) - 10초 - 2번에러(error cnt : 2) - 30초

- (error cnt : 0) -  에러 (error cnt : 1) - 12초 - 에러 (error cnt : 2)

 

2. 다음 시간 이후에 서비스 다시 시작

 

에러가 발생하고 에러에 대한 대응 액션으로 서비스 다시 시작이 설정되어 있다면, 여기에 설정되어 있는 시간 만큼 에러 이후에 기다리고서 다시 서비스를 시작하게 된다.

 

그렇다. 그렇게 하면 된다. 그런데, 문제는 이게 아니다.

 

서비스 복구 옵션을 이렇게 사용자가 직접 정하는건 상당히 없어 보인다. 그게 문제다.

설치 패키지를 배포하고, 추가 설명으로 " 서비스 속성에 들어가서 어떻게 어떻게 하세요" 라고 적어놓는건 상당히 모양 빠지는 일이다.

 

그래서, 지금 개발하고 있는 C# windows service에서 이런 복구 옵션을 설정하여, 사용자가 할일이라고는 만들어놓은 설치 패키지를 더블 클릭하는 것 뿐이도록 만들어 보고자 구글링을 열심히 했다.

 

그런데 결론은 C# Windows service 프로젝트에는 이런 옵션 없ㅋ슴ㅋ.

ㅋㅋ..

 

물론 방법이 아예 없는 것은 아니다. 남들이 다 하는걸 못하는건 방법이 없어서가 아니라 내가 그냥 모르는 거라는 걸 다시한번 느꼈다. 그 방법은 크게 2가지로 나뉘는데 첫번째 방법은 "advapi32.dll의 함수를 C#에 import하여 사용하는 방법"이고 나머지 방법은 "sc.exe라는 콘솔 프로그램을 이용하여 윈도우 서비스의 속성을 변경하는 방법"이다.

 

전자에 나와 있는 방법 어떤 착한 턱수염 아저씨가 코드 프로젝트에잘 설명 해 놨다.

 

http://www.codeproject.com/KB/install/sercviceinstallerext.aspx?display=Print

 

그런데 좀 어렵다. serviceInstaller라는 클래스를 상속한 확장 클래스를 만드는데 자세한 사항을 공부하면 이편이 좀더 깔끔한 방식이 될 것 같기는 하다.

 

그러나 지금 서비스 프로그램은 64bit로 개발하고 있는데 외부에서 import한 라이브러리가 내가 알지 못하는 어떤 예외를 던질까 무서워 일단 이방법은 보류하고 나머지 sc.exe라는 프로그램을 이용하는 방법을 선택하기로 했다.

 

sc.exe가 32bit 든 64bit든 그냥 프로세스로 sc를 만들어 일반 콘솔에서 명령어 치듯 사용할 것이기 때문에 좀더 속편하게 쓸 수 있는 장점과 간단하다는 장점이 있는 방법이라 하겠다. 쓸 수 있는 기능면에서도 앞서 설명한 방법과 차이가 없다는 장점도 있다.

 

(참고로 sc.exe에 대한 자세한 아규먼트는 아래 문서를 참조하면 된다.)

http://technet.microsoft.com/en-us/library/cc754599.aspx

 

sc.exe는 서비스와 관련된 여러가지 작업을 할 수 있게 해주는 콘솔 프로그램으로서, fail에 대한 recovery를 설정하기 위해서는 failure라는 인자를 사용하여 아래와 같이원하는 서비스의 리커버리 옵션을 설정 할 수 있다.

 

 

failure에 대한 풀 옵션은 위에 있는 링크를 타고 들어가서 확인하면 되겠고..

위 콘솔창에 나와 잇는 정보만 살펴보자면 Envision_AES라는 서비스이름을 가지는 서비스를 마지막 에러를 기점으로 300초마다 error cnt를 0으로 재 설정하면서, 에러가 발생할 때 20000 ms의 지연을 가지고나서 서비스를 재 시작하도록 한다라는 의미를 가지고 있다.

 

이걸 InstallUtil.exe가 서비스를 설치하고나서 자동으로 설치되게 하려면 서비스의 serviceInstall가 가지는 이벤트 중에 Commited라는 이벤트의 콜백함수에다가 이 기능을 하는 코드를 입력해주면 된다. committed라는 이벤트는 설치가 모두 완료되면 발생하는 이벤트 쯤 되는 것 같다.

 

 

 

 

 

 

흐릿해서 잘 안보일 수도 있겠지만 간단히 설명하자면 Process 인스턴스를 하나 만들고 프로세스의 startinfo에 실행하고자 하는 프로그램이름인 sc 설정, 보이지 않는 hidden 프로세스로 설정, 그리고 아규먼트에 failure이후에 들어갈 값들을 지정하고 프로세스를 시작한 것 밖에 없다. "start()"

 

서비스 설치시 자동 시작

 

그런데 서비스를 installutil.exe로 설치하고 나면 서비스 시작 유형을 automatic으로 설정해 두었음에도 불구하고 서비스는 중지됨 상태로 있게 된다. 이것은 automatic이라는 의미가 "시스템이 부팅되었을 때 자동 시작됨"이기 때문이다. 설치는 했지만 컴퓨터가 리부팅 되지는 않았으니 어찌보면 당연한 말이기도 하다.

 

그래서 이번에는 서비스를 설치하자 마자 자동으로 서비스 프로그램을 프로세스로 만들어 실행시키는 구문을 만들어보고자 한다.

 

이것 또한 서비스 설치시 발생되는 committed 이벤트의 콜백함수에 집어 넣을 껀데, 사실 바로 위에 있는 그림파일에 이미 들어가 있다.

 

int exitCode 위에 있는 코드가 그것인데, 서비스 리커버리 옵션 고치는 것보다 오히려 코드는 간단하다. 서비스 실행을 관장하는 ServiceController의 인스턴스를 하나 만들고 (생성자 인수로 서비스의 이름을 받는다.) 서비스를 실행 " start() " 시키고, 서비스가 running 상태에 접어들기를 기다렸다가 ServicController를 닫는 " Close() " 과정밖에 없다.

 

간단하다.

 

Posted by 굿쟌
,

64bit 로 빌드된 윈도우 서비스 등록시 BadImageFormatException

 

윈도우 서비스 프로그램을 개발하고 윈도우 인스톨러를 추가하여 설치 패키지를 만들고 나서 실행하려고 하면 다음과 같이 BadImageFormatException이라는 에러가 발생하면서 윈도우 서비스가 등록 안되는 이슈가 발생했다.

 

 

BadImageoFormatException은 실행파일이 참조한는 파일이 다른 bit로 빌드된 경우 발생하는 에러라고 하는데, 이미 윈도우 인스톨러로 설치 하고자 하는 윈도우 서비스 프로젝트와 기타 프로그램 프로젝트들 모두 64bit로 빌드하기로 한 것은 확인 했고, 윈도우 인스톨러 또한 64bit를 target으로 빌드되도록 한 것도 확인 했기 때문에 당췌 어디서 에러가 발생했는지 감을 잡을 수 없었다.

 

하지만 세상에 착하면서도 똑똑한 프로그래머들이 많은지, 이미 이런 문제에 대한 원인과 해결책까지 스택오버플로우에 나와있었다.

(http://stackoverflow.com/questions/10275106/badimageformatexception-x64-issue)

 

결론부터 말하자면, 이 문제는 윈도우 인스톨러가 빌드된 윈도우 서비스 프로그램을 타겟 파일 시스템에 복사한 뒤 InstallUtill.exe라는 프로그램을 이용해서 서비스 등록을 시키는데, 이 InstallUtill.exe 파일이 참조하는 InstallUtillLib.dll의 bit가 윈도우 서비스의 타겟 비트와 달라서 발생하는 이슈라고 한다.

 

따라서 윈도우 인스톨러가 서비스 등록에 사용할 (정확히는 InstallUtill.exe가) InstallUtillLib.dll을 윈도우 서비스의 타겟 비트와 동일하게 선정해주면 된다.

 

C:\Windows\Microsoft.NET\Framework64\v4.0.30319 그리고

C:\Windows\Microsoft.NET\Framework\v4.0.30319 에는

각 bit에 맞는 64bit, 32bit 짜리 InstallUtill.exe와 InstallUtillLib.dll이 있다고 한다.

 

그런데 이 과정은 Visual Studio에서는 설정할 방법은 없고 Orca.exe라는 외부 프로그램을 사용해야 하는데 ( Visual Studio에서 설정할 수 있는지는 나중에 더 찾아 봐야 하겠지만..) 그 과정은 아래와 같다.

 

step1. Orca.exe를 설치한다.

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin 에 있는 Orca.msi를 이용해서 설치한다. Next만 누르면 된다.

 

step2. Orca상에서빌드한 msi파일을 연다.

Orca.exe의 돌고래 아이콘이 앙증맞다.

 

 

step3. Tables에서 Binary탭을 클릭하여 오른쪽 창의 InstallUtill의 binary data부분을 더블클릭한다. "read binary from file name"을 클릭해 놓고 brows버튼을 눌러 원하는 비트의 InstallUtillLib.dll파일을 찾아 설정한 후 Orca.exe에서 msi파일을 저장하고 종료한다.

 

 

이렇게 하면, 정상적으로 윈도우 서비스가 윈도우 인스톨러를 가지고 등록되는 것을 볼 수 있었다. 세상엔 참 착하고 능력있는 프로그래머가 많다.

 

 

 

 

 

 

Posted by 굿쟌
,

1. 공유설정 변경

 

 

네트워크 및 공유 센터를 열고 아래와 같이 고급 공유 설정 변경에 들어간다.

 

파일 공유를 위한 공유 폴더 설정을 위해서 아래와 같이 설정을 변경한다.

 

 

 

 

 

공용 폴더 공유를 사용함으로 변경한다.

 

그리고 암호로 보호된 공유를 사용함으로 해 놓으면 공용 리소스에 접근할 때 미리 지정해 놓은 윈도우 계정을 물어보게 된다.

 

요번 프로젝트에서는 보안성 때문에 공용폴더에 접근 권한을 설정하지 않을까 하여 미리 접근권한을 설정한 공용폴더를 사용하기 때문에 암호 보호 공유는 사용함으로 설정했다.

 

 

 

그리고 아무 폴더나 하나 만들고 속성-공유 창으로 들어간다.

 

고급 공유에 보면, 권한이 있는데 이 부분에서 공유폴더에 접속할 윈도우 계정을 설정한다.

 

 

Everyone을 사용이름에 넣어두면 아무나 암호 설정 없이 접근 할 수 있게 된다. (Everyone이 있으면 다른 계정이 포함되어 있는 것과 상관 없이 그냥 아무나 접속 할 수 있게 된다.)

 

 만일 윈도우 사용자 계정만 넣어두면 다른 컴퓨터에서 해당 공유폴더로 접속을 시도할 때, 아래와 같이  ExportSystemUser 계정의 암호와 아이디를 물어보는 창이 뜨게 된다.

 

 

Trouble Shooting 1. 가끔 공유사용자가 잘 변경이 안되어 Everyone이 계속 껴 있는 경우가 있는데, 이런 경우에는 고급 공유설정에서 공유 체크박스를 한번 지우고 확인을 눌러서 공유안됨 상태로 돌린다음에 다시 설정하면 정상적으로 공유 설정이 된다.

 

Trouble Shooting2. 윈도우에서 공유 폴더에 접속할 때, 아무 설정이 없는 경우 자동으로 Guest계정으로 접속을 시도한다고 한다. 그래서 공유 폴더 설정시 Guest 계정을 공유에 포함시키지 않는 경우, 혹은 Everyone이 없어서 아무나 접속이 불가능 한 경우 아래와 같이 접속 권한이 없다고 접속이 안되는 경우가 있다.

 

 

이런 경우는, 아래와 같이 CMD창에서 "net use" 명령어를 이용해 해당 연결에 대한 계정을 지우고 계정정보 유지 여부를 no로 설정해 주면 정상적으로 접속이 된다.

 

계정 유지 정보 유지 여부를 no로..

 

연결정보 조회 및 제거

 

참고로 윈도우 자격증명 관리자에 해당 공유폴더에 접속할 계정정보가 이미 입력되어 있는 경우에 이 window 계정으로 자동으로 접속을 시도하기 때문에 접속 로그인창을 보고 싶다면 "제어판-자격증명 관리자"에서 자격증명을 지워주면 된다.

 

공유 폴더 설정 끝!

Posted by 굿쟌
,