diff --git a/Source/Noesis.Javascript/JavaScript.Net.vcxproj b/Source/Noesis.Javascript/JavaScript.Net.vcxproj
index aea6b78..4d60057 100644
--- a/Source/Noesis.Javascript/JavaScript.Net.vcxproj
+++ b/Source/Noesis.Javascript/JavaScript.Net.vcxproj
@@ -160,6 +160,7 @@
+
@@ -168,6 +169,7 @@
+
diff --git a/Source/Noesis.Javascript/JavaScript.Net.vcxproj.filters b/Source/Noesis.Javascript/JavaScript.Net.vcxproj.filters
index 153155f..d3666f9 100644
--- a/Source/Noesis.Javascript/JavaScript.Net.vcxproj.filters
+++ b/Source/Noesis.Javascript/JavaScript.Net.vcxproj.filters
@@ -30,6 +30,9 @@
Header Files
+
+ Header Files
+
@@ -50,6 +53,9 @@
Source Files
+
+ Source Files
+
diff --git a/Source/Noesis.Javascript/JavascriptContext.cpp b/Source/Noesis.Javascript/JavascriptContext.cpp
index c2b39a6..3af39a4 100644
--- a/Source/Noesis.Javascript/JavascriptContext.cpp
+++ b/Source/Noesis.Javascript/JavascriptContext.cpp
@@ -157,6 +157,7 @@ JavascriptContext::JavascriptContext()
mExternals = gcnew System::Collections::Generic::Dictionary();
HandleScope scope(isolate);
mContext = new Persistent(isolate, Context::New(isolate));
+ mIsDisposed = false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -173,6 +174,7 @@ JavascriptContext::~JavascriptContext()
}
if (isolate != NULL)
isolate->Dispose();
+ mIsDisposed = true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -357,6 +359,20 @@ JavascriptContext::GetCurrentIsolate()
////////////////////////////////////////////////////////////////////////////////////////////////////
+bool JavascriptContext::IsDisposed()
+{
+ return mIsDisposed;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+Handle JavascriptContext::GetGlobal()
+{
+ return mContext->Get(this->GetCurrentIsolate())->Global();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
v8::Locker *
JavascriptContext::Enter([System::Runtime::InteropServices::Out] JavascriptContext^% old_context)
{
diff --git a/Source/Noesis.Javascript/JavascriptContext.h b/Source/Noesis.Javascript/JavascriptContext.h
index 850007d..3174553 100644
--- a/Source/Noesis.Javascript/JavascriptContext.h
+++ b/Source/Noesis.Javascript/JavascriptContext.h
@@ -172,6 +172,8 @@ public ref class JavascriptContext: public System::IDisposable
static v8::Isolate *GetCurrentIsolate();
+ Handle GetGlobal();
+
v8::Locker *Enter([System::Runtime::InteropServices::Out] JavascriptContext^% old_context);
void Exit(v8::Locker *locker, JavascriptContext^ old_context);
@@ -179,12 +181,15 @@ public ref class JavascriptContext: public System::IDisposable
JavascriptExternal* WrapObject(System::Object^ iObject);
Handle GetObjectWrapperTemplate();
-
+
+ bool IsDisposed();
+
static void FatalErrorCallbackMember(const char* location, const char* message);
////////////////////////////////////////////////////////////
// Data members
////////////////////////////////////////////////////////////
+
protected:
// By entering an isolate before using a context, we can have multiple
// contexts used simultaneously in different threads.
@@ -202,6 +207,8 @@ public ref class JavascriptContext: public System::IDisposable
// the context is destroyed.
System::Collections::Generic::Dictionary ^mExternals;
+ bool mIsDisposed;
+
// Keeping track of recursion.
[System::ThreadStaticAttribute] static JavascriptContext ^sCurrentContext;
diff --git a/Source/Noesis.Javascript/JavascriptFunction.cpp b/Source/Noesis.Javascript/JavascriptFunction.cpp
new file mode 100644
index 0000000..c890a9c
--- /dev/null
+++ b/Source/Noesis.Javascript/JavascriptFunction.cpp
@@ -0,0 +1,98 @@
+#include "JavascriptFunction.h"
+#include "JavascriptInterop.h"
+#include "JavascriptContext.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace Noesis { namespace Javascript {
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+JavascriptFunction::JavascriptFunction(v8::Handle iFunction, JavascriptContext^ context)
+{
+ if (!iFunction->IsFunction())
+ throw gcnew System::ArgumentException("Trying to use non-function as function");
+
+ if(!context)
+ throw gcnew System::ArgumentException("Must provide a JavascriptContext");
+
+ mFuncHandle = new Persistent(context->GetCurrentIsolate(), Handle::Cast(iFunction));
+ mContext = context;
+}
+
+JavascriptFunction::~JavascriptFunction()
+{
+ if(mFuncHandle)
+ {
+ if (mContext && !mContext->IsDisposed())
+ {
+ JavascriptScope scope(mContext);
+ mFuncHandle->Reset();
+ }
+ delete mFuncHandle;
+ mFuncHandle = nullptr;
+ }
+ System::GC::SuppressFinalize(this);
+}
+
+JavascriptFunction::!JavascriptFunction()
+{
+ if(mFuncHandle)
+ {
+ if (mContext && !mContext->IsDisposed())
+ {
+ JavascriptScope scope(mContext);
+ mFuncHandle->Reset();
+ }
+ delete mFuncHandle;
+ mFuncHandle = nullptr;
+ }
+}
+
+System::Object^ JavascriptFunction::Call(... cli::array^ args)
+{
+ JavascriptScope scope(mContext);
+ HandleScope handleScope(mContext->GetCurrentIsolate());
+
+ Handle global = mContext->GetGlobal();
+
+ int argc = args->Length;
+ Handle *argv = new Handle[argc];
+ for (int i = 0; i < argc; i++)
+ {
+ argv[i] = JavascriptInterop::ConvertToV8(args[i]);
+ }
+
+ Local retVal = mFuncHandle->Get(mContext->GetCurrentIsolate())->Call(global, argc, argv);
+
+ delete [] argv;
+ return JavascriptInterop::ConvertFromV8(retVal);
+}
+
+bool JavascriptFunction::operator==(JavascriptFunction^ func1, JavascriptFunction^ func2)
+{
+ if(ReferenceEquals(func2, nullptr)) {
+ return false;
+ }
+ Handle jsFuncPtr1 = func1->mFuncHandle->Get(func1->mContext->GetCurrentIsolate());
+ Handle jsFuncPtr2 = func2->mFuncHandle->Get(func2->mContext->GetCurrentIsolate());
+
+ return jsFuncPtr1->Equals(jsFuncPtr2);
+}
+
+bool JavascriptFunction::Equals(JavascriptFunction^ other)
+{
+ return this == other;
+}
+
+bool JavascriptFunction::Equals(Object^ other)
+{
+ JavascriptFunction^ otherFunc = dynamic_cast(other);
+ return (otherFunc && this->Equals(otherFunc));
+}
+
+} } // namespace Noesis::Javascript
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
\ No newline at end of file
diff --git a/Source/Noesis.Javascript/JavascriptFunction.h b/Source/Noesis.Javascript/JavascriptFunction.h
new file mode 100644
index 0000000..199fe29
--- /dev/null
+++ b/Source/Noesis.Javascript/JavascriptFunction.h
@@ -0,0 +1,45 @@
+#pragma once
+
+//////////////////////////////////////////////////////////////////////////
+
+#include
+
+#include "JavascriptContext.h"
+
+using namespace v8;
+
+//////////////////////////////////////////////////////////////////////////
+
+namespace Noesis { namespace Javascript {
+
+//////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////
+// JavascriptFunction
+//
+// Wraps around JS function object and allow calling it in later time
+//////////////////////////////////////////////////////////////////////////
+public ref class JavascriptFunction
+{
+public:
+ JavascriptFunction(v8::Handle iFunction, JavascriptContext^ context);
+ ~JavascriptFunction();
+ !JavascriptFunction();
+
+ System::Object^ Call(... cli::array^ args);
+
+ static bool operator== (JavascriptFunction^ func1, JavascriptFunction^ func2);
+ bool Equals(JavascriptFunction^ other);
+
+ virtual bool Equals(Object^ other) override;
+
+private:
+ v8::Persistent* mFuncHandle;
+ JavascriptContext^ mContext;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+} } // namespace Noesis::Javascript
+
+//////////////////////////////////////////////////////////////////////////
\ No newline at end of file
diff --git a/Source/Noesis.Javascript/JavascriptInterop.cpp b/Source/Noesis.Javascript/JavascriptInterop.cpp
index d6f4de7..03f94cb 100644
--- a/Source/Noesis.Javascript/JavascriptInterop.cpp
+++ b/Source/Noesis.Javascript/JavascriptInterop.cpp
@@ -33,6 +33,7 @@
#include "SystemInterop.h"
#include "JavascriptException.h"
#include "JavascriptExternal.h"
+#include "JavascriptFunction.h"
#include
@@ -129,6 +130,8 @@ JavascriptInterop::ConvertFromV8(Handle iValue, ConvertedObjects &already
return ConvertArrayFromV8(iValue, already_converted);
if (iValue->IsDate())
return ConvertDateFromV8(iValue);
+ if (iValue->IsFunction())
+ return gcnew JavascriptFunction(iValue->ToObject(), JavascriptContext::GetCurrent());
if (iValue->IsObject())
{
Handle