비밀이라니까 좀 거창하지만… 윈도우 커맨드라인 때문에 겪었던 에피소드…
==
자바 프로그램(A)에서 다른 프로그램(B)을 새로운 프로세스로 실행해야되는 상황이었는데,
원래는 잘 되다가 B의 버전이 바뀐 후 부터 실행 하자 마자 프로그램이 죽어버렸다.
그런데 신기한건, 윈도우의 [시작]->[실행]에서 실행하면 아무 문제 없이 잘 되고,
cmd.exe 를 실행해서 커맨드 창에서 똑같이 실행하면 A에서 실행할 때와
똑같이 죽는다는 거다.
그리고 또 하나, cmd.exe에는 start 라는 내장 명령이 있는데, (자세한건 나도 모르겠다)
이놈을 이용한 경우에도 실행이잘된다. B를 실행할때 커맨드 라인을
라고 준다고 했을 때,
와 같이 실행하면 죽는데,
와 같이 실행하면 죽지 않는다.
B가 잘못된건 확실한 거 같은데… B의 소스가 없어서 확인할 방법은 없고…
좀 난감한 상황이었다.
start를 써 보려고 했으나 start는 cmd.exe의 내장 명령인지라 새로운 프로세스를 실행하는
매소드에서는 먹히지 않는다.
아무리 생각해도 달라질 수 있는 건, 환경변수와 작업 디렉토리.
그런데 시작 디렉토리를 변경해 봐도 딱히 변화가 없었고, 환경변수도 문제가 될거 같진 않았다.
그래서 우선은 파이썬으로 간단한 프로그램을 짜서 확인해 봤다.
- import os, sys
print os.getcwd()
print os.environraw_input(“press any key…”)
우선, cmd.exe에서 실행 했을때는 start 명령을 사용 여부에 관계없이
작업 디렉토리와 환경변수는 동일했다.
그리고, [시작]->[실행]에서 실행한 경우,
작업 디렉토리는 프로그램이 있는 경로로 변경되었고,
환경변수는 PATH 등이 미묘하게 달랐으나, 별 문제 될건 없을 거 같았다.
점점 문제가 미궁으로 빠질 무렵, 다른 사람을 통해 새로운 힌트를 얻었다.
커맨드 라인의 모든 아규먼트를 ” 로 묶어서 하나의 아규먼트로 만들어서 넘긴 경우,
실행 양상이 좀 달라진다는 것.
원래대로라면 실행이 안되는게 맞겠지만 일단 실행은 되고 마지막 단계에 가서 죽어버렸다.
여기서 알아낸 사실은 B가 커맨드 라인 스트링을 통째로 받아서 처리를 한다는 것이었다.
보통은 argc, argv[] 와 같은 것들을 사용해서 각 커맨드 라인 아규먼트별로 분리된 채로
받아 처리하는데, 이 경우라면, 위와 같은 현상이 나타나진 않을 거라는 판단이었다.
그래서 찾아보니 win32 API에 GetCommandLine()라는 함수가 있었다.
이 함수는 커맨드 라인 스트링을 통째로 반환하는 함수였다.
그래. 분명 이 함수를 써서 커맨드 라인 문자열을 받은 다음에 tokenizer 등을
사용해서 나눠서 썼고, 그 과정에서 토큰이 잘못 나눠져서 문제가 발생한 것일 거야.
그래서 바로 커맨드 라인 스트링을 확인하는 작업에 착수했다.
간단하게 win32 프로그램을 작성했다.
- #include “stdafx.h”
#include <windows.h>int _tmain(int argc, _TCHAR* argv[])
{
LPTSTR cmd = GetCommandLine();
printf( “cmd : [%s]\n”, cmd );
while (1) {
}
return 0;
}
(분명 입력을 받는 함수였던가.. 잠시 멈추는 함수가 하나 있었는데
너무 오래된지라 기억이 잘 안나서… 걍 무한 루프를 돌려 버렸다.-_-)
그런 다음 테스트를 해 봤다.
커맨드 라인에서 바로 실행 했을 때는…
와 같이 그대로 찍혔다.
start 명령을 사용한 경우에는,
첫 번째와 두 번째 아규먼트, 즉, cmdtest.exe와 arg1 사이에 스페이스가 하나 더 있었다.
마지막으로, [시작]->[실행]의 경우,
첫 번째 아규먼트인 프로그램명에 “가 쳐졌다.
오호라… 그래서 즉시 A에서 B를 실행하는 부분에 프로그램 경로를 줄때 “로 감싸도록 수정했다.
결과는 성공! 역시나 커맨드 라인 문자열 처리가 문제였던것.
==
아직까지 어떤식으로 커맨드라인을 처리한 건지는 알 수가 없지만…
잘못 만든 프로그램 하나가 사람 여럿 고생 시킨다는 것이 오늘의 교훈…-_-;