« Previous : 1 : ... 49 : 50 : 51 : 52 : 53 : 54 : 55 : 56 : 57 : ... 215 : Next »

1. 독특한 윈도우 클래스

Windows의 GUI에는 버튼, 리스트박스, 에디트 컨트롤 등의 잘 알려진 제1군 컨트롤 윈도우들이 있고, 공용 컨트롤이라는 제2군 윈도우도 있다. 이런 것들은 누구나 널리 사용하라고 클래스 이름도 널리 알려져 있다.
그런데 Spy++로 들여다보면, 정식으로 공개되지 않았지만 이런 클래스들이 공용으로 쓰이는 것 같다. 정체가 무엇인지 궁금하다.

  • NetUIHWND: MS Office 프로그램들, 그리고 심지어 워드패드와 그림판에서도 리본이 이 클래스 이름으로 만들어져 있다. 마소에서만 내부적으로 사용한다. (Visual C++의 MFC 확장판에서 제공되는 리본은 마소 오리지널이 아님)
  • DirectUIHWND: task dialog 내부, IE 브라우저의 탭, 탐색기 제어판에서 뭔가 웹페이지처럼 꾸며진 대화상자들에서 종종 쓰인다. 클래스 스타일에 CS_GLOBALCLASS도 버젓이 지정돼 있다. 마소 내부에서 사용하는 GUI 엔진 윈도우 같은데..
  • HwndWrapper[모듈이름;;GUID]: 닷넷이나 WPF처럼 통상적인 Windows API나 기성 컨트롤이 아닌 다른 프레임워크를 이용해서 GUI를 꾸미는 프로그램 같다. 내가 아는 프로그램 중에는 Visual Studio 2010과 그 이후 버전, 그리고 아래아한글(+ 타 오피스 제품 포함) 요 두 프로그램만이 이런 스타일이다.

2. 파일 및 디렉터리의 삭제, 디스크 제거

Windows는 프로그램을 memory-mapped file 형태로 불러온다는 특성으로 인해.. 실행 중인 프로그램을 삭제할 수 없다. 그래서 실행 중인 프로그램을 제거하거나 업데이트 하는 것도 좀 어려운 편이다.
실행 중인 프로그램 파일을 '개명'하는 건 가능하다. 여기서 개명이란 같은 드라이브 안에서의 디렉터리 이동도 포함한다.

이런 Windows와 달리 macOS나 리눅스는 실행 중인 프로그램 파일을 삭제할 수 있다.
허나, 실행 중인 프로그램의 current directory를 당장 삭제할 수 있는 운영체제는 내가 아는 한도 내에서는 없다. 삭제 예약만 해 놓은 뒤, 프로그램이 종료되거나 디렉터리가 딴 데로 바뀌었을 때 삭제되는 게 그나마 제일 관대한 처분이다.

프로세스의 current directory는 USB 메모리를 안전하게 제거할 수 없다고 운영체제가 꼬장 부리면서 사용자를 귀찮게 하는 요인 중 하나이기도 하다.
특히 Windows의 경우, 파일 열기/저장 공용 대화상자를 열어서 USB  메모리를 조회하면 해당 프로그램의 current directory도 거기로 바뀌기 때문에 대화상자를 닫은 뒤에도 저런 꼬장이 발생할 가능성이 높아진다.

뭐, 사용자가 USB 메모리를 물리적으로 강제로 제거해 버리는 것에는 장사 없다. 과거의 디스켓이나 광학 드라이브도 매체를 강제로 꺼낼 수 있었으니 말이다. 하지만 이런 일이 발생하면 운영체제의 관점에서는 current directory가 갑자기 없어지는 것이나 다름없고, 거기에 파일이 열려 있던 것들도 다 꼬여 버린다. 프로세스가 아닌 스레드를 강제 종료하는 것만큼이나 좋지 않은 현상이다.
디스크 내용을 날리고 싶지 않으면 사용자도 가능한 한 그런 짓은 하지 않는 게 좋다.

3. Windows의 런타임 환경

Windows에서 전통적인 API 기반의 네이티브 코드 데스크톱 프로그램 말고 선보였던 프로그램 실행 환경으로는..
먼저 2000년대(XP..)엔 .NET이란 게 있었다. 얘는 네이티브가 아니라 가상 머신에서 돌아갔고, 언어도 C#가 주류였다. C++에는 C++/CLI라는 변종 언어가 도입됐다.
그 뒤 2010년대(8..)엔 메트로 UI와 함께 C++/CX라는 변종 언어가 도입됐다. 얘는 데스크톱 환경은 아니지만 의외로 네이티브 코드 기반이었다.

.NET이 표방했던 것이 언어의 통합이라면, Windows 8이 표방했던 것은 기기(PC와 모바일?)의 통합이었다. 그래서 오죽했으면 시작 버튼을 없애는 초강수까지 뒀었다.
그러나 Windows 8은 망했으며, 결정적으로 Windows Phone/Mobile도 안드로이드와 iOS에 완전히 밀렸다. 이젠 마소에서도 그쪽 사업을 접었다. 그 대신 Windows 10은 ARM용이 정식으로 출시되어서 그 CPU에서 네이티브 데스크톱 앱을 그대로 돌릴 수 있게 됐다.

그럼 이 와중에 메트로 앱을 돌리는 Windows Runtime이라는 건 무슨 존재의 의미를 갖게 되는지 난 궁금하다. 답을 잘 모르겠다.
그냥 데스크톱 앱보다 글자 큼직하고 시각적으로 flat하고, 안드로이드 용어로 치자면 material design스러운 외형을 제공하는 GUI 엔진 그 이상도 이하도 아니어 보이는데..??
쉽게 말해 기존 공용 컨트롤이 '제어판'을 가동한다면 이 UI 엔진은 '설정'을 가동한다는 것이다.

마소에서 새로운 걸 시도한 것이 언제나 다 성공적이고 오래 유지된 건 아니었던 듯하다.
그래서 GDI+는 닷넷 시절에 잠깐 뜨다가 Direct2D 부류로 대체됐고, 오히려 운영체제의 근간으로서 넘사벽급의 짬밥을 자랑하는 재래식 GDI보다도 존재감이 없어졌다.
Edge 브라우저는 잘 알다시피 재개발되어서 사실상 크롬과 다를 바 없는 브라우저가 됐다. 마소의 지난 20여 년의 개발 트렌드를 회고해 보니 이런 분석과 결론이 나온다.

4. 이모지, 날개셋 입력 패드

Windows 10의 1803버전쯤부터는 win+.을 눌러서 이모지 문자표를 꺼내는 기능이 추가되었다.
날개셋 한글 입력기에서는 지난 9.81 버전부터 자체적으로 이모지 문자표가 추가되었다. 그럼 이건 언뜻 보기에는 기능 중복처럼 보이지만 실제로는 꼭 그렇지 않다.

운영체제의 이모지 문자표는 마우스로 딴 델 클릭하기만 해도 사라져 버리는 반면, 날개셋의 입력 도구는 그렇지 않다. 더구나 결정적으로 이 문자표는 날개셋 편집기에서 자체 입력기를 지정해 놓았을 때는 사용할 수 없다.
그리고 내 프로그램에서는 선택된 이모지를 복사하기, 그리고 cursor가 가리키는 이모지를 문자표에서 찾아서 역으로 표시하기 같은 기능도 갖추고 있다.

예전에도 언급했듯, 2018~19년에 걸쳐 추가된 ‘필기 인식’과 ‘이모지’는 날개셋의 고유 기능이 아니라 운영체제가 제공하는 기능을 자체적인 UI 껍데기를 씌워서 제공하는 대표적인 입력 도구이다. Full feature를 갖춘 한글 IME로서 저런 기능도 한 프로그램 내부에서 제공할 필요가 있기 때문이다.

뭐 그건 그런데.. 운영체제에서 기본 제공하는 이모지 문자표는 응용 프로그램에다가 어떤 방식으로 이모지 문자를 보내는 걸까? 그게 갑자기 궁금해졌다. 쟤는 기술적으로는 ‘날개셋 입력 패드’과 비슷하게 훅킹을 사용해서 IME 메시지를 보낼 것 같은데..

프로그램이 TSF를 감지하는지 여부를 따져서 지원하면 TSF 방식으로 문자를 보내고, 그렇지 않으면 기존의 IME 메시지를 보낸다는 것을 확인할 수 있었다. IME 메시지만을 사용하는 날개셋 입력 패드보다 더 고차원적이다. 사실, TSF를 지원해야만 메트로 앱에서도 이모지를 입력할 수 있을 것이다.

날개셋 입력 패드를 처음 개발하던 시절에 본인도 개인적으로는 TSF 방식을 뚫어 볼까 생각을 했었다. 이게 성공하면 외부 모듈뿐만 아니라 입력 패드도 편집기와 비슷하게 주변 문자를 자유자재로 변형하면서 신기한 기능을 제공할 수 있다.

그러나 외부 모듈 하나만 개발해 봐도 내 경험상 TSF는 기술 난이도가 헬이고 응용 프로그램별로 제멋대로 동작하는 구현의 파편화가 너무 심하다. 더구나 그 TSF의 혜택을 보는 프로그램은 매우 소수이며, 편집기와 외부 모듈 다음으로 입력 패드 자체도 사용 빈도가 매우 낮은 제3군의 실험적인 유틸일 뿐이다.

그렇게 TSF를 뚫어 봤자 훅킹은 어차피 메트로 앱에서는 통하지도 않기 때문에 그 단계에서 막히니..
시간과 노력 대비 타산이 맞지 않는다는 결론을 얻어서 그 이상의 연구는 포기했다. 입력 패드는 write-only인 IME 프로토콜만 사용하는 데스크톱 앱 전용 프로그램으로 굳어져서 오늘에 이르고 있다.

5. 유니코드 5.2 자모

아시다시피 지난 10여 년 전에 KS X 1026-1 및 유니코드 5.2에서 옛한글 자모가 여럿 추가되었다. 시기가 시기이다 보니 연속된 공간을 쭉 확보하지 못하고 덕지덕지 지저분하게 추가되었지만, 그래도 잘 살펴보면 프로그래머의 관점에서 복잡함과 불편함을 최소화하는 방식으로 추가되었음을 알 수 있다.

답부터 말하면, 어떤 글자가 한글 초성인지 중성인지 종성인지 판별하기 위해 과거(유니코드 1.1)에는 A<=X<=B라는 영역 검사 하나만이 필요했다. 이제는 그래도 그 영역 검사가 각 성분별로 하나씩만 더 추가되면 된다.

  • 초성은 U+1100부터 1159까지 하던 영역에서 끝부분을 115E로 늘린 뒤(5개 추가), A960부터 A97C라는 새로운 영역 한 곳만 더 살펴보면 된다.
  • 중성은 U+1160부터 11A2까지 하던 영역에서 끝부분을 11A7로 늘린 뒤(5개 추가), D7B0부터 D7C6이라는 새로운 영역을 더 살펴보면 된다.
  • 종성도 그런 식으로 기존 영역을 조금 확장하고 나서 새로운 영역을 더 살펴보면 된다.

잘 알려져 있지 않지만, KS X 1026-1은 종성에 ㅇ으로 시작하는 겹받침(ㅇㄱ, ㅇㄲ, ㅇㅇ, ㅇㅋ)을 그냥 이응이 아닌 옛이응으로 수정한 규격(잠수함 패치..)이기도 하다.

그리고 KS X 1026-2는 정규화 규칙을 추가로 규정해서 현대 한글을 옛한글 자모의 조합으로 표현하는 것을 금지하고, 현대 한글 글자마디와 옛한글 자모가 합성되는 것도 명시적으로 금지했다. 한 한글은 오직 한 가지 방식으로만 표현되게 했다.
Windows는 2012년에 나온 8부터 저게 반영됐고, 날개셋 편집기에서는 지난 2015년에 나온 8.0 버전에서야 반영됐다. 저 표준을 제정한 분과 개인적으로 얘기까지 나누며 설명을 들은 뒤에야 말이다. 엇, 그러고 보니 둘 다 8부터네?!?

유니코드 2.0에서 한글 글자마디 11172자를 따 온 건 예전에 서울 올림픽 유치 성공만큼이나 역사에 길이 남을 위대한 쾌거였다. 현대 한글이 그렇게 정립된 뒤에 옛한글도 저렇게 됨으로써 한글 코드 논란은 완전히 종식됐다.

그 뒤로 유니코드 자체도 2003년쯤이던가 4.0에서 U+10FFFF라는 상한을 명확하게 정하고, 이 이상 글자를 더 등록하지는 않을 것이라고 못을 박았다. 그 이상은 UTF-16으로는 더 표현할 수가 없기 때문이다. 그래서 UTF-8도 4바이트 방식까지만 사용하고 5~6바이트 방식은 봉인했다.

따라서 현재 유니코드에 정의된 모든 평면이 고갈되고 글자들로 꽉 차는 날이 온다면.. 유니코드 위원회는 해산될 것이다. 지금의 문자 코드 체계는 지구와 현 인류 문명이 송두리째 멸망하지 않는 한 쭉 이어질 것으로 보인다.

Posted by 사무엘

2020/07/14 19:32 2020/07/14 19:32
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1773

1. 중국(청): 삼전도비와 독립문

영국에서 높으신 분들이 한국을 방문하면 6· 25 설마리 전투에 참전했던 영국군 글로스터 대대를 기념하는 전적비를 반드시 찾아간다고 한다(파주 적성면 소재). 영국은 나름 미국 다음으로 대규모로 참전했던 나라이다. 본인은 지난 2013년에 거기를 답사한 바 있으며, 답사기가 이 블로그에도 올라와 있다.

다음으로 영국 같은 훈훈한 예는 아니겠지만, 옛날에 일본인 관광객이 서울을 들렀다가 반드시 찾아가는 관광 코스 중 하나는 광화문과 경복궁 사이에 놓여 있던 조선총독부 청사였다고 한다. 뭐, 그 건물은 잘 알다시피 김 영삼 정권 때 헐렸다.

허나, 저것보다 더 안 좋은 예가 있다. 조선 시대에 병자호란 이후로 청나라에서 사신이 오면.. 얘들은 반드시 삼전도비부터 찾아가서 저게 잘 보존돼 있나 확인했다고 한다. -_-;; 그 이유는 더 말할 필요가 없을 것이다. 부득이하게 현장에 직접 못 가면 비석 표면의 탁본 인증이라도 받았다고 한다. 우리나라 역사에 이런 시절이 있었다는 게 실감이 가는가?

사용자 삽입 이미지

물론 옛날에는 일체의 사대주의가 몽땅 다 지금 우리가 굉장히 부정적인 색안경을 끼고 보는.. 그저 목숨 부지하기 위해서 밸도 자존심도 다 저버리는 비굴한 굴종만을 의미하는 건 아니었다.

옛날에는 사람과 국가 사이에 지금보다 뭔가 수직적인 위계 관계 질서가 훨씬 더 중요시되었다. 그리고 약자가 자기 팔자대로 먹고 살기 위해서는 인근의 강자에게 조공을 바치면서 조공 이상의 가성비로 다른 강자들로부터 보호를 받는... 뭐 그런 공생 관계가 필요한 것도 있었다. 이는 일제 시대에 일제의 통치에 적극적으로 저항하지 않고 소극적으로 따랐던 사람들을 몽땅 친일파 매국노라고 욕하는 게 위험 편협한 사고방식인 것과도 비슷한 이치이다.

조선의 경우 명나라와 청나라 사이에서 어영부영 하다가 병자호란이 벌어졌는데 전쟁에서 그만 져 버렸다. 그래도 여러 나라 안팎 정세 덕분에 어째 나라가 통째로 멸망당하지는 않았다. 그 대신, 왕이 누구 보는 앞에서 이마를 몸소 땅바닥에 짓찧기까지 하면서 한국사 전체를 통틀어 유례를 찾기 힘든 모욕을 당하게 됐다(삼전도의 굴욕).

고려 시절에는 도읍을 강화도로 옮기고, 그걸로도 모자라서 몽골· 원나라의 간섭을 받으면서 왕도 계속해서 충짜 시리즈로 나오던 적이 있었다. 훗날 구한말 때는 아관파천 같은 민망한 흑역사도 발생하긴 했다만.. 저건 그 시절에 통용되던 사대주의의 범주도 넘는 수준이었다.
삼전도비는 지금으로 치면 독립기념관의 야외에 내팽개쳐진 채 방치돼 있는 조선총독부 청사 지붕 첨탑을 능가하는 극도의 치욕의 산물이었다.

그리고 서대문 형무소 근처에 놓여 있는 독립문은 바로.. 우리 조선이 드디어 황제-_-를 보유한 대한제국이 됐고 삼전도비를 애지중지 관리할 필요가 없어졌다는 걸 기념하려고 세운 것이었다! 그 시절엔 그것만으로도 엄청난 이벤트였다. 청일 전쟁 이후로 청나라는 한반도에서 완전히 아웃 당했으니까..
뭐, 조선이 대한제국으로 간판을 바꿔 봤자 나라가 돌아가는 방식이 실질적으로 바뀐 건 별로 없었다. 애초에 자기 힘으로 청나라를 몰아낸 것도 아니었으니 말이다.

독립문이 세워지기 전에는 동일 장소에 '영은문'이란 게 있었다. 이름부터가 "은혜로운 대국의 사신을 영접한다"라는 뜻이며, 명나라와 청나라의 사신이 이 문을 통과하여 개선장군처럼 들어왔었다.
그랬는데 독립협회가 주축이 되어 영은문은 헐어서 주춧돌 기둥만 남겼으며, 그 대신 독립문이란 걸 1896~97년에 걸쳐서 건립했다.

사용자 삽입 이미지

저 시절에 서 재필은 독립문, 독립협회에다가 독립 신문까지.. '독립'이라는 단어를 유난히도 좋아했다. 당시에 조선의 미래를 걱정하던 개화파 지식인들이 보기에는 청나라의 영향력에서 벗어나는 게 당장 최대의 과제이고 염원이었던가 보다.

이런 맥락을 모르고서 '독립문'이 일본으로부터의 독립을 기념하는 조형물인 줄로 아는 사람은 아마 성경에 나오는 '사자'가 lion인지 messenger인지 분간 못 하는 것과 비슷한 지적 능력의 소유자이지 싶다. (마침 위치도 서대문 형무소 근처이다 보니 일본과 관계가 있는 것으로 더욱 오해하기 쉽긴 함.ㄲㄲㄲㄲㄲㄲㄲ)

물론 옛날 개화파 사람들 중에는 중국의 대안이 오로지 일본이라고.. 일본을 과신하는 착오를 범한 사람도 있었다. 하지만 그런 사람들의 친일 성향은 훗날 등장하는 매국노 반민족행위자의 친일 성향과는 성격이 다른 것이었다.
그래서 그런지 일제는 훗날 조선의 주권을 침탈한 뒤에도, 과거에 조선이 영은문을 허물었던 것처럼 '독립문'을 또 철거한다거나 하지는 않았다. 경성 시내의 재개발을 위해 서대문(돈의문)을 헐었을 뿐이지..

일제는 오히려 그 시절에 내팽개쳐지고 방치됐던 삼전도비를 재정비했으며, 이것도 그래도 역사 유물이라며 문화재로 등재하고 관리· 보존했다. 참으로 역설적인 노릇이다. 과장 좀 보태면, 다 부서진 채 방치돼 있던 경주 석굴암을 조사하고 어설프게나마 복원 공사를 한 것과 과정이 비슷했다.

한편, 그렇게 몰락했던 청나라는 조선이 멸망한 것과 비슷한 시기에(1912) 같이 멸망했으며, 그 뒤 중화민국을 거쳤다가 나중에 공산당 중화인민공화국 & 대만로 갈라져서 현재에 이르고 있다.

중국은 땅덩이가 워낙 넓어서 몽땅 정복하기가 곤란했던 덕분에, 아편 전쟁이라든가 청일이고 중일이고 각종 전쟁에서 참패하고도 대놓고 멸망하고 외세 식민지가 되지는 않았다. 단지 홍콩 같은 몇몇 지역을 잃었으며, 덕분에 문화가 이질화돼 버려서 수복 후에도 반쯤 특별구역처럼 됐을 뿐이다.

2. 일본: 1980년대 초반, 1990년대 중반의 반일

우리나라야 해방 이래로 지금까지 원초적인 반일 감정이 없던 적이 없었지만.. 1980년대 5공 시절에는 유난히 더했던 것 같다.
다음은 1982~84년에 발간된 무려 30권짜리 '동아 원색 세계 대백과사전'의 화보에서 '일본'을 찾아보면 나오는 설명이다.

사용자 삽입 이미지

우리는 예로부터 일본에게 선진 문물을 전해 주고 일본을 근대화(?)시켜 줬건만, 걔들은 은혜를 원수로 갚고 우리에게 상처와 피해만 끼쳤다는 뿌리깊은 배신감과 피해의식, 투철한 반일의식을 엿볼 수 있다.
"일본은 이러한 잘못을 깊이 뉘우치고, 우리의 진정한 우방이 되어 세계 평화에 기여하기를 바란다"

코멘트 훈수까지.. ㅋㅋㅋ 관찰자가 아니라 전지적 작가 시점의 극치다.
얘는 지금의 두산 세계 대백과사전, 두피디아의 전신으로, 집필진을 보면 온통 스카이 대학 교수들이 즐비하다. 나름 당대 최고의 석학들이 모여서 편찬한 백과사전이다.

그런데 일면 이해가 된다. 동아 원색 세계 대백과사전이 출간되었던 저 때는 일본의 역사 왜곡 발언으로 인해 반일 감정이 전국적으로 극에 달했었다.

정 광태의 그 유명한 "독도는 우리땅" 노래가 발표된 게 1982년.
박 영희 할머니가 자신이 조선어 학회 사건의 발단이 된 그 일기장의 주인이었다고 늘그막의 나이로 언론에 커밍아웃을 하며 일본을 공개적으로 규탄한 때도 1982년 여름이었다.

어디 그 뿐이랴? 국민 성금을 모아서 독립기념관을 건립하기 시작한 때도 1982년이다! (87년에 완공, 개관)
그러니 이 정도면 저 시기에 편찬된 민간 백과사전에 "일본은 각성하길 바란다" 같은 말이 본문은 아니어도 화보에 들어가고도 남지 않았겠는가?

1970년대에 북괴의 연이은 도발 때문에 전국민이 북괴를 규탄했었고,
1983년에 대한항공 007편 격추 사건 때문에 반소 감정이 폭발했었고..
2002년에 오노 금메달 사건과 여중생 장갑차 사건 때문에 반미 감정이 치솟았던 것과 동일한 맥락이다.

누가 저질렀건 같은 수준의 잘못에 대해 같은 강도로만 규탄하면 된다. 그럼 문제될 것 없다. 그렇지 않고 진영을 가려가며 편파적으로 선동질 하는 놈들이 매우 불순하고 나쁜놈일 뿐이다.
저 책은 북한 쪽을 찾아봐도 역시 5공 시절답게 '북괴' 운운하면서 노골적인 경계심과 적개심을 표현한다. 일본이고 북괴고 다 공평하게 모두 깐다. 그러면 편파적이지 않고 차라리 낫다.

한편, 저 때로부터 10~15년쯤 뒤인 김 영삼 때도 유독 일본의 정치인들이 위안부나 독도와 관련해서 망언을 자주 했고, 반일 감정이 상승했던 것 같다. 그러니 대통령이 "쟤들 버르장머리를 고쳐 주겠다" 발언까지 하면서 조선총독부 청사를 헐어 버렸다.
정확한 근거나 출처를 찾기는 어렵지만 아마 저 때 새마을호 열차(= 국영 철도청 관할)의 안내방송에서 일본어를 잠시 빼 버린 적도 있었다고 한다. 그게 사실이라면 어지간히도 소심한 방법으로 저항했었다.;;

일본 문화가 정식으로 개방되지도 않았고 일본에 대한 피해의식과 컴플렉스가 훨씬 쩔어 있었던 옛날이야 그럴 수도 있었다고 치지만 지금은 무려 2020년이다. 1982년이 아니다. 우리가 지금 북괴로부터 6· 25 시절 같은 군사력 위협을 느끼는 건 전혀 아니듯이, 일본에 대해서도 쟤들이 지금 같은 상황에서 무슨 태평양 전쟁 시즌 2 같은 짓거리를 하면 어쩌나 걱정을 할 필요는 없다.

그럼에도 불구하고 아직도 지적 수준이 일제 쇠말뚝이니 아베 노부유키의 저주(?) 나부랭이에 머물러 있는 반일은 좀 망상 정신병을 의심해야 하지 않나 싶다. 지금 우리나라에는 악성 친일파보다 더 나쁜놈들도 수두룩하기 때문이다.

3. 한국: 꼬인 근현대사 비극의 근원

내가 분명히 말하는데, 한국 현대사의 비극들 중 상당수는
과거에 자국민의 힘으로 조선 왕조를 직접 끝장내지 못한 것에서 유래되었다고 보면 된다.
무슨 광복군이 제대로 참전하지 못한 것? 그건 별 의미 없으며 신경 쓸 필요 없다.

19세기에 조선은 말이 좋아 고요한 아침의 나라이지, 지금으로 치면 아프리카의 어느 못 사는 나라와 비슷하게 가난하고 굶주리고 비위생적이고 다른 나라와 제대로 교류하지도 않으면서 최악의 막장 고인물 썩은물이 되어 있었다.
오죽했으면 차라리 이전의 고려가 조선보다는 더 개방적이고 국제 인지도가 더 높았기 때문에 한국의 영어 명칭조차도 ‘코리아’로 굳어지지 않았던가? 조선의 입김이 닿았다면 choose의 과거분사와 비슷한 단어가 됐을 텐데 말이다.

생각해 보면 조선은 시작과 끝이 은근히 잔혹하고 악랄했다. 건국 초기부터(1400년 초) 특별히 반역이나 역모 혐의가 없었는데도 고려 왕씨들을 집요하게 색출해서 참수하거나 바다에 던져넣는 식으로 학살했다. 나중에 홍 경래의 난이 진압됐을 때는(1812) 수괴와 간부는 그렇다 치더라도 단순 가담자까지.. 10살 이상 남자는 전원 무려 1917명을 한 치의 자비심 없이 몽땅 처형했다.

하물며 말기에 개화파는..?? 그야말로 삼족이 멸해지는 참화를 당했다. 김 옥균은 외국 망명 중에도 왕이 직접 보낸 자객에게 암살 당한 게 마치 북한 김 정남이 암살 당한 것과 비슷해 보인다. 저 사람뿐만 아니라 서 재필도 가족은 조부모, 부모, 자녀, 손주 세대까지 깔끔히 순삭 당했다.
고종과 민씨 일가는 외교와 경제· 군사는 등신 같았지만, 자기 밥그릇 지키는 데는 귀신이었다. 임오군란, 갑신정변, 동학 같은 건 외국 군대까지 끌어들여 자근자근 밟아 줬다. 그리고 그 외세는 조선의 무덤을 파는 부메랑이 되어 돌아왔다.

그때가 되니 조선 정부도 일본에게 내정간섭 좀 그만 하라며 뒤늦게 손사래를 치기도 했지만.. 이미 일본군이 경복궁 주위에까지 쫙 깔렸고 때는 너무 늦었다.
이걸 가만히 생각해 보면 당시 쟤들은 거의 싸이코패스가 아닌가 생각이 들 법도 한데 국뽕 국사 교과서는 이 과오를 진지하게 다루지 않는다. 특히 민비가 워낙 적절한 타이밍 때 잘 암살 당하기도 했으니 말이다.

그리고 청산리니 봉오동이니 하는 1920년대 독립군의 전과가 많이 부풀려지고 왜곡된 것으로 밝혀졌듯이, 20여 년 뒤의 광복군도 비록 취지는 훌륭하지만 그 규모와 전투력은 정말 보잘것없는 수준에 지나지 않았다.

군대는 오로지 소비밖에 안 하는 집단이다. 지금 북한이 중국 없이 못 지내는 것 이상으로 그때 임시정부니 광복군이니 다 장 제스의 지원이 없었으면 뭘 더 할 수 있었을까? 겨우 그거 갖고 당당히 일본을 무찌른 전승국 대접을 받고 미국· 소련의 입김에서도 벗어난다? 남북 분단도 안 되었을 거라고? 꿈도 참 야무지다.

내가 예전에 몇 번 언급한 적이 있었지만.. 일본이 핵폭탄 맞고 일찍 항복하고 허겁지겁 도망간 것은 걔네들한테나 우리한테나.. 특히 우리나라 입장에서도 득이 훨씬 더 많았다.
일제가 한반도에서 뭔가를 수탈하고 망쳐 놓은 것을 논하기 전에, 구한말 때 이 헬조선 땅에 더 수탈하고 망가뜨릴 게 그렇게 많이 있기나 했는지를 이성적으로 진지하게 생각할 필요가 있다.

Posted by 사무엘

2020/07/11 19:35 2020/07/11 19:35
, , ,
Response
No Trackback , 3 Comments
RSS :
http://moogi.new21.org/tc/rss/response/1772

1. 오일러 상수: 감마

초등학교 시절에 반비례 함수라고 배웠던 1/x는 조화급수를 나타내며, 궤적은 쌍곡선이고 부정적분은 ln x (+C)가 되는 꽤 독특한 함수이다.
그런데 1/x의 값을 1 간격으로 n까지 구한 조화수열의 합과(즉, 1 간격의 구분구적법), 아예 해당 함수의 정적분(실제 면적)은.. 일단 명목상으로 값이 비슷할 것 같은데 정확하게 얼마나 차이가 날까? n이 무한대로 근접할수록 값이 어떻게 될까?

먼저, 이런 발상이 왜 나왔겠는지부터 생각을 해 보자.
1/x라는 문제의 함수는 x가 무한대로 갈 때 함수값 자체는 0으로 수렴하여 한없이 줄어들지만, 급수의 무한합 내지 정적분은 무한대로 발산한다는 아주 기괴한 특징이 있다. 보통은 다 발산하거나 다 수렴하지, 저렇게 되는 건 몹시 드물다.

1/x 말고 그냥 x라든가 1/x^2 같은 주변의 다른 함수에 대해서  급수의 무한합과 정적분의 차이를 구해 보면 구하는 게 무의미한 trivial한 결론이 나와 버린다. 그냥 무한대로 빠지거나, 아니면 한쪽이 그냥 0이 돼 버려서 차를 구할 필요가 없어지는 식이다.

하지만 1/x는 그렇게 trivial하게 빠지지 않는다. 더구나 무한급수와 정적분의 차이가 “무한대 - 무한대” 꼴의 극한이 되는지라, 극한값이 유한하게 나온다는 게 직관적으로 보장도 되지 않는다. 그러니 이 극한값은 수학적으로 파고들 명분과 의미가 있으며, 옛날 천재 수학자의 관심을 끌게 되었다.

일단 1/x에 대해서 무한합과 정적분의 차이가 특정값으로 수렴한다는 것 자체가 증명되었으며, 그 값은 대략 0.577215… 형태로 빠진다. 이 수는 관례적으로 오일러-마스케로니 상수라고 불린다.

자연상수 e야 미적분과 밀접한 관계가 있으니 중등교육 수준에서도 이과의 최종 테크 한정으로 배운다. 하지만 저 상수는 쓰이는 곳이 너무 난해한지라, 수학과에서 해석학을 전문적으로 배우는 정도가 아니라면 딱히 접할 일이 없다.

더구나 쟤는 특성이 밝혀진 것도 별로 없다. 사칙, 삼각함수, 지수, 로그만으로는 저 수를 나타낼 수 없다. 그러니 정황상 초월수 무리수인 것이 99.999% 확실해 보이긴 하지만.. 수학자들이 수긍할 수 있는 완벽 엄밀한 논리 전개만 동원해서는 초월수는커녕 무리수인지도 정확하게 증명이 못 돼 있다고 한다. 의외의 일이다.

다만, 이 수는 e^(-x) * ln(x)라는.. 비교적 친근한(?) 초등함수 조합을 0부터 무한대까지 이상적분을 해서 얻을 수 있다(음수 버전이 나옴). 친근해 봤자 쟤는 이미 부정적분은 초등함수 형태로 나타낼 수 없는 수준이지만 말이다.

그리고 이 수는 팩토리얼의 대수적 확장 버전인 감마 함수와도 관계가 있다. GAMMA(x)-1/x라는 함수에서 x=0의 극한값이 이 수의 음수 부호 형태이다. 신기하지 않은가? 그래서 이 오일러 상수는 그리스 문자 ‘감마’(γ)를 써서 표기하곤 한다. 상수는 소문자 감마이고 함수는 대문자 감마이다.
이 글의 전체 내용을 수식으로 요약하면 다음과 같다.

사용자 삽입 이미지

2. 오메가 상수와 람베르트 함수

고등학교 수학에서는 지수와 로그를 다루고, 이과 및 자연계에서는 이에 대한 미· 적분까지도 다룬다.
그럼 다음으로 지수함수 e^x에다가 x를 또 곱한 x*e^x라는 함수를 생각해 보자. 취급하기가 약간 더 복잡해졌지만.. 그래도 얘는 부분적분을 통해 부정적분을 온전한 형태로 구할 수는 있다.

그런데 x*e^x = 1 이라는 방정식의 근을 구할 수 있을까? (뭔가 오일러의 항등식과 살짝 비슷하게 생겼는데.. 그냥 기분 탓임..)
양변에 로그를 씌워서 식을 정리하면 x= -ln x까지는 나온다. 하지만 이 이상 식을 정리하는 건 무리이고, 이 시점에서 발상을 전환하여 뭔가 새로운 개념이나 용어를 창조해야 할 것 같다. 그리고 그걸 1700년대에 이미 실제로 한 사람이 있다.

일단 저 식을 실수 범위에서 만족하는 근 x는 대략 0.567143…으로 전개되는 값이다. 앞서 다뤘던 오일러 상수와 얼추 비슷한 크기라는 게 흥미롭다. 물론 특성과 의미는 전혀 다르지만 말이다. 더 나아가 x에 대해 t*e^t = x를 만족하는 t를 되돌리는 함수가 바로 고안자의 이름을 딴 “람베르트 W” 함수이다.

고안자인 요한 하인리히 람베르트는 수학, 물리, 천문학, 철학 등 다방면에서 가히 레오나르도 다 빈치 급으로 불세출의 천재였다고 전해진다. 오일러와도 같은 국적의 동시대 사람이었으나.. 좁은 세상에 태양이 둘일 수는 없어서 그런지 람베르트는 오일러보다야 인지도가 낮다.

오일러 상수에 그리스 문자 ‘감마’가 부여되어 있다면, 앞서 언급한 W(1)에는 관례적으로 그리스 문자 ‘오메가’가 부여되어 있다. 오메가가 w와 비슷하게 생겨서 두 문자가 저렇게 섞여 쓰이는 것 같다.
W(1)은 오일러 상수보다는 분석하기가 아무래도 더 용이한지, 초월수라는 것은 간편하게 증명되어 있다.

하지만 W라는 함수도 기존 초등함수의 형태로 나타낼 수 없으며 절대로 만만한 물건이 아니다. 그럼 정체를 알기 위해 만년 수치해석 근사값에만 의지해야 하느냐 하면.. 그렇지는 않다. 해석학적인 의미를 지닌 형태로 나타낼 수는 있는데, 그게 감마 함수가 들어간 무한급수이다. 이 역시 공대 수준의 숫자 공부만 한 사람이라면 그냥 포기하는 게 속 편할 것 같다..;;

하지만 이런 물건이 왜 존재하느냐 하면.. 그게 존재함으로써 더 복잡한 문제를 풀 수 있고 다른 복잡한 개념을 간결하게 표현할 수 있기 때문이다.
x*a^x뿐만 아니라 아예 x^x=b 같은 방정식의 근도 Lambert 함수 형태로 표현 가능하다.

단적인 예로 x^x = e의 근은.. 저 오메가 상수의 역수.. 1/W(1), 대략 1.763222…이다. e에다가 단순 가공을 한 게 아닌, 뭔가 차원이 다른 수가 튀어나온 셈이다. x^x 정도면 적분도, 방정식 근도 모두 통상적인 방법으로는 못 구하는 난감한 물건이니 말이다.
어쩐지 뭔가 메이플 같은 수학 패키지로 지수함수가 섞인 복잡한 방정식 풀이를 시켜 보면.. LambertW 이러는 식으로 답이 나오곤 하던데 그게 저런 뜻이었다.

Lambert 함수는 양의 실수에서는 ln x보다도 더욱 느리게 증가하는 별볼일 없는 함수이다. 하지만 수학 전공자들은 이런 함수를 실수도 모자라서 복소수 영역에서 갖고 논다. 도함수나 부정적분을 구하면 이 함수 자체가 포함된 더 복잡한 형태가 나오는 게 지수/로그함수 계열과 비슷해 보인다.

얘는 음수 -1/e부터 0 사이에서는 마치 제곱근처럼 값이 2개가 나온다는 특징이 있다.
비록 중등 교육과정에서 가르치지는 않지만.. 해석적으로 분석을 못 하는 것도 아닌데, 관점에 따라서는 얘도 초등함수의 범주에 넣을 수 있어 보인다.

사용자 삽입 이미지

참고로 람베르트 함수 말고 삼각함수 중에도..
우리가 0 극한값을 배울 때 써먹었던 sin(x)/x처럼.. 하필 sin(x), cos(x), sinh(x), cosh(x)를 x로 나눈 물건의 정적분 함수를 따로 Si(x), Ci(x), Shi(x), Chi(x) 요렇게 표기한다. 기존 초등함수들의 조합으로 나타낼 수 없는 새로운 특성을 갖지만 그래도 수학적으로 다른 의미가 있기 때문이다.

저렇게 써 놓으니 무슨 한어병음 표기처럼 보인다만=_=;; 어쨌든 저런 건 초월함수들 중에서 적분함수라고 따로 불린다.

Posted by 사무엘

2020/07/09 08:35 2020/07/09 08:35
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1771

1. 그레이스케일

이건 이미지를 흑백 형태로 바꾸는 것이 핵심이다. 색을 구성하는 정보량의 차원이 줄어들고(3차원 → 1차원으로) 결과적으로 전체 색깔수가 줄어들기는 하지만(수천~수십만 종류의 색상 → 256단계의 회색), 그래도 아예 B&W 단색으로 바꾸는 건 아니다.
각 픽셀들은 색상과 채도가 제거되고 명도만 남아서 흑부터 백 사이에 다양한 명도의 회색으로 기계적으로 바뀐다. 같은 색의 픽셀이 인접 픽셀이 무엇이냐에 따라서 다르게 바뀐다거나 하지는 않는다.

그런데 그레이스케일 공식이 딱 하나만 존재하는 게 아니다. RGB 세 성분의 산술평균을 주면 될 것 같지만, 그렇게 그레이스케일을 하면 그림이 굉장히 칙칙하고 탁하게 보이게 된다.

똑같이 최대값 255를 주더라도 빨강(255,0,0), 초록(0,255,0), 파랑(0,0,255) 각 색별로 사람이 인지하는 명도는 서로 일치하지 않는다. VGA 16색 팔레트를 다뤄 본 사람이라면, 밝은 빨강이나 밝은 파랑을 바탕으로는 흰 글자가 어울리지만, 밝은 초록은 그 자체가 너무 밝아서 흰 글자가 어울리지 않는다는 것을 알 것이다.

사용자 삽입 이미지

그러니 공평하게 33, 33, 33씩 가중치를 주는 게 아니라 거의 30, 60, 10에 가깝게.. 초록에 가중치를 제일 많이 부여하고 파랑에는 가중치를 아주 짜게 주는 것이 자연스럽다고 한다.

이런 공식은 누가 언제 고안했으며 무슨 물리 상수처럼 측정 가능한 과학적인 근거가 있는지 궁금하다. 옛날에 흑백 사진을 찍으면 색깔이 딱 저 공식에 근거한 밝기의 grayscale로 바뀌었던가?
본인은 저 그레이스케일 공식을 태어나서 처음으로 접한 곳이 아마 QBasic 내지 QuickBasic의 컬러/팔레트 관련 명령어의 도움말이었지 싶다.

2. 디더링

이건 그레이스케일과 달리, 색깔수를 확 줄이는 것이 핵심이다. 그 대신 반드시 단색 흑백이어야 할 필요가 없다. 가령, 트루컬러를 16색으로 줄이는 것이라면 RGB 원색이 살아 있는 컬러라 할지라도 디더링의 범주에 든다. 이런 것처럼 말이다.

사용자 삽입 이미지

디더링에서는 어떤 원색을 직통으로 표현할 수 없을 때 근처의 비슷한 여러 색들을 고르게 흩뿌려서 원색과 비슷한 색감을 나타낸다. 팔레트까지 임의로 지정이 가능하다면 256색 정도만 돼도 생각보다 그럴싸하게 원래 이미지를 재현할 수 있다. 그런 게 아니라 그냥 흑백 단색 디더링이라면 아까 그레이스케일처럼 어떤 공식에 근거해서 명도를 추출할지를 먼저 결정해야 할 것이다.

0부터 1까지 가중치별로 점을 골고루 균등하게 뿌리는 공식은 이미 다 만들어져 있다. 이건 Ordered dither이라고 불리며, 보통 8*8 크기의 64단계 격자가 쓰이는 편이다. 그 구체적인 방식에 대해서는 수 년 전에 이 블로그에서 이미 다룬 적이 있다.

그레이스케일은 RGB(0.4,0.2,0.6)라는 색을 0.3이라는 명도로 바꾸는 것에 해당하는 기술이고, 단색 디더링은 이 색이 0.3, 0.3, 0.3 … 이렇게 쭉 이어지는 것을 1, 0, 0, 1, 0, 0 이런 식으로 이산적으로 표현하는 것과 같다.
그런데 원색을 기계적으로 이런 격자로 치환하기만 하면 보기가 생각보다 굉장히 좋지 않다.

원래 0.3을 표현해야 하는데 지금 지점에서 부득이하게 1을 찍어 버렸다면 0.7이라는 오차의 여파를 인접 픽셀에다가 떠넘겨서 거기서 계속해서 감당하게 해야 한다. 즉, 그레이스케일은 그냥 인접 픽셀을 신경 쓰지 않고 픽셀 대 픽셀 변환만 했지만 디더링은 그렇지 않다. ordered dither 내지 더 단순무식한 nearest color 찍기 신공이 아니라면.. 이전 픽셀에서 발생한 오차를 수습하는 error diffusion을 동원해야 부드러운 결과물이 나온다.

사용자 삽입 이미지

그런 지능적인(?) 디더링 알고리즘은 196~70년대에 컴퓨터그래픽이라는 분야가 등장한 초창기부터 연구되어 왔으며, 고안자의 이름을 따서 Floyd-Steinberg, Burks, Stucki 같은 알고리즘이 있다. 이미지를 다루는 사람이라면 포토샵 같은 그래픽 편집 프로그램에서 저런 명칭들을 본 적이 있을 것이다.
이런 알고리즘들은 ordered dither와 달리, 점들이 일정 간격으로 산술· 기계적으로 단순 투박하게 찍힌 게 아니라 뭔가 한땀 한땀 손으로 입력된 것 같고 부드러운 느낌이 든다. 그리고 무엇보다 색깔이 크게 바뀌는 경계 영역이 훨씬 더 선명하다.

3. 하프톤 (망점)

그레이스케일이 색깔 표현에 제약이 없는 아날로그 영상물(특히 흑백 필름 사진) 같은 느낌이 나고, 디더링은 초기에 해상도와 색상이 부족했던 디지털 영상과 관계가 있다면.. 하프톤은 색상이 부족한 대신 해상도가 높은 '인쇄물'과 관계가 깊은 기법이다.

사용자 삽입 이미지

하프톤은.. 일정 간격으로 망점을 두두두둑.. 찍고, 그 망점의 크기/굵기만으로 명도를 조절한다. 깨알같은 점들의 양과 배치 방식을 고민하는 통상적인 디더링과는 문제 접근 방식이 약간 다르다.
출력물의 해상도가 영 시원찮은 데서 하프톤을 동원하면 망점이 너무 커서 눈에 거슬릴 수 있다. 회색을 만들려고 했는데 하양과 검정이 그대로 눈에 띄게 된다는 것이다.

그러나 아무 인쇄물에서나 흑백이든 컬러든 문자 말고 음영(색깔 배경)이나 사진을 하나 보시기 바란다. 전부 촘촘한 점들로 구성돼 있다.
컴퓨터용 프린터나 전문 출판물 인쇄기들이 무슨 수십~수백 종에 달하는 물감을 갖고 있지는 않다. 잉크는 3원색에다가 검정 이렇게 4개만 갖고 있고, 나머지 색은 전부 얘들을 적절한 배율로 섞은 망점의 조합만으로 표현한다.

컴퓨터에서 보는 사진 이미지를 프린터로 출력하기 위해서는 가산 혼합 기반인 RGB 방식의 색을 감산 혼합 CMYK 방식으로 변환하고, 색 축별 망점 배합을 계산해야 할 것이다. 이건 디더링과는 다른 영역이다. 프린터 드라이버가 하는 일 중의 하나가 이것이며, 전문적인 사진이나 출판 프로그램 역시 색 축별로 인쇄 형태의 저수준 데이터를 export하는 기능을 제공한다.

그래도 요즘은 사진조차 필름 현상이 아니라 디지털 카메라로 찍은 뒤에 포샵질을 하고 고급 인화지에다 '인쇄'해서 만들어 내는 세상이니.. 컬러 인쇄 기술도 예전보다 굉장히 많이 좋아지고 저렴해졌다. 1990년대까지만 해도 가정용으로 컬러 레이저 프린터라는 걸 생각이나 할 수 있었겠는가?

유니코드 문자 중에 U+2591 ~ U+2593은 단계별 음영을 나타낸다.
굴림· 바탕 같은 통상적인 Windows 글꼴은 이를 하프톤 형태로 표현한 반면, 함초롬바탕은 디더링 형태로 표현했음을 알 수 있다.
윤곽선 글꼴의 래스터라이즈 방식의 특성상 디더링보다는 하프톤이 부담이 덜하기도 하다. 윤곽선 글꼴은 뭔가 덩어리· 군더더기가 늘어날수록 출력 성능이 급격히 떨어지기 때문이다. 그래서 매끄러운 곡선 말고 오돌토돌, 쥐 파먹은 효과 같은 걸 표현한 글꼴은 크기도 크고 처리하기 버거운 편이다.

사용자 삽입 이미지

이상이다. 이 사이트에도 그레이스케일, ordered 디더링, 기타 휴리스틱-_- 디더링, 그리고 하프톤까지 다양한 사례가 소개되어 있으니 관심 있는 분은 참고하시기 바란다.

우리가 사는 공간이 3차원일 뿐만 아니라, 시각 정보의 기본 단위인 색깔이라는 것도 어떤 방식으로 분류하든지 결국 3개의 독립된 축으로 귀착된다는 게 신기하지 않은가? 신학에서는 이게 하나님의 속성인 삼위일체와 관계가 있다고도 말하는데, 그건 뭐 결과론적인 해석이며 물증이라기보다는 심증 수준에서 만족해야 하지 싶다.

음악에서는 음계, 음정, 화성학 같은 이론이 수학과 연결되어 오래 전부터 연구돼 왔다.
그럼 일명 color theory라고 불리는 분야는 언제부터 누구에 의해 연구돼 왔을까? RGB, CMY, HSL 사이를 변환하는 공식 같은 것 말이다. 더디링은 컴퓨터그래픽 영역이겠지만 순수하게 색에 대한 수학적인 분석은 미술과 전산학 어디에도 딱 떨어지지 않아 보인다. 내가 알기로는 전파로 영상을 주고 받는 텔레비전 기술이 개발된 20세기 초쯤에야 이런 분야가 개척됐다.

본인이 색과 관련하여 감이 오지 않고 아직도 좀 알쏭달쏭한 걸 얘기하면서 글을 맺도록 하겠다.
모니터 화면 같은 건 그 본질이 빛이며, 빛은 색을 태생적으로 지니고 있다. 그러나 다른 세상 만물들, 특히 인쇄물은 색만 있지 빛은 지니고 있지 않다. 조명을 받아야만 자기 색을 비춰 보일 수 있다.

빛은 원색이 RGB라고 여겨지며, 섞일수록 더 밝아져서 최종적으로 white에 도달하는 ‘가산 혼합’을 한다. 그러나 빛이 없는 나머지 사물의 색들은 섞일수록 더 어두워져서 최종적으로 black에 도달하는 ‘감산 혼합’을 한다. 이 정도는 이미 초등학교 미술 시간에 배운다.

다만, 빛의 3축과 색의 3축은 노랑/초록 말고 빨강/파랑 부분도 서로 미묘하게 차이가 난다는 것부터는 고등교육 이상의 영역으로 보인다. 본인도 그걸 대학 이후에나 접했기 때문이다.
왜 그런 차이가 나는지에 대해서는 논외로 하더라도, 빛이건 색이건 두 색상을 물리적으로 섞지는 말고 디더링 하듯이 오밀조밀 가까이 배치시켜 놓으면 멀리서 볼 때 정확하게 어떤 혼색이 나타날까? 이걸 잘 모르겠다.

이건 빛이든 인쇄된 색이든 차이가 없어야 하지 않을까? 그리고 만약 차이가 없다면 그 결과는 감산 혼합이나 가산 혼합 중 어느 것과도 정확하게 일치하지 않을 것이다. 그 관계가 무엇일까? 마치 산술/기하/조화 평균처럼 서로 비슷하면서도 미묘하게 다른 결과가 나오지 않을까 싶다.

이해를 돕기 위해 아래 그림을 살펴보자. 반드시 확대/축소 왜곡되지 않은 원래 크기 형태로 볼 것!! (화면 확대 배율도 96DPI/100%로 맞춰야 함)
왼쪽은 그냥 RGB(0,0,0) 검정과 RGB(255,255,255) 하양을 1:1로 섞은 것이고, 오른쪽은 RGB(0,0,255) 파랑과 RGB(0,255,0) 초록을 섞어서 청록을 만든 것이다. 여기서 섞었다는 것은 픽셀 디더링을 말한다. 그리고 우측 하단에는 본인이 보기에 이들과 가장 비슷하다고 생각하는 순색(solid color)을 칠해 보았다.

사용자 삽입 이미지

255짜리 순색 파랑 255짜리 순색 초록을 섞어서 가산 혼합이 됐다면 RGB(0,255,255) 밝은 cyan 청록이 나타나야 하겠지만 실제로는 전혀 그렇게 되지 않았다. 그런데 그렇다고 해서 평균인 128짜리의 훨씬 어두운 색이 된 것도 아니다.
본인이 보기에 가장 비슷한 순색의 명도는 대략 180~184 정도이다. 생각보다 제법 밝다. 아.. 그래서 옛날에 VGA 팔레트도 어두운 색을 무식하게 128로 지정하지 않고 170 정도의 값을 줬는가 싶은 생각이 든다. 다른 색과 섞었을 때 재현 가능한 색이 나오라고 말이다.

이런 현상을 설명하기 위해 감마 보정 등 다른 어려운 이론들도 나온 게 아닌지 추측해 본다. 디더링 알고리즘이란 게 내가 생각했던 것보다 여러 단계로 나뉘고 더 어렵고 복잡할 수도 있겠다는 생각이 든다. 적절한 명도 추출하기, 적절히 대체색으로 분비하기, 오차 보정하기 등..;; 시각 디자인의 세계는 오묘하다.

Posted by 사무엘

2020/07/06 08:35 2020/07/06 08:35
, , , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1770

도로와 철도의 터널과 교량

1. 자동차용 터널과 교량

도로나 철도를 만들다가 산 같은 장애물을 정면돌파 하려면 터널을 뚫게 되고, 기존 도로를 입체 교차하거나 강을 건너기 위해서는 교량을 건설하게 된다. 이런 시설들은 구불구불 우회해서 가야 할 경로를 굉장히 곧게 해 준다.

기술이 발달한 덕분에 요즘은 옛날에 상상하기 어려웠던 매우 크고 길고 넓은 터널과 교량이 많다.
산 하나를 통째로 관통하는 건 일도 아니고 도시 시가지를 통째로 지하로 통과한다. 2차로를 넘어 4차로 광폭 터널도 어렵지 않게 볼 수 있으며, 제한적이나마 바다를 건너는 터널(아래로)이나 교량(위로..)도 있다. 아무래도 고가(교량)보다는 지하도(터널..)가 만들기 더 어려운 것이 주지의 사실인데, 하저· 해저터널 같은 건 참 경이롭다.

다만, 이런 곳을 자동차로 운전해서 갈 때는 좀 주의해야 한다. 터널을 드나들 때는 주변의 밝기가 갑자기 변하기 때문에 운전자의 시야가 교란될 수 있으며, 교량은 바람이나 온도가 일반 평지와는 달라서 길이 미끄러울 수 있다.
그리고 둘은 형태는 다르지만 길 밖으로 벗어날 곳이 딱히 없기 때문에 비상 대피나 탈출이 취약하다는 공통점이 있다. 특히 터널은 화재라도 났다간 질식의 위험까지 있다.

이런 이유로 인해 우리나라에서는 터널이나 교량에서는 한 치의 예외 없이 차선들이 실선으로 그어졌으며, 차로 변경과 추월이 금지돼 왔다.
하지만 모든 교통사고가 오로지 과속과 추월 때문에 발생하는 것도 아닌데, 저건 현실과 안 맞는 너무 규제 위주의 악법이라는 지적이 끊이지 않았다.

사용자 삽입 이미지

요즘은 시종일관 한 차로로만 달리기에는 너무 길고 큼직한 터널도 많다. 그리고 강을 건너는 교량 말고 강과 수 km째 나란히 가는 교량도 많은데 거기도 차로를 몽땅 실선으로 틀어막아야 하는지에 대한 형평성 문제도 있다.

국도 20호선과 4호선이 만나는 북건천 분기점은 긴 건천 터널을 통과하자마자 분기점이 뿅 나타난다. 경주에서 20을 이용해서 달리다가 저기서 4로 갈아타서 영천? 대구 방면으로 가려면 아예 터널에 진입하기 전부터, 한참 전부터 맨 오른쪽 n차로로 차로를 바꿔야 한다. 터널 안에서 차로를 바꾸는 건 실선 차로와 각종 차단봉으로 막혀 있기 때문이다. 이런 문제도 있다.

그래서 요즘은 특정 조건을 만족하는 형태로 새로 만들어지는 터널에 한해서 터널 안도 점선 차선이 그어지고 차로 변경을 허용하는 추세이다. 교량 쪽은 소식을 못 들었다만, 거기도 좀 더 합리적이고 개방적인 쪽으로 변화가 생겼으면 좋겠다.

2. 철도용 터널과 교량

자동차가 다니는 터널과 교량은 그렇고.. 그럼 이제부터는 철도의 터널과 교량에 대해서 얘기하도록 하겠다.
요즘 만들어지는 큼직한 터널은 도로용이나 철도용이 외관이 크게 차이가 나지 않는 듯이 보인다. 그러나 옛날 초창기에, 특히 철도가 다들 단선 비전철 위주이던 시절에는 그렇지 않았다.

철도 차량은 레일 근처 하부의 폭과 중상부의 폭이 차이가 많이 나는 교통수단이다. 이는 제한된 레일 궤간에서 최대한 큼직한 차량을 굴리기 위한 노력의 결과이다. 그래서 한국의 경우, 법적 차량 한계가 1250mm 이하의 낮은 부위와 그 이상 높은 부위의 폭이 서로 다르게 명시돼 있다.

철도 차량은 자동차와 달리 레일을 한 치도 벗어나지 않고 정밀 정확하게 다니니.. 터널도 그야말로 차량 한계가 허용하는 한계치까지 작게 만드는 게 가능하다. 그래서 터널의 단면조차 차량의 단면과 비슷하게 하부가 상부보다 더 작으며, 단면이 말발굽 모양처럼 돼 있다. 이것은 철도 터널이 자동차용 터널과 결정적으로 다른 특징이다.

사용자 삽입 이미지

뭐, 언제까지나 옛날에 그랬다는 것이다. 요즘은 한 터널 안에 복선 선로를 집어넣고 위에 전차선도 집어넣고.. 또 고속 주행을 위해 공기가 드나들 틈을 더 내기도 하니 철도 터널도 옛날보다야 더 큼직하게 만든다.

그리고 철도는 교량도 좀 특이했다.
옛날에는 철교의 상부에 딱히 난간이나 트러스 같은 게 없었고 생긴 게 참 단촐(?) 소박했다. 뭐, 어차피 레일이 있으니 단순히 통과 차량의 안전을 위한 난간이나 가드레일 따위는 없어도 될 것이다.

과거의 단선 비전철 철길은 선로의 좌우에 아무 인공물이 보이지 않아서 좌우의 창 밖을 보면 자동차를 탈 때보다 자연의 정취랄까 그게 더 강하게 느껴졌다. 반대편 선로라는 것도 없고 전차선 전봇대도 없고.. 침목과 레일이 놓인 자갈밭이 끝인데 그건 양 옆의 시야로는 어차피 보이지 않는다. 열차가 교량을 통과할 때면 그냥 강물 위로 공중에 떠 있기라도 한 것 같다.

그리고 이런 교량은 딱히 ‘도상’이란 게 없어서, 레일 밑에 깔린 침목 아래로 곧장 강물이 출렁출렁 내려다보였다. 자갈밭조차 없었다는 뜻이다. 옛 수인선의 소래철교처럼 말이다.

사용자 삽입 이미지

하지만 오늘날은 이런 식으로 철교를 만들지 않는다. 레일 밑에 아무 지반이 없으면 열차가 지나갈 때 소음과 진동이 주변에 너무 크게 전해지기 때문이다. 궤도 아래에 침목과 자갈 같은 걸 괜히 만드는 게 아니다. 물론 요즘은 나무 침목이나 자갈조차도 안 쓰고 싹 다 콘크리트 땜빵이지만..
자동차 도로도 고속도로 같은 건 옛날처럼 아스팔트를 안 쓰고 이제 시멘트 포장을 하니, 철길 노반과 도로 노반이 생긴 모습이 다 허옇게 비슷해졌다.

내 기분상 도로 교량보다는 철도 교량이 상부에 이렇게 철골 구조물이 치렁치렁 솟아 있는 경우가 많다. 삼각형 그물 모양의 뼈대 구조이다 보니 무슨 3차원 그래픽 와이어프레임을 보는 것 같은데..
단순히 잉여 미관 때문이 아니라 교량을 안정적으로 지탱하기 위해 일부러 만들어 넣은 거라고 한다. 한강 최초의 교량인 한강 철교도 이런 형태로 만들어졌었다. 110여 년 전에 처음 만들어졌을 때부터 말이다.

사용자 삽입 이미지


Posted by 사무엘

2020/07/03 08:35 2020/07/03 08:35
, , , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1769

추억의 옛날 수필

1. 비는 반드시 옵니다 (주 기운) (☞ 전문)

요즘은 전반적으로 장마나 태풍의 위력이 예전 같지 않고.. 기계에다 비유하자면 비구름들의 출력(?)이 좀 시원찮은 것 같다. 비는 대부분 일기예보보다 늦게 적게 내리고 금방 그치는 편이다.

지난 6월, 이례적인 이상 고온이 계속됐을 때 본인은 중학교 시절에 접했던 이 수필이 문득 생각났다.
‘사후약방문’, 그리고 ‘패연히’라는 단어가 인상적이어서 기억에서 잊혀지지 않는다. 비가 패연히 내리는 건 ‘태연히’가 아니라 콸콸 세차게 내린다는 뜻이다.

글쓴이인 주 기운(1928~2007. 3. 16.)에 대해서는 검색해 보니 광주/호남 지방의 유명 문인이었던가 보다.
기일을 보니 내가 곧바로 떠오르는 건.. “아, 이분은 공항철도 1차 구간 개통 딱 1주일 전에 돌아가셨구나.”이다. 철도님이 계시해 주셨다.

그런데 정작 저 글이 언제 쓰여졌는지, 우리나라에 언제 저런 기록적인 폭염과 가뭄이 들었었는지는 알 길이 없다. 카더라 통신에 따르면 1970년대에 신문에 기고된 글이라는데.. 저게 교과서에 소개되어 실린 건 1994년부터라고 한다.
“은전 한 닢”이라든가 “방망이 깎던 노인” 같은 유명 수필도 글이 발표되고 공개된 때는 거의 1970년대이고, 그 글이 다루는 배경은 1930년대인 걸로 난 알고 있다.

2. 아버지의 손 (오 천석) (☞ 전문)

올해 초에는 어느 현직 의사가 “내과 박원장”이라는 자전적인(?) 웹툰을 연재해서 의료인뿐만 아니라 의대 지망생 내지 일반인들에게도 큰 호응과 인기를 얻었다. 그림이며 스토리며 모두 전문 웹툰 작가 뺨치는 퀄티리였다. IT업계에만 월화수목 금금금이 있는 게 아니었군..

특히 몸집 크고 나이 많고 동기들에 비해 어리버리하지만.. 성격은 정말 순진하고 착하던 소대광이라는 의사를 소개한 에피소드는 정말 대박이었다. (☞ 보기)
물론 저건 의사로서 최악에 최악의 상황만 골라서 발생한 예외에 가까운 사례이겠지만.. 실화와 각색의 비율이 어느 정도 되는지 궁금하다. 이 정도면 단편영화 한 편 찍어도 될 것 같다.

요즘은 버스 기사를 폭행하는 것도 가중 처벌되고, 심지어 신호 대기 중이라도 운전 중과 동급으로 취급되도록 법이 바뀌었다. 하물며 밤에 고생하는 의료진을 술 쳐먹은 인간쓰레기들로부터 더 강력하게 보호할 수 없나 안타깝다. 삼청교육대 같은 거 만들어서 삼청의 삼짜만 나와도 무서워서 술이 확 깨는 지경 정도는 돼야 할 텐데.. 뭐 그건 그렇고.

소대광은 처자식을 먹여 살리려고 개원 후에 지나치게 과로하다가 돌연사하고 말았다.
심장에 문제가 생겨서 쓰라린 흉통이 느껴질 때 약을 먹으려고 했는데.. 좁쌀만 한 알약을 실수로 책상과 벽 사이의 좁은 틈새로 톡 떨어뜨려 버렸다. 그걸 큰 손으로 미처 건져내지 못하고 그만..

내과 박원장을 읽으면서 졸피뎀이라는 약이 있다는 걸 알게 됐고, 니트로글리세린이 폭약일 뿐만 아니라 협심증에 대처 가능한 의약품이기도 하다는 걸 알게 됐다.;; 뭐, 의사 약사 지망생들에게는 기본 상식이겠지만 말이다.
그런데.. 생각해 보니 비슷한 스토리가 나오는 옛날 수필이 하나 더 있었다. 바로 “아버지의 손”.

저 글에서는 글쓴이의 선친이 똑같은 협심증 지병 때문에 똑같은 니트로글리세린 약을 처방 받았다.
그러나 선친은 문맹이었던지라, 위급한 상황이 됐을 때 약병을 개봉하지를 못했다. 그래서 병을 돌로 쳐서 깰 생각까지 했지만 미처 그러지 못하고 통증을 호소하다가 최후를 맞이했다. ㅠㅠㅠㅠ

“어린이가 함부로 건드릴 수 없는 안전 뚜껑. 눌러서 돌리면 열립니다”를 읽지 못해서.
게다가 저 글에서도 아버지는 힘 세고 손이 크고.. 영락없이 소대광 같은 캐릭터였다고 묘사된다.

다만, 니트로글리세린은 혈관 문제나 심장병을 근본적으로 치료해 주는 약은 아니다. 글에서도 “그 약만 먹었으면 아버지는 도움을 청할 때까지 버틸 수 있어 안 돌아가셨을 것”이라고 쓰여 있다.
저 약은 환자가 의료진에게 도착할 때까지 생존할 수 있도록 잠시 시간을 벌어 주는 역할만 한다. 하지만 그것만으로도 충분히 매우 유용하며 사람 생명을 구할 수 있다. 마치 심폐소생술처럼 말이다.

저것도 완전히 낯설지는 않게 느껴지는 글인데.. 학교에서 접한 적이 있었나 모르겠다. 교과서 아니면 문학 시험지 지문으로..?? 잘 모르겠다.
참고로 저 글은 초판이 1977년에 나온 책에 소개되었고, 저자의 생몰년도가 1901-1987년이다. 그러니 저 글 역시 다루는 시점은 1930~40년대 정도이지 싶다. 문맹률이 아직 굉장히 높던 시절 말이다.

Posted by 사무엘

2020/07/01 08:35 2020/07/01 08:35
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1768

1. 멀티스레드

지난 날개셋 한글 입력기 9.9에서는 어쩌다 보니 스레드와 관련된 작업이 좀 있었다. 각종 대화상자에서 스레드 작업이 행해지던 것을 중단시켰을 때 프로그램이 멎던 문제를 해결했으며, 반대로 사용자의 타이핑에 실시간으로 반응하며 동작하는 일부 입력 도구에다가는 랙 없이 깔끔하게 동작하기 위해 스레드를 사용하게 하는 옵션을 추가했다. 뭐, 요즘 컴퓨터에서 랙을 걱정할 지경은 아니긴 하지만 말이다.

오랜만에 멀티스레드를 다루다 보니 지금까지 이론으로만 알고 있던 동기화라는 것도 구현해야 했다. worker 스레드는 입력 데이터를 지지고 볶고 열심히 건드리고 있는데, 그걸 표시하는 UI 스레드도 아무 통제 없이 같이 돌아가게 놔 두면 프로그램은 당연히 메모리 에러가 나고 뻗는다.

Critical section을 생성하고 소멸하는 부분은 클래스의 생성자와 소멸자에다 담당시켰는데, 이걸 이용해서 실제로 락을 걸고 푸는 것까지 또 다른 클래스의 생성자와 소멸자로.. 그렇다고 기존 오브젝트의 포인터를 명시적으로 지정하지 않고 자동 구현하는 것은 C++에서 안 되는가 보다. Inner class에서 바깥 class의 non-static 멤버에 접근 가능하지 않으니까..

임계 구간을 잘 설정해야 crash를 막을 수 있다. 하지만 그렇다고 개나 소나 마구 락을 걸어 버리면 성능만 떨어지는 게 아니라 반대로 deadlock이라는 부작용이 발생해서 프로그램의 응답이 멎어 버릴 수 있다. Crash는 사람이 다쳐서 의식을 잃는 것이고, deadlock은 사람이 수술 후 마취에서 못 깨어나는 것과 비슷하다..;;

주로 어떤 상황이냐 하면, UI 스레드가 worker 스레드의 실행이 끝날 때까지 기다리게 됐는데 worker 스레드는 데이터를 고친 뒤 UI 스레드의 응답이 필요한 요청을 해 버릴 때 이렇게 된다. 특히 윈도우에다가 메시지를 보내고 응답을 기다리는 API 함수를 호출하는 것 말이다.

이런 주의 사항을 염두에 두면서 프로그램의 주요 구간에 스레드 동기화를 시켜 놓았다.
당연한 말이지만 한 critical section 오브젝트는 단일 구간이 아니라 코드의 여러 구간에다가도 배치해서 이들 모든 구간을 통틀어서 한 순간엔 한 스레드만이 접근 가능하게 제약을 걸 수 있다. 이게 강력한 면모인 것 같다.

그러고 보니 Windows 프로그래밍 헤더에 들어있는 구조체들 중에는 내부 구조가 딱히 공개돼 있지 않은 것이 좀 있다.
가령, PAINTSTRUCT 내부에 있는 rgbReserved 같은 멤버, STARTUPINFO 내부에 있는 cbReserved2, 그리고 CRITICAL_SECTION도 어쩌면 CPU 아키텍처별로 크기와 내부 멤버가 제각각 다를 가능성이 높은 비공개 구조체이다.
이런 예가 무엇이 더 있을 텐데 궁금하다. 당장은 떠오르지 않는다.

2. C 라이브러리와 스레드 생성 함수

Windows에서 스레드를 생성하는 제일 저수준 API는 잘 알다시피 CreateThread 함수이다.
요즘이야 C++도 C++11부터 언어 라이브러리 차원에서 플랫폼· 운영체제를 불문하고 멀티스레드 기능을 std::thread, std::mutex 같은 클래스로 제공하고 있지만, 이들도 내부적으로는 물론 Windows API 같은 운영체제 API를 호출하는 형태로 구현된다. 심지어 native handle값을 되돌리는 멤버 함수도 제공한다.

(그러고 보니 C++ 라이브러리는 C 라이브러리와 달리 라이브러리의 소스가 공개돼 있지 않은 듯하다.. 소스가 어쩔 수 없이 공개되는 템플릿 쪽은 도저히 알아볼 수 없는 난독화 급으로 작성돼 있고, 내부적으로 호출하는 함수 같은 것은 구현체 소스가 딱히 보이지 않는다.)

C++11 이전에는 Visual C++의 경우, 언어 확장 명목으로 CreateThread (와 ExitThread)를 얇게 감싼 _beginthread[ex] (+ _endthread[ex]) 함수를 독자적으로 제공해 왔다.
얘는 Windows SDK의 헤더와 라이브러리를 끌어들이지 않고도 스레드를 사용할 수 있게 해 주는 동시에.. C 라이브러리가 자체적으로 스레드별로 사용하는 메모리를 제때 할당하고 제때 해제하는 역할도 담당했다.
그렇기 때문에 C/C++ 함수도 사용하면서 Windows용 프로그램을 개발한다면 일반적으로는 운영체제 직통 함수 대신 이런 상위 함수를 사용해서 스레드를 생성해야 한다.

C 라이브러리가 스레드별로 무슨 메모리를 사용하는가 하면.. 전역변수로 단순하게 구현되었지만 지금 관점에서 보면 스레드별로 값이 제각기 보존되어야 하는 정보들 말이다. errno라든가, strtok 함수의 내부 state 및 context.. 비록 이런 것에 의존하는 함수가 그리 많은 건 아니지만 어쨌든 그런 예가 있다.

C 라이브러리에서 제공하는 begin/end 함수는 ex가 붙은 놈과 그렇지 않은 단순한 놈으로 나뉜다. ex는 받아들이는 인자가 Windows API의 그것과 완전히 동일하다. 그에 비해 단순한 놈은 평소에 잘 쓰이지 않는 인자들을 과감히 생략했기 때문에 사용하기가 더 쉽다.

예를 들어 begin 버전은 SECURITY_ATTRIBUTES 정보를 입력받는 부분이 생략됐고, 거의까지는 아니어도 잘 쓰이지 않는 thread ID를 받아들이는 부분도 생략됐다. 또한, 프로세스도 아니고 스레드의 실행 후 리턴값은 거의 쓰이지 않는다는 점을 감안하여 end 버전은 리턴값을 지정하는 부분도 생략되고 그냥 0으로 고정됐다.

참고로 Windows NT의 경우 ReadFile/WriteFile에서 실제로 읽거나 쓰는 데 성공한 양을 받는 DWORD 포인터, 그리고 CreateThread에서 생성된 스레드의 ID를 받는 DWORD 포인터를 생략하고 NULL을 줄 수 있다. 굳이 그 정보들이 필요하지 않다면 말이다. 하지만 과거의 Windows 9x는 저들 함수의 인자에서 NULL을 줄 수 없으며, 그냥 잉여 변수라도 하나 반드시 선언해서 넘겨줘야 한다는 차이가 있었다(NULL 주면 실행 실패).

뭐 그렇긴 한데.. C 라이브러리의 간편 버전은 사용법을 간소화하기 위해 여러 인자들을 생략했을 뿐만 아니라, 스레드 핸들을 CloseHandle로 닫는 것까지 임의로 자동으로 해 버린다. 스레드가 아주 잠깐 동안만 실행됐다가 종료돼 버리는 경우, _beginthread 함수의 리턴값이 나중의 시점에서 유효하다는 보장을 할 수 없다.

이건 사족에 가까운 간소화 조치로 여겨지며, 이 때문에 _beginthread는 사용이 그리 권장되지 않고 있다. 아니면 정말 뒷감당 할 필요 없고 한번 생성된 뒤에 “나는 책임 안 지니 니가 알아서 모든 뒷정리 하고 곱게 사라져라” 급인 스레드를 간편하게 생성하는 용도로나 적합하다. 그게 아니면 번거롭지만 결국은 _ex 함수를 쓰고 핸들은 내가 수동으로 닫아 줘야 한다.

3. 실행 주체들의 종료 리턴값

프로세스와 스레드는 종료될 때 정수를 하나 되돌릴 수 있는데, 아무 일 없이 잘 끝났으면 간단히 0을 되돌리는 게 관행이다. 옛날에 도스에서는 프로세스의 종료 코드를 ERROR_LEVEL이라는 독특한 명칭으로 불렀었다.

프로세스의 종료값은 그럭저럭 고유한 용도가 있으며, 여러 프로그램들을 순차적으로 실행하는 배치 파일이나 스크립트 같은 데서 많이 쓰인다. 종료되고 없는 먼젓번 프로그램의 실행이 성공했는지 여부를 밖에서 알 필요가 있기 때문이다.

하지만 앞에서 잠시 언급한 바와 같이.. 스레드의 종료값은 내 경험상 거의 쓰이지 않는다. 스레드의 종료값을 읽고 판단할 수 있는 코드 자체가 동일 프로세스 안의 다른 스레드밖에 없고.. 한 프로세스 안에서는 굳이 종료값 말고도 스레드의 실행 결과를 알 수 있는 방법이 매우 많기 때문이다. 애초에 같은 메모리 주소 안이니..

또한 스레드는 애초에 여러 작업을 동시에 수행하라고 만들어지지, 배치 파일처럼 여러 스레드를 순차적으로 실행하면서 실행 결과를 확인하는 식으로 운용되지도 않는다. 그럴 거면 그냥 한 스레드에서 순차 실행을 구현하고 말지.. 프로세스와는 여러 모로 사용 여건이 다르다.

그 와중에 Windows에서는 259라는 값이 STILL_ACTIVE라는 의미로 예약돼 있는지라.. 프로세스나 스레드의 종료 리턴값으로 쟤를 돌려주는 것이 금지되어 있다. 자기는 종료되어서 없는데 GetExitCodeProcess/Thread 함수가 저 값을 되돌리고 있으면 다른 프로세스나 스레드는.. 없는 프/스의 실행이 끝날 때까지 기다리면서 데드락 같은 상태에 빠지기 때문이다.

4. 타 프로세스에다 내 스레드 생성하기: CreateRemoteThread

Windows API 중에는 기본적인 기능을 제공하는 함수가 있고, 거기에 덧붙여 어느 프로세스 문맥에서 그 기능을 수행할 것인지를 지정하는 인자가 추가로 붙은 Ex버전이 또 존재하는 경우가 있다.
예를 들어 ExitProcess(현재 프로세스만)의 상위 호환인 TerminateProcess, 그리고 VirtualAlloc에다가 HANDLE hProcess가 추가된 VirtualAllocEx처럼 말이다.

그것처럼 스레드를 생성하는 CreateThread에 대해서도 target 프로세스를 지정할 수 있는 CreateRemoteThread 함수라는 게 있다.
이런 함수들은 내부적으로 구현도 하위 함수를 호출하면 상위 함수에다가 GetCurrentProcess()의 리턴값을 붙여서 호출하는 형태로 돼 있다.

그런데 남의 프로세스 주소 공간에다가 스레드를 생성한다니??
이건 물론 디버거나 보안 솔루션 같은 특수한 프로그램에서나 필요하지 자기 일만 하는 일반적인 프로그램에서 쓰일 일은 없는 기능이다.
그리고 이 함수는 각종 명령 인자들을 준비하는 게 몹시 까다롭기 때문에 타 프로세스에서는 매우 제한된 형태로밖에 활용을 할 수 없다.

제일 근본적으로는.. 실행되어야 할 스레드 함수 코드와 실행에 필요한 데이터들이 몽땅 그 target 프로세스의 메모리에 마련돼 있어야 하며 주소값 또한 걔네들의 문맥으로 줘야 하기 때문이다. 잘못되면? 요청을 한 우리가 아니라 멀쩡히 돌아가던 저 프로세스가 뻑나게 된다.
global hook 프로시저를 지정할 때처럼 DLL에다가만 분리해서 구현해 놓으면 그 DLL이 알아서 거기로 주입.. 그런 것도 없다.

다만, CreateRemoteThread를 이용해서 타 프로세스에다 내 코드를 주입하려면 어차피 DLL을 만들기는 해야 한다. 그 이유는 이렇다.
CreateRemoteThread로 할 수 있는 게 사실상.. 스레드 callback 함수로 LoadLibrary를 지정하는 것밖에 없기 때문이다.

이게 가능한 이유는 (1) LoadLibrary(+ FreeLibrary도)가 machine word 하나를 받아서 word 하나를 되돌린다는.. 스레드 callback 함수와 prototype이 일치하기 때문이며, 그리고 (2) LoadLibrary가 소속된 kernel32.dll은 어느 프로세스에서도 메모리에 load된 주소가 동일 고정이기 때문이다. 즉, LoadLibraryA/W 함수의 주소도 고정이며 예측 가능하다. 요게 핵심이다. 요즘 보안을 위한 대세인 ASLR에서 열외된 영역인 듯..

물론 LoadLibrary에다가 주는 인자는 평범한 숫자가 아니라 포인터이므로 넘겨줄 때 조심해야 한다.
VirtualAllocEx를 이용해서 그 프로세스 문맥에서의 메모리와 포인터 주소를 얻은 뒤, 문자열을 그쪽으로 써 넣을 때도 WriteProcessMemory를 호출해서 하면 된다. 얘는 그야말로 memcpy를 fwrite처럼 구현한 상위 호환 버전이라고 생각하면 되겠다.

LoadLibrary에다가 넘겨주는 문자열 인자로 바로 상대방의 프로세스에서 수행할 작업(뭔가 엿보기, 훅킹하기 등등)이 구현된 내 DLL의 주소를 넣으면 된다. DllMain 함수에서 돌아가는 것이니 몸 사리면서 조심해서 실행돼야 한다.
혹시 내 DLL을 실행하면서 다른 DLL을 읽어 놓아야 한다면 내 DLL을 주입한 것과 동일한 테크닉으로 그런 dependency DLL들을 미리 읽어 놓는 게 좋을 것이다. LoadLibrary를 수행하던 스레드가 실행이 끝났다고 해서 그 DLL들이 해제되는 건 아니기 때문이다.

주입되었던 내 DLL을 빼내는 것도.. 간단하다.
스레드 함수에다가 FreeLibrary를 주고, 인자로는 저 target 프로세스에서 되돌려진 내 DLL의 핸들값을 주면 된다.
target 프로세스에서 되돌려진 핸들값이야 내 DLL의 DllMain 함수의 인자로 들어왔을 테니 모를 수가 없을 테고, 그걸 호스트에다가 전하는 건 어려운 일이 아닐 것이다.

이런 식으로 저 함수에다가 LoadLibrary 대신 ExitProcess를 주면 그 프로세스가 알아서 자기 자신을 강제 종료하게 되니, 사실상 TerminateProcess와 같은 효과도 낼 수 있다.

16비트 시절에는 단일 address 공간에서 시스템 전체에 영향을 끼치는 프로그램을 만드는 게 용이했기 때문에 그에 상응하는 점프/복귀 주소 변조, x86 어셈블리어 삽입 같은 꼼수 테크닉이 유행했었다. 그러나 32비트 이후부터는 방법론이 이렇게 더 고차원적으로 확 바뀌었다.;;

Posted by 사무엘

2020/06/28 08:36 2020/06/28 08:36
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1767

4색 정리, 정사각형 분할 문제

일명 “4색 정리, 4색 문제”는 개념 자체는 마치 페르마의 마지막 정리처럼 초등학생도 이해할 수 있을 정도로 아주 단순하다. 하지만 엄밀한 증명은 20세기의 현대 수학자조차도 감당하지 못할 정도로 난해했던지라, 1976년이 돼서야 컴퓨터의 brute-force 계산 능력의 도움을 받아 간신히 증명됐다.

사용자 삽입 이미지

요즘으로 치면 무슨 머신 러닝을 돌리듯이 당대의 슈퍼컴 두 대를 장정 50일을 돌리면서 가능한 모든 지도 모델에서 증명이 성립함을 확인했다고 한다.
물론 저건 오늘날의 머신 러닝에 비할 바는 못 된다. 내 기억이 맞다면, 1970년대 중반의 크레이 슈퍼컴퓨터는 20여 년 뒤에 등장하여 클럭 속도가 GHz급에 도달한 펜티엄 3~4급 PC와 얼추 비슷한 성능이었다. 요즘 PC라면 GPU 세팅만 잘 하면 하루는커녕 길어야 수십 분~몇 시간이면 시뮬레이션이 끝나지 싶다. 그만치 세상이 많이 변했다.

하지만 1976년은 지금으로부터 무려 45년 가까이 전의 과거이다. 증명할 지도 모델을 설계하고 계산량을 그 시절 컴퓨터로 감당 가능하게 최소화한 것만으로도 독창적인 학술 공로이며, 대학교 수학과 교수 급의 전문가가 아니면 할 수 없는 일이었다.
또한 극도로 비싸고 귀하신 몸이던 슈퍼컴을 당장 실용적으로 필요하던 일기예보나 모의 핵실험, 탄도 예측(?)이 아닌 학술 연구용으로 끌어들여 온 것 역시 해당 연구자의 행정력과 근성과 로비 덕분이었던 셈이다.

한편, 정사각형을 크기가 서로 다른 작은 정사각형들로 분할하는 문제(lowest-order perfect squared squares)도 굉장히 난해하지만 답이 존재는 하는 굉장히 기묘한 문제인데.. 4색 정리와 비슷하다면 비슷한 시기인 1978년에 길이 112짜리 사각형을 21개로 분할하는 해법이 발견됐다. 이 역시 컴퓨터를 동원하여 찾아낸 것이었다.

사용자 삽입 이미지

또한, 저 정사각형들도 최대 4개의 색만으로 서로 경계를 구분하여 칠할 수 있을 테니, 이것도 4색 문제하고 관계가 있다고 볼 수 있겠다. =_=;;
1982년에는 동일 연구자의 후속 연구를 통해 저게 이론적으로 존재 가능한 optimal 내지 lower bound라는 것도 증명됐다. 즉, 20개 이하의 서로 다른 정사각형으로 큰 정사각형을 꽉 채우는 방법은 존재하지 않는다는 것이다.

다만, 가장 작은 정사각형 분할의 하한은 112가 아니라 110이라고 한다. 분할 개수는 21개보다 딱 1개 더 많은 22개이다. 참으로 신기한 노릇이다.

사용자 삽입 이미지

그 전에 컴퓨터의 도움 없이 사람이 찾아낸 가장 단순한 정사각형 분할은 175를 24개로 분할하는 것이었다. (81, 55, 39, …) 1946년에 데오필루스 윌콕스(1912-2014)라는 영국 사람이 발견했다.

사용자 삽입 이미지

정사각형을 서로 다른 정사각형으로 분할하는 방법 자체는 다양한 크기별로 무한히 존재하기라도 하는지? 이게 증명돼 있기라도 한지는 모르겠다. (자명한 닮은꼴은 물론 제외. 작은 정사각형의 크기값들이 모두 서로 소인 것으로 한정)

단지 2차원이 아니라 3차원에서 정육면체를 서로 크기가 다른 정육면체로 꽉 맞게 채운다거나 그 이상의 차원에서 같은 방법으로 hypercube를 채우는 방법은 아예 존재하지 않는다고 한다.
직관적으로 생각해도 명확한 것이... 3차원만 생각해 봐도 그런 정육면체가 있다면 여섯 면이 다 제각기 크기가 서로 다른 정사각형으로 거대한 정사각형을 이룬 모습을 기본적으로 하고 있어야 할 것이다. 하지만 정육면체만으로 그렇게 되는 것은 불가능하기 때문이다.

벡터의 외적이 딱 3차원 벡터에 맞게 존재하는 이항연산이듯이, a^n+b^n=c^n의 정수해가 존재하는 n의 상한이 딱 2인 것처럼.. 정사각형 분할은 딱 2차원 평면에서 존재 가능한 절묘한 문제인 것 같다.

Posted by 사무엘

2020/06/25 19:38 2020/06/25 19:38
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1766

1. 고속도로 톨비

우리가 고속도로를 주행할 때 늘 지불하는 통행료, 일명 톨비라는 건 생각보다 다양한 변수를 감안해서 복잡한 방식으로 산출된다.
가장 간단하게는 “기본 요금 + 주행 거리 * 임률”이며, 임률이 경차 포함 6종의 차종별로 차이가 있는 것까지는 다들 아실 것이다. 민자 고속도로는 여기에 부가세가 추가되어서 살짝 더 비싸진다.

그런데 이 표준 임률은 4차로(편도 2차로)짜리 고속도로 기준이다. 2차로 고속도로에서는 임률이 절반(50%)으로 할인되고, 반대로 6차로 이상의 넓은 고속도로에서는 20% 할증이 붙는다. 이런 제도도 있었다니.. 과거에 열악하던 88 올림픽 고속도로가 통행료를 반값만 받았던 건 단순 예외적인 특례가 아니라 매뉴얼 상의 규정이었다.

물론 오늘날은 2차로 고속도로는 모두들 확장되고 개량되어 사실상 전멸했으며, 1992년 이래로 국내에 새로 건설하는 고속도로는 무조건 4차로 이상의 규모로 만들고 있다.
그러니 2차로 고속도로의 50% 할인 규정은 마치 삼륜차 운전 면허처럼 비현실적인 사문이 됐다. 오늘날 실질적으로 50% 할인을 받고 있는 건 경차이다. 6종 경차의 임률은 1종 소형차의 절반이기 때문이다.

톨비는 여기에다가..

  1. 1~3종 차량(초대형 차량만 아니면 다~)에 한해서 출퇴근 시간대 할인,
  2. 사업용 화물차는 반대로 심야 시간대 할인이 적용된다. 대형 트럭 기사들이 톨비를 할인받으려고 무리해서 밤 시간대를 골라서 다니는 게 이 때문이다.
  3. 소형차는 주말과 공휴일에는 또 반대로 소폭이나마 할증되기도 한다.
  4. 끝으로, 차량이 아니라 사람을 근거로 할인해 주는 장애인 및 국가유공자 할인도 있다. 이 분야로 등급이 높으면 톨비가 아예 완전히 면제되기도 한다.

지난 2014년인가 15년부터는 설과 추석 연휴 3일 동안은 아예 전국의 모든 고속도로에서 모든 운전자를 대상으로 톨비가 면제되기 시작했다. 그 전에 무슨 임시 공휴일 때도 잠깐 면제된 적이 있었지만 그건 일회성 이벤트였고, 명절 면제는 관행이 됐다.

생각보다 변수가 굉장히 많지 않은가?
아 참, 폐쇄식 말고 개방식 구간도 있다는 걸 깜빡했다. 개방식은 차들의 실제 주행 구간을 알 수가 없는데 그럼 전국의 모든 개방식 고속도로 톨게이트는 차종별로 고정된 액수의 통행료를 징수하는지?
자동차 내비에서 경로 계산과 동시에 예상 톨비를 정확하게 계산하는 건 매우 까다로우며, 도로 공사로부터 공인 API/SDK 같은 거라도 받아야 하지 않을까 싶다.

지하철의 운임이 비현실적으로 환승을 자주 하더라도 이론적으로 가능한 최단 거리를 가정하고 산정되듯, 고속도로 톨비도 출발 IC와 도착 IC 사이에 여러 경로가 존재 가능하다면 이론적으로 가능한 가장 저렴한 구간을 가정하고 톨비가 산정될 것이다.

2. 수도권 대중교통 통합 요금제

오늘날 서울과 수도권에서 시외버스 아래 등급의 버스들, 그리고 일반열차 아래 등급의 광역전철과 지하철들은 통합 환승 할인 요금제를 적용받고 있다. 승객은 이용한 교통수단들 중 가장 비싼 것의 기본요금(마을버스 < 시내버스 < 지하철 < 좌석버스 < 광역버스..)부터 시작해서 나머지 추가 요금을 내게 되는데, 추가 요금은 이용한 거리에 비례한다.

대부분의 경우 10km 거리까지가 기본 요금이고, 그 뒤 5km당 100원씩 올라가는 게 원칙이다. 그런데 전철에는 버스에 없는 다음과 같은 바리에이션이 존재한다.

  • 총 이용거리가 50km (기본 10km + 40km, 800원 추가)를 초과하면 이후 거리부터는 8km당 100원으로 임률이 저렴해진다.
  • 단, 서울· 인천· 경기도 구간과 그 바깥 구간을 연속해서 이용하는 경우, 전자의 구간에 대해서만 위의 임률이 적용된다. 충청도(경부선 천안..)나 강원도(경춘선 춘천..) 구간은 무조건 4km당 100원으로 비싸게 계산된다.
  • 공항 철도는 역시 영종대교를 건너는 구간이 제일 비싸다. 10km까지는 900원 고정이지만 그 뒤부터는 1km당 130원으로 폭증한다.
  • 용인과 의정부에 있는 경전철들은 기본요금이 2, 300원 남짓 추가되는 것 말고 임률이 바뀌는 건 없다. 추가 요금이 발생하는 방식이 기존 기본요금 + alpha인지, 아니면 max(기존 기본요금, 경전철 기본요금)인지는 잘 모르겠다.
  • 신분당선은 1차 개통 구간인 강남-정자, 2차 개통 구간인 정자-광교로 구분해서 둘중 한 구간만 이용하면 기본요금 1000원 추가, 모두 이용하면 1300원 추가이다. 물론 거리비례 요금은 별도로.. 2차 구간이 개통했던 직후에는 요금 계산 방식이 더 복잡했고 서울-경기도 경계 구분을 했었지 싶은데.. 저건 그나마 간소화된 형태이다.
  • 경춘선 ITX 청춘, 공항철도 직통열차는 동일 승강장에서 운임 체계가 다른 별도의 좌석형 일반열차를 굴리는 예이다. 누리로는 동일 승강장까지는 아니기 때문에 좀 애매하고..

고속도로와 철도 모두 민자 구간이 등장하면서 요금을 따로 정산할 필요가 생겨서 시스템이 이렇게 복잡해져 있다.

  • 버스/전철 공통 적용: 조조할인
  • 버스: 아무리 장거리여도 추가요금이 기본요금보다 더 많이 발생하지는 않게 보정, 1회 비환승은 기본요금으로만(서울 한정), 다인승
  • 전철: 최단거리 이용 추정 원칙, 운영구간별 요금 정산, 노인 무임

3. 제한 시간

고속도로는 통행료만 지불한다고 다가 아니고.. 회당 체류 시간이 제한돼 있다.
서울 지하철이 5시간 제한이 있듯이 우리나라 고속도로의 제한 시간은 24시간이다. 즉, 진입한 지 하루 안으로는 출구 IC로 나가 줘야 한다. 시간이 경과되면 고속도로에서 도대체 뭘 했는지를 의심받을 수 있고 추가 요금을 내게 된다.

솔직히 이 좁은 땅에서 한쪽 끝에서 반대편 끝까지 이동한다 해도 자동차로 24시간이 넘게 걸릴 일은 없다. 하지만 문제가 되는 건 차로 여러 사람들이 휴게소에서 모인 뒤, 자기 차를 거기에 두고 한두 차량에만 다 모여서 타고 놀러 가서는 며칠 있다가 돌아오는 상황이다. 그러면 그 차들은 고속도로 내부에서 24시간이 넘게 세워져 있게 된다.

글쎄, 이렇게 세워진 차들이 많다면 휴게소에 장기 주차된 차들 때문에 다른 차들이 못 들어와서 문제가 될 수 있다. 그러니 장기 주차가 가능하다고 정식으로 지정된 휴게소에서 추가 요금이라도 내는 조건으로 이런 걸 허용한다면 운전자와 도로 공사들이 모두 윈윈 하는 전략이 나오지 않을까 싶다. 요즘은 화장실과 편의점 정도만 달랑 있는 '주차장' 휴게소도 있으니 말이다. (졸음 쉼터보다 크고 정규 휴게소보다는 작은..)

쉽게 말해 이런 식으로 장기 주차를 양성화 합법화하는 것이다. 주차 요금이 그 차들이 모두 움직일 때 드는 기름값과 톨비와 타지의 주차 비용보다 더 비쌀 리는 절대 없을 테니..
안 그래도 요즘은 하이패스 기술이 발전하고 휴게소도 중간 회차를 굳이 금지하지 않는 형태로 만들어지는 추세이지 않은가? 휴게소에다가 차를 장기 주차했다가 중간 회차하는 것은 마치 휴게소를 고속버스 중간 환승지로 이용하는 것만큼이나 새로운 활용 방안이 될 것으로 보인다.

Posted by 사무엘

2020/06/23 08:36 2020/06/23 08:36
, , , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1765

Windows 운영체제에서 GUI 요소로서 화면에 표시되는 윈도우들은 독자적으로 고유한 위치와 크기를 갖는 popup 및 overlapped 윈도우, 아니면 다른 창의 내부에 부속으로 딸려 있는 child 윈도우라는 두 형태로 나뉜다. 전자는 독립 윈도우이고 후자는 종속 윈도우라고 생각해도 될 것 같다.

그리고 전자는 운영체제가 자동으로 표시해 주는 제목 표시줄, 시스템 메뉴, 최소화/최대화 버튼 같은 걸 가질 수 있고 메뉴도 가질 수 있다. 물론 갖지 않는 것도 자유이며 해당 창의 재량이다.
그럼 반대로 후자는 사정이 어떨까? 차일드 윈도우가 자기가 속한 부모 윈도우 내부에서 또 제목 표시줄과 시스템 메뉴, 최소화/최대화 버튼 따위를 가질 수 있을까?

이에 대해서 결론부터, 답부터 말하자면 다음과 같다.
"외형만 그렇게 나오도록 할 수는 있다. 하지만 운영체제는 child 윈도우를 대상으로는 여느 popup/overlapped 윈도우에서 수행하는 기본 처리를 자동으로 해 주지는 않는다. 그렇기 때문에 창을 그렇게 만들어 놓은 뒤에 우리가 원하는 자연스러운 동작을 구현할 수는 없다. 이건 운영체제에서 의도한 보편적인(?) 방식대로 창을 만들고 활용하는 게 아니기 때문이다."

본인은 마소에서 보편적이지 않은 동작이 존재하는 프로그램을 만든 것을 지난 20여 년에 달하는 세월 동안 딱 하나 발견했다.
바로 HTML 도움말 파일을 생성해 주는 HTML Help Workshop이라는 툴에 내장된 그래픽 에디터이다.

도움말을 띄우면 HTML 도움말 창이 별도의 독립된 창으로 뜨는 게 아니라 자신의 도킹 패널 내부에.. child 형태로 뜬다! 시스템 메뉴와 캡션, 최소/최대화 버튼까지 있는 당당한 독립 윈도우가 무슨 MDI child 윈도우처럼 다른 윈도우 내부에 이상하게 끼여 있는 게 심히 기괴하다. 이런 것도 Windows API를 사용해서 이론적으로 만들 수 있다는 것이다.

사용자 삽입 이미지

그래서 본인도 간단히 실험을 해 봤다.
다음은 껍데기 overlapped 윈도우와 "동일한" 클래스 이름으로 자기 안에 child 윈도우를 또 만들어 돌린 모습이다. 윈도우를 생성할 때 WS_CHILD에다가 WS_CAPTION| WS_SYSMENU| WS_MINIMIZEBOX| WS_MAXIMIZEBOX| WS_THICKFRAME만 주면 됐다.

사용자 삽입 이미지

얘는 언뜻 보기에 그냥 평범한 클래식 MDI 앱처럼 생겼지만 실제로는 그렇지 않다.
자신이 껍데기일 때는 클라이언트 영역을 회색 GetSysColor(COLOR_APPWORKSPACE)로 칠하고, 차일드일 때는 흰색 COLOR_WINDOW로 칠하면 된다. 껍데기와 차일드 둘 다 동일 윈도우 프로시저가 수행한 결과물이다. 자기 창이 껍데기인지 차일드인지의 여부는 WS_CHILD 스타일의 존재 여부만으로 간단히 판별할 수 있다.

그럼 제목 표시줄이 달린 차일드 윈도우들을 저렇게 만들어 놓으면 부모 윈도우라는 틀 안에 종속된 overlapped/popup 윈도우처럼 매끄럽게 동작하는가?
안타깝지만 답은 "전혀 그렇지 않다"이다. 저 상태에서 창들을 마우스로 단 몇 분 동안만 조작해 봐도 이상한 점이 잔뜩 발견될 것이다.

마우스로 child 윈도우를 클릭하면 지금 화면의 제일 겉에 드러난 창이 아니라 엉뚱한 창이 인식된다. 윈도우를 드래그 해 보면 화면에 잔상이 생긴다.
WM_LBUTTONDOWN 메시지를 받은 child 윈도우에다가 SetFocus를 해도 제목 표시줄이 활성화/비활성화 처리가 되지도 않는다.
child 윈도우를 최대화한 모습은 꽤 어정쩡하며, 그 상태로 프로그램 창의 크기를 키워도 child 윈도우는 크기가 갱신되지 않는다.

이런 문제가 발생하는 이유는.. Windows라는 운영체제는 근본적으로 child 윈도우에 대해서는 이들이 서로 겹쳐져 있고 포개져 있을 때의 Z-order 처리를 overlapped/popup 윈도우처럼 정교하게 해 주지 않기 때문이다.
child 윈도우라는 건 저렇게 제목 표시줄과 시스템 메뉴가 있는 윈도우가 아니라.. 그냥 리스트 컨트롤, 에디트 컨트롤, 버튼 같은 물건들이다. 에디트 컨트롤이나 버튼 같은 게 서로 겹쳐질 일이 있고 포커스를 받았을 때 Z-order가 바뀌어야 할 일이 도무지 있는가? 그렇지 않다는 것이다.

사용자 삽입 이미지

더구나 child 윈도우의 제목 표시줄은 Windows 8/10에서도 옛날 Windows Vista/7의 기본 테마 모양 그대로이며 업데이트도 안 돼 있다. 푸르스름하고 모서리가 둥근 그 시절 디자인 말이다. 그만큼 이쪽 외형은 마소에서도 관심이 없으며 더 지원을 안 하고 손을 놨다는 뜻이다.

저 상황에서 화면 잔상이 발생하는 걸 조금이라도 줄이려면 이 윈도우의 클래스에다가는 화면 refresh를 적극적으로 하라고 CS_HREDRAW|CS_VREDRAW 스타일을 줘야 하더라.
그리고 마우스 메시지를 받았을 때 SetWindowPos를 호출해서 이 창의 Z-order를.. HWND_BOTTOM으로 지정해야 하더라. 왜 top이 아니라 bottom인지는 모르겠다.

저것만 한다고 해서 모든 문제가 해결되는 건 아니다. 이런 시행착오를 겪어 보면.. MDI 프로그램에서 일개 child 윈도우인 문서창들이 나름 MDI client 영역 내부에서 껍데기 독립 윈도우인 것처럼 유연하게 처리되는 게, 절대로 그냥 저절로 되는 일이 아님을 짐작할 수 있다. 운영체제 API 차원에서 추가적인/예외적인 보정을 굉장히 많이 해 주는 덕분이지 싶다.

실제로 MDI를 구현하기 위해 사용되는 윈도우 프로시저는 DefFrameProc와 DefMDIChildProc로 감싸져 있으며, 키보드 전처리도 TranslateMDISysAccel로 따로 있다. 대화상자에 고유한 윈도우 프로시저와 키보드 전처리(IsDialogMessage)가 있는 것과 비슷한 맥락이다.

MDI 문서창들은 WS_EX_MDICHILD라는 extended 스타일이 지정돼 있다. 물론 우리야 CreateMDIWindow 함수나 WM_MDICREATE 메시지로 생성 요청만 하기 때문에 저 스타일을 직접 지정할 일은 없다.
내부적으로 뭔가 큰 의미를 갖는 스타일이지 싶은데.. 진짜 MDI 문서창이 아닌 임의의 child 윈도우를 생성할 때 저 스타일을 일부러 줘 보면 CreateWindowEx 함수의 실행이 실패한다. 그러니 쟤는 비록 헤더 파일에 선언은 돼 있지만 사용법과 의미가 제대로 문서화되지 않은 내부 API나 마찬가지이다.

그 밖에 WS_CLIPCHILDREN이라든가 WS_CLIPSIBLINGS, WS_EX_TRANSPARENT는 child 윈도우가 영역이 여럿 겹쳐 있을 때 창들을 refresh 하는 방식이나 성능을 좌우하는 옵션일 텐데 본인은 구체적인 의미나 차이를 잘 모르겠다. 평소에는 몰라도 전혀 상관 없지만 child 윈도우들을 MDI 문서창처럼 정교하게 다루기 위해서는 알아야 할 기능이지 싶다.
이런 창을 마우스로 클릭하면 WM_CHILDACTIVATE라는 메시지도 온다는데 본인은 태어나서 지금까지 한 번도 안 써 봤다. 저런 메시지가 있다는 사실도 처음 알게 됐다.

오늘 이야기의 결론은 MDI 형태의 프로그램을 밑바닥부터 직접 구현하는 건 대단히 어렵고 삽질스럽다는 것이다.. =_=;; child 윈도우를 popup/overlapped 윈도우처럼 다뤄 줘야 하기 때문이다.
그런 데다가 한 프로그램 창 안에서 여러 문서창을 다루는 것은 오늘날 같은 멀티 모니터 환경하고도 그리 어울리지 않는다.

그러니 마소 프로그램들의 경우, Word는 거의 20년 전부터 문서창을 프로그램 창처럼 따로 따로 생성하는 형태로 바뀌었으며 Visual Studio IDE도 문서창을 새 탭 아니면 새 창으로 자유자재로 만들 수 있게 바뀌었다.
그래도 그 정도보다는 규모가 작은 아담한 프로그램에게는 여전히 MDI만 한 대안이 없으니 클래식 레거시 MDI 기능도 오늘날까지 완전히 멸종하지는 않고 명맥을 유지하고 있다.

Posted by 사무엘

2020/06/20 08:35 2020/06/20 08:35
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1764

« Previous : 1 : ... 49 : 50 : 51 : 52 : 53 : 54 : 55 : 56 : 57 : ... 215 : Next »

블로그 이미지

그런즉 이제 애호박, 단호박, 늙은호박 이 셋은 항상 있으나, 그 중에 제일은 늙은호박이니라.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2024/05   »
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Site Stats

Total hits:
2691576
Today:
835
Yesterday:
1354