diff --git a/NTwain.sln b/NTwain.sln
index 538b616..f111ee3 100644
--- a/NTwain.sln
+++ b/NTwain.sln
@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 2013
-VisualStudioVersion = 12.0.30110.0
+VisualStudioVersion = 12.0.30324.0
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NTwain", "NTwain\NTwain.csproj", "{0C5A6FB1-0282-4D61-8354-68DEB1515001}"
 EndProject
@@ -19,6 +19,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Others", "Others", "{4CE0B9
 		README.markdown = README.markdown
 	EndProjectSection
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tester.Console", "Tests\Tester.Console\Tester.Console.csproj", "{12D761EF-68DF-41CE-92EF-0C7AE81857A3}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -68,6 +70,16 @@ Global
 		{1715C2B7-5C35-4F8B-9D9B-8D68A3D5284D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
 		{1715C2B7-5C35-4F8B-9D9B-8D68A3D5284D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 		{1715C2B7-5C35-4F8B-9D9B-8D68A3D5284D}.Release|x86.ActiveCfg = Release|Any CPU
+		{12D761EF-68DF-41CE-92EF-0C7AE81857A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{12D761EF-68DF-41CE-92EF-0C7AE81857A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{12D761EF-68DF-41CE-92EF-0C7AE81857A3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{12D761EF-68DF-41CE-92EF-0C7AE81857A3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{12D761EF-68DF-41CE-92EF-0C7AE81857A3}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{12D761EF-68DF-41CE-92EF-0C7AE81857A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{12D761EF-68DF-41CE-92EF-0C7AE81857A3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{12D761EF-68DF-41CE-92EF-0C7AE81857A3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{12D761EF-68DF-41CE-92EF-0C7AE81857A3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{12D761EF-68DF-41CE-92EF-0C7AE81857A3}.Release|x86.ActiveCfg = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -76,6 +88,7 @@ Global
 		{6B034C50-A397-435F-8DDF-677B403FEBAA} = {2F906640-1664-4960-93D2-A054AC6E66A3}
 		{4FC243F1-318E-4FA9-9EBD-2CA3A8F35425} = {2F906640-1664-4960-93D2-A054AC6E66A3}
 		{1715C2B7-5C35-4F8B-9D9B-8D68A3D5284D} = {2F906640-1664-4960-93D2-A054AC6E66A3}
+		{12D761EF-68DF-41CE-92EF-0C7AE81857A3} = {2F906640-1664-4960-93D2-A054AC6E66A3}
 	EndGlobalSection
 	GlobalSection(TestCaseManagementSettings) = postSolution
 		CategoryFile = NTwain.vsmdi
diff --git a/NTwain/AsyncPump.cs b/NTwain/AsyncPump.cs
new file mode 100644
index 0000000..5800cc7
--- /dev/null
+++ b/NTwain/AsyncPump.cs
@@ -0,0 +1,50 @@
+//using System;
+//using System.Collections.Generic;
+//using System.Linq;
+//using System.Text;
+//using System.Threading;
+//using System.Windows.Threading;
+
+//namespace NTwain
+//{
+//    // from http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx
+
+//    /// <summary>
+//    /// Provides a pump that supports running asynchronous methods on the current thread.
+//    /// </summary>
+//    public static class AsyncPump
+//    {
+//        /// <summary>
+//        /// Runs the specified asynchronous function.
+//        /// </summary>
+//        /// <param name="func">The asynchronous function to execute.</param>
+//        /// <exception cref="System.ArgumentNullException">func</exception>
+//        /// <exception cref="System.InvalidOperationException">No task provided.</exception>
+//        public static void Run(Func<Task> func)
+//        {
+//            if (func == null) throw new ArgumentNullException("func");
+
+//            var prevCtx = SynchronizationContext.Current;
+//            try
+//            {
+//                var syncCtx = new DispatcherSynchronizationContext();
+//                SynchronizationContext.SetSynchronizationContext(syncCtx);
+
+//                var t = func();
+//                if (t == null) throw new InvalidOperationException();
+
+//                var frame = new DispatcherFrame();
+//                t.ContinueWith(_ => { frame.Continue = false; },
+//                    TaskScheduler.Default);
+//                Dispatcher.PushFrame(frame);
+
+//                t.GetAwaiter().GetResult();
+//            }
+//            finally
+//            {
+//                SynchronizationContext.SetSynchronizationContext(prevCtx);
+//            }
+
+//        }
+//    }
+//}
diff --git a/NTwain/NTwain.csproj b/NTwain/NTwain.csproj
index 725ab57..8e2ccce 100644
--- a/NTwain/NTwain.csproj
+++ b/NTwain/NTwain.csproj
@@ -53,6 +53,7 @@
     <Reference Include="WindowsBase" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="AsyncPump.cs" />
     <Compile Include="Data\TypesExtended.cs" />
     <Compile Include="DeviceEventArgs.cs" />
     <Compile Include="Extensions.cs" />
diff --git a/NTwain/TwainSession.cs b/NTwain/TwainSession.cs
index 3b71a3a..c36643a 100644
--- a/NTwain/TwainSession.cs
+++ b/NTwain/TwainSession.cs
@@ -309,10 +309,7 @@ namespace NTwain
         /// <exception cref="ArgumentNullException">context</exception>
         public ReturnCode EnableSource(SourceEnableMode mode, bool modal, HandleRef windowHandle, SynchronizationContext context)
         {
-            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
-            {
-                if (context == null) { throw new ArgumentNullException("context"); }
-            }
+            if (context == null) { throw new ArgumentNullException("context"); }
 
             Debug.WriteLine(string.Format("Thread {0}: EnableSource.", Thread.CurrentThread.ManagedThreadId));
 
@@ -378,6 +375,8 @@ namespace NTwain
         /// <summary>
         /// Forces the stepping down of an opened source when things gets out of control.
         /// Used when session state and source state become out of sync.
+        /// This should be called on the Thread that originally called the <see cref="EnableSource"/>
+        /// method, if applicable.
         /// </summary>
         /// <param name="targetState">State of the target.</param>
         public void ForceStepDown(int targetState)
diff --git a/Tests/Tester.Console/Program.cs b/Tests/Tester.Console/Program.cs
new file mode 100644
index 0000000..6b09e65
--- /dev/null
+++ b/Tests/Tester.Console/Program.cs
@@ -0,0 +1,106 @@
+using NTwain;
+using NTwain.Data;
+using NTwain.Values;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using System.Windows.Threading;
+
+namespace Tester
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            // just an amusing example to do twain in console without UI, but may not work in real life
+
+            Console.WriteLine("Running Main on thread {0}", Thread.CurrentThread.ManagedThreadId);
+            new Thread(new ParameterizedThreadStart(DoTwainWork)).Start(Dispatcher.CurrentDispatcher);
+
+            // basically just needs a msg loop to act as the UI thread
+            Dispatcher.Run();
+            Console.WriteLine("Test completed.");
+            Console.ReadLine();
+        }
+
+
+
+        static readonly TwainSession twain = InitTwain();
+        private static TwainSession InitTwain()
+        {
+            var twain = new TwainSession(TWIdentity.CreateFromAssembly(DataGroups.Image, Assembly.GetExecutingAssembly()));
+            twain.DataTransferred += twain_DataTransferred;
+            twain.TransferReady += twain_TransferReady;
+            twain.SourceDisabled += twain_SourceDisabled;
+            return twain;
+        }
+
+
+        static void DoTwainWork(object obj)
+        {
+            Console.WriteLine("Getting ready to do twain stuff on thread {0}", Thread.CurrentThread.ManagedThreadId);
+            Thread.Sleep(1000);
+
+            var mySyncer = SynchronizationContext.Current;
+
+            if (mySyncer == null)
+            {
+                mySyncer = new DispatcherSynchronizationContext(obj as Dispatcher);
+            }
+
+            var rc = twain.OpenManager(default(HandleRef));
+
+            if (rc == ReturnCode.Success)
+            {
+                rc = twain.OpenSource("TWAIN2 FreeImage Software Scanner");
+
+                if (rc == ReturnCode.Success)
+                {
+                    // enablesource must be on the thread the sync context works on
+                    mySyncer.Post(blah =>
+                    {
+                        rc = twain.EnableSource(SourceEnableMode.NoUI, false, default(HandleRef), blah as SynchronizationContext);
+                    }, mySyncer);
+                    return;
+                }
+                else
+                {
+                    twain.CloseManager();
+                }
+            }
+
+            Dispatcher.ExitAllFrames();
+        }
+
+        static void twain_SourceDisabled(object sender, EventArgs e)
+        {
+            Console.WriteLine("Source disabled on thread {0}", Thread.CurrentThread.ManagedThreadId);
+            var rc = twain.CloseSource();
+            rc = twain.CloseManager();
+
+            Dispatcher.ExitAllFrames();
+        }
+
+        static void twain_TransferReady(object sender, TransferReadyEventArgs e)
+        {
+            Console.WriteLine("Got xfer ready on thread {0}", Thread.CurrentThread.ManagedThreadId);
+        }
+
+        static void twain_DataTransferred(object sender, DataTransferredEventArgs e)
+        {
+            if (e.Data != IntPtr.Zero)
+            {
+                Console.WriteLine("Got twain data on thread {0}", Thread.CurrentThread.ManagedThreadId);
+            }
+            else
+            {
+                Console.WriteLine("No twain data on thread {0}", Thread.CurrentThread.ManagedThreadId);
+            }
+        }
+    }
+}
diff --git a/Tests/Tester.Console/Properties/AssemblyInfo.cs b/Tests/Tester.Console/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d8afa67
--- /dev/null
+++ b/Tests/Tester.Console/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Tester.Console")]
+[assembly: AssemblyDescription("Console app for quick testing implementations in the TWAIN lib.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Yin-Chun Wang")]
+[assembly: AssemblyProduct("Tester.Console")]
+[assembly: AssemblyCopyright("Copyright © Yin-Chun Wang 2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("c27df82d-5be9-4396-8905-0af6ea6e63cd")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Tests/Tester.Console/Tester.Console.csproj b/Tests/Tester.Console/Tester.Console.csproj
new file mode 100644
index 0000000..6ba359f
--- /dev/null
+++ b/Tests/Tester.Console/Tester.Console.csproj
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{12D761EF-68DF-41CE-92EF-0C7AE81857A3}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Tester</RootNamespace>
+    <AssemblyName>Tester.Console</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+    <Reference Include="WindowsBase" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\NTwain\NTwain.csproj">
+      <Project>{0c5a6fb1-0282-4d61-8354-68deb1515001}</Project>
+      <Name>NTwain</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file