Windows 7 Media Center ve Media Center SDK Uyumsuzluğu
Birkaç gün önce kullandığım Media Center için plug-in yazma ihtiyacı doğdu. Bilgisayarımda ise Windows 7 yüklü olduğundan, Media Center 6.1 versiyonunu kullanıyorum. Plug-in’i yazmak için öncelikle Media Center SDK’sına ihtiyacım oldu. Media Center plug-in’leri managed ortamda host edildiğinden plug-in’lerimizi .NET platformu altında yazmamız gerekiyor. SDK’yı indirdim ve Media Center projesini açıp plug-in’i yazmaya başlamıştım. Ta ki ilk Build işleminin başarsız olmasına kadar.
Aslında Build işlemi Compiling anlamında başarılıydı. Başarısız olan kısım compile edilen Media Center plug-in Dll’inin McmlVerifer tarafından verify edilme işleminde idi. Aşağıda gördüğünüz post-build sırasında McmlVerifier’in çökmesini görüyoruz.
Output Window’da ise şu hatayı görmekteyiz.
Unhandled Exception: System.MissingMethodException: Method not found: ‘Void Microsoft.MediaCenter.UI.Application.RegisterUIThread()’.
at MediaCenter.McmlVerifier.Main()
Hatadan anladığımız, Main metodunda kullanılan RegisterUIThread() adlı metodun olmaması. Bu noktada SDK’nın post-build event (inşa sonrası olay) sırasında kullandığı McmlVerifer’in neden RegisterUIThread metodunu bulundurmadığı sorusu aklımıza gelebilir. Ben de burada kullanılan SDK’nın son sürüm Media Center ile farklılık gösterdiğini düşündüm ve bunun doğruluğunu kesinleştirmek için araştırma kısmına geçtim. İlk önce .NET Reflector ile McmlVerifier.exe dosyasını inceledim. Çünkü McmlVerifier bir .NET uygulamasıdır.
McmlVerifier.exe %windir%\ehome dizini altında bulunmaktadır. Uygulamayı .NET Reflector ile yükleyip Main metodunun kodunu incelediğimizde gerçekten Main metodu içinde RegisterUIThread çağrısı yapıldığını görüyoruz.
Seçili satırda görüldüğü gibi RegisterUIThread Microsoft.MediaCenter.UI isimli assembly’deki Application sınıfına ait static bir metod. Uygulamanın aldığı referansa bakarsak alınan referansın geçersiz olduğunu görüyoruz. Çünkü ortada uygulama ve reference library uyumsuzluğu mevcut.
Görüldüğü gibi sistemimde yüklü Microsoft.MediaCenter.UI assembly’si 6.1 versiyonunda. Burada şu sonucu çıkarabiliriz. Media Center SDK kurulur iken McmlVerifer dosyasını güncellemek istemiş ve var olan yeni McmlVerifier.exe üstüne overwrite etmiş görünüyor. Zaten incelerken yeni versiyon Microsoft.MediaCenter.UI assembly’sinin Application sınıfında RegisterUIThread metodunun olmadığını gördüm. İncelediğim kadarı ile bunun sebebi yeni versiyon assembly’nin UI Thread’i haricen register etmesi yerine otomatik olarak kendi içerisinde bir Dispatcher yardımı ile UI işlemlerini yapıyor olması. Çünkü Windows 7 ile gelen Media Center WPF tabanlı animation yöntemlerini kullanmaktadır ve UI işlemleri için Dispatcher kullanılır. Dispatcher sayesinde UI manager’a aktif thread context’inin verilmesine gerek yoktur.
Peki, sorunun belirlediğimize göre çözümler ne olabilir?
Bu problemin çözülmesi için ya ilgili McmlVerifer kodunun RegisterUIThread metodunu çağırmasını engellemek ya da orjinal 6.1 versiyon McmlVerifer uygulaması ile değiştirmek yeterli gelebilir . Ben varolan McmlVerifier’den nasıl RegisterUIThread metodunu devre dışı bırakacağınızı anlatmak istiyorum.
Hatırlayalım. McmlVerifier Main metodu içinde RegisterUIThread metodunu çağıran kısım
L_000a: call void [Microsoft.MediaCenter.UI]Microsoft.MediaCenter.UI.Application::RegisterUIThread()
Kodu idi. MSIL olarak göstermek bize fayda sağlayacak. Yani metodun 0xA offseti ilgili kodu barındırıyor. Şimdi ilgili metodu patch etmek için ayrı CFF Explorer ile inceleyelim.
Görüldüğü gibi .NET Directory’si altında .NET’e ait bilgiler bulunuyor. Buradan ilk table düğümü de .NET’in Referans, Metod, Field gibi bilgilerini tutmaktadır. Zaten bu bilgiler sayesinde .NET Reflector gibi uygulamalar .NET uygulamalarını decompile edebiliyorlar. Ve tabi bu bilgiler decompiling için değil managed bir ortam sağlamak için bulunması gereken bilgiler. Main metodunu görüyoruz. İlgili metodu MSIL olarak disassembly edelim.
Dissambly sonrası demin öğrendiğimiz gibi 0xA offsetinde ilgili metod çağrısı ve bu metodun adresi mevcut. Bizim burayı nop işlemine sokmamız bu kısmı deaktif etmeye yarayacaktır. Bu uygulama için metodun ham ofset adresi;
RVA: 0x20d0 -> Offset: 0x2d0 + .0xC ( 12 byte NET kod giriş header bilgisi için) + 0xA (RegisterUIThread ofset) = 0x2e6 = Path edilecek offset.
komut uzunluğumuz ise 0x5 byte.
Bizim bu arayı MSIL Nop ile doldurmamız yeterlidir. Yani 0x0. Buradaki nop işlemini x86 assembly’deki 0x90 nop ile karıştırmayın. MSIL x86 instruction set’ten tamamen farklıdır.
Bu işi kolaylıkla yapabilmeniz için minik bir tool yazdım. Kaynak kodları ile birlikte vereceğim. Ama öncelikle nasıl kullanılır görelim.
Bir console açın. Ama console’u açarken “Run As Administrator” veya “Yönetici Olarak Çalıştır” seçeneği ile açmanız gerek. Aksi halde uygulama patch işlemini yapamayabilir. Ben administrator yetkileri ile console’u açtığınızı varsayıyorum. Bu işlemden sonra “mcmlverifierpatch McmlVeriferPath” komutunu kullanarak patch işlemini tamamlıyorsunuz. McmlVerifier’ın varsayılan olarak yolu C:\Windows\ehome\McmlVerifier.exe’dir.
Patch yaptıktan sonra .NET Reflector’da ugulamaya bakalım.
Uygulama başarıyla patchlenmiş. Şimdi uygulamayı rahatlıkla çalıştırabiliriz. Visual Studio ile projemizi yeniden derlediğimizde mutlu sonuca ulaşıyoruz.
Compile complete — 0 errors, 0 warnings
LVMForMediaCenter -> D:\src\LVMForMediaCenter\LVMForMediaCenter\bin\Debug\LVMForMediaCenter.dll
%windir%\eHome\McmlVerifier.exe -verbose -assemblyredirect:”D:\src\LVMForMediaCenter\LVMForMediaCenter\bin\Debug” -directory:”D:\src\LVMForMediaCenter\LVMForMediaCenter\Markup”
Microsoft (R) MediaCenter Markup Language (MCML) Verifier version 1.00
Copyright (C) Microsoft Corporation 2006. All rights reserved.
file://D:\src\LVMForMediaCenter\LVMForMediaCenter\Markup\Button.mcml – OK!
file://D:\src\LVMForMediaCenter\LVMForMediaCenter\Markup\Controls.mcml – OK!
file://D:\src\LVMForMediaCenter\LVMForMediaCenter\Markup\Menu.mcml – OK!
file://D:\src\LVMForMediaCenter\LVMForMediaCenter\Markup\RepeatItem.mcml – OK!
file://D:\src\LVMForMediaCenter\LVMForMediaCenter\Markup\Styles.mcml – OK!
file://D:\src\LVMForMediaCenter\LVMForMediaCenter\Markup\Test.mcml – OK!
No errors detected.
Evet. Bu yazının da sonuna geldim. Umarım faydalı olmuştur. Unutmadan patch tool’u ve kodunu. Buradan indirebilirsiniz.
İyi geceler…