C/C++言語だと、プリプロセッサマクロの #演算子 の文字列リテラル化機能を使って、実行行の文字列を表記するなんてマクロが簡単に書けます。
例えば、以下のように。
#define COM_CHK(hr) _com_chk(#hr, hr) inline HRESULT _com_chk(const char* msg, HRESULT hr) { System::Diagnostics::Trace::WriteLine(String::Format("{0} = 0x{1:X}", gcnew String(msg), hr)); if(FAILED(hr)) throw gcnew COMException(gcnew String(msg), hr); return hr; } ... COM_CHK(m_graphBuilder->RenderFile(filename, NULL)); COM_CHK(m_videoWindow->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN));
上のコードは、COM_CHK マクロで、囲った内部の呼び出しコードを、片方は文字列リテラル化、片方は呼び出した返値を渡して、トレース出力しちゃおうという代物です。
こうすれば、いわゆるエラーチェック付きデバッグプリントが簡単に実現できます。
で、C#でこのような機能を実現するには、どうしたら良いのか?という問題です。
色々と調べていたんですが、どうもうまく行きそうにない。
- Roppi.net - 【VB.net勉強中】ログに実行中の関数名を含めたい
http://www.roppi.net/2009/10/17/vb_net_includefunctionnametolog/
で、上のURLのコードをじ〜っと眺めていて、もう力技で作ってしまおう。と思いました。
以下が力技の例です。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using DirectShowLib; using System.Diagnostics; using System.Reflection; using System.IO; using DBG = System.Diagnostics.Trace; namespace Test03 { /// <summary> /// Geekなぺーじ : 自作ウィンドウに表示する /// http://www.geekpage.jp/programming/directshow/ivideowindow-3.php /// の、C#版みたいなもの。 /// </summary> public partial class Form1 : Form { public Form1() { InitializeComponent(); } IGraphBuilder m_graphBuilder = null; IMediaControl m_mediaControl = null; IVideoWindow m_videoWindow = null; private void Form1_Load(object sender, EventArgs e) { m_graphBuilder = new FilterGraph() as IGraphBuilder; m_graphBuilder.RenderFile(@"F:\Wacky\hoge.wmv", null); m_mediaControl = m_graphBuilder as IMediaControl; m_videoWindow = m_graphBuilder as IVideoWindow; } private void Form1_Shown(object sender, EventArgs e) { COM_CHK(m_videoWindow.put_Owner(this.Handle)); COM_CHK(m_videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipSiblings)); COM_CHK(m_videoWindow.SetWindowPosition(0, 0, this.Width, this.Height)); COM_CHK(m_videoWindow.put_Visible(OABool.True)); COM_CHK(m_videoWindow.SetWindowForeground(OABool.True)); m_mediaControl.Run(); } #region デバッグ用 static Dictionary<string, string[]> s_stackFileArray = new Dictionary<string, string[]>(); int COM_CHK(int hr) { StackTrace stkTrace = new StackTrace(true); StackFrame stkFrame = stkTrace.GetFrame(1); string fileName = stkFrame.GetFileName(); if (s_stackFileArray.ContainsKey(fileName) == false) s_stackFileArray[fileName] = File.ReadAllLines(fileName); DBG.WriteLine(string.Format("0x{0:X} = {1}", hr, s_stackFileArray[fileName][stkFrame.GetFileLineNumber() - 1].Trim())); if (hr < 0) DsError.ThrowExceptionForHR(hr); return hr; } #endregion } }
上を実行すると、以下のようにデバッグプリント出来ます。
0x0 = COM_CHK(m_videoWindow.put_Owner(this.Handle)); 0x0 = COM_CHK(m_videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipSiblings)); 0x0 = COM_CHK(m_videoWindow.SetWindowPosition(0, 0, this.Width, this.Height)); 0x0 = COM_CHK(m_videoWindow.put_Visible(OABool.True)); 0x0 = COM_CHK(m_videoWindow.SetWindowForeground(OABool.True));
StackTrace(true) を呼ぶと、詳細なスタックトレース情報が取れるので、そこから呼び出し元のファイル名と行数を取得し、直接ソースコードを取得して、プリント出力に回す。という恐ろしく力技を使っています。
とはいえ、とりあえず、少々遅くても 呼び出しの動きが見たかっただけなので、これで良しとしますか。