понедельник, 25 февраля 2013 г.

Shim-ы и RT

С развитием эмулятора x86 Windows на Windows RT - практически каждый день сталкиваюсь с новыми багами в эмулируемых приложениях. Причем, причина некоторых "злостных" багов - не недостатки эмулятора, а кривость рук или природная лень авторов данных приложений.
То, что программы обращаются к блоку памяти после его освобождения или возвращают указатели на строки, выделенные на стеке - это еще мелочи. К выходу за пределы блока памяти  и к тому, что некоторые программы используют исключения Access Violation в своей нормальной работе вместо проверки параметров функций - я уже привык. Но вот некоторые конструкции заставляют переделывать большие участки существующего кода, просто чтобы заставить подобные программы хоть как-то работать. В итоге все-равно получается "не красиво", так как инече просто не реализуемо при использвоании имеющихся x86 движков (это я, например, про использование SuspendThread для синхронизации потоков). Так что вопрос о создании своего х86 движка, неуниверсального, но зато "заточенного" под конкретные нужды - давно решен утвердительно. Осталось только выделить на него время.

Чем больше занимаюсь проектом - тем больше начинаю уважать микрософт в плане поддержки старого софта на новых версиях Windows. И тем больше понимаю, что для осуществления запуска x86 программ на RT банального враппера поверх "родного" API и трансляции x86 команд будет недостаточно. В RT микрософт наконец выкинуло большие куски legacy кода, в некоторых случаях оставшегося еще со времен Windows 1.0, и реализация всех этих "костылей" теперь ложится на меня. Можно просто сравнить размер shim-ов в папке C:\Windows\AppPatch на RT и на настольной Windows 8. В релизе RT есть только несколько тестовых, в то время как в настольной - папка занимает более 10 мб. К счастью, формат базы shim-ов хоть и не документирован официально, но информации по нему предостаточно, так что можно "позаимствовать" данную базу в моем проекте.

По поводу application compatibility, и вообще по историческим апектам того, почему в windows некоторые вещи реализованы именно так, а не иначе - есть неплохой блог the old new thing. Его автор и книгу написал (найти ее скан не проблема), и выложил пару бесплатных глав. Одна из таких глав как раз посвящена историям про совместимость. И, читая данную книгу, я нахожу некоторые ошибки у себя. Как пример такой ошибки - вызов программой функции GetWindowLong(hwnd,DWL_DLGPROC) совершенно не означает, что hwnd == диалог, и программа хочет получить адрес его диалоговой процедуры. Ведь DWL_DLGPROC это просто константа 4, и в случае обычного окна - программа может хотеть прочитать второе слово из своих cbWndExtra, а храниться там может вообще все что угодно. Про это написано по приведенной выше ссылке в разделе "If it has eight bytes, it must be a dialog box".
Приходится определять класс окна (RealGetWindowClass) и смотреть диалог ли это. И только если диалог - добавлять спец обработку для эмуляции x86 диалоговых процедур.

вторник, 19 февраля 2013 г.

Citrix Streaming клиент и некомпилрующийся проект в Visual Studio 2012

В обед на работе "озарила" идея, которую захотелось сразу проверть в своем проекте эмуляторе.  Для проверки - собираю проект студией, стоящей на рабочем ПК, и получаю странные ошибки:

15>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.CppCommon.targets(249,5): error MSB4018: The "CL" task failed unexpectedly.
15>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.CppCommon.targets(249,5): error MSB4018: System.AggregateException: One or more errors occurred. ---> System.ArgumentOutOfRangeException: Not a valid Win32 FileTime.
15>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.CppCommon.targets(249,5): error MSB4018: Parameter name: fileTime
15>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.CppCommon.targets(249,5): error MSB4018:    at System.DateTime.FromFileTimeUtc(Int64 fileTime)

либо:

1>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.CppCommon.targets(611,5): warning MSB6008: Forcing a rebuild of all sources due to an error with the tracking logs. Not a valid Win32 FileTime.
1>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.CppCommon.targets(611,5): warning MSB6008: Parameter name: fileTime
1>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.CppCommon.targets(611,5): error MSB6001: Invalid command line switch for "link.exe". Not a valid Win32 FileTime.
1>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.CppCommon.targets(611,5): error MSB6001: Parameter name: fileTime

Ошибки плавают, возникают то в одном, то в другом месте, но во всех них идет жалоба на "неправильный" FileTime. Причем, Rebuild All - работает, "поломалась" только обычная компиляция.
Как оказалось виноват клиент Citrix (вот на что бы никогда не подумал - так именно на него). Подробнее тут:
http://connect.microsoft.com/VisualStudio/feedback/details/635940/invalid-command-line-switch-for-link-exe-when-building

Мы как раз на работе "играемся" с стримингом приложений цитрикса, чтобы упростить контроль за использованием ПО на рабочих станциях. Я на днях решил протестировать как оно работает на себе, поставил стриминг клиента - и поплатился.
Вылечилось удалением streaming клиента citrix. Вариант с правкой файлов проекта не проверял, так как у меня их более 70 штук в эмуляторе.