diff --git a/pykd/bpoint.h b/pykd/bpoint.h
index cfd9128..693ac1c 100644
--- a/pykd/bpoint.h
+++ b/pykd/bpoint.h
@@ -2,6 +2,8 @@
 // Breakpoints management
 // 
 
+#pragma once
+
 #include "dbgclient.h"
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/pykd/context.cpp b/pykd/context.cpp
index 1d3dca9..b90b75f 100644
--- a/pykd/context.cpp
+++ b/pykd/context.cpp
@@ -4,6 +4,7 @@
 #include <boost\python\tuple.hpp>
 
 #include "context.h"
+#include "stkframe.h"
 
 /////////////////////////////////////////////////////////////////////////////////
 
@@ -188,21 +189,21 @@ ULONG64 ThreadContext::getSp() const
 
 /////////////////////////////////////////////////////////////////////////////////
 
-ContextPtr ThreadContext::forkByStackFrame(DEBUG_STACK_FRAME &frame) const
+ContextPtr ThreadContext::forkByStackFrame(const StackFrame &stkFrmae) const
 {
     ContextPtr newContext( new ThreadContext(*this) );
     switch (m_processorType)
     {
     case IMAGE_FILE_MACHINE_I386:
-        newContext->m_regValues[CV_REG_EIP] = frame.InstructionOffset;
-        newContext->m_regValues[CV_REG_EBP] = frame.FrameOffset;
-        newContext->m_regValues[CV_REG_ESP] = frame.StackOffset;
+        newContext->m_regValues[CV_REG_EIP] = stkFrmae.m_instructionOffset;
+        newContext->m_regValues[CV_REG_EBP] = stkFrmae.m_frameOffset;
+        newContext->m_regValues[CV_REG_ESP] = stkFrmae.m_stackOffset;
         return newContext;
 
     case IMAGE_FILE_MACHINE_AMD64:
-        newContext->m_regValues[CV_AMD64_RIP] = frame.InstructionOffset;
-        newContext->m_regValues[CV_AMD64_RBP] = frame.FrameOffset;
-        newContext->m_regValues[CV_AMD64_RSP] = frame.StackOffset;
+        newContext->m_regValues[CV_AMD64_RIP] = stkFrmae.m_instructionOffset;
+        newContext->m_regValues[CV_AMD64_RBP] = stkFrmae.m_frameOffset;
+        newContext->m_regValues[CV_AMD64_RSP] = stkFrmae.m_stackOffset;
         return newContext;
     }
 
@@ -375,20 +376,4 @@ void ThreadContext::throwUnsupportedProcessor(PCSTR szFunction) const
 
 /////////////////////////////////////////////////////////////////////////////////
 
-std::string printStackFrame(DEBUG_STACK_FRAME &frame)
-{
-    std::stringstream sstream;
-
-    sstream << std::dec << "(" << frame.FrameNumber << ")";
-
-    sstream << " ip= 0x" << std::hex << frame.InstructionOffset;
-    sstream << ", ret= 0x" << std::hex << frame.ReturnOffset;
-    sstream << ", frame= 0x" << std::hex << frame.FrameOffset;
-    sstream << ", stack= 0x" << std::hex << frame.StackOffset;
-
-    return sstream.str();
-}
-
-/////////////////////////////////////////////////////////////////////////////////
-
 }
diff --git a/pykd/context.h b/pykd/context.h
index 327157f..2196bd1 100644
--- a/pykd/context.h
+++ b/pykd/context.h
@@ -16,6 +16,8 @@ namespace pykd {
 class ThreadContext;
 typedef boost::shared_ptr< ThreadContext > ContextPtr;
 
+class StackFrame;
+
 ////////////////////////////////////////////////////////////////////////////////
 
 std::string processorToStr(ULONG processorMode);
@@ -52,7 +54,7 @@ public:
         return pykd::processorToStr(m_processorType);
     }
 
-    ContextPtr forkByStackFrame(DEBUG_STACK_FRAME &frame) const;
+    ContextPtr forkByStackFrame(const StackFrame &stkFrmae) const;
 
 private:
 
@@ -76,9 +78,5 @@ private:
 
 ////////////////////////////////////////////////////////////////////////////////
 
-std::string printStackFrame(DEBUG_STACK_FRAME &frame);
-
-////////////////////////////////////////////////////////////////////////////////
-
 }
 
diff --git a/pykd/dbgclient.cpp b/pykd/dbgclient.cpp
index bab0f5f..6f5fe44 100644
--- a/pykd/dbgclient.cpp
+++ b/pykd/dbgclient.cpp
@@ -2,7 +2,7 @@
 #include <vector>
 
 #include "dbgclient.h"
-
+#include "stkframe.h"
 
 namespace pykd {
 
diff --git a/pykd/dbgclient.h b/pykd/dbgclient.h
index f4f9d14..b0fab1e 100644
--- a/pykd/dbgclient.h
+++ b/pykd/dbgclient.h
@@ -5,6 +5,9 @@
 #include <dbghelp.h>
 
 #include <boost\smart_ptr\scoped_ptr.hpp>
+#include <boost\enable_shared_from_this.hpp>
+
+/////////////////////////////////////////////////////////////////////////////////
 
 #include "dbgobj.h"
 #include "dbgexcept.h"
@@ -41,7 +44,8 @@ struct BpCallbackMap {
 
 /////////////////////////////////////////////////////////////////////////////////
 
-class DebugClient : private DbgObject {
+class DebugClient   : private DbgObject
+                    , public boost::enable_shared_from_this<DebugClient> {
 
 private:
     // simple IDebugControl4 call wrapper
diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp
index 4cb3a14..762b9c5 100644
--- a/pykd/dbgext.cpp
+++ b/pykd/dbgext.cpp
@@ -19,6 +19,7 @@
 #include "intbase.h"
 #include "process.h"
 #include "bpoint.h"
+#include "stkframe.h"
 #include "pykdver.h"
 
 using namespace pykd;
@@ -103,6 +104,7 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_getLocals, DebugClient::getL
 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( pyDia_Symbol_findChildrenEx, pyDia::Symbol::findChildrenEx, 1, 3 );
 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_setSoftwareBp, DebugClient::setSoftwareBp, 1, 2 );
 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_setHardwareBp, DebugClient::setHardwareBp, 3, 4 );
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( StackFrame_getLocals, StackFrame::getLocals, 0, 1 );
 
 #define DEF_PY_CONST_ULONG(x)    \
     python::scope().attr(#x) = ULONG(##x)
@@ -621,19 +623,21 @@ BOOST_PYTHON_MODULE( pykd )
         .def( "ea", &Disasm::ea, "Return effective address for last disassembled instruction or 0" )
         .def( "reset", &Disasm::reset, "Reset current offset to begin" );
 
-    python::class_<DEBUG_STACK_FRAME>( "stackFrame", 
+    python::class_<StackFrame>( "stackFrame", 
          "Class representing a frame of the call stack", python::no_init )
-        .def_readonly( "instructionOffset", &DEBUG_STACK_FRAME::InstructionOffset,
+        .def_readonly( "instructionOffset", &StackFrame::m_instructionOffset,
             "Return a frame's instruction offset" )
-        .def_readonly( "returnOffset", &DEBUG_STACK_FRAME::ReturnOffset,
+        .def_readonly( "returnOffset", &StackFrame::m_returnOffset,
             "Return a frame's return offset" )
-        .def_readonly( "frameOffset", &DEBUG_STACK_FRAME::FrameOffset,
+        .def_readonly( "frameOffset", &StackFrame::m_frameOffset,
             "Return a frame's offset" )
-        .def_readonly( "stackOffset", &DEBUG_STACK_FRAME::StackOffset,
+        .def_readonly( "stackOffset", &StackFrame::m_stackOffset,
             "Return a frame's stack offset" )
-        .def_readonly( "frameNumber", &DEBUG_STACK_FRAME::FrameNumber,
+        .def_readonly( "frameNumber", &StackFrame::m_frameNumber,
             "Return a frame's number" )
-        .def( "__str__", &printStackFrame,
+        .def( "getLocals", &StackFrame::getLocals, StackFrame_getLocals( python::args( "ctx" ),
+            "Get list of local variables for this stack frame" ) )
+        .def( "__str__", &StackFrame::print,
             "Return stacks frame as string");
 
     python::class_<ThreadContext, ContextPtr>(
diff --git a/pykd/process.cpp b/pykd/process.cpp
index ac6a817..1a9115a 100644
--- a/pykd/process.cpp
+++ b/pykd/process.cpp
@@ -1,5 +1,6 @@
 #include "stdafx.h"
 #include "dbgclient.h"
+#include "stkframe.h"
 
 namespace pykd {
 
@@ -62,10 +63,10 @@ DebugClient::getCurrentStack()
     
     for ( ULONG i = 0; i < filledFrames; ++i )
     {
-        python::object       frameObj( frames[i] ); 
-    
+        python::object       frameObj( StackFrame(shared_from_this(), frames[i]) ); 
+
         frameList.append( frameObj );
-    }         
+    }
 
     return frameList; 
 }
diff --git a/pykd/pykd_2008.vcproj b/pykd/pykd_2008.vcproj
index 86fddea..30db6c7 100644
--- a/pykd/pykd_2008.vcproj
+++ b/pykd/pykd_2008.vcproj
@@ -465,6 +465,10 @@
 					/>
 				</FileConfiguration>
 			</File>
+			<File
+				RelativePath=".\stkframe.cpp"
+				>
+			</File>
 			<File
 				RelativePath=".\synsymbol.cpp"
 				>
@@ -583,6 +587,10 @@
 				RelativePath=".\stdafx.h"
 				>
 			</File>
+			<File
+				RelativePath=".\stkframe.h"
+				>
+			</File>
 			<File
 				RelativePath=".\synsymbol.h"
 				>
diff --git a/pykd/stkframe.cpp b/pykd/stkframe.cpp
new file mode 100644
index 0000000..639da60
--- /dev/null
+++ b/pykd/stkframe.cpp
@@ -0,0 +1,55 @@
+// 
+// Stack frame: DEBUG_STACK_FRAME wrapper
+// 
+
+#include "stdafx.h"
+#include "stkframe.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace pykd {
+
+////////////////////////////////////////////////////////////////////////////////
+
+StackFrame::StackFrame(DebugClientPtr client, const DEBUG_STACK_FRAME &frame)
+    : m_client(client)
+    , m_frameNumber(frame.FrameNumber)
+    , m_instructionOffset(frame.InstructionOffset)
+    , m_returnOffset(frame.ReturnOffset)
+    , m_frameOffset(frame.FrameOffset)
+    , m_stackOffset(frame.StackOffset)
+{
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+std::string StackFrame::print() const
+{
+    std::stringstream sstream;
+
+    sstream << std::dec << "(" << m_frameNumber << ")";
+
+    sstream << " ip= 0x" << std::hex << m_instructionOffset;
+    sstream << ", ret= 0x" << std::hex << m_returnOffset;
+    sstream << ", frame= 0x" << std::hex << m_frameOffset;
+    sstream << ", stack= 0x" << std::hex << m_stackOffset;
+
+    return sstream.str();
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+python::dict StackFrame::getLocals(ContextPtr ctx /*= ContextPtr()*/)
+{
+    ctx = ctx   ? ctx->forkByStackFrame(*this)
+                : m_client->getThreadContext()->forkByStackFrame(*this);
+    return m_client->getLocals(ctx);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace pykd
+
+////////////////////////////////////////////////////////////////////////////////
+
diff --git a/pykd/stkframe.h b/pykd/stkframe.h
new file mode 100644
index 0000000..7f1b712
--- /dev/null
+++ b/pykd/stkframe.h
@@ -0,0 +1,38 @@
+// 
+// Stack frame: DEBUG_STACK_FRAME wrapper
+// 
+
+#pragma once
+
+#include "dbgclient.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace pykd {
+
+////////////////////////////////////////////////////////////////////////////////
+
+class StackFrame
+{
+public:
+    StackFrame(DebugClientPtr client, const DEBUG_STACK_FRAME &frame);
+
+    ULONG m_frameNumber;
+
+    ULONG64 m_instructionOffset;
+    ULONG64 m_returnOffset;
+    ULONG64 m_frameOffset;
+    ULONG64 m_stackOffset;
+
+    python::dict getLocals(ContextPtr ctx = ContextPtr());
+
+    std::string print() const;
+private:
+    DebugClientPtr m_client;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace pykd
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/test/scripts/localstest.py b/test/scripts/localstest.py
index 5a2ad6a..79cc7a6 100644
--- a/test/scripts/localstest.py
+++ b/test/scripts/localstest.py
@@ -34,8 +34,7 @@ class LocalVarsTest(unittest.TestCase):
         newClnt.go() # targetapp!EnumWindowsProc1 -> targetapp!functionCalledFromEnumWindowsProc1
 
         # get local variables from previous stack frame
-        prevStackThreadCtx = newClnt.getContext().fork( newClnt.getCurrentStack()[1] )
-        prevLocals = newClnt.getLocals( prevStackThreadCtx )
+        prevLocals = newClnt.getCurrentStack()[1].getLocals()
 
         self.assertEqual( len(prevLocals), len(locals) )
         for varName in locals.iterkeys():