>From b2f03c85f4bdf01f4403c5a22219402ea124240f Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Thu, 29 Sep 2011 16:08:06 +1000
Subject: [PATCH] Implement ICorDebug SetManagedHandler
To: wine-patches <wine-patches@winehq.org>

---
 dlls/mscoree/cordebug.c        |  100 +++++++++--
 dlls/mscoree/corruntimehost.c  |    9 +-
 dlls/mscoree/mscoree_private.h |   15 ++-
 dlls/mscoree/tests/Makefile.in |    2 +-
 dlls/mscoree/tests/debugging.c |  377 +++++++++++++++++++++++++++++++++++++++-
 5 files changed, 474 insertions(+), 29 deletions(-)

diff --git a/dlls/mscoree/cordebug.c b/dlls/mscoree/cordebug.c
index a2ad032..62ded24 100644
--- a/dlls/mscoree/cordebug.c
+++ b/dlls/mscoree/cordebug.c
@@ -40,16 +40,15 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
 
-
-static inline RuntimeHost *impl_from_ICorDebug( ICorDebug *iface )
+static inline CorDebug *impl_from_ICorDebug( ICorDebug *iface )
 {
-    return CONTAINING_RECORD(iface, RuntimeHost, ICorDebug_iface);
+    return CONTAINING_RECORD(iface, CorDebug, ICorDebug_iface);
 }
 
 /*** IUnknown methods ***/
 static HRESULT WINAPI CorDebug_QueryInterface(ICorDebug *iface, REFIID riid, void **ppvObject)
 {
-    RuntimeHost *This = impl_from_ICorDebug( iface );
+    CorDebug *This = impl_from_ICorDebug( iface );
 
     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
 
@@ -71,41 +70,85 @@ static HRESULT WINAPI CorDebug_QueryInterface(ICorDebug *iface, REFIID riid, voi
 
 static ULONG WINAPI CorDebug_AddRef(ICorDebug *iface)
 {
-    RuntimeHost *This = impl_from_ICorDebug( iface );
-    return ICorRuntimeHost_AddRef(&This->ICorRuntimeHost_iface);
+    CorDebug *This = impl_from_ICorDebug( iface );
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("%p ref=%u\n", This, ref);
+
+    return ref;
 }
 
 static ULONG WINAPI CorDebug_Release(ICorDebug *iface)
 {
-    RuntimeHost *This = impl_from_ICorDebug( iface );
-    return ICorRuntimeHost_Release(&This->ICorRuntimeHost_iface);
+    CorDebug *This = impl_from_ICorDebug( iface );
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("%p ref=%u\n", This, ref);
+
+    if (ref == 0)
+    {
+        if(This->runtimehost)
+            ICLRRuntimeHost_Release(This->runtimehost);
+
+        if(This->pCallback)
+            ICorDebugManagedCallback2_Release(This->pCallback2);
+
+        if(This->pCallback)
+            ICorDebugManagedCallback_Release(This->pCallback);
+
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
 }
 
 /*** ICorDebug methods ***/
 static HRESULT WINAPI CorDebug_Initialize(ICorDebug *iface)
 {
-    RuntimeHost *This = impl_from_ICorDebug( iface );
+    CorDebug *This = impl_from_ICorDebug( iface );
     FIXME("stub %p\n", This);
     return S_OK;
 }
 
 static HRESULT WINAPI CorDebug_Terminate(ICorDebug *iface)
 {
-    RuntimeHost *This = impl_from_ICorDebug( iface );
+    CorDebug *This = impl_from_ICorDebug( iface );
     FIXME("stub %p\n", This);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI CorDebug_SetManagedHandler(ICorDebug *iface, ICorDebugManagedCallback *pCallback)
 {
-    RuntimeHost *This = impl_from_ICorDebug( iface );
-    FIXME("stub %p %p\n", This, pCallback);
-    return E_NOTIMPL;
+    CorDebug *This = impl_from_ICorDebug( iface );
+    HRESULT hr;
+    ICorDebugManagedCallback2 *pCallback2;
+
+    TRACE("%p (%p)\n", This, pCallback);
+
+    if(!pCallback)
+        return E_INVALIDARG;
+
+    hr = ICorDebugManagedCallback_QueryInterface(pCallback, &IID_ICorDebugManagedCallback2, (void**)&pCallback2);
+    if(hr == S_OK)
+    {
+        if(This->pCallback2)
+            ICorDebugManagedCallback2_Release(This->pCallback2);
+
+        if(This->pCallback)
+            ICorDebugManagedCallback_Release(This->pCallback);
+
+        This->pCallback = pCallback;
+        This->pCallback2 = pCallback2;
+
+        ICorDebugManagedCallback_AddRef(This->pCallback);
+    }
+
+    return hr;
 }
 
 static HRESULT WINAPI CorDebug_SetUnmanagedHandler(ICorDebug *iface, ICorDebugUnmanagedCallback *pCallback)
 {
-    RuntimeHost *This = impl_from_ICorDebug( iface );
+    CorDebug *This = impl_from_ICorDebug( iface );
     FIXME("stub %p %p\n", This, pCallback);
     return E_NOTIMPL;
 }
@@ -117,7 +160,7 @@ static HRESULT WINAPI CorDebug_CreateProcess(ICorDebug *iface, LPCWSTR lpApplica
             LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation,
             CorDebugCreateProcessFlags debuggingFlags, ICorDebugProcess **ppProcess)
 {
-    RuntimeHost *This = impl_from_ICorDebug( iface );
+    CorDebug *This = impl_from_ICorDebug( iface );
     FIXME("stub %p %s %s %p %p %d %d %p %s %p %p %d %p\n", This, debugstr_w(lpApplicationName),
             debugstr_w(lpCommandLine), lpProcessAttributes, lpThreadAttributes,
             bInheritHandles, dwCreationFlags, lpEnvironment, debugstr_w(lpCurrentDirectory),
@@ -128,21 +171,21 @@ static HRESULT WINAPI CorDebug_CreateProcess(ICorDebug *iface, LPCWSTR lpApplica
 static HRESULT WINAPI CorDebug_DebugActiveProcess(ICorDebug *iface, DWORD id, BOOL win32Attach,
             ICorDebugProcess **ppProcess)
 {
-    RuntimeHost *This = impl_from_ICorDebug( iface );
+    CorDebug *This = impl_from_ICorDebug( iface );
     FIXME("stub %p %d %d %p\n", This, id, win32Attach, ppProcess);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI CorDebug_EnumerateProcesses( ICorDebug *iface, ICorDebugProcessEnum **ppProcess)
 {
-    RuntimeHost *This = impl_from_ICorDebug( iface );
+    CorDebug *This = impl_from_ICorDebug( iface );
     FIXME("stub %p %p\n", This, ppProcess);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI CorDebug_GetProcess(ICorDebug *iface, DWORD dwProcessId, ICorDebugProcess **ppProcess)
 {
-    RuntimeHost *This = impl_from_ICorDebug( iface );
+    CorDebug *This = impl_from_ICorDebug( iface );
     FIXME("stub %p %d %p\n", This, dwProcessId, ppProcess);
     return E_NOTIMPL;
 }
@@ -150,7 +193,7 @@ static HRESULT WINAPI CorDebug_GetProcess(ICorDebug *iface, DWORD dwProcessId, I
 static HRESULT WINAPI CorDebug_CanLaunchOrAttach(ICorDebug *iface, DWORD dwProcessId,
             BOOL win32DebuggingEnabled)
 {
-    RuntimeHost *This = impl_from_ICorDebug( iface );
+    CorDebug *This = impl_from_ICorDebug( iface );
     FIXME("stub %p %d %d\n", This, dwProcessId, win32DebuggingEnabled);
     return E_NOTIMPL;
 }
@@ -171,7 +214,24 @@ static const struct ICorDebugVtbl cordebug_vtbl =
     CorDebug_CanLaunchOrAttach
 };
 
-void cordebug_init(RuntimeHost *This)
+HRESULT CorDebug_Create(ICLRRuntimeHost *runtimehost, IUnknown** ppUnk)
 {
+    CorDebug *This;
+
+    This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
+    if ( !This )
+        return E_OUTOFMEMORY;
+
     This->ICorDebug_iface.lpVtbl = &cordebug_vtbl;
+    This->ref = 1;
+    This->pCallback = NULL;
+    This->pCallback2 = NULL;
+    This->runtimehost = runtimehost;
+
+    if(This->runtimehost)
+        ICLRRuntimeHost_AddRef(This->runtimehost);
+
+    *ppUnk = (IUnknown*)This;
+
+    return S_OK;
 }
diff --git a/dlls/mscoree/corruntimehost.c b/dlls/mscoree/corruntimehost.c
index e3f4976..a676bce 100644
--- a/dlls/mscoree/corruntimehost.c
+++ b/dlls/mscoree/corruntimehost.c
@@ -787,8 +787,6 @@ HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version,
     This->ICorRuntimeHost_iface.lpVtbl = &corruntimehost_vtbl;
     This->ICLRRuntimeHost_iface.lpVtbl = &CLRHostVtbl;
 
-    cordebug_init(This);
-
     This->ref = 1;
     This->version = runtime_version;
     This->mono = loaded_mono;
@@ -826,8 +824,9 @@ HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid,
     }
     else if (IsEqualGUID(clsid, &CLSID_CLRDebuggingLegacy))
     {
-        unk = (IUnknown*)&This->ICorDebug_iface;
-        IUnknown_AddRef(unk);
+        hr = CorDebug_Create(&This->ICLRRuntimeHost_iface, &unk);
+        if (FAILED(hr))
+            return hr;
     }
     else
         unk = NULL;
@@ -851,7 +850,7 @@ HRESULT RuntimeHost_Destroy(RuntimeHost *This)
     struct DomainEntry *cursor, *cursor2;
 
     This->lock.DebugInfo->Spare[0] = 0;
-    DeleteCriticalSection(&This->lock);
+    DeleteCriticalSection(&This->lock);    
 
     LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->domains, struct DomainEntry, entry)
     {
diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h
index 15396f8..3c9ef1e 100644
--- a/dlls/mscoree/mscoree_private.h
+++ b/dlls/mscoree/mscoree_private.h
@@ -64,7 +64,6 @@ struct RuntimeHost
 {
     ICorRuntimeHost ICorRuntimeHost_iface;
     ICLRRuntimeHost ICLRRuntimeHost_iface;
-    ICorDebug       ICorDebug_iface;
     const CLRRuntimeInfo *version;
     loaded_mono *mono;
     struct list domains;
@@ -73,6 +72,18 @@ struct RuntimeHost
     LONG ref;
 };
 
+typedef struct CorDebug
+{
+    ICorDebug ICorDebug_iface;
+    LONG ref;
+
+    ICLRRuntimeHost *runtimehost;
+
+    /* ICorDebug Callback */
+    ICorDebugManagedCallback *pCallback;
+    ICorDebugManagedCallback2 *pCallback2;
+} CorDebug;
+
 extern HRESULT get_runtime_info(LPCWSTR exefile, LPCWSTR version, LPCWSTR config_file,
     DWORD startup_flags, DWORD runtimeinfo_flags, BOOL legacy, ICLRRuntimeInfo **result) DECLSPEC_HIDDEN;
 
@@ -161,6 +172,6 @@ extern HRESULT RuntimeHost_Destroy(RuntimeHost *This) DECLSPEC_HIDDEN;
 
 HRESULT WINAPI CLRMetaHost_GetRuntime(ICLRMetaHost* iface, LPCWSTR pwzVersion, REFIID iid, LPVOID *ppRuntime) DECLSPEC_HIDDEN;
 
-extern void cordebug_init(RuntimeHost *This) DECLSPEC_HIDDEN;
+extern HRESULT CorDebug_Create(ICLRRuntimeHost *runtimehost, IUnknown** ppUnk) DECLSPEC_HIDDEN;
 
 #endif   /* __MSCOREE_PRIVATE__ */
diff --git a/dlls/mscoree/tests/Makefile.in b/dlls/mscoree/tests/Makefile.in
index 20dfd88..fa24dfd 100644
--- a/dlls/mscoree/tests/Makefile.in
+++ b/dlls/mscoree/tests/Makefile.in
@@ -1,5 +1,5 @@
 TESTDLL   = mscoree.dll
-IMPORTS   = shlwapi
+IMPORTS   = ole32 shlwapi uuid
 
 C_SRCS = \
 	debugging.c \
diff --git a/dlls/mscoree/tests/debugging.c b/dlls/mscoree/tests/debugging.c
index ed5b9b1..fb5abe3 100644
--- a/dlls/mscoree/tests/debugging.c
+++ b/dlls/mscoree/tests/debugging.c
@@ -17,6 +17,7 @@
  */
 
 #define COBJMACROS
+#include <stdio.h>
 
 #include "windows.h"
 #include "ole2.h"
@@ -35,6 +36,366 @@ static HRESULT (WINAPI *pCreateDebuggingInterfaceFromVersion)(int, LPCWSTR, IUnk
 
 const WCHAR v2_0[] = {'v','2','.','0','.','5','0','7','2','7',0};
 
+static const char *debugstr_guid(REFIID riid)
+{
+    static char buf[50];
+
+    if(!riid)
+        return "(null)";
+
+    sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+            riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
+            riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
+            riid->Data4[5], riid->Data4[6], riid->Data4[7]);
+
+    return buf;
+}
+
+static HRESULT WINAPI ManagedCallback2_QueryInterface(ICorDebugManagedCallback2 *iface, REFIID riid, void **ppv)
+{
+    if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ICorDebugManagedCallback2, riid))
+    {
+        *ppv = iface;
+        return S_OK;
+    }
+
+    ok(0, "unexpected riid (%s)\n", debugstr_guid(riid));
+
+    *ppv = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ManagedCallback2_AddRef(ICorDebugManagedCallback2 *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ManagedCallback2_Release(ICorDebugManagedCallback2 *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ManagedCallback2_FunctionRemapOpportunity(ICorDebugManagedCallback2 *iface,
+                ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread,
+                ICorDebugFunction *pOldFunction, ICorDebugFunction *pNewFunction,
+                ULONG32 oldILOffset)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback2_CreateConnection(ICorDebugManagedCallback2 *iface,
+                ICorDebugProcess *pProcess, CONNID dwConnectionId, WCHAR *pConnName)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback2_ChangeConnection(ICorDebugManagedCallback2 *iface,
+                ICorDebugProcess *pProcess, CONNID dwConnectionId)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback2_DestroyConnection(ICorDebugManagedCallback2 *iface,
+                ICorDebugProcess *pProcess, CONNID dwConnectionId)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback2_Exception(ICorDebugManagedCallback2 *iface,
+                ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread,
+                ICorDebugFrame *pFrame, ULONG32 nOffset,
+                CorDebugExceptionCallbackType dwEventType, DWORD dwFlags)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback2_ExceptionUnwind(ICorDebugManagedCallback2 *iface,
+                ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread,
+                CorDebugExceptionUnwindCallbackType dwEventType, DWORD dwFlags)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback2_FunctionRemapComplete(ICorDebugManagedCallback2 *iface,
+                ICorDebugAppDomain *pAppDomain, ICorDebugThread *pThread,
+                ICorDebugFunction *pFunction)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback2_MDANotification(ICorDebugManagedCallback2 *iface,
+                ICorDebugController *pController, ICorDebugThread *pThread,
+                ICorDebugMDA *pMDA)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static struct ICorDebugManagedCallback2Vtbl managedCallback2Vtbl = {
+    ManagedCallback2_QueryInterface,
+    ManagedCallback2_AddRef,
+    ManagedCallback2_Release,
+    ManagedCallback2_FunctionRemapOpportunity,
+    ManagedCallback2_CreateConnection,
+    ManagedCallback2_ChangeConnection,
+    ManagedCallback2_DestroyConnection,
+    ManagedCallback2_Exception,
+    ManagedCallback2_ExceptionUnwind,
+    ManagedCallback2_FunctionRemapComplete,
+    ManagedCallback2_MDANotification
+};
+
+static ICorDebugManagedCallback2 ManagedCallback2 = { &managedCallback2Vtbl };
+
+static HRESULT WINAPI ManagedCallback_QueryInterface(ICorDebugManagedCallback *iface, REFIID riid, void **ppv)
+{
+    if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ICorDebugManagedCallback, riid))
+    {
+        *ppv = iface;
+        return S_OK;
+    }
+    else if(IsEqualGUID(&IID_ICorDebugManagedCallback2, riid))
+    {
+        *ppv = (void**)&ManagedCallback2;
+        return S_OK;
+    }
+
+    ok(0, "unexpected riid (%s)\n", debugstr_guid(riid));
+    *ppv = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ManagedCallback_AddRef(ICorDebugManagedCallback *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ManagedCallback_Release(ICorDebugManagedCallback *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ManagedCallback_Breakpoint(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *pThread, ICorDebugBreakpoint *pBreakpoint)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_StepComplete(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *pThread, ICorDebugStepper *pStepper, CorDebugStepReason reason)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_Break(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *thread)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_Exception(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *pThread, BOOL unhandled)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_EvalComplete(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *pThread, ICorDebugEval *pEval)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_EvalException(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *pThread, ICorDebugEval *pEval)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_CreateProcess(ICorDebugManagedCallback *iface, ICorDebugProcess *pProcess)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_ExitProcess(ICorDebugManagedCallback *iface, ICorDebugProcess *pProcess)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_CreateThread(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *thread)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_ExitThread(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *thread)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_LoadModule(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugModule *pModule)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_UnloadModule(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugModule *pModule)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_LoadClass(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugClass *c)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_UnloadClass(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugClass *c)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_DebuggerError(ICorDebugManagedCallback *iface, ICorDebugProcess *pProcess,
+                    HRESULT errorHR, DWORD errorCode)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_LogMessage(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *pThread, LONG lLevel, WCHAR *pLogSwitchName, WCHAR *pMessage)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_LogSwitch(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *pThread, LONG lLevel, ULONG ulReason,
+                    WCHAR *pLogSwitchName, WCHAR *pParentName)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_CreateAppDomain(ICorDebugManagedCallback *iface, ICorDebugProcess *pProcess,
+                    ICorDebugAppDomain *pAppDomain)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_ExitAppDomain(ICorDebugManagedCallback *iface, ICorDebugProcess *pProcess,
+                    ICorDebugAppDomain *pAppDomain)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_LoadAssembly(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugAssembly *pAssembly)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_UnloadAssembly(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugAssembly *pAssembly)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_ControlCTrap(ICorDebugManagedCallback *iface, ICorDebugProcess *pProcess)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_NameChange(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *pThread)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_UpdateModuleSymbols(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugModule *pModule, IStream *pSymbolStream)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_EditAndContinueRemap(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *pThread, ICorDebugFunction *pFunction, BOOL fAccurate)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ManagedCallback_BreakpointSetError(ICorDebugManagedCallback *iface, ICorDebugAppDomain *pAppDomain,
+                    ICorDebugThread *pThread, ICorDebugBreakpoint *pBreakpoint, DWORD dwError)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static ICorDebugManagedCallbackVtbl managedCallbackVtbl = {
+    ManagedCallback_QueryInterface,
+    ManagedCallback_AddRef,
+    ManagedCallback_Release,
+    ManagedCallback_Breakpoint,
+    ManagedCallback_StepComplete,
+    ManagedCallback_Break,
+    ManagedCallback_Exception,
+    ManagedCallback_EvalComplete,
+    ManagedCallback_EvalException,
+    ManagedCallback_CreateProcess,
+    ManagedCallback_ExitProcess,
+    ManagedCallback_CreateThread,
+    ManagedCallback_ExitThread,
+    ManagedCallback_LoadModule,
+    ManagedCallback_UnloadModule,
+    ManagedCallback_LoadClass,
+    ManagedCallback_UnloadClass,
+    ManagedCallback_DebuggerError,
+    ManagedCallback_LogMessage,
+    ManagedCallback_LogSwitch,
+    ManagedCallback_CreateAppDomain,
+    ManagedCallback_ExitAppDomain,
+    ManagedCallback_LoadAssembly,
+    ManagedCallback_UnloadAssembly,
+    ManagedCallback_ControlCTrap,
+    ManagedCallback_NameChange,
+    ManagedCallback_UpdateModuleSymbols,
+    ManagedCallback_EditAndContinueRemap,
+    ManagedCallback_BreakpointSetError
+};
+
+static ICorDebugManagedCallback ManagedCallback = { &managedCallbackVtbl };
+
 static BOOL init_functionpointers(void)
 {
     hmscoree = LoadLibraryA("mscoree.dll");
@@ -82,9 +443,20 @@ static void test_createDebugger(void)
     if(hr == S_OK)
     {
         hr = IUnknown_QueryInterface(pUnk, &IID_ICorDebug, (void**)&pCorDebug);
-        todo_wine ok(hr == S_OK, "expected S_OK got %08x\n", hr);
+        ok(hr == S_OK, "expected S_OK got %08x\n", hr);
         if(hr == S_OK)
         {
+            hr = ICorDebug_Initialize(pCorDebug);
+            ok(hr == S_OK, "expected S_OK got %08x\n", hr);
+            if(hr == S_OK)
+            {
+                hr = ICorDebug_SetManagedHandler(pCorDebug, NULL);
+                ok(hr == E_INVALIDARG, "expected E_INVALIDARG got %08x\n", hr);
+
+                hr = ICorDebug_SetManagedHandler(pCorDebug, &ManagedCallback);
+                ok(hr == S_OK, "expected S_OK got %08x\n", hr);
+            }
+
             ICorDebug_Release(pCorDebug);
         }
         IUnknown_Release(pUnk);
@@ -97,10 +469,13 @@ static void test_createDebugger(void)
 
 START_TEST(debugging)
 {
+    CoInitialize(NULL);
+
     if (!init_functionpointers())
         return;
 
     test_createDebugger();
 
     FreeLibrary(hmscoree);
+    CoUninitialize();
 }
-- 
1.7.4.1

