월별 글 목록: 2009년 4월월

윈도우 커맨드 라인의 비밀(?)

비밀이라니까 좀 거창하지만… 윈도우 커맨드라인 때문에 겪었던 에피소드…

==

자바 프로그램(A)에서 다른 프로그램(B)을 새로운 프로세스로 실행해야되는 상황이었는데,

원래는 잘 되다가 B의 버전이 바뀐 후 부터 실행 하자 마자 프로그램이 죽어버렸다.

그런데 신기한건, 윈도우의 [시작]->[실행]에서 실행하면 아무 문제 없이 잘 되고,

cmd.exe 를 실행해서 커맨드 창에서 똑같이 실행하면 A에서 실행할 때와

똑같이 죽는다는 거다.

그리고 또 하나, cmd.exe에는 start 라는 내장 명령이 있는데, (자세한건 나도 모르겠다)

이놈을 이용한 경우에도 실행이잘된다. B를 실행할때 커맨드 라인을

c:\program\b.exe arg1 arg2 arg3 arg4 arg5

라고 준다고 했을 때,

c:\> c:\program\b.exe arg1 arg2 arg3 arg4 arg5

와 같이 실행하면 죽는데,

c:\> start “” c:\program\b.exe arg1 arg2 arg3 arg4 arg5

와 같이 실행하면 죽지 않는다.

B가 잘못된건 확실한 거 같은데… B의 소스가 없어서 확인할 방법은 없고…

좀 난감한 상황이었다.

start를 써 보려고 했으나 start는 cmd.exe의 내장 명령인지라 새로운 프로세스를 실행하는

매소드에서는 먹히지 않는다.

아무리 생각해도 달라질 수 있는 건, 환경변수와 작업 디렉토리.

그런데 시작 디렉토리를 변경해 봐도 딱히 변화가 없었고, 환경변수도 문제가 될거 같진 않았다.

그래서 우선은 파이썬으로 간단한 프로그램을 짜서 확인해 봤다.

  1. import os, sys

    print os.getcwd()
    print os.environ

    raw_input(“press any key…”)

우선, cmd.exe에서 실행 했을때는 start 명령을 사용 여부에 관계없이

작업 디렉토리와 환경변수는 동일했다.

그리고, [시작]->[실행]에서 실행한 경우,

작업 디렉토리는 프로그램이 있는 경로로 변경되었고,

환경변수는 PATH 등이 미묘하게 달랐으나, 별 문제 될건 없을 거 같았다.

점점 문제가 미궁으로 빠질 무렵, 다른 사람을 통해 새로운 힌트를 얻었다.

커맨드 라인의 모든 아규먼트를 ” 로 묶어서 하나의 아규먼트로 만들어서 넘긴 경우,

실행 양상이 좀 달라진다는 것.

원래대로라면 실행이 안되는게 맞겠지만 일단 실행은 되고 마지막 단계에 가서 죽어버렸다.

여기서 알아낸 사실은 B가 커맨드 라인 스트링을 통째로 받아서 처리를 한다는 것이었다.

보통은 argc, argv[] 와 같은 것들을 사용해서 각 커맨드 라인 아규먼트별로 분리된 채로

받아 처리하는데, 이 경우라면, 위와 같은 현상이 나타나진 않을 거라는 판단이었다.

그래서 찾아보니 win32 API에 GetCommandLine()라는 함수가 있었다.

이 함수는 커맨드 라인 스트링을 통째로 반환하는 함수였다.

그래. 분명 이 함수를 써서 커맨드 라인 문자열을 받은 다음에 tokenizer 등을

사용해서 나눠서 썼고, 그 과정에서 토큰이 잘못 나눠져서 문제가 발생한 것일 거야.

그래서 바로 커맨드 라인 스트링을 확인하는 작업에 착수했다.

간단하게 win32 프로그램을 작성했다.

  1. #include “stdafx.h”
    #include <windows.h>

    int _tmain(int argc, _TCHAR* argv[])
    {
        LPTSTR cmd = GetCommandLine();
        printf( “cmd : [%s]\n”, cmd );
        while (1) {
        }
        return 0;
    }

(분명 입력을 받는 함수였던가.. 잠시 멈추는 함수가 하나 있었는데

너무 오래된지라 기억이 잘 안나서… 걍 무한 루프를 돌려 버렸다.-_-)

그런 다음 테스트를 해 봤다.

c:\program\cmdtest.exe arg1 arg2 arg3

커맨드 라인에서 바로 실행 했을 때는…

cmd : [c:\program\cmdtest.exe arg1 arg2 arg3]

와 같이 그대로 찍혔다.

start 명령을 사용한 경우에는,

cmd : [c:\program\cmdtest.exe  arg1 arg2 arg3]

첫 번째와 두 번째 아규먼트, 즉, cmdtest.exe와 arg1 사이에 스페이스가 하나 더 있었다.

마지막으로, [시작]->[실행]의 경우,

cmd : [“c:\program\cmdtest.exe” arg1 arg2 arg3]

첫 번째 아규먼트인 프로그램명에 “가 쳐졌다.

오호라… 그래서 즉시 A에서 B를 실행하는 부분에 프로그램 경로를 줄때 “로 감싸도록 수정했다.

결과는 성공! 역시나 커맨드 라인 문자열 처리가 문제였던것.

==

아직까지 어떤식으로 커맨드라인을 처리한 건지는 알 수가 없지만…

잘못 만든 프로그램 하나가 사람 여럿 고생 시킨다는 것이 오늘의 교훈…-_-;