dotPeek 早期アクセスビルド版をリリース
ちょっと誤解していた。
てっきり ReSharper の一部としてリリースされると思っていたのだけれど、単独ツールだった。
しかも名言しているように "Free .NET Decompiler" だ。
http://www.jetbrains.com/decompiler/
すばらしい。
Decompile ツールいろいろ。
.NET Reflector の有料化が決まってから、 いろいろ decompile ツールが出てきた。
いろいろ選択肢があるようなので、知りうる限りを以下に纏めてみる。
ツール名 | 開発元 | URL、ほか | 解説 | ||||
.NET Reflector | redgate | http://reflector.red-gate.com/ | 7から完全商用に。6.5を無期限無料版として提供することを決めた | ||||
JustDecompile | telerik | http://www.telerik.com/products/decompiling.aspx | Beta ながら 永遠に無料であることを謳っている | ||||
ILSpy | SharpDevelop | http://wiki.sharpdevelop.net/ilspy.ashx | redgateのs商用アナウンスを受けて開発。使い勝手も .NET Reflector 似ている。 | ||||
dotPeek | JetBrains | @dotPeek | 次期ReSharperに導入されるdecompiler機能。ReSharperに内蔵されるので有償と思われる |
C# アプリケーションでミニダンプを生成してみた
ずいぶん前に C# で minidump を生成する方法という記事を見つけていたのだけれど、今更引っ張り出して試してみた。
# 理由は自宅に帰れなくなったからなんだけど、そこは気にしない。
元ネタ
ここに記載されている MiniDump クラスを感謝しつつ、まるっともらいました。
http://blogs.msdn.com/b/dondu/archive/2010/10/24/writing-minidumps-in-c.aspx
minidump を生成する
MiniDump クラスはこんな感じ。
コードを見るとわかりますが、dbghelp.dll にある MiniDumpWriteDump 関数を P/Invoke で呼び出してダンプを生成してます。
using System; using System.Diagnostics; using System.Runtime.InteropServices; namespace MiniDumpSample { public static class MiniDump { // Taken almost verbatim from http://blog.kalmbach-software.de/2008/12/13/writing-minidumps-in-c/ [Flags] public enum Option : uint { // From dbghelp.h: Normal = 0x00000000, WithDataSegs = 0x00000001, WithFullMemory = 0x00000002, WithHandleData = 0x00000004, FilterMemory = 0x00000008, ScanMemory = 0x00000010, WithUnloadedModules = 0x00000020, WithIndirectlyReferencedMemory = 0x00000040, FilterModulePaths = 0x00000080, WithProcessThreadData = 0x00000100, WithPrivateReadWriteMemory = 0x00000200, WithoutOptionalData = 0x00000400, WithFullMemoryInfo = 0x00000800, WithThreadInfo = 0x00001000, WithCodeSegs = 0x00002000, WithoutAuxiliaryState = 0x00004000, WithFullAuxiliaryState = 0x00008000, WithPrivateWriteCopyMemory = 0x00010000, IgnoreInaccessibleMemory = 0x00020000, ValidTypeFlags = 0x0003ffff, }; public enum ExceptionInfo { None, Present } //typedef struct _MINIDUMP_EXCEPTION_INFORMATION { // DWORD ThreadId; // PEXCEPTION_POINTERS ExceptionPointers; // BOOL ClientPointers; //} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION; [StructLayout(LayoutKind.Sequential, Pack = 4)] // Pack=4 is important! So it works also for x64! public struct MiniDumpExceptionInformation { public uint ThreadId; public IntPtr ExceptionPointers; [MarshalAs(UnmanagedType.Bool)] public bool ClientPointers; } //BOOL //WINAPI //MiniDumpWriteDump( // __in HANDLE hProcess, // __in DWORD ProcessId, // __in HANDLE hFile, // __in MINIDUMP_TYPE DumpType, // __in_opt PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, // __in_opt PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, // __in_opt PMINIDUMP_CALLBACK_INFORMATION CallbackParam // ); // Overload requiring MiniDumpExceptionInformation [DllImport("dbghelp.dll", EntryPoint = "MiniDumpWriteDump", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] static extern bool MiniDumpWriteDump(IntPtr hProcess, uint processId, SafeHandle hFile, uint dumpType, ref MiniDumpExceptionInformation expParam, IntPtr userStreamParam, IntPtr callbackParam); // Overload supporting MiniDumpExceptionInformation == NULL [DllImport("dbghelp.dll", EntryPoint = "MiniDumpWriteDump", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] static extern bool MiniDumpWriteDump(IntPtr hProcess, uint processId, SafeHandle hFile, uint dumpType, IntPtr expParam, IntPtr userStreamParam, IntPtr callbackParam); [DllImport("kernel32.dll", EntryPoint = "GetCurrentThreadId", ExactSpelling = true)] static extern uint GetCurrentThreadId(); public static bool Write(SafeHandle fileHandle, Option options, ExceptionInfo exceptionInfo) { Process currentProcess = Process.GetCurrentProcess(); IntPtr currentProcessHandle = currentProcess.Handle; uint currentProcessId = (uint)currentProcess.Id; MiniDumpExceptionInformation exp; exp.ThreadId = GetCurrentThreadId(); exp.ClientPointers = false; exp.ExceptionPointers = IntPtr.Zero; if (exceptionInfo == ExceptionInfo.Present) { exp.ExceptionPointers = System.Runtime.InteropServices.Marshal.GetExceptionPointers(); } bool bRet = false; if (exp.ExceptionPointers == IntPtr.Zero) { bRet = MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint)options, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); } else { bRet = MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint)options, ref exp, IntPtr.Zero, IntPtr.Zero); } return bRet; } public static bool Write(SafeHandle fileHandle, Option dumpType) { return Write(fileHandle, dumpType, ExceptionInfo.None); } } }
検証用コード
試しに例外が出たらダンプを生成するようにして、 try の中で 0 除算をしています。
というわけで、 DivideByZeroException 例外が出て、ダンプが生成されるはずです。
class Program { static void Main(string[] args) { try { int a = 100; int b = 0; int c = a/b; Console.WriteLine(c); } catch (Exception) { // create minidump string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "MiniDumpDemo_Mainline.dmp"); using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Write)) { MiniDump.Write(fs.SafeFileHandle, MiniDump.Option.WithFullMemory); } } } }
minidump を見る
実際に実行すると、ダンプファイルが生成されます。
Visual Studio でもいいですが、 windbg で開きます。
Windbg.exe -Q -z MiniDumpDemo_Mainline.dmp
開いたら、 sos をロードします。
(実験環境が .NET4 なのでモジュール名は clr です)
.loadby sos clr
ロードしたら、 !threads コマンドでスレッドの状況を確認。
結果はこんな感じに。
0:000> !threads ThreadCount: 10 UnstartedThread: 0 BackgroundThread: 5 PendingThread: 0 DeadThread: 3 Hosted Runtime: no PreEmptive GC Alloc Lock ID OSID ThreadOBJ State GC Context Domain Count APT Exception 0 1 1ce8 006307e8 201a220 Enabled 02272448:02273fe8 0062abb0 0 MTA 2 2 2128 00671720 b220 Enabled 00000000:00000000 0062abb0 0 MTA (Finalizer) XXXX 3 006b2588 10820 Enabled 00000000:00000000 0062abb0 0 Ukn XXXX 5 006be310 19820 Enabled 00000000:00000000 0062abb0 0 MTA XXXX 6 006df178 19820 Enabled 00000000:00000000 0062abb0 0 MTA 5 4 b44 006eb1f8 220 Enabled 0227fdbc:0227ffe8 0062abb0 0 Ukn 8 7 1de8 006e8470 b020 Enabled 0228a848:0228c798 0062abb0 0 MTA 6 8 620 006f04a8 220 Enabled 00000000:00000000 0062abb0 0 Ukn 9 9 1bfc 05085848 b220 Enabled 022843a0:02285fe8 0062abb0 0 MTA 10 a 21e4 0507e860 b020 Enabled 022a775c:022a7fe8 0062abb0 0 MTA System.DivideByZeroException (0228e99c)
ID 10 (a) を確認すると、Exception に DivideByZeroException 例外が出ていることを確認。
詳細を見るために、スレッドを切り替えます。
~10s
切り替えたら、今度は例外情報を出力します。
!pe
すると次のように結果が表示されます。
0:010> !pe Exception object: 0228e99c Exception type: System.DivideByZeroException Message: 0 で除算しようとしました。 InnerException: <none> StackTrace (generated): SP IP Function 06D0E9E8 003024BF MiniDumpSample!MiniDumpSample.Program.Main(System.String[])+0x7f StackTraceString: <none> HResult: 80020012
スタックトレースの結果から、 Program.Main メソッドで例外が発生した、ということが分かりました。
アセンブリでこの関数を追いかけてみます。
!U 003024BF
すると、次の実行結果が得られました。*1
0:010> !U 003024BF Normal JIT generated code MiniDumpSample.Program.Main(System.String[]) Begin 00302440, size 14f *** WARNING: Unable to verify checksum for MiniDumpSample.exe (略) C:\Users\xxxxx\Documents\Visual Studio 2010\Projects\MiniDumpSample\MiniDumpSample\Program.cs @ 19: 003024b6 33d2 xor edx,edx 003024b8 8955bc mov dword ptr [ebp-44h],edx C:\Users\xxxxx\Documents\Visual Studio 2010\Projects\MiniDumpSample\MiniDumpSample\Program.cs @ 20: 003024bb 8b45c0 mov eax,dword ptr [ebp-40h] 003024be 99 cdq >>> 003024bf f77dbc idiv eax,dword ptr [ebp-44h] 003024c2 8945b8 mov dword ptr [ebp-48h],eax (略)
例外が発生した該当のアドレスを見ると idiv 命令を実行しています。( >>> で強調されている行)
0 除算なので、この時の dword ptr [ebp-44h] が 0 になっているはずです。
直ぐ上を見ると「 xor edx edx 」の結果を代入していることが分かります。
お気づきの通り、ブール代数的には 同じ値でXOR(排他的論理和) をとると、 0 になります。
ということで、 0 除算している処理が Program.cs の 19 行目にあるみたいですよ。と言えそうです
今回はまさに自分でそういうコードを書いますから、これで無事解決。
実際のケースでは例外の内容を確認してからの調査方法はケース毎に異なるでしょうね。
お勉強はここまで。(夜が明け始めた!)
*1:私の名前の部分は xxxxx に置換してます。
Microsoft Expression Encoder 3 Screen Capture がクラッシュした時に録画した内容を探す
既に Expression 4 が出ているので、このケースが改善されているかはわからないが、録画後に長時間の画面キャプチャを変換するとクラッシュが多発する。*1
クラッシュすると録画していたファイルは復旧できない。普通は。
だが、実際問題として長時間の録画内容をすべてオンメモリで持っているはずはない。
どかにファイルとして保存してあるはずだ、ということで探してみた。
結論から言うと、この場所に保存されている。
C:\Users\<ユーザ名>\AppData\Local\Temp
サイズでソートすると、ファイルの種類が「Expression Encoder 画面キャプチャ ファイル」として発見することが出来るはずだ。
私の場合は、このファイルをダブルクリックで普通に開くことが出来た。
もしクラッシュして諦めていた録画があった場合は確認してみると良い。*2
Wii テレビリモコン 設定コマンド一覧
ニンテンドークラブのプレミアム会員限定で配布された Wii リモコン風テレビリモコンの設定コマンドを掲載しておきます。
メーカー名 | 設定コマンド | |
---|---|---|
パナソニック(松下) | ↑↑↓ または ↑↑← | |
ソニー | ↑↑↑ または ↑↑→ | |
東芝 | →→↑ | |
日立 | →→→ | |
三菱 | →→↓ | |
ビクター | →→← | |
サンヨー | ↓↓↑ または ↓↓→ | |
アイワ | ↓↓↓ | |
シャープ | ↓↓← または ←←↑ | |
フナイ | ←←→ | |
NEC | ←←↓ | |
富士通ゼネラル | ←←← | |
パイオニア | ↑→↑ | |
フィリップス | ↑→→ | |
サムスン | ↑→↓ または ↑→← | |
LG電子 | ↑↓↑ | |
オリオン | ↑↓→ |
※ 2つの設定コマンドがある場合は、入力しても反応しない場合にもう一方の設定コマンドを入力します。