올해의 추석은 유난히도 길어서 컴퓨터까지 가지고 본가에 돌아와서 뒹굴뒹굴 하고 있습니다.
음식 만드는 것을 돕고, 먹고, 자고, 먹고, 자고, 운동하고, 먹고, 자고의 반복.
6일이나 마음 편히 쉬었더니 슬슬 추석이 끝난 이후에 해야할 일들이 생각납니다.
그래서 휴일에도 일 해야하는 생각을 하고 있으니 기분이 안좋아져서 장난감을 샀습니다.

▲ Voiceroid2 Yuzuki Yukari(結月ゆかり)
보이스로이드를 샀습니다.
보이스로이드는 TTS 프로그램이고, 기능은 당연히 문장을 소리로 읽어주는 기능을 합니다.
일본 프로그램이므로 일본어만 읽을 수 있습니다. 영어도 읽을 수 있지만... 카타카나로 읽기 때문에 일본어만 읽을 수 있다고 표현하겠습니다.
그래서 뭘 하기 위해 이 전자아가씨를 샀냐면...
파이널판타지 14 글로벌 서버에서 게임할 때 채팅을 읽어줬으면 했습니다. 운전할 때 네비게이션처럼요.

▲ 쏟아지는 일본어 속에 얼마 안되는 한자조차 잘 못읽는 현대판 문맹이 있습니다.
예전에 개인적인 부탁으로 카카오 API를 쓰지 않고 직접 카카오톡의 대화창의 Child Window를 가져와서 SendMessage를 이용해 조작한 적이 있습니다.
그래서 비슷한 느낌으로 보이스로이드의 TextBox를 포함한 Child Window를 찾아서 조작하는 것으로 쉽게 가능할 것이라고 생각했죠...
GitHub에도 그렇게 구현한 보이스로이드 연동 프로그램이 몇 가지 있었습니다.
그래서 가능할거라고 생각했는데... 연동 프로그램의 버전이 하나를 빼고는 구버전의 보이스로이드에 대응하는 프로그램이었습니다.
으... 담담하게 써내려왔지만 Spy++ 로 Child Window가 없는 것을 확인하고... 코드로도 Child Window를 찾으려고 해봤는데 null만 받고...
프로그램 구조에 대해 무지한 댓가로 많은 시간을 소비했습니다.
그리고 stackoverflow와 github를 전전하던 중에 Snoop 이라는 프로그램을 알게 됐습니다.

▲ Snoop으로 Voiceroid2의 구조를 훔쳐본 결과
Snoop을 통해서 위 그림처럼 Voiceroid2의 구조를 확인할 수 있었습니다. TextBox의 클래스가 TextBoxEx라는 것도 확인할 수 있었죠.
Snoop으로 알게 된 것은 다른 것보다 일단 접근 방법을 모를 뿐, 구조는 제가 알고 있는 것에서 크게 다르지 않다는 것입니다.
제가 생각했던 방식(Child Window 탐색 -> SendMessage)은 Win32API 구조에서 가능한 것이고 지금 제가 눈 앞에 두고 있는 Voiceroid2는 WPF 구조라는 것도 이 시점에서 알게 됐습니다. 여기까지가 약 9시간을 들여다봐서 얻은 것입니다. 허허허....
WPF 구조에 대한 것과 WPF에서 TextBox를 위한 찾기 위해 어느정도 감을 잡고 구글링을 하는 중에 UI Automation 과 Visual Tree Helper에 대해서 알게 됩니다.
위에서 여러 개의 연동 프로그램 중에 '하나를 빼고' 구버전하고만 연동되었다는 말을 적었었는데...
유일하게 Voiceroid2도 연동되는 프로그램이 ルーチェ님의 VoiceroidUtil 입니다. (루체라고 읽습니다.)
그리고 친절히도 GitHub에 코드까지 공유가 되어있는 프로그램입니다.
작업을 시작할 때쯤에 VoiceroidUtil의 코드도 봤었는데 제가 참조하기엔... 제 수준이 너무 낮아서 어떻게 읽을 수가 없었습니다.
VoiceroidUtil의 코드에선 Child Window에서 TextBox를 찾아오는 것 같은 부분도 검색이 안되고 싶어서 마지막 보루로 미뤄놓았었죠...
UI Automation과 Visual Tree Helper에 대해 알고나서 VoiceroidUtil의 코드를 봤을 때 UI Automation과 관련된 코드를 찾을 수 있었습니다.
결국 저는 UI Automation을 공부해야한다는 결론을 얻었죠!
일 생각하기 싫어서 산 장난감이... 공부하고 일이나 하라는 교훈을 줬습니다.
그리고 루체님의 트위터에서 저랑 비슷한 목적을 갖고 물어보신 분이 있었나봅니다.
그에 대한 루체님의 답변

그리고, Win32API로 직접 Window Handle을 조작하는 하는 방법은
WPF 프로그램에서 사용할 수 없기 때문에 어느 정도 공부한 이후에도 관심이 생긴다면
UI Automation 등에도 손을 대보면 좋습니다.
예를 들어 VOICEROID2는 Win32API 로는 Common Dialog 이외에는 조작할 수 없습니다.
Common Dialog는 MainWindowHandler를 의미하는 것 같네요.
제가 계속 붙잡고 있던게 MainWindowHandler 였습니다. (...) 제가 트위터를 할 줄 몰라서 이전 대화가 어떤지는 모르겠네요.
비록 Voiceroid 관련 뿐만 아니라도, 루체님의 코드가 세련되고 정갈한 구조인 것 같아서 C# 코딩에 있어선 하나의 교과서를 얻은 기분입니다.
얼른 UI Automation을 공부해서 유카리가 글을 읽도록 해야겠네요. :D
ルーチェ님의 GitHub : https://github.com/ruche7
ルーチェ님의 Homepage : http://www.ruche-home.net/