EternalWindows
デバッグ API / デバッガ サンプル

今回作成したデバッガのコードを見ていきます。 まず、ヘッダーファイルを示します。

class CManagedCallback : public ICorDebugManagedCallback, public ICorDebugManagedCallback2
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
	
	STDMETHODIMP Breakpoint(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugBreakpoint *pBreakpoint);
	STDMETHODIMP StepComplete(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugStepper *pStepper, CorDebugStepReason reason);
	STDMETHODIMP Break(ICorDebugAppDomain *pAppDomain, ICorDebugThread *thread);
	STDMETHODIMP Exception(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, BOOL unhandled);
	STDMETHODIMP EvalComplete(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugEval *pEval);
	STDMETHODIMP EvalException(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugEval *pEval);
	STDMETHODIMP CreateProcess(ICorDebugProcess *pProcess);
	STDMETHODIMP ExitProcess(ICorDebugProcess *pProcess);
	STDMETHODIMP CreateThread(ICorDebugAppDomain *pAppDomain, ICorDebugThread *thread);
	STDMETHODIMP ExitThread(ICorDebugAppDomain *pAppDomain, ICorDebugThread *thread);
	STDMETHODIMP LoadModule(ICorDebugAppDomain *pAppDomain, ICorDebugModule *pModule);
	STDMETHODIMP UnloadModule(ICorDebugAppDomain *pAppDomain, ICorDebugModule *pModule);
	STDMETHODIMP LoadClass(ICorDebugAppDomain *pAppDomain, ICorDebugClass *c);
	STDMETHODIMP UnloadClass(ICorDebugAppDomain *pAppDomain, ICorDebugClass *c);
	STDMETHODIMP DebuggerError(ICorDebugProcess *pProcess, HRESULT errorHR, DWORD errorCode);
	STDMETHODIMP LogMessage(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, LONG lLevel, WCHAR *pLogSwitchName, WCHAR *pMessage);
	STDMETHODIMP LogSwitch(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, LONG lLevel, ULONG ulReason, WCHAR *pLogSwitchName, WCHAR *pParentName);
	STDMETHODIMP CreateAppDomain(ICorDebugProcess *pProcess, ICorDebugAppDomain *pAppDomain);
	STDMETHODIMP ExitAppDomain(ICorDebugProcess *pProcess, ICorDebugAppDomain *pAppDomain);
	STDMETHODIMP LoadAssembly(ICorDebugAppDomain *pAppDomain, ICorDebugAssembly *pAssembly);
	STDMETHODIMP UnloadAssembly(ICorDebugAppDomain *pAppDomain, ICorDebugAssembly *pAssembly);
	STDMETHODIMP ControlCTrap(ICorDebugProcess *pProcess);
	STDMETHODIMP NameChange(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread);
	STDMETHODIMP UpdateModuleSymbols(ICorDebugAppDomain *pAppDomain, ICorDebugModule *pModule, IStream *pSymbolStream);
	STDMETHODIMP EditAndContinueRemap(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugFunction *pFunction, BOOL fAccurate);
	STDMETHODIMP BreakpointSetError(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugBreakpoint *pBreakpoint, DWORD dwError);

	STDMETHODIMP FunctionRemapOpportunity(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugFunction *pOldFunction, ICorDebugFunction *pNewFunction, ULONG32 oldILOffset);
	STDMETHODIMP CreateConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId, WCHAR *pConnName);
	STDMETHODIMP ChangeConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId);
	STDMETHODIMP DestroyConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId);
	STDMETHODIMP Exception(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugFrame *pFrame, ULONG32 nOffset, CorDebugExceptionCallbackType dwEventType, DWORD dwFlags);
	STDMETHODIMP ExceptionUnwind(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, CorDebugExceptionUnwindCallbackType dwEventType, DWORD dwFlags);
	STDMETHODIMP FunctionRemapComplete(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugFunction *pFunction);
	STDMETHODIMP MDANotification(ICorDebugController *pController, ICorDebugThread *pThread, ICorDebugMDA *pMDA);

	void EnumValueAndFrame(ICorDebugThread *pThread);
	void EnumLocalVariables(ICorDebugThread *pThread);
	void EnumArguments(ICorDebugThread *pThread);
	void EnumFrame(ICorDebugThread *pThread);
	void GetElementTypeName(ICorDebugValue *pValue, LPWSTR lpszBuf);
	void GetGenericType(CorElementType type, LPWSTR lpszBuf);
	void GetValue(ICorDebugValue *pValue, LPWSTR lpszBuf);
	void GetGenericValue(LPVOID lpValue, CorElementType type, LPWSTR lpszBuf);
	BOOL ObjectDereference(ICorDebugValue **ppDebugValue);
	void CreateVariableArray(HDPA hdpa, ISymUnmanagedScope *pScope);
	void GetVariable(HDPA hdpa, int nIndex, ISymUnmanagedVariable **ppVariable);
	ULONG32 GetOffsetFromSource(LPWSTR lpszSource, ULONG32 uLine, ULONG32 uColumn);
	ULONG32 GetSourceLine(ICorDebugThread *pThread);
	void SetBreakpoint(ICorDebugModule *pModule, LPWSTR lpszClass, LPWSTR lpszMethod, ULONG32 uOffset);
	void GetModuleNameFromFunction(ICorDebugFunction *pFunction, LPWSTR lpszBuf);
	void GetClassName(ICorDebugClass *pClass, LPWSTR lpszClassName);
	void GetFullMethodName(ICorDebugFunction *pFunction, LPWSTR lpszFunctionName);

	CManagedCallback();
	~CManagedCallback();

public:
	LONG m_cRef;
};

#define WM_STOP WM_APP
#define WM_END WM_APP + 1

次に、GUI関連のコードを示します。

#include <windows.h>
#include <cor.h>
#include <cordebug.h>
#include <mscoree.h>
#include <commctrl.h>
#include <corsym.h>
#include "sample.h"

#pragma comment (lib, "corguids.lib")
#pragma comment (lib, "mscoree.lib")
#pragma comment (lib, "shlwapi.lib")
#pragma comment (lib, "comctl32.lib")

#define ID_DEBUG  10
#define ID_DEBUG_START  20
#define ID_DEBUG_END  30
#define ID_CONTINUE  40

HWND g_hwnd;
HWND g_hwndListBox;
HWND g_hwndListViewValue;
HWND g_hwndListViewFrame;

WCHAR g_szModule[] = L"C:\\WindowsFormsApplication1\\bin\\Debug\\WindowsFormsApplication1.exe";

void ShowString(LPWSTR lpszData);
void InitializeMenuItem(HMENU hmenu, LPTSTR lpszItemName, int nId, HMENU hmenuSub);
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("sample");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static ICorDebug                *pDebug = NULL;
	static ICorDebugManagedCallback *pManagedCallback = NULL;
	static ICorDebugProcess         *pProcess = NULL;
	
	switch (uMsg) {

	case WM_CREATE: {
		HMENU                hmenu;
		HMENU                hmenuPopup;
		HRESULT              hr;
		IUnknown             *pUnknown;
		LVCOLUMN             column;
		INITCOMMONCONTROLSEX ic;
		int                  i;
		LPTSTR               lpszColumn[] = {TEXT("変数"), TEXT("値"), TEXT("型")};

		CoInitialize(NULL);
		
		hr = CreateDebuggingInterfaceFromVersion(CorDebugVersion_2_0, L"v2.0.50727", &pUnknown);
		if (FAILED(hr))
			return -1;
		pUnknown->QueryInterface(IID_PPV_ARGS(&pDebug));
		pUnknown->Release();
		
		pDebug->Initialize();

		pManagedCallback = new CManagedCallback();
		pDebug->SetManagedHandler(pManagedCallback);

		g_hwndListBox = CreateWindowEx(0, TEXT("LISTBOX"), NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL, 0, 0, 0, 0, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);

		ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
		ic.dwICC  = ICC_LISTVIEW_CLASSES;
		InitCommonControlsEx(&ic);

		g_hwndListViewValue = CreateWindowEx(0, WC_LISTVIEW, TEXT(""), WS_CHILD | WS_VISIBLE | LVS_REPORT, 0, 0, 0, 0, hwnd, (HMENU)2, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
		for (i = 0; i < 3; i++) {
			column.mask    = LVCF_WIDTH | LVCF_TEXT;
			column.cx      = 0;
			column.pszText = lpszColumn[i];
			ListView_InsertColumn(g_hwndListViewValue, i, &column);
		}

		g_hwndListViewFrame = CreateWindowEx(0, WC_LISTVIEW, TEXT(""), WS_CHILD | WS_VISIBLE | LVS_REPORT, 0, 0, 0, 0, hwnd, (HMENU)3, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
		column.mask    = LVCF_TEXT | LVCF_WIDTH;
		column.cx      = 0;
		column.pszText = TEXT("スタックフレーム");
		ListView_InsertColumn(g_hwndListViewFrame, 0, &column);

		hmenu  = CreateMenu();
		hmenuPopup = CreatePopupMenu();

		InitializeMenuItem(hmenuPopup, TEXT("デバッグ開始"), ID_DEBUG_START, NULL);
		InitializeMenuItem(hmenuPopup, TEXT("デバッグ停止"), ID_DEBUG_END, NULL);
		InitializeMenuItem(hmenuPopup, TEXT("続行"), ID_CONTINUE, NULL);
		InitializeMenuItem(hmenu, TEXT("デバッグ"), ID_DEBUG, hmenuPopup);
		EnableMenuItem(hmenuPopup, ID_DEBUG_END, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hmenuPopup, ID_CONTINUE, MF_BYCOMMAND | MF_GRAYED);
		
		SetMenu(hwnd, hmenu);

		g_hwnd = hwnd;

		return 0;
	}
	
	case WM_COMMAND: {
		int   nId = LOWORD(wParam);
		HMENU hmenuPopup = GetSubMenu(GetMenu(hwnd), 0);

		if (nId == ID_DEBUG_START) {
			STARTUPINFOW        startupInfo;
			PROCESS_INFORMATION processInformation;
			
			SendMessage(g_hwndListBox, LB_RESETCONTENT, 0, 0);
			ListView_DeleteAllItems(g_hwndListViewValue);
			ListView_DeleteAllItems(g_hwndListViewFrame);
			
			ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
			startupInfo.cb = sizeof(STARTUPINFO);
			pDebug->CreateProcess(NULL, g_szModule, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation, DEBUG_NO_SPECIAL_OPTIONS, &pProcess);
			if (pProcess != NULL) {
				CloseHandle(processInformation.hThread);
				CloseHandle(processInformation.hProcess);		
				EnableMenuItem(hmenuPopup, ID_DEBUG_START, MF_BYCOMMAND | MF_GRAYED);
				EnableMenuItem(hmenuPopup, ID_DEBUG_END, MF_BYCOMMAND | MF_ENABLED);
			}
			else
				SendMessage(g_hwndListBox, LB_ADDSTRING, 0, (LPARAM)TEXT("プロセスの作成に失敗しました。"));
		}
		else if (nId == ID_DEBUG_END)
			PostMessage(g_hwnd, WM_END, 0, 0);
		else if (nId == ID_CONTINUE) {
			ListView_DeleteAllItems(g_hwndListViewValue);
			ListView_DeleteAllItems(g_hwndListViewFrame);

			pProcess->Continue(FALSE);
			EnableMenuItem(hmenuPopup, ID_CONTINUE, MF_BYCOMMAND | MF_GRAYED);
		}
		else
			;
		
		return 0;
	}
	
	case WM_STOP:
		EnableMenuItem(GetSubMenu(GetMenu(hwnd), 0), ID_CONTINUE, MF_BYCOMMAND | MF_ENABLED);
		return 0;
	
	case WM_END: {
		HMENU hmenuPopup = GetSubMenu(GetMenu(hwnd), 0);
		pProcess->Detach();
		pProcess->Release();
		EnableMenuItem(hmenuPopup, ID_DEBUG_START, MF_BYCOMMAND | MF_ENABLED);
		EnableMenuItem(hmenuPopup, ID_DEBUG_END, MF_BYCOMMAND | MF_GRAYED);
		EnableMenuItem(hmenuPopup, ID_CONTINUE, MF_BYCOMMAND | MF_GRAYED);
		return 0;
	}
	
	case WM_SIZE: {
		int i;
		int nWidth = LOWORD(lParam) / 2;
		int nHeight = HIWORD(lParam) / 3;
		MoveWindow(g_hwndListBox, 0, 0, LOWORD(lParam), HIWORD(lParam) - nHeight, TRUE);
		MoveWindow(g_hwndListViewValue, 0, HIWORD(lParam) - nHeight, nWidth, nHeight, TRUE);
		MoveWindow(g_hwndListViewFrame, nWidth, HIWORD(lParam) - nHeight, nWidth, nHeight, TRUE);
		for (i = 0; i < 3; i++)
			ListView_SetColumnWidth(g_hwndListViewValue, i, nWidth / 3);
		ListView_SetColumnWidth(g_hwndListViewFrame, 0, nWidth);
		return 0;
	}

	case WM_DESTROY:
		if (pProcess != NULL) {
			pProcess->Detach();
			pProcess->Release();
		}
		
		if (pManagedCallback != NULL)
			pManagedCallback->Release();
	
		if (pDebug != NULL)
			pDebug->Release();

		CoUninitialize();
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

void DebugStop()
{
	PostMessage(g_hwnd, WM_STOP, 0, 0);
}

void DebugEnd()
{
	PostMessage(g_hwnd, WM_END, 0, 0);
}

void SetValueItem(LPWSTR lpszName, LPWSTR lpszValue, LPWSTR lpszType, int i)
{
	LVITEM item;

	item.mask     = LVIF_TEXT;
	item.iItem    = i;
	item.iSubItem = 0;
	item.pszText  = lpszName;
	ListView_InsertItem(g_hwndListViewValue, &item);
	
	item.mask     = LVIF_TEXT;
	item.iItem    = i;
	item.iSubItem = 1;
	item.pszText  = lpszValue;
	ListView_SetItem(g_hwndListViewValue, &item);

	item.mask     = LVIF_TEXT;
	item.iItem    = i;
	item.iSubItem = 2;
	item.pszText  = lpszType;
	ListView_SetItem(g_hwndListViewValue, &item);
}

void SetFrameItem(LPWSTR lpszName, int i)
{
	LVITEM item;

	item.mask     = LVIF_TEXT;
	item.iItem    = i;
	item.iSubItem = 0;
	item.pszText  = lpszName;
	ListView_InsertItem(g_hwndListViewFrame, &item);
}

void ShowString(LPWSTR lpszData)
{
	SendMessage(g_hwndListBox, LB_ADDSTRING, 0, (LPARAM)lpszData);
}

void InitializeMenuItem(HMENU hmenu, LPTSTR lpszItemName, int nId, HMENU hmenuSub)
{
	MENUITEMINFO mii;
	
	mii.cbSize = sizeof(MENUITEMINFO);
	mii.fMask  = MIIM_ID | MIIM_TYPE;
	mii.wID    = nId;

	if (lpszItemName != NULL) {
		mii.fType      = MFT_STRING;
		mii.dwTypeData = lpszItemName;
	}
	else
		mii.fType = MFT_SEPARATOR;

	if (hmenuSub != NULL) {
		mii.fMask   |= MIIM_SUBMENU;
		mii.hSubMenu = hmenuSub;
	}

	InsertMenuItem(hmenu, nId, FALSE, &mii);
}

次に、ICorDebugManagedCallbackの実装を示します。

#include <windows.h>
#include <cor.h>
#include <cordebug.h>
#include <corsym.h>
#include <shlobj.h>
#include <shlwapi.h>
#include "sample.h"

ISymUnmanagedReader *g_pSymReader;
extern WCHAR g_szModule[];

extern void DebugStop();
extern void DebugEnd();
extern void SetValueItem(LPWSTR lpszName, LPWSTR lpszValue, LPWSTR lpszType, int i);
extern void SetFrameItem(LPWSTR lpszName, int i);
extern void ShowString(LPWSTR lpszData);

CManagedCallback::CManagedCallback()
{
	m_cRef = 1;
}

CManagedCallback::~CManagedCallback()
{
}

STDMETHODIMP CManagedCallback::QueryInterface(REFIID riid, void **ppvObject)
{
	*ppvObject = NULL;

	if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ICorDebugManagedCallback))
		*ppvObject = static_cast(this);
	else if (IsEqualIID(riid, IID_ICorDebugManagedCallback2))
		*ppvObject = static_cast(this);
	else
		return E_NOINTERFACE;

	AddRef();

	return S_OK;
}

STDMETHODIMP_(ULONG) CManagedCallback::AddRef()
{
	return InterlockedIncrement(&m_cRef);
}

STDMETHODIMP_(ULONG) CManagedCallback::Release()
{
	if (InterlockedDecrement(&m_cRef) == 0) {
		delete this;
		return 0;
	}

	return m_cRef;
}

STDMETHODIMP CManagedCallback::Breakpoint(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugBreakpoint *pBreakpoint)
{
	ICorDebugFunction *pFunction;
	ICorDebugFrame    *pFrame;
	WCHAR             szName[256], szBuf[512];

	EnumValueAndFrame(pThread);
	
	pThread->GetActiveFrame(&pFrame);
	pFrame->GetFunction(&pFunction);

	GetFullMethodName(pFunction, szName);
	wsprintfW(szBuf, L"Breakpoint : %s", szName);
	ShowString(szBuf);
	
	pFunction->Release();
	pFrame->Release();

	return S_OK;
}

STDMETHODIMP CManagedCallback::StepComplete(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugStepper *pStepper, CorDebugStepReason reason)
{
	ShowString(L"StepComplete");
	
	return S_OK;
}

STDMETHODIMP CManagedCallback::Break(ICorDebugAppDomain *pAppDomain, ICorDebugThread *thread)
{
	ShowString(L"Break");

	return S_OK;
}

STDMETHODIMP CManagedCallback::Exception(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, BOOL unhandled)
{
	ICorDebugValue       *pValue;
	ICorDebugObjectValue *pObjectValue;
	ICorDebugClass       *pClass;
	WCHAR                szError[256], szBuf[512];

	EnumValueAndFrame(pThread);

	pThread->GetCurrentException(&pValue);
	ObjectDereference(&pValue);
	pValue->QueryInterface(IID_PPV_ARGS(&pObjectValue));
	
	pObjectValue->GetClass(&pClass);
	GetClassName(pClass, szError);

	wsprintfW(szBuf, L"Exception : %s %s", szError, unhandled ? L"例外未処理" : L"例外処理");
	ShowString(szBuf);

	pClass->Release();
	pObjectValue->Release();
	pValue->Release();

	return S_OK;
}

STDMETHODIMP CManagedCallback::EvalComplete(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugEval *pEval)
{
	ShowString(L"EvalComplete");

	return S_OK;
}

STDMETHODIMP CManagedCallback::EvalException(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugEval *pEval)
{
	ShowString(L"EvalException");

	return S_OK;
}

STDMETHODIMP CManagedCallback::CreateProcess(ICorDebugProcess *pProcess)
{
	ShowString(L"CreateProcess");
	
	pProcess->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::ExitProcess(ICorDebugProcess *pProcess)
{
	DebugEnd();

	if (g_pSymReader != NULL) {
		g_pSymReader->Release();
		CoUninitialize();
	}

	ShowString(L"ExitProcess");

	return S_OK;
}

STDMETHODIMP CManagedCallback::CreateThread(ICorDebugAppDomain *pAppDomain, ICorDebugThread *thread)
{
	ShowString(L"CreateThread");
	
	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::ExitThread(ICorDebugAppDomain *pAppDomain, ICorDebugThread *thread)
{
	ShowString(L"ExitThread");

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::LoadModule(ICorDebugAppDomain *pAppDomain, ICorDebugModule *pModule)
{
	ULONG32 uSize;
	WCHAR   szName[256], szModule[256], szBuf[512];

	pModule->GetName(256, &uSize, szModule);
	if (lstrcmpW(szModule, g_szModule) == 0) {
		ISymUnmanagedBinder *pSymBinder;
		ULONG32             uOffset = 0;

		CoInitialize(0);

		HRESULT hr = CoCreateInstance(CLSID_CorSymBinder_deprecated, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSymBinder));
		if (SUCCEEDED(hr)) {
			IUnknown *pUnknown;
			
			pModule->GetMetaDataInterface(IID_IUnknown, &pUnknown);
			hr = pSymBinder->GetReaderForFile(pUnknown, szModule, NULL, &g_pSymReader);
			if (SUCCEEDED(hr)) {
				ShowString(L"pdbファイル参照");
				uOffset = GetOffsetFromSource(L"C:\\WindowsFormsApplication1\\Program.cs", 32, 9);
			}
			pUnknown->Release();
		}
		
		SetBreakpoint(pModule, L"Program", L"ShowParam", uOffset);

		pSymBinder->Release();
	}

	pModule->GetName(256, &uSize, szName);
	wsprintfW(szBuf, L"LoadModule : %s", szName);

	ShowString(szBuf);
	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::UnloadModule(ICorDebugAppDomain *pAppDomain, ICorDebugModule *pModule)
{
	ShowString(L"UnloadModule");

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::LoadClass(ICorDebugAppDomain *pAppDomain, ICorDebugClass *c)
{
	ShowString(L"LoadClass");

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::UnloadClass(ICorDebugAppDomain *pAppDomain, ICorDebugClass *c)
{
	ShowString(L"UnloadClass");

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::DebuggerError(ICorDebugProcess *pProcess, HRESULT errorHR, DWORD errorCode)
{
	ShowString(L"DebuggerError");

	return S_OK;
}

STDMETHODIMP CManagedCallback::LogMessage(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, LONG lLevel, WCHAR *pLogSwitchName, WCHAR *pMessage)
{
	WCHAR szBuf[256];

	wsprintfW(szBuf, L"LogMessage : %s", pMessage);
	ShowString(szBuf);

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::LogSwitch(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, LONG lLevel, ULONG ulReason, WCHAR *pLogSwitchName, WCHAR *pParentName)
{
	ShowString(L"LogSwitch");

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::CreateAppDomain(ICorDebugProcess *pProcess, ICorDebugAppDomain *pAppDomain)
{
	ULONG32 uSize;
	WCHAR   szBuf[512], szName[256];
	
	pAppDomain->GetName(256, &uSize, szName);
	wsprintfW(szBuf, L"CreateAppDomain : %s", szName);
	ShowString(szBuf);
	
	pAppDomain->Continue(FALSE);

	return E_NOTIMPL;
}

STDMETHODIMP CManagedCallback::ExitAppDomain(ICorDebugProcess *pProcess, ICorDebugAppDomain *pAppDomain)
{
	ShowString(L"ExitAppDomain");

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::LoadAssembly(ICorDebugAppDomain *pAppDomain, ICorDebugAssembly *pAssembly)
{
	WCHAR   szName[256], szBuf[512];
	ULONG32 uSize;

	pAssembly->GetName(256, &uSize, szName);
	wsprintfW(szBuf, L"LoadAssembly : %s", szName);
	ShowString(szBuf);

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::UnloadAssembly(ICorDebugAppDomain *pAppDomain, ICorDebugAssembly *pAssembly)
{
	ShowString(L"UnloadAssembly");

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::ControlCTrap(ICorDebugProcess *pProcess)
{
	ShowString(L"ControlCTrap");

	return S_OK;
}

STDMETHODIMP CManagedCallback::NameChange(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread)
{
	ShowString(L"NameChange");
	
	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::UpdateModuleSymbols(ICorDebugAppDomain *pAppDomain, ICorDebugModule *pModule, IStream *pSymbolStream)
{
	ShowString(L"UpdateModuleSymbols");

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::EditAndContinueRemap(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugFunction *pFunction, BOOL fAccurate)
{
	ShowString(L"EditAndContinueRemap");

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::BreakpointSetError(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugBreakpoint *pBreakpoint, DWORD dwError)
{
	ShowString(L"BreakpointSetError");

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::FunctionRemapOpportunity(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugFunction *pOldFunction, ICorDebugFunction *pNewFunction, ULONG32 oldILOffset)
{
	ShowString(L"FunctionRemapOpportunity");

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::CreateConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId, WCHAR *pConnName)
{
	ShowString(L"CreateConnection");

	pProcess->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::ChangeConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId)
{
	ShowString(L"ChangeConnection");

	pProcess->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::DestroyConnection(ICorDebugProcess *pProcess, CONNID dwConnectionId)
{
	ShowString(L"DestroyConnection");

	pProcess->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::Exception(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugFrame *pFrame, ULONG32 nOffset, CorDebugExceptionCallbackType dwEventType, DWORD dwFlags)
{
	WCHAR szBuf[256];

	wsprintf(szBuf, TEXT("Exception : %d"), dwEventType);
	ShowString(szBuf);

	return S_OK;
}

STDMETHODIMP CManagedCallback::ExceptionUnwind(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, CorDebugExceptionUnwindCallbackType dwEventType, DWORD dwFlags)
{
	ShowString(L"ExceptionUnwind");

	return S_OK;
}

STDMETHODIMP CManagedCallback::FunctionRemapComplete(ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread, ICorDebugFunction *pFunction)
{
	ShowString(L"FunctionRemapComplete");

	pAppDomain->Continue(FALSE);

	return S_OK;
}

STDMETHODIMP CManagedCallback::MDANotification(ICorDebugController *pController, ICorDebugThread *pThread, ICorDebugMDA *pMDA)
{
	ShowString(L"MDANotification");

	pController->Continue(FALSE);

	return S_OK;
}

void CManagedCallback::EnumValueAndFrame(ICorDebugThread *pThread)
{
	if (1)
		EnumArguments(pThread);
	else
		EnumLocalVariables(pThread);

	EnumFrame(pThread);

	DebugStop();
}

void CManagedCallback::EnumArguments(ICorDebugThread *pThread)
{
	ICorDebugFrame     *pFrame;
	ICorDebugILFrame   *pILFrame;
	ICorDebugValueEnum *pValueEnum;
	ICorDebugValue     *pValue;
	ICorDebugModule    *pModule;
	ICorDebugFunction  *pFunction;
	IMetaDataImport    *pMetaDataImport;
	mdMethodDef        methodDef;
	HCORENUM           hCorEnum;
	ULONG              uCount;
	mdParamDef         paramDefs[2048];
	WCHAR              szName[256], szType[256], szValue[256];
	int                i;

	pThread->GetActiveFrame(&pFrame);
	pFrame->QueryInterface(IID_PPV_ARGS(&pILFrame));
	pILFrame->EnumerateArguments(&pValueEnum);

	pFrame->GetFunction(&pFunction);
	pFunction->GetToken(&methodDef);
	pFunction->GetModule(&pModule);
	pModule->GetMetaDataInterface(IID_IMetaDataImport, (IUnknown **)&pMetaDataImport);

	hCorEnum = NULL;
	pMetaDataImport->EnumParams(&hCorEnum, methodDef, paramDefs, sizeof(paramDefs), &uCount);
	
	i = 0;
	while (pValueEnum->Next(1, &pValue, NULL) == S_OK) {
		pMetaDataImport->GetParamProps(paramDefs[i], NULL, NULL, szName, 256, NULL, NULL, NULL, NULL, NULL);
		GetValue(pValue, szValue);
		GetElementTypeName(pValue, szType);
		SetValueItem(szName, szValue, szType, i);
		pValue->Release();
		i++;
	}
	
	pMetaDataImport->CloseEnum(hCorEnum);
	pMetaDataImport->Release();
	pModule->Release();
	pFunction->Release();
	pValueEnum->Release();
	pILFrame->Release();
	pFrame->Release();
}

void CManagedCallback::EnumLocalVariables(ICorDebugThread *pThread)
{
	ICorDebugFrame        *pFrame;
	ICorDebugILFrame      *pILFrame;
	ICorDebugValueEnum    *pValueEnum;
	ICorDebugValue        *pValue;
	ICorDebugFunction     *pFunction;
	ISymUnmanagedMethod   *pSymMethod;
	ISymUnmanagedScope    *pScope;
	ISymUnmanagedVariable *pVariable;
	mdMethodDef           methodDef;
	WCHAR                 szName[256], szValue[256], szType[256];
	BOOL                  bSym = g_pSymReader != NULL;
	HDPA                  hdpa = NULL;
	int                   i;

	pThread->GetActiveFrame(&pFrame);
	pFrame->QueryInterface(IID_PPV_ARGS(&pILFrame));
	pILFrame->EnumerateLocalVariables(&pValueEnum);

	if (bSym) {
		pFrame->GetFunction(&pFunction);
		pFunction->GetToken(&methodDef);
		g_pSymReader->GetMethod(methodDef, &pSymMethod);
		pSymMethod->GetRootScope(&pScope);
		hdpa = DPA_Create(1);
		CreateVariableArray(hdpa, pScope);

		pSymMethod->Release();
		pFunction->Release();
	}

	i = 0;
	while (pValueEnum->Next(1, &pValue, NULL) == S_OK) {
		if (bSym) {
			ULONG32 uSize;

			GetVariable(hdpa, i, &pVariable);
			if (pVariable != NULL)
				pVariable->GetName(256, &uSize, szName);
			else
				lstrcpyW(szName, L"?");
		}
		else
			lstrcpyW(szName, L"?");

		GetValue(pValue, szValue);
		GetElementTypeName(pValue, szType);
		SetValueItem(szName, szValue, szType, i);
		pValue->Release();
		i++;
	}

	if (bSym) {
		int n = DPA_GetPtrCount(hdpa);

		for (i = 0; i < n; i++) {
			pVariable = (ISymUnmanagedVariable *)DPA_GetPtr(hdpa, i);
			pVariable->Release();
		}

		DPA_Destroy(hdpa);
	}
	
	pValueEnum->Release();
	pILFrame->Release();
	pFrame->Release();
}

void CManagedCallback::EnumFrame(ICorDebugThread *pThread)
{
	ICorDebugChain     *pChain;
	ICorDebugFrame     *pFrame;
	ICorDebugFrameEnum *pFrameEnum;
	ICorDebugFunction  *pFunction;
	WCHAR              szModule[256], szName[256], szBuf[512];
	ULONG32            uLine;
	int                i;

	pThread->GetActiveChain(&pChain);
	pChain->EnumerateFrames(&pFrameEnum);

	i = 0;
	while (pFrameEnum->Next(1, &pFrame, NULL) == S_OK) {
		pFrame->GetFunction(&pFunction);
		GetFullMethodName(pFunction, szName);
		GetModuleNameFromFunction(pFunction, szModule);

		uLine = GetSourceLine(pThread);
		if (i == 0 && uLine > 0)
			wsprintfW(szBuf, L"%s!%s %d行", szModule, szName, uLine);
		else
			wsprintfW(szBuf, L"%s!%s", szModule, szName);

		SetFrameItem(szBuf, i);
	
		pFunction->Release();
		pFrame->Release();
		i++;
	}

	pFrameEnum->Release();
	pChain->Release();
}

void CManagedCallback::GetElementTypeName(ICorDebugValue *pValue, LPWSTR lpszBuf)
{
	CorElementType type;
	HRESULT        hr;

	pValue->GetType(&type);

	if (type == ELEMENT_TYPE_VALUETYPE || type == ELEMENT_TYPE_CLASS) {
		ICorDebugValue2 *pValue2;
		ICorDebugType   *pType;
		ICorDebugClass  *pClass;
		
		pValue->QueryInterface(IID_PPV_ARGS(&pValue2));
		pValue2->GetExactType(&pType);
		pType->GetClass(&pClass);

		GetClassName(pClass, lpszBuf);

		pClass->Release();
		pType->Release();
		pValue2->Release();
		
		return;
	}
	else if (type == ELEMENT_TYPE_STRING)
		lstrcpyW(lpszBuf, L"string");
	else if (type == ELEMENT_TYPE_SZARRAY) {
		ICorDebugArrayValue *pArrayValue;
		WCHAR               szType[256];

		ObjectDereference(&pValue);
		hr = pValue->QueryInterface(IID_PPV_ARGS(&pArrayValue));
		if (SUCCEEDED(hr)) {
			ICorDebugValue *p;
			hr = pArrayValue->GetElementAtPosition(0, &p);
			if (SUCCEEDED(hr)) {
				GetElementTypeName(p, szType);
				wsprintfW(lpszBuf, L"%s[]", szType);
				pArrayValue->Release();
				p->Release();
			}
			else
				lstrcpyW(lpszBuf, L"?");
		}
		else
			lstrcpyW(lpszBuf, L"?");
		return;
	}
	else
		GetGenericType(type, lpszBuf);
}

void CManagedCallback::GetGenericType(CorElementType type, LPWSTR lpszBuf)
{
	WCHAR szType[256];

	if (type == ELEMENT_TYPE_BOOLEAN)
		lstrcpyW(szType, L"bool");
	else if (type == ELEMENT_TYPE_CHAR)
		lstrcpyW(szType, L"char");
	else if (type == ELEMENT_TYPE_I1)
		lstrcpyW(szType, L"sbyte");
	else if (type == ELEMENT_TYPE_U1)
		lstrcpyW(szType, L"byte");
	else if (type == ELEMENT_TYPE_I2)
		lstrcpyW(szType, L"short");
	else if (type == ELEMENT_TYPE_U2)
		lstrcpyW(szType, L"ushort");
	else if (type == ELEMENT_TYPE_I4)
		lstrcpyW(szType, L"int");
	else if (type == ELEMENT_TYPE_U4)
		lstrcpyW(szType, L"uint");
	else if (type == ELEMENT_TYPE_I8)
		lstrcpyW(szType, L"long");
	else if (type == ELEMENT_TYPE_U8)
		lstrcpyW(szType, L"ulong");
	else if (type == ELEMENT_TYPE_R4)
		lstrcpyW(szType, L"float");
	else if (type == ELEMENT_TYPE_R8)
		lstrcpyW(szType, L"double");
	else
		wsprintfW(szType, L"unknown", type);

	lstrcpyW(lpszBuf, szType);
}

void CManagedCallback::GetValue(ICorDebugValue *pValue, LPWSTR lpszBuf)
{
	CorElementType type;
	HRESULT        hr;

	pValue->GetType(&type);
	
	if (type == ELEMENT_TYPE_VALUETYPE) {
		ICorDebugObjectValue *pObjectValue;

		hr = pValue->QueryInterface(IID_PPV_ARGS(&pObjectValue));
		if (SUCCEEDED(hr)) {
			lstrcpyW(lpszBuf, L"[struct]");
			pObjectValue->Release();
		}
		else
			lstrcpyW(lpszBuf, L"?");
	}
	else if (type == ELEMENT_TYPE_CLASS) {
		ICorDebugObjectValue *pObjectValue;

		ObjectDereference(&pValue);
		
		hr = pValue->QueryInterface(IID_PPV_ARGS(&pObjectValue));
		if (SUCCEEDED(hr)) {
			lstrcpyW(lpszBuf, L"[class]");
			pObjectValue->Release();
		}
		else {
			ICorDebugBoxValue    *pBoxValue;
			ICorDebugObjectValue *p;
			
			hr = pValue->QueryInterface(IID_PPV_ARGS(&pBoxValue));
			if (SUCCEEDED(hr)) {
				pBoxValue->GetObject(&p);
				GetValue(p, lpszBuf);
				p->Release();
			}
			else
				lstrcpyW(lpszBuf, L"null");
		}
	}
	else if (type == ELEMENT_TYPE_STRING) {
		ICorDebugStringValue *pStringValue;
		ULONG32              uSize;

		ObjectDereference(&pValue);

		hr = pValue->QueryInterface(IID_PPV_ARGS(&pStringValue));
		if (SUCCEEDED(hr)) {
			pStringValue->GetString(256, &uSize, lpszBuf);
			pStringValue->Release();
		}
		else
			lstrcpyW(lpszBuf, L"null");
	}
	else if (type == ELEMENT_TYPE_SZARRAY) {
		ICorDebugArrayValue *pArrayValue;

		ObjectDereference(&pValue);

		hr = pValue->QueryInterface(IID_PPV_ARGS(&pArrayValue));
		if (SUCCEEDED(hr)) {
			lstrcpyW(lpszBuf, L"[array]");
			pArrayValue->Release();
		}
		else
			lstrcpyW(lpszBuf, L"?");
	}
	else {
		ICorDebugGenericValue *pGenericValue;

		hr = pValue->QueryInterface(IID_PPV_ARGS(&pGenericValue));
		if (SUCCEEDED(hr)) {
			BYTE   byte[100];
			LPBYTE lpValue = byte;
			
			pGenericValue->GetValue(lpValue);
			GetGenericValue(lpValue, type, lpszBuf);

			pGenericValue->Release();
		}
		else
			lstrcpyW(lpszBuf, L"?");
	}
}

void CManagedCallback::GetGenericValue(LPVOID lpValue, CorElementType type, LPWSTR lpszBuf)
{
	if (type == ELEMENT_TYPE_BOOLEAN) {
		if (*(bool *)lpValue == true)
			lstrcpyW(lpszBuf, L"true");
		else
			lstrcpyW(lpszBuf, L"false");
	}
	else if (type == ELEMENT_TYPE_CHAR)
		wsprintfW(lpszBuf, L"%c", *(char *)lpValue);	
	else if (type == ELEMENT_TYPE_I1)
		wsprintfW(lpszBuf, L"%d", *(char *)lpValue);
	else if (type == ELEMENT_TYPE_U1)
		wsprintfW(lpszBuf, L"%u", *(unsigned char *)lpValue);
	else if (type == ELEMENT_TYPE_I2)
		wsprintfW(lpszBuf, L"%d", *(short *)lpValue);
	else if (type == ELEMENT_TYPE_U2)
		wsprintfW(lpszBuf, L"%u", *(unsigned short *)lpValue);
	else if (type == ELEMENT_TYPE_I4)
		wsprintfW(lpszBuf, L"%d", *(int *)lpValue);
	else if (type == ELEMENT_TYPE_U4)
		wsprintfW(lpszBuf, L"%u", *(unsigned int *)lpValue);
	else if (type == ELEMENT_TYPE_I8)
		wsprintfW(lpszBuf, L"%d", *(LONGLONG *)lpValue);
	else if (type == ELEMENT_TYPE_U8)
		wsprintfW(lpszBuf, L"%u", *(ULONGLONG *)lpValue);
	else if (type == ELEMENT_TYPE_R4)
		lstrcpyW(lpszBuf, L"[float]");
	else if (type == ELEMENT_TYPE_R8)
		lstrcpyW(lpszBuf, L"[double]");
	else
		lstrcpyW(lpszBuf, L"?");
}

BOOL CManagedCallback::ObjectDereference(ICorDebugValue **ppDebugValue)
{
	ICorDebugValue          *pDebugValueOld = *ppDebugValue;
	ICorDebugValue          *pDebugValueNew;
	ICorDebugReferenceValue *pDebugReferenceValue;
	HRESULT                 hr;
	BOOL                    bNull;

	hr = pDebugValueOld->QueryInterface(IID_PPV_ARGS(&pDebugReferenceValue));
	if (FAILED(hr)) {
		pDebugReferenceValue->Release();
		return FALSE;
	}
	
	hr = pDebugReferenceValue->IsNull(&bNull);
	if (FAILED(hr) || bNull) {
		pDebugReferenceValue->Release();
		return FALSE;
	}

	pDebugValueOld->Release();
	pDebugReferenceValue->Dereference(&pDebugValueNew);
	*ppDebugValue = pDebugValueNew;

	return TRUE;
}

void CManagedCallback::CreateVariableArray(HDPA hdpa, ISymUnmanagedScope *pScope)
{
	ULONG32               i, uCount, uSize;
	ISymUnmanagedVariable **ppVariables;
	ISymUnmanagedScope    **ppScopes;

	pScope->GetLocalCount(&uCount);
	if (uCount > 0) {
		pScope->GetLocals(NULL, &uCount, NULL);
		uSize = uCount * sizeof(ISymUnmanagedScope);
		ppVariables = (ISymUnmanagedVariable **)HeapAlloc(GetProcessHeap(), 0, uSize);
		pScope->GetLocals(uSize, &uCount, ppVariables);
		for (i = 0; i < uCount; i++)
			DPA_InsertPtr(hdpa, 0, ppVariables[i]);
		HeapFree(GetProcessHeap(), 0, ppVariables);
	}
	
	pScope->GetChildren(NULL, &uCount, NULL);
	if (uCount > 0) {
		uSize = uCount * sizeof(ISymUnmanagedScope);
		ppScopes = (ISymUnmanagedScope **)HeapAlloc(GetProcessHeap(), 0, uSize);
		pScope->GetChildren(uSize, &uCount, ppScopes);
		for (i = 0; i < uCount; i++)
			CreateVariableArray(hdpa, ppScopes[i]);
		HeapFree(GetProcessHeap(), 0, ppScopes);
	}

	pScope->Release();
}

void CManagedCallback::GetVariable(HDPA hdpa, int nIndex, ISymUnmanagedVariable **ppVariable)
{
	int                   i;
	int                   n = DPA_GetPtrCount(hdpa);
	ISymUnmanagedVariable *pVariable;
	ULONG32               u;

	*ppVariable = NULL;

	for (i = 0; i < n; i++) {
		pVariable = (ISymUnmanagedVariable *)DPA_GetPtr(hdpa, i);
		pVariable->GetAddressField1(&u);
		if (u == (ULONG32)nIndex) {
			*ppVariable = pVariable;
			break;
		}
	}
}

ULONG32 CManagedCallback::GetOffsetFromSource(LPWSTR lpszSource, ULONG32 uLine, ULONG32 uColumn)
{
	ISymUnmanagedDocument *pSymDocument;
	ISymUnmanagedMethod   *pSymMethod;
	HRESULT               hr;
	GUID                  guid = {0};
	ULONG32               uOffset, uRangeArraySize, *pRangeArray;

	hr = g_pSymReader->GetDocument(lpszSource, guid, guid, guid, &pSymDocument);
	if (FAILED(hr))
		return 0;

	hr = g_pSymReader->GetMethodFromDocumentPosition(pSymDocument, uLine, uColumn, &pSymMethod);
	if (FAILED(hr)) {
		pSymDocument->Release();
		return 0;
	}

	uRangeArraySize = 0;
	pSymMethod->GetRanges(pSymDocument, uLine, uColumn, 0, &uRangeArraySize, NULL);
	pRangeArray = (ULONG32 *)HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG32) * uRangeArraySize);
	pSymMethod->GetRanges(pSymDocument, uLine, uColumn, uRangeArraySize, &uRangeArraySize, pRangeArray);
	uOffset = pRangeArray[0];
	
	pSymMethod->Release();
	pSymDocument->Release();
	HeapFree(GetProcessHeap(), 0, pRangeArray);

	return uOffset;
}

ULONG32 CManagedCallback::GetSourceLine(ICorDebugThread *pThread)
{
	ICorDebugFrame      *pFrame;
	ICorDebugILFrame    *pILFrame;
	ICorDebugFunction   *pFunction;
	ISymUnmanagedMethod *pSymMethod;
	mdMethodDef         methodDef;
	BOOL                bSym = g_pSymReader != NULL;
	ULONG32             uCount, uIP, i, uLine;
	ULONG32             *pOffsets, *pLines;

	if (!bSym)
		return 0;
	
	pThread->GetActiveFrame(&pFrame);
	pFrame->GetFunction(&pFunction);
	pFunction->GetToken(&methodDef);
	
	g_pSymReader->GetMethod(methodDef, &pSymMethod);
	pSymMethod->GetSequencePointCount(&uCount);
	
	pOffsets = (ULONG32 *)HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(ULONG32));
	pLines = (ULONG32 *)HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(ULONG32));
	
	pSymMethod->GetSequencePoints(uCount, NULL, pOffsets, NULL, pLines, NULL, NULL, NULL);
	pFrame->QueryInterface(IID_PPV_ARGS(&pILFrame));
	pILFrame->GetIP(&uIP, NULL);
	
	uLine = 0;
	for (i = 0; i < uCount; i++) {
		if (pOffsets[i] == uIP) {
			uLine = pLines[i];
			break;
		}
	}

	HeapFree(GetProcessHeap(), 0, pOffsets);
	HeapFree(GetProcessHeap(), 0, pLines);

	pILFrame->Release();
	pSymMethod->Release();
	pFunction->Release();
	pFrame->Release();
	
	return uLine;
}

void CManagedCallback::SetBreakpoint(ICorDebugModule *pModule, LPWSTR lpszClass, LPWSTR lpszMethod, ULONG32 uOffset)
{
	IMetaDataImport             *pMetaDataImport;
	ICorDebugFunction           *pFunction;
	ICorDebugCode               *pCode;
	ICorDebugFunctionBreakpoint *pFunctionBreakpoint;
	HRESULT                     hr;
	mdTypeDef                   typeDef;
	mdMethodDef                 methodDef;

	pModule->GetMetaDataInterface(IID_IMetaDataImport, (IUnknown **)&pMetaDataImport);
	
	hr = pMetaDataImport->FindTypeDefByName(lpszClass, NULL, &typeDef);
	if (FAILED(hr)) {
		pMetaDataImport->Release();
		return;
	}

	hr = pMetaDataImport->FindMethod(typeDef, lpszMethod, NULL, 0, &methodDef);
	if (FAILED(hr)) {
		pMetaDataImport->Release();
		return;
	}
	
	pModule->GetFunctionFromToken(methodDef, &pFunction);
	pFunction->GetILCode(&pCode);
	pCode->CreateBreakpoint(uOffset, &pFunctionBreakpoint);
	pFunctionBreakpoint->Activate(TRUE);

	pFunctionBreakpoint->Release();
	pCode->Release();
	pFunction->Release();
	pMetaDataImport->Release();
}

void CManagedCallback::GetModuleNameFromFunction(ICorDebugFunction *pFunction, LPWSTR lpszBuf)
{
	ICorDebugModule *pModule;
	WCHAR           szName[256];
	ULONG32         uSize;

	pFunction->GetModule(&pModule);

	pModule->GetName(256, &uSize, szName);
	lstrcpyW(lpszBuf, PathFindFileNameW(szName));
}

void CManagedCallback::GetClassName(ICorDebugClass *pClass, LPWSTR lpszClassName)
{
	ICorDebugModule *pModule;
	IMetaDataImport *pMetaDataImport;
	mdTypeDef       typeDef;

	pClass->GetToken(&typeDef);
	pClass->GetModule(&pModule);
	pModule->GetMetaDataInterface(IID_IMetaDataImport, (IUnknown **)&pMetaDataImport);

	pMetaDataImport->GetTypeDefProps(typeDef, lpszClassName, 256, NULL, NULL, NULL);
	
	pMetaDataImport->Release();
	pModule->Release();
}

void CManagedCallback::GetFullMethodName(ICorDebugFunction *pFunction, LPWSTR lpszFunctionName)
{
	ICorDebugClass  *pClass;
	ICorDebugModule *pModule;
	IMetaDataImport *pMetaDataImport;
	mdTypeDef       typeDef;
	mdMethodDef     methodDef;
	WCHAR           szClassName[256], szMethodName[256];
	
	pFunction->GetClass(&pClass);
	pClass->GetModule(&pModule);
	pModule->GetMetaDataInterface(IID_IMetaDataImport, (IUnknown **)&pMetaDataImport);
	
	pClass->GetToken(&typeDef);
	pMetaDataImport->GetTypeDefProps(typeDef, szClassName, 256, NULL, NULL, NULL);

	pFunction->GetToken(&methodDef);
	pMetaDataImport->GetMethodProps(methodDef, NULL, szMethodName, 256, NULL, 0, 0, NULL, NULL, NULL);

	wsprintfW(lpszFunctionName, L"%s.%s", szClassName, szMethodName);

	pMetaDataImport->Release();
	pModule->Release();
	pClass->Release();
	pFunction->Release();
}

必要ないと思われますが、一応デバッグ対象として使用したアプリケーションのコードを示します。

using System;
using System.Windows.Forms;

class class1
{
    public string s;
}

static class Program
{
    static void Main()
    {
        int n = 10;
        long[] l = new long[2];
        class1 c = new class1();

      //  System.Diagnostics.Debug.WriteLine("メッセージ");

        c.s = "str";
        l[0] = 1;
        l[1] = 2;

        ShowParam(n, l, c);
    }

    static void ShowParam(int n, long[] l, class1 c)
    {
        int a = 1;
        int b = 2;

        if (n == 10)
        {
            string cur = System.IO.Directory.GetCurrentDirectory();
            MessageBox.Show(cur);

            if (a + b == 4)
            {
                string var = System.Environment.OSVersion.ToString();
                MessageBox.Show(var);
            }
        }

        if (l[0] == 2)
        {
            Random r = new Random();
            MessageBox.Show(r.Next(100).ToString());
        }
        
        if (c.s == "st")
        {
            DateTime date = DateTime.Now;
            MessageBox.Show(date.ToString());
        }
    }
}

戻る