From adf139294694a57e6854b35dcdf9ae69e41501a3 Mon Sep 17 00:00:00 2001
From: "SND\\ussrhero_cp"
 <SND\ussrhero_cp@9b283d60-5439-405e-af05-b73fd8c4d996>
Date: Tue, 26 Apr 2016 17:56:16 +0000
Subject: [PATCH] [pykd_ext_2.0] added : new pykd bootstrapper

git-svn-id: https://pykd.svn.codeplex.com/svn@90978 9b283d60-5439-405e-af05-b73fd8c4d996
---
 pykd_ext/arglist.cpp                    |   81 ++
 pykd_ext/arglist.h                      |   27 +
 pykd_ext/dbgout.h                       |  116 +++
 pykd_ext/dllmain.cpp                    |   30 +
 pykd_ext/export.def                     |    6 +
 pykd_ext/packages.pykd_ext_vc120.config |    4 +
 pykd_ext/pyapi.h                        |  201 ++++
 pykd_ext/pyclass.h                      |  198 ++++
 pykd_ext/pycontext.h                    |   23 +
 pykd_ext/pyinterpret.cpp                |  692 +++++++++++++
 pykd_ext/pyinterpret.h                  |   46 +
 pykd_ext/pykd_ext_vc120.vcxproj         |  229 +++++
 pykd_ext/pykd_ext_vc120.vcxproj.filters |   82 ++
 pykd_ext/pymodule.h                     |   10 +
 pykd_ext/resource.h                     |   14 +
 pykd_ext/stdafx.cpp                     |    8 +
 pykd_ext/stdafx.h                       |   17 +
 pykd_ext/targetver.h                    |    8 +
 pykd_ext/version.h                      |   15 +
 pykd_ext/version.rc                     |  Bin 0 -> 5292 bytes
 pykd_ext/windbgext.cpp                  | 1204 +++++++++++++++++++++++
 21 files changed, 3011 insertions(+)
 create mode 100644 pykd_ext/arglist.cpp
 create mode 100644 pykd_ext/arglist.h
 create mode 100644 pykd_ext/dbgout.h
 create mode 100644 pykd_ext/dllmain.cpp
 create mode 100644 pykd_ext/export.def
 create mode 100644 pykd_ext/packages.pykd_ext_vc120.config
 create mode 100644 pykd_ext/pyapi.h
 create mode 100644 pykd_ext/pyclass.h
 create mode 100644 pykd_ext/pycontext.h
 create mode 100644 pykd_ext/pyinterpret.cpp
 create mode 100644 pykd_ext/pyinterpret.h
 create mode 100644 pykd_ext/pykd_ext_vc120.vcxproj
 create mode 100644 pykd_ext/pykd_ext_vc120.vcxproj.filters
 create mode 100644 pykd_ext/pymodule.h
 create mode 100644 pykd_ext/resource.h
 create mode 100644 pykd_ext/stdafx.cpp
 create mode 100644 pykd_ext/stdafx.h
 create mode 100644 pykd_ext/targetver.h
 create mode 100644 pykd_ext/version.h
 create mode 100644 pykd_ext/version.rc
 create mode 100644 pykd_ext/windbgext.cpp

diff --git a/pykd_ext/arglist.cpp b/pykd_ext/arglist.cpp
new file mode 100644
index 0000000..0a8151b
--- /dev/null
+++ b/pykd_ext/arglist.cpp
@@ -0,0 +1,81 @@
+#include "stdafx.h"
+
+#include <boost/tokenizer.hpp>
+#include <regex>
+
+#include "arglist.h"
+
+typedef  boost::escaped_list_separator<char>    char_separator_t;
+typedef  boost::tokenizer< char_separator_t >   char_tokenizer_t;
+
+
+ArgsList  getArgsList(const char* args)
+{
+    std::string  argsStr(args);
+
+    char_tokenizer_t  token(argsStr, char_separator_t("", " \t", "\""));
+    ArgsList  argsList;
+
+    for (char_tokenizer_t::iterator it = token.begin(); it != token.end(); ++it)
+    {
+        if (*it != "")
+            argsList.push_back(*it);
+    }
+
+    return argsList;
+}
+
+static const std::regex  versionRe("^-([2,3])(?:\\.(\\d+))?$");
+
+Options::Options(const ArgsList& argList) :
+    pyMajorVersion(2),
+    pyMinorVersion(-1),
+    global(true),
+    showHelp(false)
+{
+
+    args = argList;
+
+    for (auto it = args.begin(); it != args.end();)
+    {
+        if (*it == "--global" || *it == "-g")
+        {
+            global = true;
+            it = args.erase(it);
+            continue;
+        }
+
+        if (*it == "--local" || *it == "-l")
+        {
+            global = false;
+            it = args.erase(it);
+            continue;
+        }
+
+        if (*it == "--help" || *it == "-h")
+        {
+            showHelp = true;
+            it = args.erase(it);
+            continue;
+        }
+
+        std::smatch  mres;
+        if (std::regex_match(*it, mres, versionRe))
+        {
+            pyMajorVersion = atol(std::string(mres[1].first, mres[1].second).c_str());
+
+            if (mres[2].matched)
+            {
+                pyMinorVersion = atol(std::string(mres[2].first, mres[2].second).c_str());
+            }
+
+            it = args.erase(it);
+            continue;
+        }
+            
+        break;
+    }
+
+}
+
+
diff --git a/pykd_ext/arglist.h b/pykd_ext/arglist.h
new file mode 100644
index 0000000..e921f7f
--- /dev/null
+++ b/pykd_ext/arglist.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <vector>
+#include <string>
+
+typedef  std::vector< std::string >  ArgsList;
+
+ArgsList  getArgsList(const char* args);
+
+struct Options
+{
+    int  pyMajorVersion;
+    int  pyMinorVersion;
+    bool  global;
+    bool  showHelp;
+    std::vector<std::string>  args;
+
+    Options() :
+        pyMajorVersion(-1),
+        pyMinorVersion(-1),
+        global(true),
+        showHelp(false)
+    {}
+
+    Options(const ArgsList& argList);
+
+};
diff --git a/pykd_ext/dbgout.h b/pykd_ext/dbgout.h
new file mode 100644
index 0000000..1c6e3dd
--- /dev/null
+++ b/pykd_ext/dbgout.h
@@ -0,0 +1,116 @@
+#pragma once
+
+
+#include <DbgEng.h>
+#include <atlbase.h>
+#include <comutil.h>
+
+#include <string>
+#include <vector>
+
+#include "pycontext.h"
+#include "pyclass.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+class DbgOut
+{
+public:
+
+    DbgOut(PDEBUG_CLIENT client) :
+        m_control(client)
+    {}
+
+    void write(const std::wstring& str)
+    {
+        AutoRestorePyState  pystate;
+
+        m_control->ControlledOutputWide(
+            DEBUG_OUTCTL_THIS_CLIENT,
+            DEBUG_OUTPUT_NORMAL,
+            L"%ws",
+            str.c_str()
+            );
+
+    }
+
+    void writedml(const std::wstring& str)
+    {
+        AutoRestorePyState  pystate;
+
+        m_control->ControlledOutputWide(
+            DEBUG_OUTCTL_THIS_CLIENT | DEBUG_OUTCTL_DML,
+            DEBUG_OUTPUT_NORMAL,
+            L"%ws",
+            str.c_str()
+            );
+    }
+
+    void flush() {
+    }
+
+    std::wstring encoding() {
+        return L"ascii";
+    }
+
+    bool closed() {
+        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");
+    END_PYTHON_METHOD_MAP
+
+private:
+
+    CComQIPtr<IDebugControl4>  m_control;
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class DbgIn
+{
+public:
+
+    DbgIn(PDEBUG_CLIENT client) :
+        m_control(client)
+    {}
+
+    std::wstring readline()
+    {
+        AutoRestorePyState  pystate;
+
+        std::vector<wchar_t>  inputBuffer(0x10000);
+
+        ULONG  read = 0;
+        m_control->InputWide(&inputBuffer[0], static_cast<ULONG>(inputBuffer.size()), &read);
+
+        std::wstring  inputstr = std::wstring(&inputBuffer[0]);
+
+        return inputstr.empty() ? L"\n" : inputstr;
+    }
+
+    bool closed() {
+        return false;
+    }
+
+public:
+
+    BEGIN_PYTHON_METHOD_MAP(DbgIn, "dbgin")
+        PYTHON_METHOD0("readline", readline, "readline");
+        PYTHON_METHOD0("closed", closed, "closed");
+    END_PYTHON_METHOD_MAP
+    
+private:
+
+    CComQIPtr<IDebugControl4>  m_control;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
diff --git a/pykd_ext/dllmain.cpp b/pykd_ext/dllmain.cpp
new file mode 100644
index 0000000..6284baf
--- /dev/null
+++ b/pykd_ext/dllmain.cpp
@@ -0,0 +1,30 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "stdafx.h"
+
+
+static HMODULE  pinHandle = NULL;
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+                       DWORD  ul_reason_for_call,
+                       LPVOID lpReserved
+					 )
+{
+	if (!pinHandle)
+	{
+		GetModuleHandleEx(
+			GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN,
+			(LPCTSTR)hModule,
+			&pinHandle);
+	}
+
+	switch (ul_reason_for_call)
+	{
+	case DLL_PROCESS_ATTACH:
+	case DLL_THREAD_ATTACH:
+	case DLL_THREAD_DETACH:
+	case DLL_PROCESS_DETACH:
+		break;
+	}
+	return TRUE;
+}
+
diff --git a/pykd_ext/export.def b/pykd_ext/export.def
new file mode 100644
index 0000000..e355850
--- /dev/null
+++ b/pykd_ext/export.def
@@ -0,0 +1,6 @@
+EXPORTS
+	DebugExtensionInitialize
+	DebugExtensionUninitialize
+	py
+	info
+	pip
diff --git a/pykd_ext/packages.pykd_ext_vc120.config b/pykd_ext/packages.pykd_ext_vc120.config
new file mode 100644
index 0000000..5122450
--- /dev/null
+++ b/pykd_ext/packages.pykd_ext_vc120.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="boost" version="1.57.0.0" targetFramework="Native" />
+</packages>
diff --git a/pykd_ext/pyapi.h b/pykd_ext/pyapi.h
new file mode 100644
index 0000000..d1c9211
--- /dev/null
+++ b/pykd_ext/pyapi.h
@@ -0,0 +1,201 @@
+#pragma once
+
+
+typedef void*  PyObject;
+typedef void*  PyThreadState;
+typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
+
+
+typedef enum { PyGILState_LOCKED, PyGILState_UNLOCKED } PyGILState_STATE;
+
+const int Py_single_input = 256;
+const int Py_file_input = 257;
+const int Py_eval_input = 258;
+
+const int METH_VARARGS = 0x0001;
+
+struct PyMethodDef {
+    const char  *ml_name;   /* The name of the built-in function/method */
+    PyCFunction ml_meth;    /* The C function that implements it */
+    int         ml_flags;   /* Combination of METH_xxx flags, which mostly
+                            describe the args expected by the C func */
+    const char  *ml_doc;    /* The __doc__ attribute, or NULL */
+};
+
+typedef struct PyMethodDef PyMethodDef;
+
+void __stdcall Py_IncRef(PyObject* object);
+void __stdcall Py_DecRef(PyObject* object);
+
+PyObject* __stdcall PyString_FromString(const char *v);
+char* PyString_AsString(PyObject *string);
+
+PyObject* PyImport_Import(PyObject *name);
+PyObject* __stdcall PyImport_ImportModule(const char *name);
+
+PyObject* __stdcall  PyDict_New();
+int __stdcall PyDict_SetItemString(PyObject *p, const char *key, PyObject *val);
+
+PyObject* __stdcall PyTuple_New(size_t len);
+PyObject* __stdcall PyTuple_GetItem(PyObject *p, size_t pos);
+int __stdcall PyTuple_SetItem(PyObject *p, size_t pos, PyObject *obj);
+PyObject* __stdcall PyDict_GetItemString(PyObject *p, const char *key);
+size_t __stdcall PyTuple_Size(PyObject *p);
+
+size_t PyList_Size(PyObject* list);
+PyObject* PyList_GetItem(PyObject *list, size_t index);
+
+PyObject* __stdcall PyCFunction_NewEx(PyMethodDef *, PyObject *, PyObject *);
+PyObject* __stdcall PyClass_New(PyObject* className, PyObject* classBases, PyObject* classDict);
+PyObject* __stdcall PyMethod_New(PyObject *func, PyObject *self, PyObject *classobj);
+PyObject* __stdcall PyInstance_New(PyObject *classobj, PyObject *arg, PyObject *kw);
+
+PyThreadState* __stdcall PyEval_SaveThread();
+void __stdcall PyEval_RestoreThread(PyThreadState *tstate);
+
+int __stdcall PySys_SetObject(char *name, PyObject *v);
+PyObject* __stdcall PySys_GetObject(char *name);
+void __stdcall PySys_SetArgv(int argc, char **argv);
+void __stdcall PySys_SetArgv_Py3(int argc, wchar_t **argv);
+
+int __stdcall PyRun_SimpleString(const char* str);
+PyObject* __stdcall PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals);
+PyObject* PyRun_File(FILE *fp, const char *filename, int start, PyObject *globals, PyObject *locals);
+
+typedef void(*PyCapsule_Destructor)(PyObject *);
+PyObject* PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor);
+void* PyCapsule_GetPointer(PyObject *capsule, const char *name);
+
+int PyObject_SetAttrString(PyObject *o, const char *attr_name, PyObject *v);
+PyObject* PyObject_GetAttrString(PyObject *o, const char *attr_name);
+PyObject* PyObject_CallObject(PyObject *callable_object, PyObject *args);
+PyObject* PyObject_Call(PyObject *callable_object, PyObject *args, PyObject *kw);
+PyObject* PyUnicode_FromWideChar(const wchar_t *w, size_t size);
+
+PyObject* PyBool_FromLong(long v);
+
+PyObject* Py_None();
+PyObject* PyExc_SystemExit();
+PyObject* PyType_Type();
+
+void PyErr_Fetch(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback);
+void PyErr_NormalizeException(PyObject**exc, PyObject**val, PyObject**tb);
+void PyErr_SetString(PyObject *type, const char *message);
+
+PyObject* PyFile_FromString(char *filename, char *mode);
+FILE* PyFile_AsFile(PyObject *pyfile);
+FILE* _Py_fopen(const char* filename, const char* mode);
+
+PyObject* __stdcall PyUnicode_FromString(const char*  str);
+PyObject* __stdcall PyInstanceMethod_New(PyObject *func);
+size_t __stdcall PyUnicode_AsWideChar(PyObject *unicode, wchar_t *w, size_t size);
+int __stdcall Py_AddPendingCall(int(*func)(void *), void *arg);
+
+PyGILState_STATE __stdcall PyGILState_Ensure();
+void __stdcall PyGILState_Release(PyGILState_STATE);
+
+bool IsPy3();
+
+class  PyObjectRef;
+
+
+class PyObjectBorrowedRef
+{
+    friend PyObjectRef;
+
+public:
+
+    PyObjectBorrowedRef(PyObject* obj)
+    {
+        m_obj = obj;
+        if (m_obj)
+            Py_IncRef(m_obj);
+    }
+
+    ~PyObjectBorrowedRef()
+    {
+        if (m_obj)
+            Py_DecRef(m_obj);
+    }
+
+    operator PyObject*()
+    {
+        return m_obj;
+    }
+
+private:
+
+
+    PyObjectBorrowedRef(const PyObjectRef& obj) = delete;
+
+    PyObject*  m_obj;
+};
+
+
+class PyObjectRef
+{
+public:
+
+    PyObjectRef() : m_obj(0)
+    {}
+
+    PyObjectRef(PyObject* obj)
+    {
+        m_obj = obj;
+    }
+
+    ~PyObjectRef()
+    {
+        if (m_obj)
+            Py_DecRef(m_obj);
+    }
+
+    operator PyObject*()
+    {
+        return m_obj;
+    }
+
+    PyObjectRef& operator= (const PyObjectRef& ref)
+    {
+        if (m_obj)
+            Py_DecRef(m_obj);
+
+        m_obj = ref.m_obj;
+        if (m_obj)
+            Py_IncRef(m_obj);
+
+        return *this;
+    }
+
+    PyObjectRef& operator= (const PyObjectBorrowedRef& ref)
+    {
+        if (m_obj)
+            Py_DecRef(m_obj);
+
+        m_obj = ref.m_obj;
+        if (m_obj)
+            Py_IncRef(m_obj);
+
+        return *this;
+    }
+
+    PyObjectRef& operator= (PyObject* obj)
+    {
+        if (m_obj)
+            Py_DecRef(m_obj);
+
+        m_obj = obj;
+
+        return *this;
+    }
+
+private:
+
+    PyObjectRef(const PyObjectRef& obj) = delete;
+
+    PyObject*  m_obj;
+};
+
+
+
+
diff --git a/pykd_ext/pyclass.h b/pykd_ext/pyclass.h
new file mode 100644
index 0000000..282c901
--- /dev/null
+++ b/pykd_ext/pyclass.h
@@ -0,0 +1,198 @@
+#pragma once
+
+#include "pyapi.h"
+
+
+#include <comutil.h>
+
+#include <string>
+
+struct convert_from_python
+{
+    convert_from_python(PyObject* obj) : m_obj(obj){}
+
+    operator std::wstring()
+    {
+        if (IsPy3())
+        {
+            wchar_t  buf[0x100];
+            size_t  len = 0x100;
+            len = PyUnicode_AsWideChar(m_obj, buf, len);
+            return std::wstring(buf, len);
+        }
+        else
+            return std::wstring(_bstr_t(PyString_AsString(m_obj)));
+    }
+
+    operator std::string()
+    {
+        if (IsPy3())
+        {
+            wchar_t  buf[0x100];
+            size_t  len = 0x100;
+            len = PyUnicode_AsWideChar(m_obj, buf, len);
+            std::wstring  str(buf, len);
+            return std::string(_bstr_t(str.c_str()));
+        }
+        else
+            return std::string(PyString_AsString(m_obj));
+    }
+
+    PyObject* m_obj;
+};
+
+struct convert_to_python
+{
+    operator PyObject* (){
+        return m_obj;
+    }
+
+    convert_to_python()
+    {
+
+    }
+
+    convert_to_python(const std::wstring& str)
+    {
+        m_obj = PyUnicode_FromWideChar(str.c_str(), str.size());
+    }
+
+    convert_to_python(bool v)
+    {
+        m_obj = PyBool_FromLong(v == true ? 1 : 0);
+    }    
+
+    PyObject* m_obj;
+};
+
+
+
+#define BEGIN_PYTHON_METHOD_MAP(classType, className) \
+    template <typename TRet> \
+    PyObject* callMethod0( \
+        TRet (classType::*method)()) \
+      { \
+          TRet r = (this->*method)(); \
+          return convert_to_python(r); \
+      } \
+    PyObject* callMethod0(\
+        void (classType::*method)()) \
+    { \
+        (this->*method)(); \
+        Py_IncRef(Py_None()); \
+        return Py_None(); \
+    } \
+    template <typename TRet, typename V1> \
+    PyObject* callMethod1( \
+        TRet (classType::*method)(V1& v1), \
+        convert_from_python& v1)\
+      { \
+          return (this->*method)(v1); \
+      } \
+    template <typename V1> \
+    PyObject* callMethod1(\
+      void(classType::*method)(V1& v1), \
+      convert_from_python& v1)\
+    { \
+      (this->*method)(v1); \
+      Py_IncRef(Py_None()); \
+      return Py_None(); \
+    } \
+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); \
+        PyObject*  classTypeObj = PyObject_CallObject(PyType_Type(), args); \
+        Py_DecRef(args), Py_DecRef(classNameObj), Py_DecRef(classDictObj), Py_DecRef(classBases); \
+
+#define END_PYTHON_METHOD_MAP  \
+        return classTypeObj; \
+    }
+
+#define PYTHON_METHOD0(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_SetAttrString(classTypeObj, name, methodObj); \
+    Py_DecRef(cFuncObj), Py_DecRef(methodObj); \
+    }
+
+#define PYTHON_METHOD1(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); \
+            PyObject* v1 = PyTuple_GetItem(args, 1); \
+            return _this->callMethod1(&fn, convert_from_python(v1)); \
+        } \
+    };  \
+    {\
+    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_SetAttrString(classTypeObj, name, methodObj); \
+    Py_DecRef(cFuncObj), Py_DecRef(methodObj); \
+    }
+
+
+
+template<typename T1>
+void delete_pyobject(PyObject* obj)
+{
+    T1*  cppobj = reinterpret_cast<T1*>(PyCapsule_GetPointer(obj, "cppobject"));
+    delete cppobj;
+}
+
+template<typename T1, typename T2>
+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);
+    PyObject*  p2 = PyCapsule_New(t1, "cppobject", delete_pyobject<T1>);
+
+    PyObject_SetAttrString(p1, "cppobject", p2);
+
+    Py_DecRef(p2);
+
+    return p1;
+}
+
+
+
diff --git a/pykd_ext/pycontext.h b/pykd_ext/pycontext.h
new file mode 100644
index 0000000..5d06fd2
--- /dev/null
+++ b/pykd_ext/pycontext.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "pyapi.h"
+
+class AutoRestorePyState
+{
+public:
+
+    AutoRestorePyState()
+    {
+        m_state = PyEval_SaveThread();
+    }
+
+    ~AutoRestorePyState()
+    {
+        PyEval_RestoreThread(m_state);
+    }
+
+private:
+
+    PyThreadState*    m_state;
+};
+
diff --git a/pykd_ext/pyinterpret.cpp b/pykd_ext/pyinterpret.cpp
new file mode 100644
index 0000000..caf2d8b
--- /dev/null
+++ b/pykd_ext/pyinterpret.cpp
@@ -0,0 +1,692 @@
+#include "stdafx.h"
+#include "pyinterpret.h"
+
+#include <memory>
+#include <sstream>
+#include <map>
+
+#include "pymodule.h"
+#include "pyclass.h"
+#include "dbgout.h"
+
+class PyModule;
+class PythonInterpreter;
+
+class HKey 
+{
+
+public:
+
+    HKey() : m_key(NULL)
+    {}
+
+    ~HKey()
+    {
+        if (m_key)
+            RegCloseKey(m_key);
+    }
+
+    operator HKEY*()
+    {
+        return &m_key;
+    }
+
+    operator HKEY() const
+    {
+        return m_key;
+    }
+
+private:
+
+    HKEY  m_key;
+};
+
+
+class PyModule
+{
+public:
+
+    PyModule(int majorVesion, int minorVersion);
+
+    ~PyModule();
+
+    bool isPy3;
+
+    PyObject* PyType_Type;
+    PyObject* Py_None;
+    PyObject* PyExc_SystemExit;
+
+    void(__stdcall *Py_Initialize)();
+    void(__stdcall *Py_Finalize)();
+
+    PyThreadState* (__stdcall *Py_NewInterpreter)();
+    void(__stdcall *Py_EndInterpreter)(PyThreadState *tstate);
+    PyObject* (__stdcall *PyEval_GetGlobals)();
+    PyObject* (__stdcall *PyImport_Import)(PyObject *name);
+    PyObject* (__stdcall *PyImport_ImportModule)(const char *name);
+    void(__stdcall *PyEval_InitThreads)();
+    PyThreadState* (__stdcall *PyEval_SaveThread)();
+    void(__stdcall *PyEval_RestoreThread)(PyThreadState *tstate);
+    PyThreadState* (__stdcall *PyThreadState_Swap)(PyThreadState *tstate);
+    PyObject* (__stdcall *PyRun_String)(const char *str, int start, PyObject *globals, PyObject *locals);
+    int(__stdcall *PyRun_SimpleString)(const char*  str);
+    PyObject* (__stdcall *PyRun_File)(FILE *fp, const char *filename, int start, PyObject *globals, PyObject *locals);
+    PyObject* (__stdcall *PyDict_New)();
+    int(__stdcall *PyDict_SetItemString)(PyObject *p, const char *key, PyObject *val);
+    PyObject*(__stdcall *PyDict_GetItemString)(PyObject *p, const char* key);
+    void(__stdcall *Py_IncRef)(PyObject* object);
+    void(__stdcall *Py_DecRef)(PyObject* object);
+    PyObject* (__stdcall *PyObject_Call)(PyObject *callable_object, PyObject *args, PyObject *kw);
+    PyObject* (__stdcall *PyObject_GetAttr)(PyObject *object, PyObject *attr_name);
+    PyObject* (__stdcall *PyObject_GetAttrString)(PyObject *object, const char *attr_name);
+    int(__stdcall *PyObject_SetAttr)(PyObject *object, PyObject *attr_name, PyObject *value);
+    PyObject* (__stdcall *PyObject_CallObject)(PyObject *callable_object, PyObject *args);
+    PyObject* (__stdcall *PyTuple_New)(size_t len);
+    int(__stdcall *PyTuple_SetItem)(PyObject *p, size_t pos, PyObject *o);
+    PyObject* (__stdcall *PyTuple_GetItem)(PyObject *p, size_t pos);
+    size_t(__stdcall *PyTuple_Size)(PyObject *p);
+    PyObject* (__stdcall *PyCFunction_NewEx)(PyMethodDef *, PyObject *, PyObject *);
+    PyObject* (__stdcall *PySys_GetObject)(char *name);
+    int(__stdcall *PySys_SetObject)(char *name, PyObject *v);
+    void(__stdcall *PySys_SetArgv)(int argc, char **argv);
+    void(__stdcall *PySys_SetArgv_Py3)(int argc, wchar_t **argv);
+    PyObject* (__stdcall *PyString_FromString)(const char *v);
+    char* (__stdcall *PyString_AsString)(PyObject *string);
+    void(__stdcall *PyErr_Fetch)(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback);
+    void(__stdcall *PyErr_NormalizeException)(PyObject**exc, PyObject**val, PyObject**tb);
+    void (__stdcall *PyErr_SetString)(PyObject *type, const char *message);
+    PyObject* (__stdcall *PyImport_AddModule)(const char *name);
+    PyObject* (__stdcall *PyClass_New)(PyObject* className, PyObject* classBases, PyObject* classDict);
+    PyObject* (__stdcall *PyInstance_New)(PyObject *classobj, PyObject *arg, PyObject *kw);
+    PyObject* (__stdcall *PyMethod_New)(PyObject *func, PyObject *self, PyObject *classobj);
+    PyObject* (__stdcall *PyCapsule_New)(void *pointer, const char *name, PyCapsule_Destructor destructor);
+    void* (__stdcall *PyCapsule_GetPointer)(PyObject *capsule, const char *name);
+    int(__stdcall *PyObject_SetAttrString)(PyObject *o, const char *attr_name, PyObject *v);
+    PyObject* (__stdcall *PyUnicode_FromWideChar)(const wchar_t *w, size_t size);
+    PyObject* (__stdcall *PyBool_FromLong)(long v);
+    size_t(__stdcall *PyList_Size)(PyObject* list);
+    PyObject* (__stdcall *PyList_GetItem)(PyObject *list, size_t index);
+    PyObject* (__stdcall *PyFile_FromString)(char *filename, char *mode);
+    FILE* (__stdcall *PyFile_AsFile)(PyObject *pyfile);
+    PyObject* (__stdcall *PyUnicode_FromString)(const char *u);
+    PyObject* (__stdcall *PyInstanceMethod_New)(PyObject *func);
+    size_t(__stdcall *PyUnicode_AsWideChar)(PyObject *unicode, wchar_t *w, size_t size);
+    FILE* ( __stdcall *_Py_fopen)(const char* filename, const char* mode);
+    int(__stdcall *Py_AddPendingCall)(int(*func)(void *), void *arg);
+    PyGILState_STATE(__stdcall *PyGILState_Ensure)();
+    void(__stdcall *PyGILState_Release)(PyGILState_STATE state);
+
+    HMODULE  m_handlePython;
+    PyThreadState*  m_globalState;
+    PythonInterpreter*  m_globalInterpreter;
+};
+
+class PythonInterpreter
+{
+public:
+
+    PythonInterpreter(PyModule* mod) :
+        m_module(mod)
+    {
+        PyThreadState*  state = mod->Py_NewInterpreter();
+
+        m_module->PyThreadState_Swap(state);
+
+        m_state = m_module->PyEval_SaveThread();
+    }
+
+    ~PythonInterpreter()
+    {
+        m_module->PyEval_RestoreThread(m_state);
+
+        m_module->Py_EndInterpreter(m_state);
+    }
+
+    PyModule*  m_module;
+
+    PyThreadState*  m_state;
+};
+
+
+
+
+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()
+    {
+        if (m_singleton.get() == 0)
+            m_singleton.reset(new PythonSingleton());
+        return m_singleton.get();
+    }
+
+    PythonInterpreter* _getInterpreter(int majorVersion, int minorVersion, bool global)
+    {
+
+        PyModule*  module = 0;
+
+        if (m_modules.find(std::make_pair(majorVersion, minorVersion)) == m_modules.end())
+        {
+            module = new PyModule(majorVersion, minorVersion);
+            m_modules.insert(std::make_pair(std::make_pair(majorVersion, minorVersion), module));
+        }
+        else
+        {
+            module = m_modules[std::make_pair(majorVersion, minorVersion)];
+        }
+
+        if (global)
+        {
+            if (module->m_globalInterpreter == 0)
+            {
+                module->PyEval_RestoreThread(module->m_globalState);
+                module->m_globalInterpreter = new PythonInterpreter(module);
+            }
+
+            m_currentInterpter = module->m_globalInterpreter;
+            m_currentIsGlobal = true;
+        }
+        else
+        {
+            module->PyEval_RestoreThread(module->m_globalState);
+            m_currentInterpter = new PythonInterpreter(module);
+            m_currentIsGlobal = false;
+        }
+
+        m_currentInterpter->m_module->PyEval_RestoreThread(m_currentInterpter->m_state);
+
+        return m_currentInterpter;
+    }
+
+    void _releaseInterpretor(PythonInterpreter* interpret)
+    {
+        PyModule*  module = m_currentInterpter->m_module;
+
+        m_currentInterpter->m_state = module->PyEval_SaveThread();
+
+        if (!m_currentIsGlobal)
+        {
+            delete m_currentInterpter;
+
+            module->PyThreadState_Swap(module->m_globalState);
+            module->m_globalState = module->PyEval_SaveThread();
+        }
+
+        m_currentInterpter = 0;
+    }
+
+public:
+
+    std::map<std::pair<int,int>, PyModule*>  m_modules;
+   
+    PythonInterpreter*  m_currentInterpter;
+    bool  m_currentIsGlobal;
+};
+
+std::auto_ptr<PythonSingleton>  PythonSingleton::m_singleton; 
+
+
+HMODULE LoadPythonLibrary(int majorVesion, int minorVersion)
+{
+
+    HKey  pythonCoreKey;
+
+    for (auto rootKey : std::list<HKEY>({ HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER }))
+    {
+        if (ERROR_SUCCESS == RegOpenKeyA(rootKey, "SOFTWARE\\Python\\PythonCore", pythonCoreKey))
+        {
+            HKey  installPathKey;
+
+            std::stringstream   installPathStr;
+            installPathStr << majorVesion << '.' << minorVersion << "\\InstallPath";
+
+            if (ERROR_SUCCESS == RegOpenKeyA(pythonCoreKey, installPathStr.str().c_str(), installPathKey))
+            {
+                char  installPath[1000];
+                DWORD  installPathSize = sizeof(installPath);
+
+                if (ERROR_SUCCESS == RegQueryValueExA(installPathKey, NULL, NULL, NULL, (LPBYTE)installPath, &installPathSize))
+                {
+                    std::stringstream  dllName;
+                    dllName << "python" << majorVesion << minorVersion << ".dll";
+
+                    HMODULE  hmodule = LoadLibraryA(dllName.str().c_str());
+                    if (hmodule)
+                        return hmodule;
+
+                    std::stringstream  imagePath;
+                    imagePath << installPath << dllName.str();
+
+                    hmodule = LoadLibraryExA(imagePath.str().c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+                    if (hmodule)
+                        return hmodule;
+                }
+            }
+        }
+    }
+
+    return NULL;
+}
+
+std::list<InterpreterDesc>  getInstalledInterpreter()
+{
+    std::list<InterpreterDesc>  lst;
+
+    for (auto rootKey : std::list<HKEY>({ HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER }))
+    {
+        HKey  pythonCoreKey;
+
+        if (ERROR_SUCCESS != RegOpenKeyA(rootKey, "SOFTWARE\\Python\\PythonCore", pythonCoreKey))
+            continue;
+
+        for (DWORD i = 0;; ++i)
+        {
+            char  versionStr[20];
+            if (ERROR_SUCCESS != RegEnumKeyA(pythonCoreKey, i, versionStr, sizeof(versionStr)))
+                break;
+
+            int  majorVersion, minorVersion;
+
+            sscanf_s(versionStr, "%d.%d", &majorVersion, &minorVersion);
+
+            HMODULE  hmodule = LoadPythonLibrary(majorVersion, minorVersion);
+
+            if (hmodule)
+            {
+                char  fullPath[1000];
+
+                if (GetModuleFileNameA(hmodule, fullPath, sizeof(fullPath)))
+                    lst.push_back({ majorVersion, minorVersion, fullPath });
+
+                FreeLibrary(hmodule);
+            }
+        }
+    }
+
+    return lst;
+}
+
+PyModule::PyModule(int majorVesion, int minorVersion)
+{
+    m_handlePython = LoadPythonLibrary(majorVesion, minorVersion);
+
+    if (!m_handlePython)
+        throw std::exception("failed to load python module");
+
+    isPy3 = majorVesion == 3;
+
+    *reinterpret_cast<FARPROC*>(&PyType_Type) = GetProcAddress(m_handlePython, "PyType_Type");
+    *reinterpret_cast<FARPROC*>(&Py_None) = GetProcAddress(m_handlePython, "_Py_NoneStruct");
+    PyExc_SystemExit = *reinterpret_cast<PyObject**>(GetProcAddress(m_handlePython, "PyExc_SystemExit"));
+
+    *reinterpret_cast<FARPROC*>(&Py_Initialize) = GetProcAddress(m_handlePython, "Py_Initialize");
+    *reinterpret_cast<FARPROC*>(&Py_Finalize) = GetProcAddress(m_handlePython, "Py_Finalize");
+    *reinterpret_cast<FARPROC*>(&Py_NewInterpreter) = GetProcAddress(m_handlePython, "Py_NewInterpreter");
+    *reinterpret_cast<FARPROC*>(&Py_EndInterpreter) = GetProcAddress(m_handlePython, "Py_EndInterpreter");
+    *reinterpret_cast<FARPROC*>(&Py_DecRef) = GetProcAddress(m_handlePython, "Py_DecRef");
+    *reinterpret_cast<FARPROC*>(&Py_IncRef) = GetProcAddress(m_handlePython, "Py_IncRef");
+    *reinterpret_cast<FARPROC*>(&PyEval_GetGlobals) = GetProcAddress(m_handlePython, "PyEval_GetGlobals");
+    *reinterpret_cast<FARPROC*>(&PyEval_InitThreads) = GetProcAddress(m_handlePython, "PyEval_InitThreads");
+    *reinterpret_cast<FARPROC*>(&PyEval_SaveThread) = GetProcAddress(m_handlePython, "PyEval_SaveThread");
+    *reinterpret_cast<FARPROC*>(&PyEval_RestoreThread) = GetProcAddress(m_handlePython, "PyEval_RestoreThread");
+    *reinterpret_cast<FARPROC*>(&PyThreadState_Swap) = GetProcAddress(m_handlePython, "PyThreadState_Swap");
+    *reinterpret_cast<FARPROC*>(&PyRun_String) = GetProcAddress(m_handlePython, "PyRun_String");
+    *reinterpret_cast<FARPROC*>(&PyRun_SimpleString) = GetProcAddress(m_handlePython, "PyRun_SimpleString");
+    *reinterpret_cast<FARPROC*>(&PyRun_File) = GetProcAddress(m_handlePython, "PyRun_File");
+    *reinterpret_cast<FARPROC*>(&PyDict_New) = GetProcAddress(m_handlePython, "PyDict_New");
+    *reinterpret_cast<FARPROC*>(&PyDict_SetItemString) = GetProcAddress(m_handlePython, "PyDict_SetItemString");
+    *reinterpret_cast<FARPROC*>(&PyDict_GetItemString) = GetProcAddress(m_handlePython, "PyDict_GetItemString");
+    *reinterpret_cast<FARPROC*>(&PyObject_Call) = GetProcAddress(m_handlePython, "PyObject_Call");
+    *reinterpret_cast<FARPROC*>(&PyObject_GetAttr) = GetProcAddress(m_handlePython, "PyObject_GetAttr");
+    *reinterpret_cast<FARPROC*>(&PyObject_GetAttrString) = GetProcAddress(m_handlePython, "PyObject_GetAttrString");
+    *reinterpret_cast<FARPROC*>(&PyObject_SetAttr) = GetProcAddress(m_handlePython, "PyObject_SetAttr");
+    *reinterpret_cast<FARPROC*>(&PyObject_CallObject) = GetProcAddress(m_handlePython, "PyObject_CallObject");
+    *reinterpret_cast<FARPROC*>(&PyTuple_New) = GetProcAddress(m_handlePython, "PyTuple_New");
+    *reinterpret_cast<FARPROC*>(&PyTuple_SetItem) = GetProcAddress(m_handlePython, "PyTuple_SetItem");
+    *reinterpret_cast<FARPROC*>(&PyTuple_GetItem) = GetProcAddress(m_handlePython, "PyTuple_GetItem");
+    *reinterpret_cast<FARPROC*>(&PyTuple_Size) = GetProcAddress(m_handlePython, "PyTuple_Size");
+    *reinterpret_cast<FARPROC*>(&PyString_FromString) = GetProcAddress(m_handlePython, "PyString_FromString");
+    *reinterpret_cast<FARPROC*>(&PyCFunction_NewEx) = GetProcAddress(m_handlePython, "PyCFunction_NewEx");
+    *reinterpret_cast<FARPROC*>(&PySys_GetObject) = GetProcAddress(m_handlePython, "PySys_GetObject");
+    *reinterpret_cast<FARPROC*>(&PySys_SetObject) = GetProcAddress(m_handlePython, "PySys_SetObject");
+    *reinterpret_cast<FARPROC*>(&PySys_SetArgv) = !isPy3 ? GetProcAddress(m_handlePython, "PySys_SetArgv") : 0 ;
+    *reinterpret_cast<FARPROC*>(&PySys_SetArgv_Py3) = isPy3 ? GetProcAddress(m_handlePython, "PySys_SetArgv") : 0;
+    *reinterpret_cast<FARPROC*>(&PyString_FromString) = GetProcAddress(m_handlePython, "PyString_FromString");
+    *reinterpret_cast<FARPROC*>(&PyString_AsString) = GetProcAddress(m_handlePython, "PyString_AsString");
+    *reinterpret_cast<FARPROC*>(&PyErr_Fetch) = GetProcAddress(m_handlePython, "PyErr_Fetch");
+    *reinterpret_cast<FARPROC*>(&PyErr_NormalizeException) = GetProcAddress(m_handlePython, "PyErr_NormalizeException");
+    *reinterpret_cast<FARPROC*>(&PyErr_SetString) = GetProcAddress(m_handlePython, "PyErr_SetString");
+    *reinterpret_cast<FARPROC*>(&PyImport_AddModule) = GetProcAddress(m_handlePython, "PyImport_AddModule");
+    *reinterpret_cast<FARPROC*>(&PyImport_ImportModule) = GetProcAddress(m_handlePython, "PyImport_ImportModule");    
+    *reinterpret_cast<FARPROC*>(&PyClass_New) = GetProcAddress(m_handlePython, "PyClass_New");
+    *reinterpret_cast<FARPROC*>(&PyInstance_New) = GetProcAddress(m_handlePython, "PyInstance_New");
+    *reinterpret_cast<FARPROC*>(&PyMethod_New) = GetProcAddress(m_handlePython, "PyMethod_New");
+    *reinterpret_cast<FARPROC*>(&PyCapsule_New) = GetProcAddress(m_handlePython, "PyCapsule_New");
+    *reinterpret_cast<FARPROC*>(&PyCapsule_GetPointer) = GetProcAddress(m_handlePython, "PyCapsule_GetPointer");
+    *reinterpret_cast<FARPROC*>(&PyObject_SetAttrString) = GetProcAddress(m_handlePython, "PyObject_SetAttrString");
+    *reinterpret_cast<FARPROC*>(&PyUnicode_FromWideChar) = isPy3 ? GetProcAddress(m_handlePython, "PyUnicode_FromWideChar") :
+         GetProcAddress(m_handlePython, "PyUnicodeUCS2_FromWideChar");
+    *reinterpret_cast<FARPROC*>(&PyImport_Import) = GetProcAddress(m_handlePython, "PyImport_Import");
+    *reinterpret_cast<FARPROC*>(&PyBool_FromLong) = GetProcAddress(m_handlePython, "PyBool_FromLong");
+    *reinterpret_cast<FARPROC*>(&PyList_Size) = GetProcAddress(m_handlePython, "PyList_Size");
+    *reinterpret_cast<FARPROC*>(&PyList_GetItem) = GetProcAddress(m_handlePython, "PyList_GetItem");
+    *reinterpret_cast<FARPROC*>(&PyFile_FromString) = GetProcAddress(m_handlePython, "PyFile_FromString");
+    *reinterpret_cast<FARPROC*>(&PyFile_AsFile) = GetProcAddress(m_handlePython, "PyFile_AsFile");
+    *reinterpret_cast<FARPROC*>(&PyUnicode_FromString) = GetProcAddress(m_handlePython, "PyUnicode_FromString");
+    *reinterpret_cast<FARPROC*>(&PyInstanceMethod_New) = GetProcAddress(m_handlePython, "PyInstanceMethod_New");
+    *reinterpret_cast<FARPROC*>(&PyUnicode_AsWideChar) = GetProcAddress(m_handlePython, "PyUnicode_AsWideChar");
+    *reinterpret_cast<FARPROC*>(&_Py_fopen) = GetProcAddress(m_handlePython, "_Py_fopen");
+    *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");
+    
+    Py_Initialize();
+    PyEval_InitThreads();
+    m_globalState = PyEval_SaveThread();
+}
+
+
+PyModule::~PyModule()
+{
+    PyEval_RestoreThread(m_globalState);
+
+    Py_Finalize();
+
+    FreeLibrary(m_handlePython);
+}
+
+
+PythonInterpreter* activateInterpreter(bool global, int majorVersion, int minorVersion)
+{
+    return PythonSingleton::getInterpreter(majorVersion, minorVersion, global);
+}
+
+void releaseInterpretor(PythonInterpreter* interpret)
+{
+    PythonSingleton::releaseInterpretor(interpret);
+}
+
+
+void __stdcall Py_IncRef(PyObject* object)
+{
+    PythonSingleton::currentInterpreter()->m_module->Py_IncRef(object);
+}
+
+void __stdcall Py_DecRef(PyObject* object)
+{
+    PythonSingleton::currentInterpreter()->m_module->Py_DecRef(object);
+}
+
+PyObject* __stdcall PyString_FromString(const char *v)
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyString_FromString(v);
+}
+
+PyObject* __stdcall  PyDict_New()
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyDict_New();
+}
+
+PyObject* __stdcall PyDict_GetItemString(PyObject *p, const char *key)
+{
+    return PythonSingleton::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);
+}
+
+PyObject* __stdcall PyCFunction_NewEx(PyMethodDef* pydef, PyObject *p1, PyObject *p2)
+{
+    return PythonSingleton::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);
+}
+
+PyObject* __stdcall PyMethod_New(PyObject *func, PyObject *self, PyObject *classobj)
+{
+    return PythonSingleton::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);
+}
+
+void __stdcall PySys_SetArgv(int argc, char **argv)
+{
+    PythonSingleton::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);
+}
+
+PyObject* __stdcall PySys_GetObject(char *name)
+{
+    return PythonSingleton::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);
+}
+
+int __stdcall PyRun_SimpleString(const char* str)
+{
+    return PythonSingleton::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);
+}
+
+PyObject* PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
+{
+    return PythonSingleton::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);
+}
+
+int PyObject_SetAttrString(PyObject *o, const char *attr_name, PyObject *v)
+{
+    return PythonSingleton::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);
+}
+
+PyObject* PyObject_CallObject(PyObject *callable_object, PyObject *args)
+{
+    return PythonSingleton::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);
+}
+
+PyObject* __stdcall PyTuple_New(size_t len)
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyTuple_New(len);
+}
+
+PyObject* __stdcall PyTuple_GetItem(PyObject *p, size_t pos)
+{
+    return PythonSingleton::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);
+}
+
+size_t __stdcall PyTuple_Size(PyObject *p)
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyTuple_Size(p);
+}
+
+char* PyString_AsString(PyObject *string)
+{
+    return PythonSingleton::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);
+}
+
+PyObject* PyImport_Import(PyObject *name)
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyImport_Import(name);
+}
+
+PyObject* PyBool_FromLong(long v)
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyBool_FromLong(v);
+}
+
+PyObject* Py_None()
+{
+    return PythonSingleton::currentInterpreter()->m_module->Py_None;
+}
+
+PyObject* PyExc_SystemExit()
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyExc_SystemExit;
+}
+
+PyObject* PyType_Type()
+{
+    return  PythonSingleton::currentInterpreter()->m_module->PyType_Type;
+}
+
+void PyErr_Fetch(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback)
+{
+    PythonSingleton::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);
+}
+
+void PyErr_SetString(PyObject *type, const char *message)
+{
+    PythonSingleton::currentInterpreter()->m_module->PyErr_SetString(type, message);
+}
+
+size_t PyList_Size(PyObject* list)
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyList_Size(list);
+}
+
+PyObject* PyList_GetItem(PyObject *list, size_t index)
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyList_GetItem(list, index);
+}
+
+PyObject* PyFile_FromString(char *filename, char *mode)
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyFile_FromString(filename, mode);
+}
+
+FILE* PyFile_AsFile(PyObject *pyfile)
+{
+    return PythonSingleton::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);
+}
+
+PyObject* __stdcall PyUnicode_FromString(const char*  str)
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyUnicode_FromString(str);
+}
+
+PyObject* __stdcall PyInstanceMethod_New(PyObject *func)
+{
+    return PythonSingleton::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);
+}
+
+PyObject* __stdcall PyImport_ImportModule(const char *name)
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyImport_ImportModule(name);
+}
+
+PyThreadState* __stdcall PyEval_SaveThread()
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyEval_SaveThread();
+}
+
+void __stdcall PyEval_RestoreThread(PyThreadState *tstate)
+{
+    PythonSingleton::currentInterpreter()->m_module->PyEval_RestoreThread(tstate);
+}
+
+FILE* _Py_fopen(const char* filename, const char* mode)
+{
+    return PythonSingleton::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);
+}
+
+PyGILState_STATE __stdcall PyGILState_Ensure()
+{
+    return PythonSingleton::currentInterpreter()->m_module->PyGILState_Ensure();
+}
+
+void __stdcall PyGILState_Release(PyGILState_STATE state)
+{
+    PythonSingleton::currentInterpreter()->m_module->PyGILState_Release(state);
+}
+
+bool IsPy3()
+{
+    return PythonSingleton::currentInterpreter()->m_module->isPy3;
+}
+
+
diff --git a/pykd_ext/pyinterpret.h b/pykd_ext/pyinterpret.h
new file mode 100644
index 0000000..08f772c
--- /dev/null
+++ b/pykd_ext/pyinterpret.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <string>
+#include <list>
+
+#include "pymodule.h"
+
+class PythonInterpreter;
+
+PythonInterpreter*  activateInterpreter(bool global = true, int majorVersion = -1, int minorVersion = -1);
+
+void releaseInterpretor(PythonInterpreter* interpret);
+
+class AutoInterpreter
+{
+public:
+
+    explicit AutoInterpreter(bool global = true, int majorVersion = -1, int minorVersion = -1)
+    {
+        m_interpreter = activateInterpreter(global, majorVersion, minorVersion);
+    }
+    
+    ~AutoInterpreter()
+    {
+        if (m_interpreter)
+            releaseInterpretor(m_interpreter);
+    }
+
+private:
+
+    AutoInterpreter(const AutoInterpreter&) = delete;
+
+    PythonInterpreter*  m_interpreter;
+};
+
+
+struct  InterpreterDesc {
+    int  majorVersion;
+    int  minorVersion;
+    std::string  imagePath;
+};
+
+std::list<InterpreterDesc>  getInstalledInterpreter();
+
+
+
diff --git a/pykd_ext/pykd_ext_vc120.vcxproj b/pykd_ext/pykd_ext_vc120.vcxproj
new file mode 100644
index 0000000..c5fad86
--- /dev/null
+++ b/pykd_ext/pykd_ext_vc120.vcxproj
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug_2.7|Win32">
+      <Configuration>Debug_2.7</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug_2.7|x64">
+      <Configuration>Debug_2.7</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release_2.7|Win32">
+      <Configuration>Release_2.7</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release_2.7|x64">
+      <Configuration>Release_2.7</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{583F9A6C-AF6D-45E0-A8F4-290D93611185}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>pykd_bootstrapper</RootNamespace>
+    <ProjectName>pykd_ext_2.0</ProjectName>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+    <RestorePackages>true</RestorePackages>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120_xp</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120_xp</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_2.7|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120_xp</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_2.7|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120_xp</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_2.7|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_2.7|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros">
+    <NuGetPackageImportStamp>7f4aed3e</NuGetPackageImportStamp>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <TargetName>$(ProjectName)</TargetName>
+    <OutDir>$(SolutionDir)out\$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <TargetName>$(ProjectName)</TargetName>
+    <OutDir>$(SolutionDir)out\$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_2.7|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <TargetName>$(ProjectName)</TargetName>
+    <OutDir>$(SolutionDir)out\$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_2.7|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <TargetName>$(ProjectName)</TargetName>
+    <OutDir>$(SolutionDir)out\$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;PYKD_BOOTSTRAPPER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\kdlibcpp\include;</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <ModuleDefinitionFile>export.def</ModuleDefinitionFile>
+      <OutputFile>$(OutDir)pykd$(TargetExt)</OutputFile>
+      <AdditionalDependencies>comsuppw.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|x64'">
+    <ClCompile>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;PYKD_BOOTSTRAPPER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\kdlibcpp\include;</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <ModuleDefinitionFile>export.def</ModuleDefinitionFile>
+      <OutputFile>$(OutDir)pykd$(TargetExt)</OutputFile>
+      <AdditionalDependencies>comsuppw.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_2.7|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PYKD_BOOTSTRAPPER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\kdlibcpp\include;</AdditionalIncludeDirectories>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ModuleDefinitionFile>export.def</ModuleDefinitionFile>
+      <OutputFile>$(OutDir)pykd$(TargetExt)</OutputFile>
+      <AdditionalDependencies>comsuppw.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_2.7|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PYKD_BOOTSTRAPPER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <AdditionalIncludeDirectories>$(ProjectDir)..\kdlibcpp\include;</AdditionalIncludeDirectories>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ModuleDefinitionFile>export.def</ModuleDefinitionFile>
+      <OutputFile>$(OutDir)pykd$(TargetExt)</OutputFile>
+      <AdditionalDependencies>comsuppw.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="arglist.h" />
+    <ClInclude Include="dbgout.h" />
+    <ClInclude Include="pyapi.h" />
+    <ClInclude Include="pyclass.h" />
+    <ClInclude Include="pycontext.h" />
+    <ClInclude Include="pyinterpret.h" />
+    <ClInclude Include="pymodule.h" />
+    <ClInclude Include="resource.h" />
+    <ClInclude Include="stdafx.h" />
+    <ClInclude Include="targetver.h" />
+    <ClInclude Include="version.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="arglist.cpp" />
+    <ClCompile Include="dllmain.cpp">
+      <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|Win32'">false</CompileAsManaged>
+      <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|x64'">false</CompileAsManaged>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|Win32'">
+      </PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|x64'">
+      </PrecompiledHeader>
+      <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release_2.7|Win32'">false</CompileAsManaged>
+      <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release_2.7|x64'">false</CompileAsManaged>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release_2.7|Win32'">
+      </PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release_2.7|x64'">
+      </PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="pyinterpret.cpp" />
+    <ClCompile Include="stdafx.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug_2.7|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release_2.7|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release_2.7|x64'">Create</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="windbgext.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="export.def" />
+    <None Include="packages.pykd_bootstrapper_vc120.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="version.rc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+    <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
+    <Import Project="..\packages\boost.1.57.0.0\build\native\boost.targets" Condition="Exists('..\packages\boost.1.57.0.0\build\native\boost.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
+    <Error Condition="!Exists('..\packages\boost.1.57.0.0\build\native\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\boost.1.57.0.0\build\native\boost.targets'))" />
+  </Target>
+</Project>
\ No newline at end of file
diff --git a/pykd_ext/pykd_ext_vc120.vcxproj.filters b/pykd_ext/pykd_ext_vc120.vcxproj.filters
new file mode 100644
index 0000000..4873e94
--- /dev/null
+++ b/pykd_ext/pykd_ext_vc120.vcxproj.filters
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="stdafx.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="targetver.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="resource.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="version.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="dbgout.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="pycontext.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="arglist.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="pyinterpret.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="pymodule.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="pyclass.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="pyapi.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="stdafx.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="dllmain.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="windbgext.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="arglist.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="pyinterpret.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="export.def">
+      <Filter>Source Files</Filter>
+    </None>
+    <None Include="packages.pykd_bootstrapper_vc120.config">
+      <Filter>Source Files</Filter>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="version.rc">
+      <Filter>Resource Files</Filter>
+    </ResourceCompile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/pykd_ext/pymodule.h b/pykd_ext/pymodule.h
new file mode 100644
index 0000000..e0af157
--- /dev/null
+++ b/pykd_ext/pymodule.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <Windows.h>
+
+#include "pyapi.h"
+
+
+
+
+
diff --git a/pykd_ext/resource.h b/pykd_ext/resource.h
new file mode 100644
index 0000000..c3bc570
--- /dev/null
+++ b/pykd_ext/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by version.rc
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        101
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/pykd_ext/stdafx.cpp b/pykd_ext/stdafx.cpp
new file mode 100644
index 0000000..75c83a9
--- /dev/null
+++ b/pykd_ext/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// pykd_bootstrapper.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/pykd_ext/stdafx.h b/pykd_ext/stdafx.h
new file mode 100644
index 0000000..a8b112f
--- /dev/null
+++ b/pykd_ext/stdafx.h
@@ -0,0 +1,17 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
+// Windows Header Files:
+#include <windows.h>
+
+
+#define BOOST_PYTHON_STATIC_LIB
+
+// TODO: reference additional headers your program requires here
diff --git a/pykd_ext/targetver.h b/pykd_ext/targetver.h
new file mode 100644
index 0000000..90e767b
--- /dev/null
+++ b/pykd_ext/targetver.h
@@ -0,0 +1,8 @@
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include <SDKDDKVer.h>
diff --git a/pykd_ext/version.h b/pykd_ext/version.h
new file mode 100644
index 0000000..e455f7a
--- /dev/null
+++ b/pykd_ext/version.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#define PYKDEXT_VERSION_MAJOR      2
+#define PYKDEXT_VERSION_MINOR      0
+#define PYKDEXT_VERSION_SUBVERSION 0
+#define PYKDEXT_VERSION_BUILDNO    1
+
+#define __VER_STR2__(x) #x
+#define __VER_STR1__(x) __VER_STR2__(x)
+
+#define PYKDEXT_VERSION_BUILD_COMMA    PYKDEXT_VERSION_MAJOR, PYKDEXT_VERSION_MINOR, PYKDEXT_VERSION_SUBVERSION, PYKDEXT_VERSION_BUILDNO
+#define PYKDEXT_VERSION_BUILD          PYKDEXT_VERSION_MAJOR.PYKDEXT_VERSION_MINOR.PYKDEXT_VERSION_SUBVERSION.PYKDEXT_VERSION_BUILDNO
+
+#define PYKDEXT_VERSION_BUILD_STR_COMMA    __VER_STR1__(PYKDEXT_VERSION_BUILD_COMMA)
+#define PYKDEXT_VERSION_BUILD_STR          __VER_STR1__(PYKDEXT_VERSION_BUILD)
diff --git a/pykd_ext/version.rc b/pykd_ext/version.rc
new file mode 100644
index 0000000000000000000000000000000000000000..d21dc690c2bc4651b7e98d0f484eb7040fd6ac91
GIT binary patch
literal 5292
zcmd6rSx-|z6vxlAiQnN`UL-1;zW4~VRAQloE|G+!0Sed%t?A;D_}SIpf2PA-dap}G
zax<CE+*!{2&pC6J>5uR0wr-If*uXAqY$KacuWZU#m$8Y>?96WX+O=nt$gb_uhSV|R
zQ`$abV_NN-(Yv4@@g-^l`^cI#du)$5W!<$aj1HN-VRhfFtt{+cv-ehUtF?2*t-Esj
zM0?wgtYvNMSk?BeX+1l(8lzSEht{wYMq2zH*bXBN`r&+GC|?QaLK|5fxnyO0g_K5i
z3;$E3BRRC;`W?UfaJ>tkl1Gj4EoxRHzt_QMCttrWmVchMK5_aO4G+LGM7v2{l~1|>
zk-teZ5bM@mA*1E)QP5JLTdp>si?E3qI+B*o;5o9Vsgc#3J2FXF+`vibNy_s2(Ac&;
z?wq%{7S`2)>Mpmg$K7jCME4sdD%{zI#xXZsG&<Pksyns8=pmyW+Pb^NVI-_;anH5p
zIka1>+u=07M`zc-wasV)dyovgw#7xUwq-Y6czDb1s@qX6T_({4y@s~P`op|h)lH;T
z<R>)01MhX`LG%^POTI@wwT-z~t|2)uG3}DSS>}v9-%_zfKUA?({LLx1*vEtzWf7v6
zOCtK)b5@+6?qg%}C%#B)dA?=wwn=uy6qdE$<gF=JU;KtzE@VkGLa6Tu%NUaF+@ReF
zF-{(|!^q$+>uJ&RInc!Uy==^VXn!iJ?EHa0)w(*KavwkXCfA>)SM;FjbEqJjq`b=0
z59mUx3^tjmgmJa1UAXG;TO$%Fx+r_>IbXO(U%QhtvR{pBXGCuw3Dz=eA~Mqx;)&vs
zGP6bMJIGQytIX{}?SQg9r+Ea9CNmvo+V@I1pxxtS#n+ZQwFS}$pZ>*O;=dXWg?w@x
zGks(g=6Z(jn3AWkdAI)(i<uzzw4Ac*HxlcWk?GX*jwUEQ?N?w_c{Se?OTUe@kC3%r
zx3w_u^Mv%OaB_a+Q&!PL{*p`u1XCi9-YeH=d;n*cXm1GCQ6?7UQwuR6O;wz1*lWkp
zIlt+s7VpW6%waaPUG%BUUoxoNVXT5P`2zEqdd1m#g*Vw(`+&^Xs5g|zUQo~BX#~F$
z$MYGhK051(9Jgau#QW6i7vTOivb05dM1Ny5diNdAZ%Q~R-KHfXZRwRdrqw(4kl$Or
zi)4|ni*Q1kcGKOBYj;0HJKPYRbYEv2amEN)&v-FUe~bPhG?_;9|MVH>m_hoBBWb(p
zBKPr~7M8Kow0_%A)7xo+ZWZT~RwS?Ktyu4oO>$s)DDS~M-WYA%(|mEpcR%??dE#*v
ziMUTzA8UT~9$(Cvvoy=|EzX1{wEy}qj@~fYj57T%PLO4JWROK7gvIxL=;F<vzm<Lh
D_*Q}H

literal 0
HcmV?d00001

diff --git a/pykd_ext/windbgext.cpp b/pykd_ext/windbgext.cpp
new file mode 100644
index 0000000..f265a80
--- /dev/null
+++ b/pykd_ext/windbgext.cpp
@@ -0,0 +1,1204 @@
+#include "stdafx.h"
+
+#include <algorithm>
+#include <sstream>
+#include <iomanip> 
+
+#include <DbgEng.h>
+
+#include "dbgout.h"
+#include "arglist.h"
+#include "pyinterpret.h"
+#include "pyapi.h"
+#include "pyclass.h"
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+void handleException();
+std::string getScriptFileName(const std::string &scriptName);
+void  getPythonVersion(int&  majorVersion, int& minorVersion);
+
+//////////////////////////////////////////////////////////////////////////////
+
+class InterruptWatch
+{
+public:
+
+    InterruptWatch(PDEBUG_CLIENT client)
+    {
+        m_control = client;
+        m_stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+        m_thread = CreateThread(NULL, 0, threadRoutine, this, 0, NULL);
+    }
+
+    ~InterruptWatch()
+    {
+        SetEvent(m_stopEvent);
+        WaitForSingleObject(m_thread, INFINITE);
+        CloseHandle(m_stopEvent);
+        CloseHandle(m_thread);
+    }
+
+    static int quit(void *context)
+    {
+        HANDLE   quitEvent = (HANDLE)context;
+        PyErr_SetString(PyExc_SystemExit(), "CTRL+BREAK");
+        SetEvent(quitEvent);
+        return -1;
+    }
+
+private:
+
+    static DWORD WINAPI threadRoutine(LPVOID lpParameter) {
+        return  static_cast<InterruptWatch*>(lpParameter)->interruptWatchRoutine();
+    }
+
+    DWORD InterruptWatch::interruptWatchRoutine()
+    {
+        while (WAIT_TIMEOUT == WaitForSingleObject(m_stopEvent, 250))
+        {
+            HRESULT  hres = m_control->GetInterrupt();
+            if (hres == S_OK)
+            {
+                HANDLE  quitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+                PyGILState_STATE state = PyGILState_Ensure();
+                Py_AddPendingCall(&quit, (void*)quitEvent);
+                PyGILState_Release(state);
+                WaitForSingleObject(quitEvent, INFINITE);
+                CloseHandle(quitEvent);
+            }
+        }
+
+        return 0;
+    }
+
+    HANDLE  m_thread;
+
+    HANDLE  m_stopEvent;
+
+    CComQIPtr<IDebugControl>  m_control;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern "C"
+HRESULT
+CALLBACK
+DebugExtensionInitialize(
+    PULONG  Version,
+    PULONG  Flags
+)
+{
+    return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern "C"
+VOID
+CALLBACK
+DebugExtensionUninitialize()
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+std::string make_version(int major, int minor)
+{
+    std::stringstream sstr;
+    sstr << std::dec << major << '.' << minor;
+    return sstr.str();
+}
+
+extern "C"
+HRESULT
+CALLBACK
+info(
+    PDEBUG_CLIENT client,
+    PCSTR args
+)
+{
+    std::list<InterpreterDesc>   interpreterList = getInstalledInterpreter();
+    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::endl;
+    if (interpreterList.size() > 0)
+    {
+        for (const InterpreterDesc& desc : interpreterList)
+        {
+            sstr << std::setw(12) << std::left << make_version(desc.majorVersion, desc.minorVersion);
+            sstr << desc.imagePath << std::endl;
+        }
+    }
+    else
+    {
+        sstr << "No python interpreter found" << std::endl; 
+    }
+
+    sstr << std::endl;
+
+    CComQIPtr<IDebugControl>  control = client;
+
+    control->ControlledOutput(
+        DEBUG_OUTCTL_THIS_CLIENT,
+        DEBUG_OUTPUT_NORMAL,
+        sstr.str().c_str()
+        );
+
+    return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static const char  printUsageMsg[] =
+    "usage:\n"
+    "!py [options] [file]\n"
+    "\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";
+
+extern "C"
+HRESULT
+CALLBACK
+py(
+    PDEBUG_CLIENT client,
+    PCSTR args
+)
+{
+    ULONG   oldMask;
+    client->GetOutputMask(&oldMask);
+    client->SetOutputMask(DEBUG_OUTPUT_NORMAL | DEBUG_OUTPUT_ERROR);
+
+    try {
+
+        Options  opts(getArgsList(args));
+
+        if (opts.showHelp)
+            throw std::exception(printUsageMsg);
+
+        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__");
+
+        InterruptWatch  interruptWatch(client);
+
+        if (opts.args.empty())
+        {
+            PyObjectRef  result = PyRun_String("__import__('code').InteractiveConsole(__import__('__main__').__dict__).interact()\n", Py_file_input, globals, globals);
+        }
+        else
+        {
+            std::string  scriptFileName = getScriptFileName(opts.args[0]);
+            if (scriptFileName.empty())
+                throw std::invalid_argument("script not found\n");
+
+            if (IsPy3())
+            {
+                // �������������� ����������� ���������
+                std::vector<wchar_t*>  pythonArgs(opts.args.size());
+
+                std::wstring  scriptFileNameW = _bstr_t(scriptFileName.c_str());
+
+                pythonArgs[0] = const_cast<wchar_t*>(scriptFileNameW.c_str());
+
+                for (size_t i = 1; i < opts.args.size(); ++i)
+                {
+                    std::wstring  argw = _bstr_t(opts.args[i].c_str());
+                    pythonArgs[i] = const_cast<wchar_t*>(argw.c_str());
+                }
+
+                PySys_SetArgv_Py3((int)opts.args.size(), &pythonArgs[0]);
+
+                FILE*  fs = _Py_fopen(scriptFileName.c_str(), "r");
+                if ( !fs )
+                    throw std::invalid_argument("script not found\n");
+
+                PyObjectRef result = PyRun_File(fs, scriptFileName.c_str(), Py_file_input, globals, globals);
+            }
+            else
+            {
+                std::vector<char*>  pythonArgs(opts.args.size());
+
+                pythonArgs[0] = const_cast<char*>(scriptFileName.c_str());
+
+                for (size_t i = 1; i < opts.args.size(); ++i)
+                    pythonArgs[i] = const_cast<char*>(opts.args[i].c_str());
+
+                PySys_SetArgv((int)opts.args.size(), &pythonArgs[0]);
+
+                PyObjectRef  pyfile = PyFile_FromString(pythonArgs[0], "r");
+                if (!pyfile)
+                    throw std::invalid_argument("script not found\n");
+
+                FILE *fs = PyFile_AsFile(pyfile);
+
+                PyObjectRef result = PyRun_File(fs, scriptFileName.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()
+            );
+    }
+
+    client->SetOutputMask(oldMask);
+
+    return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern "C"
+HRESULT
+CALLBACK
+pip(
+    PDEBUG_CLIENT client,
+    PCSTR args
+)
+{
+
+    return S_OK;
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+void handleException()
+{
+    // ������ � �������
+    PyObject  *errtype = NULL, *errvalue = NULL, *traceback = NULL;
+
+    PyErr_Fetch(&errtype, &errvalue, &traceback);
+
+    PyErr_NormalizeException(&errtype, &errvalue, &traceback);
+
+    if (errtype != PyExc_SystemExit() )
+    {
+        PyObjectRef  traceback_module = PyImport_ImportModule("traceback");
+
+        std::stringstream  sstr;
+
+        PyObjectRef  format_exception = PyObject_GetAttrString(traceback_module, "format_exception");
+
+        PyObjectRef  args = PyTuple_New(3);
+        PyTuple_SetItem(args, 0, errtype ? errtype : Py_None());
+        PyTuple_SetItem(args, 1, errvalue ? errvalue : Py_None());
+        PyTuple_SetItem(args, 2, traceback ? traceback : Py_None());
+
+        PyObjectRef  lst = PyObject_Call(format_exception, args, NULL);
+
+        sstr << std::endl << std::endl;
+
+        for (size_t i = 0; i < PyList_Size(lst); ++i)
+        {
+            PyObjectBorrowedRef  item = PyList_GetItem(lst, i);
+            sstr << std::string(convert_from_python(item)) << std::endl;
+        }
+
+        throw std::exception(sstr.str().c_str());
+    }
+
+    Py_DecRef(errtype);
+    if (errvalue) Py_DecRef(errvalue);
+    if (traceback) Py_DecRef(traceback);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+std::string findScript(const std::string &fullFileName)
+{
+    if (GetFileAttributesA(fullFileName.c_str()) != INVALID_FILE_ATTRIBUTES)
+        return fullFileName;
+
+    PyObjectBorrowedRef  pathLst = PySys_GetObject("path");
+
+    size_t  pathLstSize = PyList_Size(pathLst);
+
+    for (size_t i = 0; i < pathLstSize; i++)
+    {
+        char  *path = PyString_AsString(PyList_GetItem(pathLst, i));
+
+        DWORD bufSize = SearchPathA(
+            path,
+            fullFileName.c_str(),
+            NULL,
+            0,
+            NULL,
+            NULL);
+
+        if (bufSize > 0)
+        {
+            bufSize += 1;
+            std::vector<char> fullFileNameCStr(bufSize);
+            char *partFileNameCStr = NULL;
+
+            bufSize = SearchPathA(
+                path,
+                fullFileName.c_str(),
+                NULL,
+                bufSize,
+                &fullFileNameCStr[0],
+                &partFileNameCStr);
+
+            DWORD   fileAttr = GetFileAttributesA(&fullFileNameCStr[0]);
+
+            if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY) == 0)
+                return std::string(&fullFileNameCStr[0]);
+        }
+
+    }
+
+    return "";
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+std::string getScriptFileName(const std::string &scriptName)
+{
+    std::string scriptFileName = findScript(scriptName);
+
+    if (scriptFileName.empty())
+    {
+        std::string scriptNameLow;
+        scriptNameLow.resize(scriptName.size());
+        std::transform(
+            scriptName.begin(),
+            scriptName.end(),
+            scriptNameLow.begin(),
+            ::tolower);
+        if (scriptNameLow.rfind(".py") != (scriptNameLow.length() - 3))
+            scriptFileName = findScript(scriptName + ".py");
+    }
+
+    return scriptFileName;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void  getPythonVersion(int&  majorVersion, int& minorVersion)
+{
+    std::list<InterpreterDesc>   interpreterList = getInstalledInterpreter();
+
+    bool  found = false;
+    bool  anyMinorVersion = minorVersion == -1;
+    for (auto interpret : interpreterList)
+    {
+        if (majorVersion == interpret.majorVersion && 
+            anyMinorVersion ? (minorVersion <= interpret.minorVersion) : (minorVersion == interpret.minorVersion))
+        {
+            found = true;
+            minorVersion = interpret.minorVersion;
+        }
+    }
+
+    if (!found)
+        throw std::exception("failed to find python interpreter\n");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+#include <vector>
+
+#include <DbgEng.h>
+#include <atlbase.h>
+#include <comutil.h>
+
+#include <boost/python.hpp>
+namespace python = boost::python;
+
+#include <boost/tokenizer.hpp>
+
+///////////////////////////////////////////////////////////////////////////////
+
+class AutoRestorePyState
+{
+public:
+
+    AutoRestorePyState()
+    {
+        m_state = PyEval_SaveThread();
+    }
+
+    ~AutoRestorePyState()
+    {
+        PyEval_RestoreThread(m_state);
+    }
+
+private:
+
+    PyThreadState*    m_state;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+class DbgOut
+{
+public:
+
+    DbgOut(PDEBUG_CLIENT client)
+        : m_control(client)
+    {}
+
+    void write(const std::wstring& str)
+    {
+        AutoRestorePyState  pystate;
+
+        m_control->ControlledOutputWide(
+            DEBUG_OUTCTL_THIS_CLIENT,
+            DEBUG_OUTPUT_NORMAL,
+            L"%ws",
+            str.c_str()
+            );
+
+    }
+
+    void writedml(const std::wstring& str) 
+    {
+        AutoRestorePyState  pystate;
+
+        m_control->ControlledOutputWide(
+            DEBUG_OUTCTL_THIS_CLIENT | DEBUG_OUTCTL_DML,
+            DEBUG_OUTPUT_NORMAL,
+            L"%ws",
+            str.c_str()
+            );
+    }
+
+    void flush() {
+    }
+
+    std::wstring encoding() {
+        return L"ascii";
+    }
+
+    bool closed() {
+        return false;
+    }
+
+private:
+
+    CComQIPtr<IDebugControl4>  m_control;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class DbgIn
+{
+public:
+
+    DbgIn(PDEBUG_CLIENT client)
+        : m_control(client)
+        {}
+
+    std::wstring readline()
+    {
+        AutoRestorePyState  pystate;
+
+        std::vector<wchar_t>  inputBuffer(0x10000);
+
+        ULONG  read = 0;
+        m_control->InputWide(&inputBuffer[0], static_cast<ULONG>(inputBuffer.size()), &read);
+
+        std::wstring  inputstr = std::wstring(&inputBuffer[0]);
+
+        return inputstr.empty() ? L"\n" : inputstr;
+    }
+
+    bool closed() {
+        return false;
+    }
+
+
+private:
+
+    CComQIPtr<IDebugControl4>  m_control;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class PythonInterpreter
+{
+public:
+
+    PythonInterpreter()
+    {
+        PyThreadState*  state = Py_NewInterpreter();
+
+        PyThreadState_Swap(state);
+
+        m_state = PyEval_SaveThread();
+    }
+
+    ~PythonInterpreter()
+    {
+        PyEval_RestoreThread(m_state);
+
+        PyInterpreterState  *interpreter = m_state->interp;
+
+        while (interpreter->tstate_head != NULL)
+        {
+            PyThreadState   *threadState = (PyThreadState*)(interpreter->tstate_head);
+
+            PyThreadState_Clear(threadState);
+
+            PyThreadState_Swap(NULL);
+
+            PyThreadState_Delete(threadState);
+        }
+
+        PyInterpreterState_Clear(interpreter);
+
+        PyInterpreterState_Delete(interpreter);
+    }
+
+    void acivate()
+    {
+        PyEval_RestoreThread(m_state);
+    }
+
+    void deactivate()
+    {
+        m_state = PyEval_SaveThread();
+    }
+
+private:
+
+    PyThreadState*  m_state;
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class PythonSingleton
+{
+
+public:
+
+    static PythonSingleton* get()
+    {
+        if (!m_instance)
+            m_instance = new PythonSingleton();
+
+        return m_instance;
+    }
+
+    void stop()
+    {
+        delete m_globalInterpreter;
+        m_globalInterpreter = 0;
+        PyThreadState_Swap(m_globalState);
+        m_globalState = PyEval_SaveThread();
+    }
+
+    void start()
+    {
+        PyEval_RestoreThread(m_globalState);
+
+        m_globalInterpreter = new PythonInterpreter();
+
+        //m_globalInterpreter->acivate();
+
+        //python::object  main = boost::python::import("__main__");
+
+        //python::object  main_namespace = main.attr("__dict__");
+
+        //m_globalInterpreter->deactivate();
+    }
+
+    void acivateGlobal() {
+        m_globalInterpreter->acivate();
+    }
+
+    void deactivateGlobal() {
+        m_globalInterpreter->deactivate();
+    }
+
+    void acivateLocal() {
+        PyEval_RestoreThread(m_globalState);
+        m_locallInterpreter = new PythonInterpreter();
+        m_locallInterpreter->acivate();
+    }
+
+    void deactivateLocal() {
+        m_locallInterpreter->deactivate();
+        delete m_locallInterpreter;
+        m_locallInterpreter = 0;
+        PyThreadState_Swap(m_globalState);
+        m_globalState = PyEval_SaveThread();
+    }
+
+    void checkPykd()
+    {
+        if (m_pykdInit)
+            return;
+
+        python::handle<>  pykdHandle(python::allow_null(PyImport_ImportModule("pykd")));
+        if (!pykdHandle)
+            throw std::exception("Pykd package is not installed.You can install it by command \"!pykd.install\"");
+
+        python::object       main = python::import("__main__");
+        python::object       globalScope(main.attr("__dict__"));
+        python::exec("__import__('pykd').initialize()", globalScope);
+
+        m_pykdInit = true;
+    }
+
+private:
+
+    static PythonSingleton*  m_instance;
+
+    PythonSingleton()
+    {
+        Py_Initialize();
+        PyEval_InitThreads();
+
+        // Python debug output console helper classes
+        python::class_<DbgOut>("dout", "dout", python::no_init)
+            .def("write", &DbgOut::write)
+            .def("writedml", &DbgOut::writedml)
+            .def("flush", &DbgOut::flush)
+            .add_property("encoding", &DbgOut::encoding)
+            .add_property("closed", &DbgOut::closed);
+
+        python::class_<DbgIn>("din", "din", python::no_init)
+            .def("readline", &DbgIn::readline)
+            .add_property("closed", &DbgIn::closed);
+
+
+        m_globalState = PyEval_SaveThread();
+    }
+
+    PythonInterpreter*  m_globalInterpreter;
+    PythonInterpreter*  m_locallInterpreter;
+    PyThreadState*  m_globalState;
+
+    bool  m_pykdInit;
+};
+
+PythonSingleton*   PythonSingleton::m_instance = 0;
+
+//////////////////////////////////////////////////////////////////////////////
+
+class InterruptWatch
+{
+public:
+
+    InterruptWatch(PDEBUG_CLIENT client)
+    {
+        m_control = client;
+        m_stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+        m_thread = CreateThread(NULL, 0, threadRoutine, this, 0, NULL);
+    }
+
+    ~InterruptWatch()
+    {
+        SetEvent(m_stopEvent);
+        WaitForSingleObject(m_thread, INFINITE);
+        CloseHandle(m_stopEvent);
+        CloseHandle(m_thread);
+    }
+
+    bool onInterrupt()
+    {
+        HANDLE  quitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+        PyGILState_STATE state = PyGILState_Ensure();
+        Py_AddPendingCall(&quit, (void*)quitEvent);
+        PyGILState_Release(state);
+        WaitForSingleObject(quitEvent, INFINITE);
+        CloseHandle(quitEvent);
+        return true;
+    }
+
+    static int quit(void *context)
+    {
+        HANDLE   quitEvent = (HANDLE)context;
+        PyErr_SetString(PyExc_SystemExit, "CTRL+BREAK");
+        SetEvent(quitEvent);
+        return -1;
+    }
+
+private:
+
+    static DWORD WINAPI threadRoutine(LPVOID lpParameter) {
+        return  static_cast<InterruptWatch*>(lpParameter)->interruptWatchRoutine();
+    }
+
+    DWORD InterruptWatch::interruptWatchRoutine()
+    {
+        while (WAIT_TIMEOUT == WaitForSingleObject(m_stopEvent, 250))
+        {
+            HRESULT  hres = m_control->GetInterrupt();
+            if (hres == S_OK)
+            {
+                HANDLE  quitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+                PyGILState_STATE state = PyGILState_Ensure();
+                Py_AddPendingCall(&quit, (void*)quitEvent);
+                PyGILState_Release(state);
+                WaitForSingleObject(quitEvent, INFINITE);
+                CloseHandle(quitEvent);
+            }
+        }
+
+        return 0;
+    }
+
+    HANDLE  m_thread;
+
+    HANDLE  m_stopEvent;
+
+    CComQIPtr<IDebugControl>  m_control;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+typedef  std::vector< std::string >  ArgsList;
+typedef  boost::escaped_list_separator<char>    char_separator_t;
+typedef  boost::tokenizer< char_separator_t >   char_tokenizer_t;
+
+ArgsList  getArgsList(
+    PCSTR args
+    )
+{
+    std::string  argsStr(args);
+
+    char_tokenizer_t  token(argsStr, char_separator_t("", " \t", "\""));
+    ArgsList  argsList;
+
+    for (char_tokenizer_t::iterator it = token.begin(); it != token.end(); ++it)
+    {
+        if (*it != "")
+            argsList.push_back(*it);
+    }
+
+    return argsList;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static const char  printUsageMsg[] =
+    "usage:\n"
+    "!py [options] [file]\n"
+    "\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";
+
+void printUsage(PDEBUG_CLIENT client)
+{
+    CComQIPtr<IDebugControl>(client)->
+        ControlledOutput(
+            DEBUG_OUTCTL_THIS_CLIENT,
+            DEBUG_OUTPUT_NORMAL,
+            "%s",
+            printUsageMsg
+            );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern "C"
+HRESULT
+CALLBACK
+DebugExtensionInitialize(
+    PULONG  Version,
+    PULONG  Flags
+    )
+{
+    PythonSingleton::get()->start();
+    return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern "C"
+VOID
+CALLBACK
+DebugExtensionUninitialize()
+{
+    PythonSingleton::get()->stop();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+std::string getScriptFileName(const std::string &scriptName);
+
+void printException(DbgOut &dbgOut);
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern "C"
+HRESULT
+CALLBACK
+py(
+    PDEBUG_CLIENT client,
+    PCSTR args
+    )
+{
+    ArgsList  argsList = getArgsList(args);
+
+    bool  global = false;
+    bool  local = false;
+    bool  clean = false;
+
+    if (!argsList.empty())
+    {
+        if (argsList[0] == "-h" || argsList[0] == "--help")
+        {
+            printUsage(client);
+            return S_OK;
+        }
+        else
+        if (argsList[0] == "-g" || argsList[0] == "--global")
+        {
+            global = true;
+            argsList.erase(argsList.begin());
+        }
+        else
+        if (argsList[0] == "-l" || argsList[0] == "--local")
+        {
+            local = true;
+            argsList.erase(argsList.begin());
+        }
+    }
+
+    if (argsList.size() > 0)
+    {
+        global = !(global || local) ? false : global; //set local by default
+    }
+    else
+    {
+        global = !(global || local) ? true : global; //set global by default
+    }
+
+    DbgOut   dbgOut(client);
+    DbgOut   dbgErr(client);
+    DbgIn    dbgIn(client);
+
+    ULONG   oldMask;
+    client->GetOutputMask(&oldMask);
+    client->SetOutputMask(DEBUG_OUTPUT_NORMAL | DEBUG_OUTPUT_ERROR);
+
+
+    if (global)
+        PythonSingleton::get()->acivateGlobal();
+    else
+        PythonSingleton::get()->acivateLocal();
+
+    try {
+
+        InterruptWatch  interruptWatch(client);
+
+        python::object  sys = python::import("sys");
+
+        sys.attr("stdout") = python::object(dbgOut);
+        sys.attr("stderr") = python::object(dbgErr);
+        sys.attr("stdin") = python::object(dbgIn);
+
+        python::object  main = python::import("__main__");
+        python::object  globalScope(main.attr("__dict__"));
+
+        PythonSingleton::get()->checkPykd();
+
+        if (argsList.size() == 0)
+        {
+
+            python::exec("import pykd", globalScope);
+            python::exec("from pykd import *", globalScope);
+            python::exec("__import__('code').InteractiveConsole(__import__('__main__').__dict__).interact()", globalScope);
+        }
+        else
+        {
+
+            std::string  scriptFileName = getScriptFileName(argsList[0]);
+            if (scriptFileName.empty())
+                throw std::invalid_argument("script not found");
+
+            // �������������� ����������� ���������
+            char  **pythonArgs = new char*[argsList.size()];
+        
+            pythonArgs[0] = const_cast<char*>(scriptFileName.c_str());
+        
+            for (size_t i = 1; i < argsList.size(); ++i)
+                pythonArgs[i] = const_cast<char*>(argsList[i].c_str());
+        
+            PySys_SetArgv((int)argsList.size(), pythonArgs);
+        
+            delete[]  pythonArgs;
+
+            python::exec_file(scriptFileName.c_str(), globalScope);
+        }
+    }
+    catch (const python::error_already_set&)
+    {
+        printException(dbgOut);
+    }
+    catch (const std::exception& invalidArg)
+    {
+        _bstr_t    bstrInavalidArg(invalidArg.what());
+        dbgOut.write(std::wstring(bstrInavalidArg));
+    }
+
+    if (global)
+        PythonSingleton::get()->deactivateGlobal();
+    else
+        PythonSingleton::get()->deactivateLocal();
+
+    client->SetOutputMask(oldMask);
+
+    return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern "C"
+HRESULT
+CALLBACK
+install(
+    PDEBUG_CLIENT client,
+    PCSTR args
+    )
+{
+    DbgOut   dbgOut(client);
+    DbgOut   dbgErr(client);
+    DbgIn    dbgIn(client);
+
+    PythonSingleton::get()->acivateGlobal();
+    
+    try {
+    
+        python::object  sys = python::import("sys");
+
+        sys.attr("stdout") = python::object(dbgOut);
+        sys.attr("stderr") = python::object(dbgErr);
+        sys.attr("stdin") = python::object(dbgIn);
+
+        // �������� ������ � ����������� ���� ( ����� ��� ������ exec_file )
+        python::object       main = python::import("__main__");
+        python::object       global(main.attr("__dict__"));
+
+        python::exec("import pip\n", global);
+        python::exec("pip.logger.consumers = []\n", global);
+        python::exec("pip.main(['install', 'pykd'])\n", global);
+    
+    }
+    catch (const python::error_already_set&)
+    {
+        printException(dbgOut);
+    }
+    catch (const std::exception& invalidArg)
+    {
+        _bstr_t    bstrInavalidArg(invalidArg.what());
+        dbgOut.write(std::wstring(bstrInavalidArg));
+    }
+    
+    PythonSingleton::get()->deactivateGlobal();
+
+    return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern "C"
+HRESULT
+CALLBACK
+upgrade(
+    PDEBUG_CLIENT client,
+    PCSTR args
+    )
+{
+    DbgOut   dbgOut(client);
+    DbgOut   dbgErr(client);
+    DbgIn    dbgIn(client);
+
+    PythonSingleton::get()->acivateGlobal();
+
+    try {
+
+        python::object  sys = python::import("sys");
+
+        sys.attr("stdout") = python::object(dbgOut);
+        sys.attr("stderr") = python::object(dbgErr);
+        sys.attr("stdin") = python::object(dbgIn);
+
+        // �������� ������ � ����������� ���� ( ����� ��� ������ exec_file )
+        python::object       main = python::import("__main__");
+        python::object       global(main.attr("__dict__"));
+
+        python::exec("import pip\n", global);
+        python::exec("pip.logger.consumers = []\n", global);
+        python::exec("pip.main(['install', '--upgrade', 'pykd'])\n", global);
+
+    }
+    catch (const python::error_already_set&)
+    {
+        printException(dbgOut);
+    }
+    catch (const std::exception& invalidArg)
+    {
+        _bstr_t    bstrInavalidArg(invalidArg.what());
+        dbgOut.write(std::wstring(bstrInavalidArg));
+    }
+
+    PythonSingleton::get()->deactivateGlobal();
+
+    return S_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+std::string findScript(const std::string &fullFileName)
+{
+    if (GetFileAttributesA(fullFileName.c_str()) != INVALID_FILE_ATTRIBUTES)
+        return fullFileName;
+
+    python::object  sys = python::import("sys");
+
+    python::list  pathList(sys.attr("path"));
+
+    python::ssize_t  n = python::len(pathList);
+
+    for (python::ssize_t i = 0; i < n; i++)
+    {
+        std::string  path = boost::python::extract<std::string>(pathList[i]);
+
+        DWORD bufSize = SearchPathA(
+            path.c_str(),
+            fullFileName.c_str(),
+            NULL,
+            0,
+            NULL,
+            NULL);
+
+        if (bufSize > 0)
+        {
+            bufSize += 1;
+            std::vector<char> fullFileNameCStr(bufSize);
+            char *partFileNameCStr = NULL;
+
+            bufSize = SearchPathA(
+                path.c_str(),
+                fullFileName.c_str(),
+                NULL,
+                bufSize,
+                &fullFileNameCStr[0],
+                &partFileNameCStr);
+
+            DWORD   fileAttr = GetFileAttributesA(&fullFileNameCStr[0]);
+
+            if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY) == 0)
+                return std::string(&fullFileNameCStr[0]);
+        }
+    }
+
+    return "";
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+std::string getScriptFileName(const std::string &scriptName)
+{
+    std::string scriptFileName = findScript(scriptName);
+
+    if (scriptFileName.empty())
+    {
+        std::string scriptNameLow;
+        scriptNameLow.resize(scriptName.size());
+        std::transform(
+            scriptName.begin(),
+            scriptName.end(),
+            scriptNameLow.begin(),
+            ::tolower);
+        if (scriptNameLow.rfind(".py") != (scriptNameLow.length() - 3))
+            scriptFileName = findScript(scriptName + ".py");
+    }
+
+    return scriptFileName;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void printException(DbgOut &dbgOut)
+{
+    // ������ � �������
+    PyObject  *errtype = NULL, *errvalue = NULL, *traceback = NULL;
+
+    PyErr_Fetch(&errtype, &errvalue, &traceback);
+
+    PyErr_NormalizeException(&errtype, &errvalue, &traceback);
+
+    if (errtype != PyExc_SystemExit)
+    {
+        python::object  tracebackModule = python::import("traceback");
+
+        std::wstringstream  sstr;
+
+        python::object   lst =
+            python::object(tracebackModule.attr("format_exception"))(
+            python::handle<>(errtype),
+            python::handle<>(python::allow_null(errvalue)),
+            python::handle<>(python::allow_null(traceback)));
+
+        sstr << std::endl << std::endl;
+
+        for (long i = 0; i < python::len(lst); ++i)
+            sstr << std::wstring(python::extract<std::wstring>(lst[i])) << std::endl;
+
+        dbgOut.write(sstr.str());
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+*/