V8Sharp的中文乱码问题解决
V8是一个开源的javascript引擎,到现在为止堪称为是性能最好最稳定的javascript。因此还诞生了一个基于此引擎的服务端开发框架:Node.js。由此可见此引擎的牛逼之处。由于打算在后续项目中使用javascript,从而使项目的变化部分变更为动态配置的。
基于C#和V8的javascript引擎有很多。但到目前为止都存在一些问题,以下将分别说明:
javascript.net:
项目地址:http://javascriptdotnet.codeplex.com/
特点:
1 使用简单
2 不存在中文乱码的问题
缺点:脚本中不支持直接访问C#的类和静态函数。
示例代码如下:
// Initialize a context
using (JavascriptContext context = new JavascriptContext()) { // Setting external parameters for the context
context.SetParameter("console", new SystemConsole());
context.SetParameter("message", "Hello World !");
context.SetParameter("number", ); // Script
string script = @"
var i;
for (i = 0; i < 5; i++)
console.Print(message + ' (' + i + ')');
number += i;
"; // Running the script
context.Run(script); // Getting a parameter
Console.WriteLine("number: " + context.GetParameter("number"));
}
v8.net:
项目地址:http://v8dotnet.codeplex.com/
特点:
1 功能支持全面
缺点:
1 项目处理的库管理做的太不好了,生成后一共5个dll,而且区分x86和x64
2 源码编译太难了,完成v8.net下载后,还得下载V8的源码及相关工具源码,倒腾了半天没个所以然
3 项目虽然到2015年都有人更新,但是发布的版本完全无法使用,连release中已经生成好的例子都直接报错。怀疑是发布的项目中没包含V8的dll。
static void Main(string[] args)
{
AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; try
{
Console.Write(Environment.NewLine + "Creating a V8Engine instance ...");
V8Engine _JSServer = new V8Engine();
Console.WriteLine(" Done!"); Console.Write("Testing marshalling compatibility...");
_JSServer.RunMarshallingTests();
Console.WriteLine(" Pass!"); _TitleUpdateTimer = new System.Timers.Timer();
_TitleUpdateTimer.AutoReset = true;
_TitleUpdateTimer.Elapsed += (_o, _e) =>
{
if (!_JSServer.IsDisposed)
Console.Title = "V8.Net Console - " + (IntPtr.Size == ? "32-bit" : "64-bit") + " mode (Handles: " + _JSServer.TotalHandles
+ " / Pending Native GC: " + _JSServer.TotalHandlesPendingDisposal
+ " / Cached: " + _JSServer.TotalHandlesCached
+ " / In Use: " + (_JSServer.TotalHandles - _JSServer.TotalHandlesCached) + ")";
else
Console.Title = "V8.Net Console - Shutting down...";
};
_TitleUpdateTimer.Start(); {
Console.WriteLine(Environment.NewLine + "Creating some global CLR types ..."); // (Note: It's not required to explicitly register a type, but it is recommended for more control.) _JSServer.RegisterType(typeof(Object), "Object", true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(Type), "Type", true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(String), "String", true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(Boolean), "Boolean", true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(Array), "Array", true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(System.Collections.ArrayList), null, true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(char), null, true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(int), null, true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(Int16), null, true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(Int32), null, true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(Int64), null, true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(UInt16), null, true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(UInt32), null, true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(UInt64), null, true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(Enumerable), null, true, ScriptMemberSecurity.Locked);
_JSServer.RegisterType(typeof(System.IO.File), null, true, ScriptMemberSecurity.Locked); ObjectHandle hSystem = _JSServer.CreateObject();
_JSServer.DynamicGlobalObject.System = hSystem;
hSystem.SetProperty(typeof(Object)); // (Note: No optional parameters used, so this will simply lookup and apply the existing registered type details above.)
hSystem.SetProperty(typeof(String));
hSystem.SetProperty(typeof(Boolean));
hSystem.SetProperty(typeof(Array));
_JSServer.GlobalObject.SetProperty(typeof(Type));
_JSServer.GlobalObject.SetProperty(typeof(System.Collections.ArrayList));
_JSServer.GlobalObject.SetProperty(typeof(char));
_JSServer.GlobalObject.SetProperty(typeof(int));
_JSServer.GlobalObject.SetProperty(typeof(Int16));
_JSServer.GlobalObject.SetProperty(typeof(Int32));
_JSServer.GlobalObject.SetProperty(typeof(Int64));
_JSServer.GlobalObject.SetProperty(typeof(UInt16));
_JSServer.GlobalObject.SetProperty(typeof(UInt32));
_JSServer.GlobalObject.SetProperty(typeof(UInt64));
_JSServer.GlobalObject.SetProperty(typeof(Enumerable));
_JSServer.GlobalObject.SetProperty(typeof(Environment));
_JSServer.GlobalObject.SetProperty(typeof(System.IO.File)); _JSServer.GlobalObject.SetProperty(typeof(Uri), V8PropertyAttributes.Locked, null, true, ScriptMemberSecurity.Locked); // (Note: Not yet registered, but will auto register!)
_JSServer.GlobalObject.SetProperty("uri", new Uri("http://www.example.com")); _JSServer.GlobalObject.SetProperty(typeof(GenericTest<int, string>), V8PropertyAttributes.Locked, null, true, ScriptMemberSecurity.Locked);
_JSServer.GlobalObject.SetProperty(typeof(GenericTest<string, int>), V8PropertyAttributes.Locked, null, true, ScriptMemberSecurity.Locked); Console.WriteLine(Environment.NewLine + "Creating a global 'dump(obj)' function to dump properties of objects (one level only) ...");
_JSServer.ConsoleExecute(@"dump = function(o) { var s=''; if (typeof(o)=='undefined') return 'undefined';"
+ @" if (typeof o.valueOf=='undefined') return ""'valueOf()' is missing on '""+(typeof o)+""' - if you are inheriting from V8ManagedObject, make sure you are not blocking the property."";"
+ @" if (typeof o.toString=='undefined') return ""'toString()' is missing on '""+o.valueOf()+""' - if you are inheriting from V8ManagedObject, make sure you are not blocking the property."";"
+ @" for (var p in o) {var ov='', pv=''; try{ov=o.valueOf();}catch(e){ov='{error: '+e.message+': '+dump(o)+'}';} try{pv=o[p];}catch(e){pv=e.message;} s+='* '+ov+'.'+p+' = ('+pv+')\r\n'; } return s; }"); Console.WriteLine(Environment.NewLine + "Creating a global 'assert(msg, a,b)' function for property value assertion ...");
_JSServer.ConsoleExecute(@"assert = function(msg,a,b) { msg += ' ('+a+'==='+b+'?)'; if (a === b) return msg+' ... Ok.'; else throw msg+' ... Failed!'; }"); Console.WriteLine(Environment.NewLine + "Creating a global 'Console' object ...");
_JSServer.GlobalObject.SetProperty(typeof(Console), V8PropertyAttributes.Locked, null, true, ScriptMemberSecurity.Locked);
//??_JSServer.CreateObject<JS_Console>(); Console.WriteLine(Environment.NewLine + "Creating a new global type 'TestEnum' ...");
_JSServer.GlobalObject.SetProperty(typeof(TestEnum), V8PropertyAttributes.Locked, null, true, ScriptMemberSecurity.Locked); Console.WriteLine(Environment.NewLine + "Creating a new global type 'SealedObject' as 'Sealed_Object' ...");
Console.WriteLine("(represents a 3rd-party inaccessible V8.NET object.)");
_JSServer.GlobalObject.SetProperty(typeof(SealedObject), V8PropertyAttributes.Locked, null, true); Console.WriteLine(Environment.NewLine + "Creating a new wrapped and locked object 'sealedObject' ...");
_JSServer.GlobalObject.SetProperty("sealedObject", new SealedObject(null, null), null, true, ScriptMemberSecurity.Locked); Console.WriteLine(Environment.NewLine + "Dumping global properties ...");
_JSServer.VerboseConsoleExecute(@"dump(this)"); Console.WriteLine(Environment.NewLine + "Here is a contrived example of calling and passing CLR methods/types ...");
_JSServer.VerboseConsoleExecute(@"r = Enumerable.Range(1,Int32('10'));");
_JSServer.VerboseConsoleExecute(@"a = System.String.Join$1([Int32], ', ', r);"); Console.WriteLine(Environment.NewLine + "Example of changing 'System.String.Empty' member security attributes to 'NoAccess'...");
_JSServer.GetTypeBinder(typeof(String)).ChangeMemberSecurity("Empty", ScriptMemberSecurity.NoAcccess);
_JSServer.VerboseConsoleExecute(@"System.String.Empty;");
Console.WriteLine("(Note: Access denied is only for static types - bound instances are more dynamic, and will hide properties instead [name/index interceptors are not available on V8 Function objects])"); Console.WriteLine(Environment.NewLine + "Finally, how to view method signatures...");
_JSServer.VerboseConsoleExecute(@"dump(System.String.Join);"); var funcTemp = _JSServer.CreateFunctionTemplate<SamplePointFunctionTemplate>("SamplePointFunctionTemplate");
} Console.WriteLine(Environment.NewLine + @"Ready - just enter script to execute. Type '\' or '\help' for a list of console specific commands."); string input, lcInput; while (true)
{
try
{
Console.Write(Environment.NewLine + "> "); input = Console.ReadLine();
lcInput = input.Trim().ToLower(); if (lcInput == @"\help" || lcInput == @"\")
{
Console.WriteLine(@"Special console commands (all commands are triggered via a preceding '\' character so as not to confuse it with script code):");
Console.WriteLine(@"\cls - Clears the screen.");
Console.WriteLine(@"\test - Starts the test process.");
Console.WriteLine(@"\gc - Triggers garbage collection (for testing purposes).");
Console.WriteLine(@"\v8gc - Triggers garbage collection in V8 (for testing purposes).");
Console.WriteLine(@"\gctest - Runs a simple GC test against V8.NET and the native V8 engine.");
Console.WriteLine(@"\speedtest - Runs a simple test script to test V8.NET performance with the V8 engine.");
Console.WriteLine(@"\mtest - Runs a simple test script to test V8.NET integration/marshalling compatibility with the V8 engine on your system.");
Console.WriteLine(@"\newenginetest - Creates 3 new engines (each time) and runs simple expressions in each one (note: new engines are never removed once created).");
Console.WriteLine(@"\exit - Exists the console.");
}
else if (lcInput == @"\cls")
Console.Clear();
else if (lcInput == @"\test")
{
try
{
/* This command will serve as a means to run fast tests against various aspects of V8.NET from the JavaScript side.
* This is preferred over unit tests because 1. it takes a bit of time for the engine to initialize, 2. internal feedback
* can be sent to the console from the environment, and 3. serves as a nice implementation example.
* The unit testing project will serve to test basic engine instantiation and solo utility classes.
* In the future, the following testing process may be redesigned to be runnable in both unit tests and console apps.
*/ Console.WriteLine("\r\n===============================================================================");
Console.WriteLine("Setting up the test environment ...\r\n"); {
// ... create a function template in order to generate our object! ...
// (note: this is not using ObjectTemplate because the native V8 does not support class names for those objects [class names are object type names]) Console.Write("\r\nCreating a FunctionTemplate instance ...");
var funcTemplate = _JSServer.CreateFunctionTemplate(typeof(V8DotNetTesterWrapper).Name);
Console.WriteLine(" Ok."); // ... use the template to generate our object ... Console.Write("\r\nRegistering the custom V8DotNetTester function object ...");
var testerFunc = funcTemplate.GetFunctionObject<V8DotNetTesterFunction>();
_JSServer.DynamicGlobalObject.V8DotNetTesterWrapper = testerFunc;
Console.WriteLine(" Ok. 'V8DotNetTester' is now a type [Function] in the global scope."); Console.Write("\r\nCreating a V8DotNetTester instance from within JavaScript ...");
// (note: Once 'V8DotNetTester' is constructed, the 'Initialize()' override will be called immediately before returning,
// but you can return "engine.GetObject<V8DotNetTester>(_this.Handle, true, false)" to prevent it.)
_JSServer.VerboseConsoleExecute("testWrapper = new V8DotNetTesterWrapper();");
_JSServer.VerboseConsoleExecute("tester = testWrapper.tester;");
Console.WriteLine(" Ok."); // ... Ok, the object exists, BUT, it is STILL not yet part of the global object, so we add it next ... Console.Write("\r\nRetrieving the 'tester' property on the global object for the V8DotNetTester instance ...");
var handle = _JSServer.GlobalObject.GetProperty("tester");
var tester = (V8DotNetTester)_JSServer.DynamicGlobalObject.tester;
Console.WriteLine(" Ok."); Console.WriteLine("\r\n===============================================================================");
Console.WriteLine("Dumping global properties ...\r\n"); _JSServer.VerboseConsoleExecute("dump(this)"); Console.WriteLine("\r\n===============================================================================");
Console.WriteLine("Dumping tester properties ...\r\n"); _JSServer.VerboseConsoleExecute("dump(tester)"); // ... example of adding a functions via script (note: V8Engine.GlobalObject.Properties will have 'Test' set) ... Console.WriteLine("\r\n===============================================================================");
Console.WriteLine("Ready to run the tester, press any key to proceed ...\r\n");
Console.ReadKey(); tester.Execute(); Console.WriteLine("\r\nReleasing managed tester object ...\r\n");
tester.Handle.ReleaseManagedObject();
} Console.WriteLine("\r\n===============================================================================\r\n");
Console.WriteLine("Test completed successfully! Any errors would have interrupted execution.");
Console.WriteLine("Note: The 'dump(obj)' function is available to use for manual inspection.");
Console.WriteLine("Press any key to dump the global properties ...");
Console.ReadKey();
_JSServer.VerboseConsoleExecute("dump(this);");
}
catch
{
Console.WriteLine("\r\nTest failed.\r\n");
throw;
}
}
else if (lcInput == @"\gc")
{
Console.Write("\r\nForcing garbage collection ... ");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Done.\r\n");
}
else if (lcInput == @"\v8gc")
{
Console.Write("\r\nForcing V8 garbage collection ... ");
_JSServer.ForceV8GarbageCollection();
Console.WriteLine("Done.\r\n");
}
else if (lcInput == @"\gctest")
{
Console.WriteLine("\r\nTesting garbage collection ... "); V8NativeObject tempObj;
InternalHandle internalHandle = InternalHandle.Empty;
int i; {
Console.WriteLine("Setting 'this.tempObj' to a new managed object ..."); tempObj = _JSServer.CreateObject<V8NativeObject>();
internalHandle = tempObj.Handle;
Handle testHandle = internalHandle;
_JSServer.DynamicGlobalObject.tempObj = tempObj; // ... because we have a strong reference to the handle in 'testHandle', the managed and native objects are safe; however,
// this block has the only strong reference, so once the reference goes out of scope, the managed GC should attempt to
// collect it, which will mark the handle as ready for collection (but it will not be destroyed just yet until V8 is ready) ... Console.WriteLine("Clearing managed references and running the garbage collector ...");
testHandle = null;
} GC.Collect();
GC.WaitForPendingFinalizers();
// (we wait for the 'testHandle' handle object to be collected, which will dispose the handle)
// (note: we do not call 'Set()' on 'internalHandle' because the "Handle" type takes care of the disposal) for (i = ; i < && internalHandle.ReferenceCount > ; i++)
System.Threading.Thread.Sleep(); // (just wait for the worker) if (internalHandle.ReferenceCount > )
throw new Exception("Handle is still not ready for GC ... something is wrong."); Console.WriteLine("Success! The managed handle instance is pending disposal.");
Console.WriteLine("Clearing the handle object reference next ..."); // ... because we still have a reference to 'tempObj' at this point, the managed and native objects are safe; however, this
// block scope has the only strong reference to the managed object keeping everything alive (including the underlying handle),
// so once the reference goes out of scope, the managed GC will collect it, which will mark the managed object as ready for
// collection. Once both the managed object and handle are marked, this in turn marks the native handle as weak. When the native
// V8 engine's garbage collector is ready to dispose of the handle, as call back is triggered and the native object and
// handles will finally be removed ... tempObj = null; Console.WriteLine("Forcing CLR garbage collection ... ");
GC.Collect();
GC.WaitForPendingFinalizers(); Console.WriteLine("Waiting on the worker to make the object weak on the native V8 side ... "); for (i = ; i < && !internalHandle.IsNativelyWeak; i++)
System.Threading.Thread.Sleep(); if (!internalHandle.IsNativelyWeak)
throw new Exception("Object is not weak yet ... something is wrong."); Console.WriteLine("The native side object is now weak and ready to be collected by V8."); Console.WriteLine("Forcing V8 garbage collection ... ");
_JSServer.DynamicGlobalObject.tempObj = null;
for (i = ; i < && !internalHandle.IsDisposed; i++)
{
_JSServer.ForceV8GarbageCollection();
System.Threading.Thread.Sleep();
} Console.WriteLine("Looking for object ..."); if (!internalHandle.IsDisposed) throw new Exception("Managed object was not garbage collected.");
// (note: this call is only valid as long as no more objects are created before this point)
Console.WriteLine("Success! The managed V8NativeObject instance is disposed.");
Console.WriteLine("\r\nDone.\r\n");
}
else if (lcInput == @"\speedtest")
{
var timer = new Stopwatch();
long startTime, elapsed;
long count;
double result1, result2, result3, result4; Console.WriteLine(Environment.NewLine + "Running the speed tests ... "); timer.Start(); //??Console.WriteLine(Environment.NewLine + "Running the property access speed tests ... ");
Console.WriteLine("(Note: 'V8NativeObject' objects are always faster than using the 'V8ManagedObject' objects because native objects store values within the V8 engine and managed objects store theirs on the .NET side.)"); count = ; Console.WriteLine("\r\nTesting global property write speed ... ");
startTime = timer.ElapsedMilliseconds;
_JSServer.Execute("o={i:0}; for (o.i=0; o.i<" + count + "; o.i++) n = 0;"); // (o={i:0}; is used in case the global object is managed, which will greatly slow down the loop)
elapsed = timer.ElapsedMilliseconds - startTime;
result1 = (double)elapsed / count;
Console.WriteLine(count + " loops @ " + elapsed + "ms total = " + result1.ToString("0.0#########") + " ms each pass."); Console.WriteLine("\r\nTesting global property read speed ... ");
startTime = timer.ElapsedMilliseconds;
_JSServer.Execute("for (o.i=0; o.i<" + count + "; o.i++) n;");
elapsed = timer.ElapsedMilliseconds - startTime;
result2 = (double)elapsed / count;
Console.WriteLine(count + " loops @ " + elapsed + "ms total = " + result2.ToString("0.0#########") + " ms each pass."); count = ; Console.WriteLine("\r\nTesting property write speed on a managed object (with interceptors) ... ");
_JSServer.DynamicGlobalObject.mo = _JSServer.CreateObjectTemplate().CreateObject();
startTime = timer.ElapsedMilliseconds;
_JSServer.Execute("o={i:0}; for (o.i=0; o.i<" + count + "; o.i++) mo.n = 0;");
elapsed = timer.ElapsedMilliseconds - startTime;
result3 = (double)elapsed / count;
Console.WriteLine(count + " loops @ " + elapsed + "ms total = " + result3.ToString("0.0#########") + " ms each pass."); Console.WriteLine("\r\nTesting property read speed on a managed object (with interceptors) ... ");
startTime = timer.ElapsedMilliseconds;
_JSServer.Execute("for (o.i=0; o.i<" + count + "; o.i++) mo.n;");
elapsed = timer.ElapsedMilliseconds - startTime;
result4 = (double)elapsed / count;
Console.WriteLine(count + " loops @ " + elapsed + "ms total = " + result4.ToString("0.0#########") + " ms each pass."); Console.WriteLine("\r\nUpdating native properties is {0:N2}x faster than managed ones.", result3 / result1);
Console.WriteLine("\r\nReading native properties is {0:N2}x faster than managed ones.", result4 / result2); Console.WriteLine("\r\nDone.\r\n");
}
else if (lcInput == @"\exit")
{
Console.WriteLine("User requested exit, disposing the engine instance ...");
_JSServer.Dispose();
Console.WriteLine("Engine disposed successfully. Press any key to continue ...");
Console.ReadKey();
Console.WriteLine("Goodbye. :)");
break;
}
else if (lcInput == @"\mtest")
{
Console.WriteLine("Loading and marshalling native structs with test data ..."); _JSServer.RunMarshallingTests(); Console.WriteLine("Success! The marshalling between native and managed side is working as expected.");
}
else if (lcInput == @"\newenginetest")
{
Console.WriteLine("Creating 3 more engines ..."); var engine1 = new V8Engine();
var engine2 = new V8Engine();
var engine3 = new V8Engine(); Console.WriteLine("Running test expressions ..."); var resultHandle = engine1.Execute("1 + 2");
var result = resultHandle.AsInt32;
Console.WriteLine("Engine 1: 1+2=" + result);
resultHandle.Dispose(); resultHandle = engine2.Execute("2+3");
result = resultHandle.AsInt32;
Console.WriteLine("Engine 2: 2+3=" + result);
resultHandle.Dispose(); resultHandle = engine3.Execute("3 + 4");
result = resultHandle.AsInt32;
Console.WriteLine("Engine 3: 3+4=" + result);
resultHandle.Dispose(); Console.WriteLine("Done.");
}
else if (lcInput == @"\memleaktest")
{
string script = @"
for (var i=0; i < 1000; i++) {
// if the loop is empty no memory leak occurs.
// if any of the following 3 method calls are uncommented then a bad memory leak occurs.
//SomeMethods.StaticDoNothing();
//shared.StaticDoNothing();
shared.InstanceDoNothing();
}
";
_JSServer.GlobalObject.SetProperty(typeof(SomeMethods), recursive: true, memberSecurity: ScriptMemberSecurity.ReadWrite);
var sm = new SomeMethods();
_JSServer.GlobalObject.SetProperty("shared", sm, recursive: true);
var hScript = _JSServer.Compile(script, null, true);
int i = ;
try
{
while (true)
{
// putting a using statement on the returned handle stops the memory leak when running just the for loop.
// using a compiled script seems to reduce garbage collection, but does not affect the memory leak
using (var h = _JSServer.Execute(hScript, true))
{
} // end using handle returned by execute
_JSServer.DoIdleNotification();
Thread.Sleep();
i++;
if (i % == )
{
GC.Collect();
GC.WaitForPendingFinalizers();
_JSServer.ForceV8GarbageCollection();
i = ;
}
} // end infinite loop
}
catch (OutOfMemoryException ex)
{
Console.WriteLine(ex);
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadKey();
}
//?catch
//{
// Console.WriteLine("We caught something");
// Console.ReadKey();
//}
}
else if (lcInput.StartsWith(@"\"))
{
Console.WriteLine(@"Invalid console command. Type '\help' to see available commands.");
}
else
{
Console.WriteLine(); try
{
var result = _JSServer.Execute(input, "V8.NET Console");
Console.WriteLine(result.AsString);
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine();
Console.WriteLine(Exceptions.GetFullErrorMessage(ex));
Console.WriteLine();
Console.WriteLine("Error! Press any key to continue ...");
Console.ReadKey();
}
}
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine();
Console.WriteLine(Exceptions.GetFullErrorMessage(ex));
Console.WriteLine();
Console.WriteLine("Error! Press any key to continue ...");
Console.ReadKey();
}
}
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine();
Console.WriteLine(Exceptions.GetFullErrorMessage(ex));
Console.WriteLine();
Console.WriteLine("Error! Press any key to exit ...");
Console.ReadKey();
} if (_TitleUpdateTimer != null)
_TitleUpdateTimer.Dispose();
}
个人觉得最好的登场了:V8Sharp
源码地址:http://v8sharp.codeplex.com/
特点:
1 支持的功能全面
2 下载的源码可以直接编译通过,编译环境:VS2010 VS2013
缺点:
1 不支持中文。
代码如下:
static void Main() {
//registering with v8sharp
V8Engine engine = V8Engine.Create();
engine.Register<App.Point>();
//execute javascript
object rtn = engine.Execute("new App.Point(10, 10);");
}
以上几个项目都是基于V8引擎的,唯独V8Sharp存在中文乱码问题,这说明是由于此项目本身导致。然后对比了几分代码后,发现是V8Sharp代码的bug。具体如下:
代码文件v8value.cpp的内容如下。
String^ V8ValueWrapper::WrapString(v8::Handle<v8::Value> value) {
//v8::String::AsciiValue ascii(value);
//return gcnew String((const char*)*ascii);
return gcnew String((wchar_t*)*v8::String::Value(value->ToString()));
}
v8::Handle<v8::Value> V8ValueWrapper::UnwrapString(String^ value) {
/*pin_ptr<const wchar_t> ptr = PtrToStringChars(value);
return v8::String::New((const uint16_t*)ptr);*/
pin_ptr<const wchar_t> valuePtr = PtrToStringChars(safe_cast<System::String^>(value));
wchar_t* tmpValue = (wchar_t*) valuePtr;
return v8::String::New((uint16_t*)tmpValue);
}
其中被注释的部分则是之前的代码,未注释的则是修改后的代码。以上代码借鉴于javascript.net的Noesis.Javascript/JavascriptInterop.cpp。按照这个修改后,现在可以正常支持中文了。并且V8sharp使用方便,支持全面。所以最后推荐V8Sharp给大家。修改后的源码地址:链接: http://pan.baidu.com/s/1i58QdCx 密码: 4cj9
V8Sharp的中文乱码问题解决的更多相关文章
- WingIDE中文乱码问题解决方法
WingIDE中文乱码问题解决方法 安装完WingIDE后,首次运行python脚本时,若脚本中含有UTF-8中文,在Debug I/O输出框中,全部变成了乱码. 这时其实我们设置下WingIDE的编 ...
- ubuntu mysql emma中文乱码问题解决
ubuntu mysql emma中文乱码问题解决 emma默认用apt-get 安装的话,emma是不支持中文的,配置文件或直接修改emma程序源文件(python). apt-get安装emma ...
- Spring MVC3返回JSON数据中文乱码问题解决(转)
Spring MVC3返回JSON数据中文乱码问题解决 查了下网上的一些资料,感觉比较复杂,这里,我这几使用两种很简单的办法解决了中文乱码问题. Spring版本:3.2.2.RELEASE Jack ...
- Ubuntu下Eclipse中文乱码问题解决(转)
Ubuntu下Eclipse中文乱码问题解决 把Windows下的工程导入到了Linux下Eclipse中,由于以前的工程代码,都是GBK编码的(Windows下的Eclipse 默认会去读取系统的编 ...
- 【转】asp.net Cookie值中文乱码问题解决方法
来源:脚本之家.百度空间.网易博客 http://www.jb51.net/article/34055.htm http://hi.baidu.com/honfei http://tianminqia ...
- soapUI参数中文乱码问题解决方法 (groovy脚本中文乱码)
soapUI参数中文乱码问题解决方法 可能方案1: 字体不支持中文,将字体修改即可: file-preferences-editor settings-select font 修改字体,改成能显示中文 ...
- oracle中文乱码问题解决
中文乱码问题解决:1.查看服务器端编码select userenv('language') from dual;我实际查到的结果为:AMERICAN_AMERICA.ZHS16GBK2.执行语句 se ...
- 【其他】【navicat】【1】navicat导入txt文件中文乱码问题解决
正文: TXT文件默认编码为ANSI,另存为编码为UTF-8的文本文件即可 备注: 1,一般需要导入的数据都是一张excel表,需要将excel表另存为“文本文件(制表符分隔)(*.txt)”保存类型 ...
- LoadRunner中文乱码问题解决方法
LoadRunner中文乱码问题解决方法 前段时间在录制,增强,整合LoadRunner脚本,期间两次遇到了中文乱码问题.在此记录一下中文乱码问题的解决办法. 一.录制回放中文乱码 我录制登陆的脚本, ...
随机推荐
- 枚举类valueOf方法的疑问
枚举类中valueOf方法只有一个参数而Enum类中有两个参数,请问Enum实例类中的valueOf方法是从何处继承而来? 答案:jvm进行编译的时候添加的.
- 如果客户端禁用cookie,session还能使用吗?
记得在以前找工作的时候,可多次被问到如果客户端被禁用cookie,session还能使用吗? 今天终于找到了相关的答案:我们来看一下: session是在服务器段保持会话数据的一种方法,对应的cook ...
- CSS3基础03(3D②) 求粉丝
3 D (3.1)rotateY 围绕着Y轴进行旋转 (1)正数是(站在右边推),负数是(站在左边推) (2.1)定义元素背过去是否可见 backface-visibility: visible|hi ...
- 设计winform自带动态加载工具按钮和实现热键响应
1.初衷 主要是想设计一个自带添加工具按钮和按钮的快捷键的基窗体.这样以后所设计的窗体只要继承自这个窗体就可以实现热键响应和动态加工具按钮的功能了 写这边文章主要是为了以后使用的时候有个参考,因为这只 ...
- linux 学习3 第四讲 文件常用命令
好几天没有在网上总结了.我把ppt先誊写在本子上,这样听的时候记录就方便很多,添些东西就可以. 我想先看shell那部分,但是没有之前几章的准备,是没法跟着视频动手操作的.所以还是按部就班得学习. 虽 ...
- oracle SQLPLUS 常用set设置
SQL>set colsep' '; //-域输出分隔符 SQL>set echo off; //显示start启动的脚本中的每个sql命令,缺省为on SQL> set echo ...
- Oracle并行执行特性应用初探
1. 序 在历史数据转出测试过程中,通过不断的优化,包括SQL调整和数据库调整,从AWR中看到,基本上难以进行更多的性能提升,于是准备试试并行执行的特性,从这个任务的特点来分析,也比较适合采 ...
- CentOS6.5中配置Rabbitmq3.6.6集群方案
一.安装Erlang环境 1.下载erlang源代码 wget http://erlang.org/download/otp_src_19.1.tar.gz 2.安装依赖相关库文件 yum insta ...
- MySql 数据库导入到 SQL Service
1.下载安装ODBC驱动程序 地址:http://dev.mysql.com/downloads/connector/odbc/ 注意:系统的版本问题( 我的是64位的win7系统,但是SQL Ser ...
- -moz-transform: rotate(-5deg);
目前越来越多的浏览器兼容CSS3标准了,就连IE浏览器老大哥也开始向CSS3低头,微软宣布IE9浏览器支持更多的CSS3属性,IE9更注重 HTML5标准.不过CSS3里有一个使对象旋转的属性tran ...