ふにゃるんv2

もとは、http://d.hatena.ne.jp/Wacky/

assertマクロのような実行関数行のトレース文字列表示を行う

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#でこのような機能を実現するには、どうしたら良いのか?という問題です。
色々と調べていたんですが、どうもうまく行きそうにない。


で、上の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) を呼ぶと、詳細なスタックトレース情報が取れるので、そこから呼び出し元のファイル名と行数を取得し、直接ソースコードを取得して、プリント出力に回す。という恐ろしく力技を使っています。


とはいえ、とりあえず、少々遅くても 呼び出しの動きが見たかっただけなので、これで良しとしますか。