Форум : WarCraft II

Название : Кракозябры вместо русских букв в меню, nls-фикс bat-файл

© 2005 www.runcms.org
https://www.war2.ru

URL этой темы
https://www.war2.ru/modules/newbb_plus/viewtopic.php?topic_id=2370&forum=1


 il :

28.1.19 13:46
 Захожу русской версией комбата на сервер, а там в некоторых диалогах bnet - вместо слов "победы", "поражения" и т.п. - кракозябры. Например, в профилях пользователей или прямо при входе.

Проблема старая, распространена много где, в том числе во всяких 1с v7 и прочем.
В общем, в старых до-UTF-ных приложениях.
Одно из популярных решений - залезть в реестр и выставить c_1251.nls для всех кодировок. Это решение больше не работает, как минимум с windows 7.
Зато работает подмена nls-файла в c:\windows\system32\c_1252.nls на c_1251.nls.
Конечно, после такой подмены надо перезагрузиться.

Возникла идея встроить эту подмену в русский комбат, чтобы инсталлятор делал это автоматически.
Соответственно, нужен скрипт.

Решение конечно спорное: как минимум, это испортит такие же старые до-UTF-ные приложения на других языках, которые не русский и не английский, которые используют этот самый c_1252.nls.
Но русскоязычные пользователи, думаю, в большинстве своем, такую порчу переживут.
Наоборот, спасибо может быть скажут: многие другие старые русские приложения могут заработать.

В общем, выкладываю скрипт на всеобщее обозрение. Получилось неожиданно много кода, но аккуратно иначе не сделать. На windows 7 и 10 работают, на windows xp не проверял!
Заодно, может быть, кто-нибудь подскажет, может, можно как-то починить русские буквы в вар2 не подменяя nls глобально по всей системе?

Цитата:

@echo off

set SRC_SHORT_FILENAME=C_1251.NLS
set SRC_FILE="%windir%\System32\%SRC_SHORT_FILENAME%"
set DST_SHORT_FILENAME=C_1252.NLS
set DST_DIR=%windir%\System32
set DST_FILE="%DST_DIR%\%DST_SHORT_FILENAME%"
set DST_BACKUP_SHORT_FILENAME="%DST_SHORT_FILENAME%_backup"
set ACL_TMPFILE="%tmp%\%DST_SHORT_FILENAME%_acl_%random%"

if not exist %DST_FILE% goto NOTEXIST_ERR

"%windir%\System32\fc.exe" /b %SRC_FILE% %DST_FILE% >nul
if ERRORLEVEL 1 goto PERM
echo files already similar, nothing to do
goto END_NOTHING

:PERM
"%windir%\System32\icacls.exe" "%DST_FILE%" /save %ACL_TMPFILE%
if ERRORLEVEL 1 goto ACLSAVE_ERR
"%windir%\System32\takeown.exe" /F "%DST_FILE%"
if ERRORLEVEL 1 goto SETOWNER_ERR
"%windir%\System32\icacls.exe" "%DST_FILE%" /grant "%username%":(D)
if ERRORLEVEL 1 goto SETPERM_ERR
ren "%DST_FILE%" "%DST_BACKUP_SHORT_FILENAME%"
if ERRORLEVEL 1 goto REN_ERR
copy %SRC_FILE% %DST_FILE%
if ERRORLEVEL 1 goto COPY_ERR
"%windir%\System32\icacls.exe" "%DST_DIR%" /restore %ACL_TMPFILE%
if ERRORLEVEL 1 goto ACLRESTORE_ERR

echo done
if exist %ACL_TMPFILE% del %ACL_TMPFILE%
goto END_OK

:NOTEXIST_ERR
echo file not exist: %DST_FILE%
goto END_NOTHING
:ACLSAVE_ERR
echo error saving permissions: %DST_FILE% to file: %ACL_TMPFILE%
goto END_NOTHING
:SETOWNER_ERR
echo error changing owner to "%username%": %DST_FILE%
goto END_DELTMP
:SETPERM_ERR
echo error setting permissions: %DST_FILE%
goto END_DELTMP
:REN_ERR
echo error renaming file: %DST_FILE% to %DST_SHORT_FILENAME%
goto END_DELTMP
:COPY_ERR
echo error copying file: %SRC_FILE% to %DST_FILE%
rem if not exist %DST_FILE% ren "%DST_DIR%\DST_BACKUP_SHORT_FILENAME" "%DST_SHORT_FILENAME%"
goto END_NOTHING
:ACLRESTORE_ERR
echo error restoring permissions: %DST_FILE% from file: %ACL_TMPFILE%
goto END_OK

:END_DELTMP
if exist %ACL_TMPFILE% del %ACL_TMPFILE%
:END_NOTHING
exit /b 0
:END_OK
echo if you appeared here, that means you should reboot your computer to take effect
exit /b 1



Это все надо запускать как bat-файл, в режиме администратора, после успешной замены файла надо перезагрузиться.

Что делает скрипт:
просто заменить файл нельзя - нет прав, он системный.
Сначала меняем владельца на себя, потом, будучи владельцем, разрешаем себе его удалять-переименовывать.
Переименовываем, вместо него копируем c_1251.nls
на новый получившийся файл - восстанавливаем права "как было", запрещая себе его удалять, чтобы не ослаблять безопасность системы своими действиями.
Единственное, что не возвращаем как было - владельца файла, т.к. это невозможно штатными средствами, к сожалению.

При любом сбое - пишет ошибку и завершается, в этом смысле безопасен.
Единственный опасный момент: если файл удалось переименовать, но новый не удалось скопировать.
При этом система после перезагрузки почувствует себя очень плохо, хотя не очень представляю, как такое может получиться хотя бы теоретически.

Слеши форматирование грызет если его оформить как код, сделал код в виде цитаты. Ну и выложил файл сюда:
ftp://war2.ru/war2/utils/c_1252.nls.bat

[ Редактировано il в 28.1.19 12:54 ]

[ Редактировано il в 28.1.19 13:02 ]

[ Редактировано il в 28.1.19 13:04 ]

[ Редактировано il в 28.1.19 13:09 ]

 il :

30.1.19 03:47
 Доделал скрипт:
1. сделал отмену изменений (нам же надо не только уметь подменять файл, но и возвращать "как было"). С параметром do - заменить файл, undo - вернуть обратно, без параметров - проверить необходимость изменений. Результат определяется кроме текстовых сообщений по коду возврата.
2. если мы отменяем изменения - логично удалить старые файлы бекапов. Так вот - нюанс в том, что при переименовании какой-то из файлов блокируется. Причем, после переименования файла до перезагрузки заблокирован на удаление файл бекапа, а после перезагрузки - подозреваю, что основной файл c_1252.nls.
Значит, надо корректно обрабатывать ошибку удаления файла. Чтобы и в этом случае адекватно работало и переименование файла, и отмена. Или хотя бы возвращало ошибку, ничего не переименовывая. В итоге работает так: при переменовании туда-обратно без перезагрузок - следующее переименование закончится прогнозируемой ошибкой удаления бекап-файла.
3. при отмене изменений, бепакы удалять можно, но очень аккуратно, только при условии, что они действительно бекапы, а не случайно подвернувшиеся файлики с теми же именами. Сравниваем содержимое перед удалением.
4. подумал, что копирование теоретически может быть не выполнено если диск на 100% переполнен. В этом случае, если переименование туда сработало, значит по идее переименование обратно тоже должно сработать. Добавил.
5. весь скрипт сделан в едином стиле, довольно гибко и расширяемо, во всяком случае, самому мне за него не стыдно, хотя и с учетом специфики bat-файла в олдскульном стиле через set и goto.

Цитата:

@echo off

set ORIG_SHORT_FILENAME=C_1251.NLS
set SYS_DIR=%windir%\System32
set BACKUP_SUFFIX=backup
set BACKUP_UNDO_SUFFIX=backup_undo

set DST_SHORT_FILENAME=C_1252.NLS
set DST_FILE="%SYS_DIR%\%DST_SHORT_FILENAME%"
set ACL_TMPFILE="%tmp%\%DST_SHORT_FILENAME%_acl_%random%"

if "_%1" == "_undo" goto UNDO
if "_%1" == "_do" goto DO
"%windir%\System32\fc.exe" /b "%SYS_DIR%\%ORIG_SHORT_FILENAME%" %DST_FILE% >nul
if ERRORLEVEL 1 exit /b 1
echo files are similar, nothing to do
goto END_NOTHING
:DO
set DST_BACKUP_SHORT_FILENAME=%DST_SHORT_FILENAME%_%BACKUP_SUFFIX%
set SRC_SHORT_FILENAME=%ORIG_SHORT_FILENAME%
set SRC_FILE="%SYS_DIR%\%SRC_SHORT_FILENAME%"
goto START_DEL_OLD
:UNDO
set DST_BACKUP_SHORT_FILENAME=%DST_SHORT_FILENAME%_%BACKUP_UNDO_SUFFIX%
set SRC_SHORT_FILENAME=%DST_SHORT_FILENAME%_backup
set SRC_FILE="%SYS_DIR%\%SRC_SHORT_FILENAME%"
goto START_DEL_OLD
:START_DEL_OLD
if not exist "%SYS_DIR%\%DST_BACKUP_SHORT_FILENAME%" goto START
echo file "%SYS_DIR%\%DST_BACKUP_SHORT_FILENAME%" exist, comparing
"%windir%\System32\fc.exe" /b "%SYS_DIR%\%DST_BACKUP_SHORT_FILENAME%" %DST_FILE% >nul
if ERRORLEVEL 1 goto START
echo file "%SYS_DIR%\%DST_BACKUP_SHORT_FILENAME%" is similar to %DST_FILE%, deleting
del "%SYS_DIR%\%DST_BACKUP_SHORT_FILENAME%"

if exist "%SYS_DIR%\%DST_BACKUP_SHORT_FILENAME%" goto EXIST_AFTER_DEL
:START
if not exist %SRC_FILE% goto NOTEXIST_SRC_ERR
if not exist %DST_FILE% goto NOTEXIST_DST_ERR
"%windir%\System32\fc.exe" /b %SRC_FILE% %DST_FILE% >nul
if ERRORLEVEL 1 goto PERM
echo files already similar, nothing to do
set RESULT=nothing
goto END_NOTHING
:PERM
"%windir%\System32\icacls.exe" %DST_FILE% /save %ACL_TMPFILE%
if ERRORLEVEL 1 goto ACLSAVE_ERR
"%windir%\System32\takeown.exe" /F %DST_FILE%
if ERRORLEVEL 1 goto SETOWNER_ERR
"%windir%\System32\icacls.exe" %DST_FILE% /grant "%username%":(D)
if ERRORLEVEL 1 goto SETPERM_ERR

:REN
ren %DST_FILE% "%DST_BACKUP_SHORT_FILENAME%"
if ERRORLEVEL 1 goto REN_ERR
copy %SRC_FILE% %DST_FILE%
if ERRORLEVEL 1 goto COPY_ERR
:RESTORE_PERMS
"%windir%\System32\icacls.exe" "%SYS_DIR%" /restore %ACL_TMPFILE%
if ERRORLEVEL 1 goto ACLRESTORE_ERR
:ACLSAVE_DELETE
if exist %ACL_TMPFILE% del %ACL_TMPFILE%
set RESULT=ok
if "_%RESULT%" == "_nothing" goto END_NOTHING
if "_%RESULT%" == "_ok" goto END_NOTHING
echo Error! result is unknown
exit /b 2
goto END_OK
:NOTEXIST_DST_ERR
echo file not exist: %DST_FILE%
goto END_NOTHING
:NOTEXIST_SRC_ERR
echo file not exist: %SRC_FILE%
goto END_NOTHING
:EXIST_AFTER_DEL
echo file delete failed: "%SYS_DIR%\%DST_BACKUP_SHORT_FILENAME%"
goto END_NOTHING
:ACLSAVE_ERR
echo error saving permissions: %DST_FILE% to file: %ACL_TMPFILE%
set RESULT=nothing
goto ACLSAVE_DELETE
:SETOWNER_ERR
echo error changing owner to "%username%": %DST_FILE%
set RESULT=nothing
goto ACLSAVE_DELETE
:SETPERM_ERR
echo error setting permissions: %DST_FILE%
set RESULT=nothing
goto ACLSAVE_DELETE
:REN_ERR
echo error renaming file: %DST_FILE% to %DST_SHORT_FILENAME%, restoring permissions
set RESULT=nothing
goto RESTORE_PERMS
:COPY_ERR
echo error copying file: %SRC_FILE% to %DST_FILE%, renaming back: ren "%SYS_DIR%\%DST_BACKUP_SHORT_FILENAME%" "%DST_SHORT_FILENAME%"
ren "%SYS_DIR%\%DST_BACKUP_SHORT_FILENAME%" "%DST_SHORT_FILENAME%"
set RESULT=nothing
goto RESTORE_PERMS
:ACLRESTORE_ERR
echo error restoring permissions: %DST_FILE% from file: %ACL_TMPFILE%
set RESULT=ok
goto ACLSAVE_DELETE

:END_NOTHING
exit /b 0
:END_OK
echo if you appeared here, that means you should reboot your computer to take effect
exit /b 1

 Dar :

30.1.19 10:16
 Ил нам простым смертным нужно что то переустанавливать на своих ПК? Может надо новую версию игры к примеру инсталировать?

 il :

30.1.19 12:02
 Переустанавливать ничего не надо, в принципе, можно просто запустить первую версию скрипта (ее достаточно чтобы подменить файл), только это можно делать на виндовс 7-8-10.
На XP не тестировал, поэтому не советую.

А лучше пока подождать - это в принципе задел на будущее, которое, надеюсь, скоро настанет.

 Dar :

30.1.19 12:53
 Ясно, ну тогда ждемс

© 2005 www.runcms.org
https://www.war2.ru

URL этой темы
https://www.war2.ru/modules/newbb_plus/viewtopic.php?topic_id=2370&forum=1