>From ebcfcdf4272b24a6803a6a84b69e7d4f827909af Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Fri, 4 Nov 2011 12:18:21 +1100
Subject: [PATCH] Implement ICorDebug CreateProcess
To: wine-patches <wine-patches@winehq.org>

---
 dlls/mscoree/Makefile.in       |    1 +
 dlls/mscoree/cordebug.c        |   41 ++++-
 dlls/mscoree/corprocess.c      |  430 ++++++++++++++++++++++++++++++++++++++++
 dlls/mscoree/mscoree_private.h |    1 +
 4 files changed, 469 insertions(+), 4 deletions(-)
 create mode 100644 dlls/mscoree/corprocess.c

diff --git a/dlls/mscoree/Makefile.in b/dlls/mscoree/Makefile.in
index 114b130..6940b96 100644
--- a/dlls/mscoree/Makefile.in
+++ b/dlls/mscoree/Makefile.in
@@ -5,6 +5,7 @@ C_SRCS = \
 	assembly.c \
 	config.c \
 	cordebug.c \
+	corprocess.c \
 	corruntimehost.c \
 	metadata.c \
 	metahost.c \
diff --git a/dlls/mscoree/cordebug.c b/dlls/mscoree/cordebug.c
index 498493e..9cea45d 100644
--- a/dlls/mscoree/cordebug.c
+++ b/dlls/mscoree/cordebug.c
@@ -215,18 +215,21 @@ static HRESULT WINAPI CorDebug_Terminate(ICorDebug *iface)
 {
     struct CorProcess *cursor, *cursor2;
     CorDebug *This = impl_from_ICorDebug( iface );
-    FIXME("stub %p\n", This);
+    TRACE("stub %p\n", This);
 
     LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->processes, struct CorProcess, entry)
     {
         if(cursor->pProcess)
+        {
+            ICorDebugProcess_Terminate(cursor->pProcess, 0);
             ICorDebugProcess_Release(cursor->pProcess);
+        }
 
         list_remove(&cursor->entry);
         HeapFree(GetProcessHeap(), 0, cursor);
     }
 
-    return E_NOTIMPL;
+    return S_OK;
 }
 
 static HRESULT WINAPI CorDebug_SetManagedHandler(ICorDebug *iface, ICorDebugManagedCallback *pCallback)
@@ -277,11 +280,41 @@ static HRESULT WINAPI CorDebug_CreateProcess(ICorDebug *iface, LPCWSTR lpApplica
             CorDebugCreateProcessFlags debuggingFlags, ICorDebugProcess **ppProcess)
 {
     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),
+    ICorDebugProcess *pDebugProcess;
+    HRESULT hr;
+
+    TRACE("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),
             lpStartupInfo, lpProcessInformation, debuggingFlags, ppProcess);
-    return E_NOTIMPL;
+
+    if(CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes,
+            bInheritHandles, dwCreationFlags | CREATE_SUSPENDED, lpEnvironment, lpCurrentDirectory,
+            lpStartupInfo, lpProcessInformation))
+    {
+        hr = CorDebugProcess_Create(This, (IUnknown**)&pDebugProcess, lpProcessInformation);
+        if(hr == S_OK)
+        {
+            struct CorProcess *new_process = HeapAlloc( GetProcessHeap(), 0, sizeof(CorProcess) );
+
+            new_process->pProcess = pDebugProcess;
+            list_add_tail(&This->processes, &new_process->entry);
+
+            ICorDebugProcess_AddRef(pDebugProcess);
+            *ppProcess = pDebugProcess;
+
+            if(This->pCallback)
+                ICorDebugManagedCallback_CreateProcess(This->pCallback, pDebugProcess);
+        }
+        else
+        {
+            TerminateProcess(lpProcessInformation->hProcess, 0);
+        }
+    }
+    else
+        hr = E_FAIL;
+
+    return hr;
 }
 
 static HRESULT WINAPI CorDebug_DebugActiveProcess(ICorDebug *iface, DWORD id, BOOL win32Attach,
diff --git a/dlls/mscoree/corprocess.c b/dlls/mscoree/corprocess.c
new file mode 100644
index 0000000..a8ee18e
--- /dev/null
+++ b/dlls/mscoree/corprocess.c
@@ -0,0 +1,430 @@
+/*
+ *
+ * Copyright 2011 Alistair Leslie-Hughes
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+
+#include "winuser.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "ole2.h"
+#include "shellapi.h"
+#include "mscoree.h"
+#include "corhdr.h"
+#include "metahost.h"
+#include "cordebug.h"
+#include "wine/list.h"
+#include "mscoree_private.h"
+#include "wine/debug.h"
+
+
+WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
+
+typedef struct DebugProcess
+{
+    ICorDebugProcess ICorDebugProcess_iface;
+
+    CorDebug *cordebug;
+
+    DWORD dwProcessID;
+    HANDLE handle;
+    HANDLE thread;
+
+    LONG ref;
+} DebugProcess;
+
+
+static inline DebugProcess *impl_from_ICorDebugProcess( ICorDebugProcess *iface )
+{
+    return CONTAINING_RECORD(iface, DebugProcess, ICorDebugProcess_iface);
+}
+
+static HRESULT WINAPI cordebugprocess_QueryInterface(ICorDebugProcess *iface,
+                REFIID riid, void **ppvObject)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+
+    TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
+
+    if ( IsEqualGUID( riid, &IID_ICorDebugProcess ) ||
+         IsEqualGUID( riid, &IID_ICorDebugController ) ||
+         IsEqualGUID( riid, &IID_IUnknown ) )
+    {
+        *ppvObject = &This->ICorDebugProcess_iface;
+    }
+    else
+    {
+        FIXME("Unsupported interface %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    ICorDebug_AddRef(iface);
+
+    return S_OK;
+}
+
+static ULONG WINAPI cordebugprocess_AddRef(ICorDebugProcess *iface)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("%p ref=%u\n", This, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI cordebugprocess_Release(ICorDebugProcess *iface)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("%p ref=%u\n", This, ref);
+
+    if (ref == 0)
+    {
+        if(This->handle)
+            CloseHandle(This->handle);
+
+        if(This->thread)
+            CloseHandle(This->thread);
+
+        if(This->cordebug)
+            ICorDebug_Release(&This->cordebug->ICorDebug_iface);
+
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI cordebugprocess_Stop(ICorDebugProcess *iface, DWORD dwTimeoutIgnored)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_Continue(ICorDebugProcess *iface, BOOL fIsOutOfBand)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    TRACE("%p\n", This);
+
+    if(This->thread)
+        ResumeThread(This->thread);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI cordebugprocess_IsRunning(ICorDebugProcess *iface, BOOL *pbRunning)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_HasQueuedCallbacks(ICorDebugProcess *iface,
+                ICorDebugThread *pThread, BOOL *pbQueued)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_EnumerateThreads(ICorDebugProcess *iface,
+                ICorDebugThreadEnum **ppThreads)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_SetAllThreadsDebugState(ICorDebugProcess *iface,
+                CorDebugThreadState state, ICorDebugThread *pExceptThisThread)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_Detach(ICorDebugProcess *iface)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_Terminate(ICorDebugProcess *iface, UINT exitCode)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    BOOL ret = TRUE;
+
+    TRACE("%p\n", This);
+
+    if(This->handle)
+    {
+        ret = TerminateProcess(This->handle, exitCode);
+        CloseHandle(This->handle);
+        This->handle = NULL;
+    }
+    return ret ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI cordebugprocess_CanCommitChanges(ICorDebugProcess *iface,
+                ULONG cSnapshots, ICorDebugEditAndContinueSnapshot * pSnapshots[],
+                ICorDebugErrorInfoEnum **pError)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_CommitChanges(ICorDebugProcess *iface,
+                ULONG cSnapshots, ICorDebugEditAndContinueSnapshot * pSnapshots[],
+                ICorDebugErrorInfoEnum **pError)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_GetID(ICorDebugProcess *iface, DWORD *pdwProcessId)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    TRACE("%p\n", This);
+
+    if(!pdwProcessId)
+        return E_INVALIDARG;
+
+    *pdwProcessId = This->dwProcessID;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI cordebugprocess_GetHandle(ICorDebugProcess *iface, HPROCESS *phProcessHandle)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    TRACE("%p\n", This);
+
+    if(!phProcessHandle)
+        return E_INVALIDARG;
+
+    *phProcessHandle = This->handle;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI cordebugprocess_GetThread(ICorDebugProcess *iface, DWORD dwThreadId,
+                ICorDebugThread **ppThread)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_EnumerateObjects(ICorDebugProcess *iface,
+                ICorDebugObjectEnum **ppObjects)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_IsTransitionStub(ICorDebugProcess *iface,
+                CORDB_ADDRESS address, BOOL *pbTransitionStub)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_IsOSSuspended(ICorDebugProcess *iface,
+                DWORD threadID, BOOL *pbSuspended)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_GetThreadContext(ICorDebugProcess *iface,
+                DWORD threadID, ULONG32 contextSize, BYTE context[])
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_SetThreadContext(ICorDebugProcess *iface,
+                DWORD threadID, ULONG32 contextSize, BYTE context[])
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_ReadMemory(ICorDebugProcess *iface,
+                CORDB_ADDRESS address, DWORD size, BYTE buffer[],
+                SIZE_T *read)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_WriteMemory(ICorDebugProcess *iface,
+                CORDB_ADDRESS address, DWORD size, BYTE buffer[],
+                SIZE_T *written)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_ClearCurrentException(ICorDebugProcess *iface,
+                DWORD threadID)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_EnableLogMessages(ICorDebugProcess *iface,
+                BOOL fOnOff)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_ModifyLogSwitch(ICorDebugProcess *iface,
+                WCHAR *pLogSwitchName, LONG lLevel)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_EnumerateAppDomains(ICorDebugProcess *iface,
+                ICorDebugAppDomainEnum **ppAppDomains)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_GetObject(ICorDebugProcess *iface,
+                ICorDebugValue **ppObject)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_ThreadForFiberCookie(ICorDebugProcess *iface,
+                DWORD fiberCookie, ICorDebugThread **ppThread)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI cordebugprocess_GetHelperThreadID(ICorDebugProcess *iface,
+                DWORD *pThreadID)
+{
+    DebugProcess *This = impl_from_ICorDebugProcess(iface);
+    FIXME("stub %p\n", This);
+    return E_NOTIMPL;
+}
+
+
+/***************************************/
+static const ICorDebugProcessVtbl cordebugprocessVtbl = {
+    cordebugprocess_QueryInterface,
+    cordebugprocess_AddRef,
+    cordebugprocess_Release,
+    cordebugprocess_Stop,
+    cordebugprocess_Continue,
+    cordebugprocess_IsRunning,
+    cordebugprocess_HasQueuedCallbacks,
+    cordebugprocess_EnumerateThreads,
+    cordebugprocess_SetAllThreadsDebugState,
+    cordebugprocess_Detach,
+    cordebugprocess_Terminate,
+    cordebugprocess_CanCommitChanges,
+    cordebugprocess_CommitChanges,
+    cordebugprocess_GetID,
+    cordebugprocess_GetHandle,
+    cordebugprocess_GetThread,
+    cordebugprocess_EnumerateObjects,
+    cordebugprocess_IsTransitionStub,
+    cordebugprocess_IsOSSuspended,
+    cordebugprocess_GetThreadContext,
+    cordebugprocess_SetThreadContext,
+    cordebugprocess_ReadMemory,
+    cordebugprocess_WriteMemory,
+    cordebugprocess_ClearCurrentException,
+    cordebugprocess_EnableLogMessages,
+    cordebugprocess_ModifyLogSwitch,
+    cordebugprocess_EnumerateAppDomains,
+    cordebugprocess_GetObject,
+    cordebugprocess_ThreadForFiberCookie,
+    cordebugprocess_GetHelperThreadID
+};
+
+
+HRESULT CorDebugProcess_Create(CorDebug *cordebug, IUnknown** ppUnk, LPPROCESS_INFORMATION lpProcessInformation)
+{
+    DebugProcess *This;
+
+    This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
+    if ( !This )
+        return E_OUTOFMEMORY;
+
+    if(!DuplicateHandle(GetCurrentProcess(), lpProcessInformation->hProcess,
+                    GetCurrentProcess(), &This->handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
+    {
+        ERR("Failed to duplicate process handle\n");
+        HeapFree(GetProcessHeap(), 0, This);
+        return E_FAIL;
+    }
+    if(!DuplicateHandle(GetCurrentProcess(), lpProcessInformation->hThread,
+                    GetCurrentProcess(), &This->thread, 0, FALSE, DUPLICATE_SAME_ACCESS))
+    {
+        CloseHandle(This->handle);
+
+        ERR("Failed to duplicate thread handle\n");
+        HeapFree(GetProcessHeap(), 0, This);
+        return E_FAIL;
+    }
+
+    This->ICorDebugProcess_iface.lpVtbl = &cordebugprocessVtbl;
+    This->ref = 1;
+    This->cordebug = cordebug;
+    This->dwProcessID = lpProcessInformation->dwProcessId;
+
+    if(This->cordebug)
+        ICorDebug_AddRef(&This->cordebug->ICorDebug_iface);
+
+    *ppUnk = (IUnknown*)This;
+
+    return S_OK;
+}
diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h
index 71bf738..b934801 100644
--- a/dlls/mscoree/mscoree_private.h
+++ b/dlls/mscoree/mscoree_private.h
@@ -183,5 +183,6 @@ extern HRESULT RuntimeHost_Destroy(RuntimeHost *This) DECLSPEC_HIDDEN;
 HRESULT WINAPI CLRMetaHost_GetRuntime(ICLRMetaHost* iface, LPCWSTR pwzVersion, REFIID iid, LPVOID *ppRuntime) DECLSPEC_HIDDEN;
 
 extern HRESULT CorDebug_Create(ICLRRuntimeHost *runtimehost, IUnknown** ppUnk) DECLSPEC_HIDDEN;
+extern HRESULT CorDebugProcess_Create(CorDebug *cordebug, IUnknown** ppUnk, LPPROCESS_INFORMATION proc_info) DECLSPEC_HIDDEN;
 
 #endif   /* __MSCOREE_PRIVATE__ */
-- 
1.7.5.4

