From 08d0cc8bfd7933c2ed42d8c8cba6c94f9a6628a1 Mon Sep 17 00:00:00 2001
From: "SND\\ussrhero_cp"
 <SND\ussrhero_cp@9b283d60-5439-405e-af05-b73fd8c4d996>
Date: Wed, 27 Apr 2016 22:18:55 +0000
Subject: [PATCH] [pykd_ext_2.0] added : python properties for binding

git-svn-id: https://pykd.svn.codeplex.com/svn@90979 9b283d60-5439-405e-af05-b73fd8c4d996
---
 pykd_ext/dbgout.h        |  11 ++-
 pykd_ext/dllmain.cpp     |  14 +--
 pykd_ext/export.def      |   1 +
 pykd_ext/pyapi.h         |   3 +
 pykd_ext/pyclass.h       |  52 ++++++-----
 pykd_ext/pyinterpret.cpp | 185 ++++++++++++++++++++++-----------------
 pykd_ext/pyinterpret.h   |  22 +++--
 pykd_ext/windbgext.cpp   | 102 +++++++++++++++++++--
 8 files changed, 263 insertions(+), 127 deletions(-)

diff --git a/pykd_ext/dbgout.h b/pykd_ext/dbgout.h
index 1c6e3dd..d124a4a 100644
--- a/pykd_ext/dbgout.h
+++ b/pykd_ext/dbgout.h
@@ -57,13 +57,18 @@ public:
         return false;
     }
 
+    bool isatty() {
+        return false;
+    }
+
 public:
 
     BEGIN_PYTHON_METHOD_MAP(DbgOut, "dbgout")
        PYTHON_METHOD1("write", write, "write");
        PYTHON_METHOD0("flush", flush, "flush");
-       PYTHON_METHOD0("encoding", encoding, "encoding");
-       PYTHON_METHOD0("closed", closed, "closed");
+       PYTHON_PROPERTY("encoding", encoding, "encoding");
+       PYTHON_PROPERTY("closed", closed, "closed");
+       PYTHON_METHOD0("isatty", isatty, "isatty");
     END_PYTHON_METHOD_MAP
 
 private:
@@ -104,7 +109,7 @@ public:
 
     BEGIN_PYTHON_METHOD_MAP(DbgIn, "dbgin")
         PYTHON_METHOD0("readline", readline, "readline");
-        PYTHON_METHOD0("closed", closed, "closed");
+        PYTHON_PROPERTY("closed", closed, "closed");
     END_PYTHON_METHOD_MAP
     
 private:
diff --git a/pykd_ext/dllmain.cpp b/pykd_ext/dllmain.cpp
index 6284baf..bc42683 100644
--- a/pykd_ext/dllmain.cpp
+++ b/pykd_ext/dllmain.cpp
@@ -9,13 +9,13 @@ BOOL APIENTRY DllMain( HMODULE hModule,
                        LPVOID lpReserved
 					 )
 {
-	if (!pinHandle)
-	{
-		GetModuleHandleEx(
-			GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN,
-			(LPCTSTR)hModule,
-			&pinHandle);
-	}
+	//if (!pinHandle)
+	//{
+	//	GetModuleHandleEx(
+	//		GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN,
+	//		(LPCTSTR)hModule,
+	//		&pinHandle);
+	//}
 
 	switch (ul_reason_for_call)
 	{
diff --git a/pykd_ext/export.def b/pykd_ext/export.def
index e355850..f029bfc 100644
--- a/pykd_ext/export.def
+++ b/pykd_ext/export.def
@@ -4,3 +4,4 @@ EXPORTS
 	py
 	info
 	pip
+	help
diff --git a/pykd_ext/pyapi.h b/pykd_ext/pyapi.h
index d1c9211..9dd2fbd 100644
--- a/pykd_ext/pyapi.h
+++ b/pykd_ext/pyapi.h
@@ -77,6 +77,7 @@ PyObject* PyBool_FromLong(long v);
 PyObject* Py_None();
 PyObject* PyExc_SystemExit();
 PyObject* PyType_Type();
+PyObject* PyProperty_Type();
 
 void PyErr_Fetch(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback);
 void PyErr_NormalizeException(PyObject**exc, PyObject**val, PyObject**tb);
@@ -94,6 +95,8 @@ int __stdcall Py_AddPendingCall(int(*func)(void *), void *arg);
 PyGILState_STATE __stdcall PyGILState_Ensure();
 void __stdcall PyGILState_Release(PyGILState_STATE);
 
+PyObject* __stdcall PyDescr_NewMethod(PyObject* type, struct PyMethodDef *meth);
+
 bool IsPy3();
 
 class  PyObjectRef;
diff --git a/pykd_ext/pyclass.h b/pykd_ext/pyclass.h
index 282c901..85cd875 100644
--- a/pykd_ext/pyclass.h
+++ b/pykd_ext/pyclass.h
@@ -100,15 +100,12 @@ struct convert_to_python
     } \
 template<typename T = classType> \
 static PyObject* getPythonClass() { \
-        PyObject*  classNameObj = IsPy3() ? PyUnicode_FromString(className) : PyString_FromString(className); \
-        PyObject*  classBases = PyTuple_New(0); \
-        PyObject*  classDictObj = PyDict_New(); \
         PyObject*  args = PyTuple_New(3); \
-        PyTuple_SetItem(args, 0, classNameObj); \
-        PyTuple_SetItem(args, 1, classBases); \
-        PyTuple_SetItem(args, 2, classDictObj); \
+        PyTuple_SetItem(args, 0, IsPy3() ? PyUnicode_FromString(className) : PyString_FromString(className)); \
+        PyTuple_SetItem(args, 1, PyTuple_New(0)); \
+        PyTuple_SetItem(args, 2, PyDict_New()); \
         PyObject*  classTypeObj = PyObject_CallObject(PyType_Type(), args); \
-        Py_DecRef(args), Py_DecRef(classNameObj), Py_DecRef(classDictObj), Py_DecRef(classBases); \
+        Py_DecRef(args);
 
 #define END_PYTHON_METHOD_MAP  \
         return classTypeObj; \
@@ -153,6 +150,32 @@ static PyObject* getPythonClass() { \
     Py_DecRef(cFuncObj), Py_DecRef(methodObj); \
     }
 
+#define PYTHON_PROPERTY(name, fn, doc) \
+    struct Call_##fn{ \
+            static PyObject* pycall(PyObject *s, PyObject *args) \
+             { \
+                PyObject*  self = PyTuple_GetItem(args, 0); \
+                PyObject*  cppobj =  PyObject_GetAttrString(self, "cppobject"); \
+                T*  _this = reinterpret_cast<T*>(PyCapsule_GetPointer(cppobj, "cppobject")); \
+                Py_DecRef(cppobj); \
+                return _this->callMethod0(&fn); \
+            } \
+        };  \
+        {\
+        static PyMethodDef methodDef = { name, Call_##fn::pycall, METH_VARARGS }; \
+        PyObject*  cFuncObj = PyCFunction_NewEx(&methodDef, NULL, NULL); \
+        PyObject*  methodObj = IsPy3() ? PyInstanceMethod_New(cFuncObj) : PyMethod_New(cFuncObj, NULL, classTypeObj); \
+        PyObject*  args = PyTuple_New(4); \
+        Py_IncRef(PyProperty_Type()); \
+        PyTuple_SetItem(args, 0, methodObj); \
+        PyTuple_SetItem(args, 1, Py_None()); \
+        PyTuple_SetItem(args, 2, Py_None()); \
+        PyTuple_SetItem(args, 3, IsPy3() ? PyUnicode_FromString(doc) : PyString_FromString(doc));\
+        PyObject*  propertyObj = PyObject_CallObject(PyProperty_Type(), args); \
+        PyObject_SetAttrString(classTypeObj, name, propertyObj); \
+        Py_DecRef(cFuncObj), Py_DecRef(propertyObj), Py_DecRef(args); \
+        }
+
 
 
 template<typename T1>
@@ -167,21 +190,6 @@ PyObject*  make_pyobject(const T2& var)
 {
     PyObject* cls = T1::getPythonClass();
     PyObject* p1 = PyObject_CallObject(cls, NULL);
-
-    PyObject  *errtype = NULL, *errvalue = NULL, *traceback = NULL;
-    PyErr_Fetch(&errtype, &errvalue, &traceback);
-
-    char*  str;
-    if (errtype)
-        Py_DecRef(errtype);
-    if (errvalue)
-    {
-        str = PyString_AsString(errvalue);
-        Py_DecRef(errvalue);
-    }
-    if (traceback)
-        Py_DecRef(traceback);
-
     Py_DecRef(cls);
 
     T1*  t1 = new T1(var);
diff --git a/pykd_ext/pyinterpret.cpp b/pykd_ext/pyinterpret.cpp
index caf2d8b..d987f3d 100644
--- a/pykd_ext/pyinterpret.cpp
+++ b/pykd_ext/pyinterpret.cpp
@@ -53,6 +53,7 @@ public:
     bool isPy3;
 
     PyObject* PyType_Type;
+    PyObject* PyProperty_Type;
     PyObject* Py_None;
     PyObject* PyExc_SystemExit;
 
@@ -115,6 +116,7 @@ public:
     int(__stdcall *Py_AddPendingCall)(int(*func)(void *), void *arg);
     PyGILState_STATE(__stdcall *PyGILState_Ensure)();
     void(__stdcall *PyGILState_Release)(PyGILState_STATE state);
+    PyObject* (__stdcall *PyDescr_NewMethod)(PyObject* type, struct PyMethodDef *meth);
 
     HMODULE  m_handlePython;
     PyThreadState*  m_globalState;
@@ -148,42 +150,26 @@ public:
 };
 
 
-
-
 class PythonSingleton
 {
 public:
 
 
-    static PythonInterpreter* getInterpreter(int majorVersion, int minorVersion, bool global)
-    {
-        return getSingleton()->_getInterpreter(majorVersion, minorVersion, global);
-    }
-
-    static void releaseInterpretor(PythonInterpreter* interpret)
-    {
-        return getSingleton()->_releaseInterpretor(interpret);
-    }
-
-    static PythonInterpreter* currentInterpreter()
-    {
-        return getSingleton()->m_currentInterpter;
-    }
-
-private:
-
-    static std::auto_ptr<PythonSingleton>  m_singleton;
-
-    static  PythonSingleton*  getSingleton()
+    static  PythonSingleton* get()
     {
         if (m_singleton.get() == 0)
             m_singleton.reset(new PythonSingleton());
         return m_singleton.get();
     }
 
-    PythonInterpreter* _getInterpreter(int majorVersion, int minorVersion, bool global)
-    {
 
+    PythonInterpreter* currentInterpreter()
+    {
+        return m_currentInterpter;
+    }
+
+    PythonInterpreter* getInterpreter(int majorVersion, int minorVersion, bool global)
+    {
         PyModule*  module = 0;
 
         if (m_modules.find(std::make_pair(majorVersion, minorVersion)) == m_modules.end())
@@ -219,7 +205,7 @@ private:
         return m_currentInterpter;
     }
 
-    void _releaseInterpretor(PythonInterpreter* interpret)
+    void releaseInterpretor(PythonInterpreter* interpret)
     {
         PyModule*  module = m_currentInterpter->m_module;
 
@@ -236,7 +222,22 @@ private:
         m_currentInterpter = 0;
     }
 
-public:
+    bool isInterpreterLoaded(int majorVersion, int minorVersion)
+    {
+        return m_modules.find(std::make_pair(majorVersion, minorVersion)) != m_modules.end();
+    }
+
+    void stopAllInterpreter()
+    {
+        for (auto m : m_modules)
+            delete m.second;
+
+        m_modules.clear();
+    }
+
+private:
+
+    static std::auto_ptr<PythonSingleton>  m_singleton;
 
     std::map<std::pair<int,int>, PyModule*>  m_modules;
    
@@ -337,6 +338,7 @@ PyModule::PyModule(int majorVesion, int minorVersion)
     isPy3 = majorVesion == 3;
 
     *reinterpret_cast<FARPROC*>(&PyType_Type) = GetProcAddress(m_handlePython, "PyType_Type");
+    *reinterpret_cast<FARPROC*>(&PyProperty_Type) = GetProcAddress(m_handlePython, "PyProperty_Type");
     *reinterpret_cast<FARPROC*>(&Py_None) = GetProcAddress(m_handlePython, "_Py_NoneStruct");
     PyExc_SystemExit = *reinterpret_cast<PyObject**>(GetProcAddress(m_handlePython, "PyExc_SystemExit"));
 
@@ -400,6 +402,8 @@ PyModule::PyModule(int majorVesion, int minorVersion)
     *reinterpret_cast<FARPROC*>(&Py_AddPendingCall) = GetProcAddress(m_handlePython, "Py_AddPendingCall");
     *reinterpret_cast<FARPROC*>(&PyGILState_Ensure) = GetProcAddress(m_handlePython, "PyGILState_Ensure");
     *reinterpret_cast<FARPROC*>(&PyGILState_Release) = GetProcAddress(m_handlePython, "PyGILState_Release");
+    *reinterpret_cast<FARPROC*>(&PyDescr_NewMethod) = GetProcAddress(m_handlePython, "PyDescr_NewMethod");
+    
     
     Py_Initialize();
     PyEval_InitThreads();
@@ -419,274 +423,295 @@ PyModule::~PyModule()
 
 PythonInterpreter* activateInterpreter(bool global, int majorVersion, int minorVersion)
 {
-    return PythonSingleton::getInterpreter(majorVersion, minorVersion, global);
+    return PythonSingleton::get()->getInterpreter(majorVersion, minorVersion, global);
 }
 
 void releaseInterpretor(PythonInterpreter* interpret)
 {
-    PythonSingleton::releaseInterpretor(interpret);
+    PythonSingleton::get()->releaseInterpretor(interpret);
 }
 
+bool isInterpreterLoaded(int majorVersion, int minorVersion)
+{
+    return PythonSingleton::get()->isInterpreterLoaded(majorVersion, minorVersion);
+}
+
+void stopAllInterpreter()
+{
+    PythonSingleton::get()->stopAllInterpreter();
+}
 
 void __stdcall Py_IncRef(PyObject* object)
 {
-    PythonSingleton::currentInterpreter()->m_module->Py_IncRef(object);
+    PythonSingleton::get()->currentInterpreter()->m_module->Py_IncRef(object);
 }
 
 void __stdcall Py_DecRef(PyObject* object)
 {
-    PythonSingleton::currentInterpreter()->m_module->Py_DecRef(object);
+    PythonSingleton::get()->currentInterpreter()->m_module->Py_DecRef(object);
 }
 
 PyObject* __stdcall PyString_FromString(const char *v)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyString_FromString(v);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyString_FromString(v);
 }
 
 PyObject* __stdcall  PyDict_New()
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyDict_New();
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyDict_New();
 }
 
 PyObject* __stdcall PyDict_GetItemString(PyObject *p, const char *key)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyDict_GetItemString(p, key);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyDict_GetItemString(p, key);
 }
 
 int __stdcall PyDict_SetItemString(PyObject *p, const char *key, PyObject *val)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyDict_SetItemString(p, key, val);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyDict_SetItemString(p, key, val);
 }
 
 PyObject* __stdcall PyCFunction_NewEx(PyMethodDef* pydef, PyObject *p1, PyObject *p2)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyCFunction_NewEx(pydef, p1, p2);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyCFunction_NewEx(pydef, p1, p2);
 }
 
 PyObject* __stdcall PyClass_New(PyObject* className, PyObject* classBases, PyObject* classDict)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyClass_New(className, classBases, classDict);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyClass_New(className, classBases, classDict);
 }
 
 PyObject* __stdcall PyMethod_New(PyObject *func, PyObject *self, PyObject *classobj)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyMethod_New(func, self, classobj);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyMethod_New(func, self, classobj);
 }
 
 int __stdcall PySys_SetObject(char *name, PyObject *v)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PySys_SetObject(name, v);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PySys_SetObject(name, v);
 }
 
 void __stdcall PySys_SetArgv(int argc, char **argv)
 {
-    PythonSingleton::currentInterpreter()->m_module->PySys_SetArgv(argc, argv);
+    PythonSingleton::get()->currentInterpreter()->m_module->PySys_SetArgv(argc, argv);
 }
 
 void __stdcall PySys_SetArgv_Py3(int argc, wchar_t **argv)
 {
-    PythonSingleton::currentInterpreter()->m_module->PySys_SetArgv_Py3(argc, argv);
+    PythonSingleton::get()->currentInterpreter()->m_module->PySys_SetArgv_Py3(argc, argv);
 }
 
 PyObject* __stdcall PySys_GetObject(char *name)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PySys_GetObject(name);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PySys_GetObject(name);
 }
 
 PyObject* __stdcall PyInstance_New(PyObject *classobj, PyObject *arg, PyObject *kw)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyInstance_New(classobj, arg, kw);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyInstance_New(classobj, arg, kw);
 }
 
 int __stdcall PyRun_SimpleString(const char* str)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyRun_SimpleString(str);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyRun_SimpleString(str);
 }
 
 PyObject* __stdcall PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyRun_String(str, start, globals, locals);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyRun_String(str, start, globals, locals);
 }
 
 PyObject* PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyCapsule_New(pointer, name, destructor);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyCapsule_New(pointer, name, destructor);
 }
 
 void* PyCapsule_GetPointer(PyObject *capsule, const char *name)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyCapsule_GetPointer(capsule, name);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyCapsule_GetPointer(capsule, name);
 }
 
 int PyObject_SetAttrString(PyObject *o, const char *attr_name, PyObject *v)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyObject_SetAttrString(o, attr_name, v);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyObject_SetAttrString(o, attr_name, v);
 }
 
 PyObject* PyObject_GetAttrString(PyObject *o, const char *attr_name)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyObject_GetAttrString(o, attr_name);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyObject_GetAttrString(o, attr_name);
 }
 
 PyObject* PyObject_CallObject(PyObject *callable_object, PyObject *args)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyObject_CallObject(callable_object, args);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyObject_CallObject(callable_object, args);
 }
 
 PyObject* PyObject_Call(PyObject *callable_object, PyObject *args, PyObject *kw)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyObject_Call(callable_object, args, kw);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyObject_Call(callable_object, args, kw);
 }
 
 PyObject* __stdcall PyTuple_New(size_t len)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyTuple_New(len);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyTuple_New(len);
 }
 
 PyObject* __stdcall PyTuple_GetItem(PyObject *p, size_t pos)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyTuple_GetItem(p, pos);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyTuple_GetItem(p, pos);
 }
 
 int __stdcall PyTuple_SetItem(PyObject *p, size_t pos, PyObject *obj)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyTuple_SetItem(p, pos, obj);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyTuple_SetItem(p, pos, obj);
 }
 
 size_t __stdcall PyTuple_Size(PyObject *p)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyTuple_Size(p);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyTuple_Size(p);
 }
 
 char* PyString_AsString(PyObject *string)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyString_AsString(string);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyString_AsString(string);
 }
 
 PyObject* PyUnicode_FromWideChar(const wchar_t *w, size_t size)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyUnicode_FromWideChar(w, size);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyUnicode_FromWideChar(w, size);
 }
 
 PyObject* PyImport_Import(PyObject *name)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyImport_Import(name);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyImport_Import(name);
 }
 
 PyObject* PyBool_FromLong(long v)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyBool_FromLong(v);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyBool_FromLong(v);
 }
 
 PyObject* Py_None()
 {
-    return PythonSingleton::currentInterpreter()->m_module->Py_None;
+    return PythonSingleton::get()->currentInterpreter()->m_module->Py_None;
 }
 
 PyObject* PyExc_SystemExit()
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyExc_SystemExit;
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyExc_SystemExit;
 }
 
 PyObject* PyType_Type()
 {
-    return  PythonSingleton::currentInterpreter()->m_module->PyType_Type;
+    return  PythonSingleton::get()->currentInterpreter()->m_module->PyType_Type;
+}
+
+PyObject* PyProperty_Type()
+{
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyProperty_Type;
 }
 
 void PyErr_Fetch(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback)
 {
-    PythonSingleton::currentInterpreter()->m_module->PyErr_Fetch(ptype, pvalue, ptraceback);
+    PythonSingleton::get()->currentInterpreter()->m_module->PyErr_Fetch(ptype, pvalue, ptraceback);
 }
 
 
 void PyErr_NormalizeException(PyObject**exc, PyObject**val, PyObject**tb)
 {
-    PythonSingleton::currentInterpreter()->m_module->PyErr_NormalizeException(exc, val, tb);
+    PythonSingleton::get()->currentInterpreter()->m_module->PyErr_NormalizeException(exc, val, tb);
 }
 
 void PyErr_SetString(PyObject *type, const char *message)
 {
-    PythonSingleton::currentInterpreter()->m_module->PyErr_SetString(type, message);
+    PythonSingleton::get()->currentInterpreter()->m_module->PyErr_SetString(type, message);
 }
 
 size_t PyList_Size(PyObject* list)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyList_Size(list);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyList_Size(list);
 }
 
 PyObject* PyList_GetItem(PyObject *list, size_t index)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyList_GetItem(list, index);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyList_GetItem(list, index);
 }
 
 PyObject* PyFile_FromString(char *filename, char *mode)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyFile_FromString(filename, mode);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyFile_FromString(filename, mode);
 }
 
 FILE* PyFile_AsFile(PyObject *pyfile)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyFile_AsFile(pyfile);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyFile_AsFile(pyfile);
 }
 
 PyObject* PyRun_File(FILE *fp, const char *filename, int start, PyObject *globals, PyObject *locals)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyRun_File(fp, filename, start, globals, locals);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyRun_File(fp, filename, start, globals, locals);
 }
 
 PyObject* __stdcall PyUnicode_FromString(const char*  str)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyUnicode_FromString(str);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyUnicode_FromString(str);
 }
 
 PyObject* __stdcall PyInstanceMethod_New(PyObject *func)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyInstanceMethod_New(func);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyInstanceMethod_New(func);
 }
 
 size_t __stdcall PyUnicode_AsWideChar(PyObject *unicode, wchar_t *w, size_t size)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyUnicode_AsWideChar(unicode, w, size);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyUnicode_AsWideChar(unicode, w, size);
 }
 
 PyObject* __stdcall PyImport_ImportModule(const char *name)
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyImport_ImportModule(name);
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyImport_ImportModule(name);
 }
 
 PyThreadState* __stdcall PyEval_SaveThread()
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyEval_SaveThread();
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyEval_SaveThread();
 }
 
 void __stdcall PyEval_RestoreThread(PyThreadState *tstate)
 {
-    PythonSingleton::currentInterpreter()->m_module->PyEval_RestoreThread(tstate);
+    PythonSingleton::get()->currentInterpreter()->m_module->PyEval_RestoreThread(tstate);
 }
 
 FILE* _Py_fopen(const char* filename, const char* mode)
 {
-    return PythonSingleton::currentInterpreter()->m_module->_Py_fopen(filename, mode);
+    return PythonSingleton::get()->currentInterpreter()->m_module->_Py_fopen(filename, mode);
 }
 
 int __stdcall Py_AddPendingCall(int(*func)(void *), void *arg)
 {
-    return PythonSingleton::currentInterpreter()->m_module->Py_AddPendingCall(func, arg);
+    return PythonSingleton::get()->currentInterpreter()->m_module->Py_AddPendingCall(func, arg);
 }
 
 PyGILState_STATE __stdcall PyGILState_Ensure()
 {
-    return PythonSingleton::currentInterpreter()->m_module->PyGILState_Ensure();
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyGILState_Ensure();
 }
 
 void __stdcall PyGILState_Release(PyGILState_STATE state)
 {
-    PythonSingleton::currentInterpreter()->m_module->PyGILState_Release(state);
+    PythonSingleton::get()->currentInterpreter()->m_module->PyGILState_Release(state);
 }
 
+PyObject* __stdcall PyDescr_NewMethod(PyObject* type, struct PyMethodDef *meth)
+{
+    return PythonSingleton::get()->currentInterpreter()->m_module->PyDescr_NewMethod(type, meth);
+}
+
+
+
 bool IsPy3()
 {
-    return PythonSingleton::currentInterpreter()->m_module->isPy3;
+    return PythonSingleton::get()->currentInterpreter()->m_module->isPy3;
 }
 
 
diff --git a/pykd_ext/pyinterpret.h b/pykd_ext/pyinterpret.h
index 08f772c..4bff860 100644
--- a/pykd_ext/pyinterpret.h
+++ b/pykd_ext/pyinterpret.h
@@ -9,8 +9,22 @@ class PythonInterpreter;
 
 PythonInterpreter*  activateInterpreter(bool global = true, int majorVersion = -1, int minorVersion = -1);
 
+
 void releaseInterpretor(PythonInterpreter* interpret);
 
+struct  InterpreterDesc {
+    int  majorVersion;
+    int  minorVersion;
+    std::string  imagePath;
+};
+
+std::list<InterpreterDesc>  getInstalledInterpreter();
+
+bool isInterpreterLoaded(int majorVersion, int minorVersion);
+
+void stopAllInterpreter();
+
+
 class AutoInterpreter
 {
 public:
@@ -34,13 +48,7 @@ private:
 };
 
 
-struct  InterpreterDesc {
-    int  majorVersion;
-    int  minorVersion;
-    std::string  imagePath;
-};
-
-std::list<InterpreterDesc>  getInstalledInterpreter();
+
 
 
 
diff --git a/pykd_ext/windbgext.cpp b/pykd_ext/windbgext.cpp
index f265a80..f87c9c2 100644
--- a/pykd_ext/windbgext.cpp
+++ b/pykd_ext/windbgext.cpp
@@ -100,6 +100,7 @@ VOID
 CALLBACK
 DebugExtensionUninitialize()
 {
+   // stopAllInterpreter();
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -107,7 +108,18 @@ DebugExtensionUninitialize()
 std::string make_version(int major, int minor)
 {
     std::stringstream sstr;
-    sstr << std::dec << major << '.' << minor;
+    sstr << std::dec << major << '.' << minor; 
+
+#ifdef _WIN64
+
+    sstr << " x86-64";
+
+#else
+
+    sstr << " x86-32";
+
+#endif
+
     return sstr.str();
 }
 
@@ -123,13 +135,16 @@ info(
     std::stringstream   sstr;
 
     sstr << std::endl << "Installed python" << std::endl << std::endl;
-    sstr << std::setw(12) << std::left << "Version:" <<  std::left << "Image:" <<  std::endl;
+    sstr << std::setw(14) << std::left << "Version:" << std::setw(12) << std::left << "Status: " << std::left << "Image:" <<  std::endl;
     sstr << "------------------------------------------------------------------------------" << std::endl;
     if (interpreterList.size() > 0)
     {
         for (const InterpreterDesc& desc : interpreterList)
         {
-            sstr << std::setw(12) << std::left << make_version(desc.majorVersion, desc.minorVersion);
+            sstr << std::setw(14) << std::left << make_version(desc.majorVersion, desc.minorVersion);
+            
+            sstr << std::setw(12) << std::left << (isInterpreterLoaded(desc.majorVersion, desc.minorVersion) ? "Loaded" : "Unloaded");
+
             sstr << desc.imagePath << std::endl;
         }
     }
@@ -159,8 +174,31 @@ static const char  printUsageMsg[] =
     "\tOptions:\n"
     "\t-g --global  : run code in the common namespace\n"
     "\t-l --local   : run code in the isolate namespace\n"
-    "!install\n"
-    "!upgrade\n";
+    "!pip\n"
+    "!info\n";
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern "C"
+HRESULT
+CALLBACK
+help(
+    PDEBUG_CLIENT client,
+    PCSTR args
+    )
+{
+    CComQIPtr<IDebugControl>  control = client;
+
+    control->ControlledOutput(
+        DEBUG_OUTCTL_THIS_CLIENT,
+        DEBUG_OUTPUT_NORMAL,
+        printUsageMsg
+        );
+
+    return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////////
 
 extern "C"
 HRESULT
@@ -286,8 +324,56 @@ pip(
 )
 {
 
-    return S_OK;
+    try {
 
+        Options  opts(getArgsList(args));
+
+        int  majorVersion = opts.pyMajorVersion;
+        int  minorVersion = opts.pyMinorVersion;
+
+        getPythonVersion(majorVersion, minorVersion);
+
+        AutoInterpreter  autoInterpreter(opts.global, majorVersion, minorVersion);
+
+        PyObjectRef  dbgOut = make_pyobject<DbgOut>(client);
+        PySys_SetObject("stdout", dbgOut);
+
+        PyObjectRef  dbgErr = make_pyobject<DbgOut>(client);
+        PySys_SetObject("stderr", dbgErr);
+
+        PyObjectRef dbgIn = make_pyobject<DbgIn>(client);
+        PySys_SetObject("stdin", dbgIn);
+
+        PyObjectRef  mainName = IsPy3() ? PyUnicode_FromString("__main__") : PyString_FromString("__main__");
+        PyObjectRef  mainMod = PyImport_Import(mainName);
+        PyObjectRef  globals = PyObject_GetAttrString(mainMod, "__dict__");
+
+
+        std::stringstream  sstr;
+        sstr << "pip.main([";
+        for (auto arg : opts.args)
+            sstr << '\'' << arg << '\'' << ',';
+        sstr << "])\n";
+
+        PyObjectRef result;
+        result = PyRun_String("import pip\n", Py_file_input, globals, globals);
+        result = PyRun_String("pip.logger.consumers = []\n", Py_file_input, globals, globals);
+        result = PyRun_String(sstr.str().c_str(), Py_file_input, globals, globals);
+
+        handleException();
+    }
+    catch (std::exception &e)
+    {
+        CComQIPtr<IDebugControl>  control = client;
+
+        control->ControlledOutput(
+            DEBUG_OUTCTL_THIS_CLIENT,
+            DEBUG_OUTPUT_ERROR,
+            e.what()
+            );
+    }
+
+    return S_OK;
 }
 
 
@@ -303,7 +389,7 @@ void handleException()
 
     PyErr_NormalizeException(&errtype, &errvalue, &traceback);
 
-    if (errtype != PyExc_SystemExit() )
+    if (errtype && errtype != PyExc_SystemExit())
     {
         PyObjectRef  traceback_module = PyImport_ImportModule("traceback");
 
@@ -329,7 +415,7 @@ void handleException()
         throw std::exception(sstr.str().c_str());
     }
 
-    Py_DecRef(errtype);
+    if (errtype) Py_DecRef(errtype);
     if (errvalue) Py_DecRef(errvalue);
     if (traceback) Py_DecRef(traceback);
 }