beatcracker (
beatcracker) wrote2008-01-07 07:37 pm
![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Карательная локализация на марше
Итак, сегодня я в очередной раз расскажу вам о чудесах современной софтостроительной индустрии. Обычно, для просмотра DVD я использую Media Player Classic, однако, у меня давно было желание попробовать InterVideo WinDVD (нынче купленный Corel) и посмотреть на его фирменную функцию Trimension DNM лицензированную у Philips (используется в ее 100 Гц телевизорах). Вкратце, при ее использовании плеер просчитывает промежуточные кадры, повышая их количество в секунду от стандартных 24 PAL и 25 NTSC до 50, 60 и 75 Гц и 48, 50, 60 и 72 Гц соответственно. Это дает гораздо более плавную картинку, однако расплачиваться приходиться дикой нагрузкой на процессор. У меня местами притормаживает, хотя сам эффект безусловно интересен и фильмы с ним смотрятся совсем по другому. Хотя, поначалу непривычно.
Наигравшись, с различными аудио и видео эффектами, я решил, что было бы неплохо сменить язык интерфейса плеера на английский, т.к. русский прямотой перевода не блистал, и тут началось самое интересное ...
Вот так это выглядело в оригинале:
Погуляв по настройкам плеера, я к своему удивлению не нашел, как сменить язык. Странно. Может быть что-то в реестре? Недолгий поиск вывел меня на ветку HKEY_LOCAL_MACHINE\SOFTWARE\InterVideo\DVD8 одним из параметров в которой было следующее
LANGUAGE="RCRUS"
Меняю значение на "RCENU" и перезапускаем плеер. Никакого эффекта :( ... Бывает (с) ... Заглядываю в ветку-близнец в HKEY_CURRENT_USER\Software\InterVideo\DVD8 - ничего похожего, жаль. Однако, может быть я не угадал значение? Например, надо было вписать "RCENG", или что-то подобное. Чтобы не гадать лишний раз, ищем по всем файлам в каталоге WinDVD строку "RCRUS". Получаем кучу файлов. Наметанный глаз отметает все ocx и ax, т.к вряд-ли такие настройки будут вынесены в контролы реализованные, как COM-обьекты и DirectShow фильтры. Остаются два файла: "AppAIO.dll" и собственно "WinDVD.exe". "AppAIO.dll" занимает два мегабайта, против 700Кб в "WinDVD.exe", поэтому решено было начать с него. Открываем встроенным просмотрщиком TC и видим следующее (выделение красным - мое):
Я был прав и писать надо было действительно "RCENU", но большой радости это не приносит, т.к не работает в любом случае. Тут у меня возникает глупая мысль, "а есть ли вобще в плеере англоязычные ресурсы?". Вполне возможно, что нет и я занимаюсь ерундой. Открываем тот-же "AppAIO.dll" в ResHacker:
Отлично, ресурсы есть, значит дело в чем-то другом. По идее, если в exe присутствуют ресурсы для разных языков, Windows должен сам выбрать нужные ресурсы при запуске приложения, и зависит это от региональных настроек. Иду в панель управления, в "Языках и стандартах" меняю все на "Английский" и жму "Применить". Запускаю WinDVD - безрезультатно. Возможно, надо было перезагрузиться, однако, такой вариант меня не устраивает еще больше чем смена локали, поэтому будем искать другой способ.
Быстро поглядев несколько других файлов, в которых встречалась строка "RCRUS", заметил, что этот блок в них отличается от аналогичных, в "WinDVD.exe" и "AppAIO.dll". В этой парочке рядом со списком языков фигурирует еще загадочное "GetUserDefaultUILanguage". По виду очень напоминает api-функцию. Быстрый гугель подтверждает мои догадки. Дело за малым, засовываем "AppAIO.dll" в дизассемблер (в этот раз я не стал пользоваться IDA, а взял более легкий и простой HDasm, для моих целей его вполне достаточно). HDasm дизассемблирует практически мгновенно, и вот уже я просматриваю список импортируемых функций. Странно, но "GetUserDefaultUILanguage" там нет. Ищу ссылки на строки и нахожу нужный кусок кода. Оказывается, функция вызывается явно, через GetProcAdddress:
Однако интересно не это, а то, что идет выше, т.е. откуда вызывается эта функция. Вкратце логика такова: по адресу 1000BA40 вызывается кусок кода, вызывающий GetUserDefaultUILanguage, а затем это значение скармливается функции SetThreadLocale. Говорящее название, гуглим:
Sets the current locale of the calling thread.
BOOL SetThreadLocale (
LCID Locale
);
говорит нам MSDN. Попутно находим пост в блоге одного из разработчиков Майкрософт: Why I think the thread locale really stinks и What are these directories called 0409 and 1033? в The Old New Thing.
Отлично, выглядит как раз, как то, что нам нужно. Чтобы проверить свою догадку, открываю "AppAIO.dll" в HIEW и вбиваю по адресу 1000BA40 СС (int3). Запускаю WinDVD, всплывает OllyDbg, исправляю СС обратно на E8, прохожу вызов "GetUserDefaultUILanguage" и обнаруживаю в eax, как и ожидалось "419h". Это русская локаль (1049 в десятичной системе). Теперь попробуем поменять на английскую (409h=1033). Все проходит хорошо, однако интерфейс плеера все еще на русском. Вспоминаю, что видел такой-же код в "WinDVD.exe". Так и есть, по адресу 408BA0 находится код, абсолютно идентичный тому, что был в "AppAIO.dll". Делаем все по аналогии, и вуаля! После того, как я заменил в eax значение 419h на 409h и продолжил выполнение программы, я увидел почти родной английский язык :)!
Все бы хорошо, но мне нужно, чтобы английский включался без шаманства с отладчиком. А что, если не вызывать "GetUserDefaultUILanguage", а сразу занести в eax нужную нам локаль? Пробуем: открываем в HIEW "WinDVD.exe", и в режиме ассемблирования вписываю вместо call 408BB0 - mov eax, 409. Мне повезло и размер новой команды в точности такой же, как у предыдущей, так что мне не приходиться извращаться с прописыванием кода в незанятом месте и прыжками туда и обратно. Теперь код выглядит так:
00408BA0: B809040000 mov eax, 00000409
00408BA5: 0FB7C0 movzx eax, ax
00408BA8: 50 push eax
00408BA9: FF1504014200 call KERNEL32.SetThreadLocale
00408BAF: C3 ret
Запускаем ... Ура, работает!
На всякий случай, я оставил пропатченными "AppAIO.dll" и "WinDVD.exe", хотя на мой взгляд, вполне достаточно патча одного exe.
Однако, странный у разработчиков принудительно-добровольный подход к локализации, не находите? На самом деле, если внимательно посмотреть, то по адресу 41276A в "WinDVD.exe" есть ссылка на строковый ресурс "ChangeLanguage" и еще чуть ниже на диалог "IDD_NEC_RESOLUTION", который присутствует в exe. Однако способа добраться до них я не нашел (да и не особенно искал, мое решение меня вполне устраивает :).
P.S. Кстати, Trimension DNM, из-за которого собственно и разгорелся всеь сыр-бор как выяснилось не единственная в своем роде. Я нагуглил очень интересную разработку на compression.ru: AviSynth MSU Frame Rate Conversion Filter. Вот результаты его работы (из статьи по предыдущей ссылке):
Выглядит впечатляюще. Обсуждение работы этого фильтра - здесь.
UPD. По просьбам трудящихся - патч
Наигравшись, с различными аудио и видео эффектами, я решил, что было бы неплохо сменить язык интерфейса плеера на английский, т.к. русский прямотой перевода не блистал, и тут началось самое интересное ...
Вот так это выглядело в оригинале:
Страшный зверь "Субтитр" и "Установка..." неизвестно чего вгоняют в уныние. Не говоря о не переведенном пункте меню ...
Погуляв по настройкам плеера, я к своему удивлению не нашел, как сменить язык. Странно. Может быть что-то в реестре? Недолгий поиск вывел меня на ветку HKEY_LOCAL_MACHINE\SOFTWARE\InterVideo\DVD8 одним из параметров в которой было следующее
LANGUAGE="RCRUS"
Меняю значение на "RCENU" и перезапускаем плеер. Никакого эффекта :( ... Бывает (с) ... Заглядываю в ветку-близнец в HKEY_CURRENT_USER\Software\InterVideo\DVD8 - ничего похожего, жаль. Однако, может быть я не угадал значение? Например, надо было вписать "RCENG", или что-то подобное. Чтобы не гадать лишний раз, ищем по всем файлам в каталоге WinDVD строку "RCRUS". Получаем кучу файлов. Наметанный глаз отметает все ocx и ax, т.к вряд-ли такие настройки будут вынесены в контролы реализованные, как COM-обьекты и DirectShow фильтры. Остаются два файла: "AppAIO.dll" и собственно "WinDVD.exe". "AppAIO.dll" занимает два мегабайта, против 700Кб в "WinDVD.exe", поэтому решено было начать с него. Открываем встроенным просмотрщиком TC и видим следующее (выделение красным - мое):
Я был прав и писать надо было действительно "RCENU", но большой радости это не приносит, т.к не работает в любом случае. Тут у меня возникает глупая мысль, "а есть ли вобще в плеере англоязычные ресурсы?". Вполне возможно, что нет и я занимаюсь ерундой. Открываем тот-же "AppAIO.dll" в ResHacker:
Отлично, ресурсы есть, значит дело в чем-то другом. По идее, если в exe присутствуют ресурсы для разных языков, Windows должен сам выбрать нужные ресурсы при запуске приложения, и зависит это от региональных настроек. Иду в панель управления, в "Языках и стандартах" меняю все на "Английский" и жму "Применить". Запускаю WinDVD - безрезультатно. Возможно, надо было перезагрузиться, однако, такой вариант меня не устраивает еще больше чем смена локали, поэтому будем искать другой способ.
Быстро поглядев несколько других файлов, в которых встречалась строка "RCRUS", заметил, что этот блок в них отличается от аналогичных, в "WinDVD.exe" и "AppAIO.dll". В этой парочке рядом со списком языков фигурирует еще загадочное "GetUserDefaultUILanguage". По виду очень напоминает api-функцию. Быстрый гугель подтверждает мои догадки. Дело за малым, засовываем "AppAIO.dll" в дизассемблер (в этот раз я не стал пользоваться IDA, а взял более легкий и простой HDasm, для моих целей его вполне достаточно). HDasm дизассемблирует практически мгновенно, и вот уже я просматриваю список импортируемых функций. Странно, но "GetUserDefaultUILanguage" там нет. Ищу ссылки на строки и нахожу нужный кусок кода. Оказывается, функция вызывается явно, через GetProcAdddress:
Однако интересно не это, а то, что идет выше, т.е. откуда вызывается эта функция. Вкратце логика такова: по адресу 1000BA40 вызывается кусок кода, вызывающий GetUserDefaultUILanguage, а затем это значение скармливается функции SetThreadLocale. Говорящее название, гуглим:
Sets the current locale of the calling thread.
BOOL SetThreadLocale (
LCID Locale
);
говорит нам MSDN. Попутно находим пост в блоге одного из разработчиков Майкрософт: Why I think the thread locale really stinks и What are these directories called 0409 and 1033? в The Old New Thing.
Отлично, выглядит как раз, как то, что нам нужно. Чтобы проверить свою догадку, открываю "AppAIO.dll" в HIEW и вбиваю по адресу 1000BA40 СС (int3). Запускаю WinDVD, всплывает OllyDbg, исправляю СС обратно на E8, прохожу вызов "GetUserDefaultUILanguage" и обнаруживаю в eax, как и ожидалось "419h". Это русская локаль (1049 в десятичной системе). Теперь попробуем поменять на английскую (409h=1033). Все проходит хорошо, однако интерфейс плеера все еще на русском. Вспоминаю, что видел такой-же код в "WinDVD.exe". Так и есть, по адресу 408BA0 находится код, абсолютно идентичный тому, что был в "AppAIO.dll". Делаем все по аналогии, и вуаля! После того, как я заменил в eax значение 419h на 409h и продолжил выполнение программы, я увидел почти родной английский язык :)!
Все бы хорошо, но мне нужно, чтобы английский включался без шаманства с отладчиком. А что, если не вызывать "GetUserDefaultUILanguage", а сразу занести в eax нужную нам локаль? Пробуем: открываем в HIEW "WinDVD.exe", и в режиме ассемблирования вписываю вместо call 408BB0 - mov eax, 409. Мне повезло и размер новой команды в точности такой же, как у предыдущей, так что мне не приходиться извращаться с прописыванием кода в незанятом месте и прыжками туда и обратно. Теперь код выглядит так:
00408BA0: B809040000 mov eax, 00000409
00408BA5: 0FB7C0 movzx eax, ax
00408BA8: 50 push eax
00408BA9: FF1504014200 call KERNEL32.SetThreadLocale
00408BAF: C3 ret
Запускаем ... Ура, работает!
На всякий случай, я оставил пропатченными "AppAIO.dll" и "WinDVD.exe", хотя на мой взгляд, вполне достаточно патча одного exe.
Однако, странный у разработчиков принудительно-добровольный подход к локализации, не находите? На самом деле, если внимательно посмотреть, то по адресу 41276A в "WinDVD.exe" есть ссылка на строковый ресурс "ChangeLanguage" и еще чуть ниже на диалог "IDD_NEC_RESOLUTION", который присутствует в exe. Однако способа добраться до них я не нашел (да и не особенно искал, мое решение меня вполне устраивает :).
P.S. Кстати, Trimension DNM, из-за которого собственно и разгорелся всеь сыр-бор как выяснилось не единственная в своем роде. Я нагуглил очень интересную разработку на compression.ru: AviSynth MSU Frame Rate Conversion Filter. Вот результаты его работы (из статьи по предыдущей ссылке):
|
|
Выглядит впечатляюще. Обсуждение работы этого фильтра - здесь.
UPD. По просьбам трудящихся - патч