JsValueRefはvoid* のtypedefなので、何者なのか掴みにくい。また、スタック上でない場所でキープする場合は、AddRefしなければならない。多分、GarvageCollectが働いた時に回収されてしまうのを避けるため。
そこで、CJsValueRefというラッパークラスを作ってみた。スクリプト上での型が分かっている場合に使える。
(少なくともWM_DESTROYのタイミングで、使用したすべてのCJsValueRefをReleaseして下さい。)

#include "stdafx.h"
#define _JSRT_
#include "ChakraCore.h"

#include
#include
#include
#include

#pragma comment (lib, "chakracore")
using namespace std;

class CJsValueRef
{
public:
CJsValueRef() :ref_(nullptr) {}
explicit CJsValueRef(JsValueRef ref);
CJsValueRef(const CJsValueRef& r);
~CJsValueRef() { Release(); }

CJsValueRef(int val);
CJsValueRef(double val);
CJsValueRef(LPCWSTR str);
CJsValueRef(bool bl);
CJsValueRef(const std::vector& ar);
CJsValueRef(const std::map& m);

UINT AddRef();
UINT Release();

// Convert functions
std::vector ToArray() const;
int ToInt() const;
double ToDouble() const;
std::wstring ToString() const;
std::map ToMap() const;
bool ToBool() const;

bool empty() { return (ref_ == nullptr); }

CJsValueRef& operator=(const CJsValueRef& x);
private:
JsValueRef ref_;

};

int main()
{
JsRuntimeHandle runtime;
JsContextRef context;
JsValueRef result;
unsigned currentSourceContext = 0;

wstring script = L"(()=>{ var a = { 'tokyo':'03', 'yokohama':'045', 'oosaka':'06'}; return a;})()"; // <-- map
JsCreateRuntime(JsRuntimeAttributeNone, nullptr, &runtime);

// Create an execution context.
JsCreateContext(runtime, &context);

// Now set the execution context as being the current one on this thread.
JsSetCurrentContext(context);

// Run the script.
JsRunScript(script.c_str(), currentSourceContext++, L"", &result);

{
CJsValueRef x = result;
auto m = x.ToMap();

wcout << L'{';

for( auto& it : m )
{
wcout << it.first << L':' << it.second.ToString();
}

wcout << L'}' << endl;

// output is "{tokyo:03,yokohama:045,oosaka:06,}"
}
system("pause");

// Dispose runtime
JsSetCurrentContext(JS_INVALID_REFERENCE);
JsDisposeRuntime(runtime);
return 0;
}

///////////////////////////////////////////////////
CJsValueRef::CJsValueRef(JsValueRef ref)
{
ref_ = ref;
AddRef();
}
CJsValueRef::CJsValueRef(const CJsValueRef& r)
{
ref_ = r.ref_;
AddRef();
}
CJsValueRef::CJsValueRef(int val)
{
JsIntToNumber(val,&ref_);
//AddRef(); 不要
}
CJsValueRef::CJsValueRef(double val)
{
JsDoubleToNumber(val,&ref_);
//AddRef();
}
CJsValueRef::CJsValueRef(LPCWSTR str)
{
JsPointerToString(str,lstrlen(str), &ref_);
AddRef();
}
CJsValueRef::CJsValueRef(bool bl)
{
JsBoolToBoolean( bl, &ref_ );
//AddRef();
}
CJsValueRef::CJsValueRef(const std::vector& ar)
{
JsCreateArray( ar.size(), &ref_ );
AddRef();

int i = 0;
for( auto& it : ar )
{
JsValueRef index;
JsIntToNumber(i++, &index );
JsSetIndexedProperty( ref_, index, it.ref_ );
}

}
CJsValueRef::CJsValueRef( const std::map& m)
{
JsCreateArray( m.size(), &ref_ );
AddRef();

JsValueRef jsobj;
JsConvertValueToObject(ref_, &jsobj );
JsValueRef xnm;
JsGetOwnPropertyNames( jsobj, &xnm );

int i = 0;
for( auto& it : m )
{
auto& key = it.first;

JsValueRef index;
JsIntToNumber(i++, &index);

JsValueRef ck;
JsPointerToString( key.c_str(),key.length(), &ck );

auto er = JsSetIndexedProperty(xnm, index, ck); // set xnm.
_ASSERT( er == JsNoError);

JsValueRef IndexedProperty;
er = JsGetIndexedProperty(xnm, index, &IndexedProperty);
_ASSERT( er == JsNoError);

er = JsSetIndexedProperty( jsobj, IndexedProperty, it.second.ref_ ); // set jsobj.
_ASSERT( er == JsNoError);
}
}
UINT CJsValueRef::AddRef()
{
UINT refcnt = 0;
JsAddRef(ref_, &refcnt);
return refcnt;
}

UINT CJsValueRef::Release()
{
UINT refcnt = 0;
if (ref_)
JsRelease(ref_, &refcnt);

ref_ = nullptr;
return refcnt;
}
CJsValueRef& CJsValueRef::operator=(const CJsValueRef& x)
{
if (this == &x)
return *this;

Release();
ref_ = x.ref_;
AddRef();

return *this;
}

std::vector CJsValueRef::ToArray() const
{
std::vector ar;
JsValueRef jsobj;
if ( JsNoError == JsConvertValueToObject(ref_, &jsobj))
{
JsValueRef xnm;
JsGetOwnPropertyNames(jsobj, &xnm);
JsValueRef lengthName, lengthValue;
ret = JsGetPropertyIdFromName(L"length", &lengthName);
ret = JsGetProperty(xnm, lengthName, &lengthValue);
int count;
JsNumberToInt(lengthValue, &count);
if (count)
{

ar.resize(count - 1);

for (int i = 0; i < count - 1; i++)
{
JsValueRef index;
JsIntToNumber(i, &index);

JsValueRef IndexedProperty;
JsGetIndexedProperty(jsobj, index, &IndexedProperty);

ar[i] = CJsValueRef(IndexedProperty);
}
}
}
return ar;

}
bool CJsValueRef::ToBool() const
{
bool ret = false;
JsValueRef a;
JsConvertValueToBoolean(ref_,&a);
JsBooleanToBool(a,&ret);
return ret;
}
int CJsValueRef::ToInt() const
{
int ret = 0;
JsValueRef a;
JsConvertValueToNumber(ref_, &a);
JsNumberToInt(a, &ret);

return ret;
}
double CJsValueRef::ToDouble() const
{
double ret = 0;
JsValueRef a;
JsConvertValueToNumber(ref_, &a);
JsNumberToDouble(a, &ret);

return ret;
}
std::wstring CJsValueRef::ToString() const
{
JsValueRef a;
JsConvertValueToString(ref_, &a);

const wchar_t* cb; size_t len;
JsStringToPointer(a, &cb, &len);

return std::wstring(cb, len);
}
std::map CJsValueRef::ToMap() const
{
std::map map;
JsValueRef jsobj;
if ( JsNoError == JsConvertValueToObject(ref_, &jsobj))
{
JsValueRef xnm;
JsGetOwnPropertyNames(jsobj, &xnm);
JsValueRef lengthName, lengthValue;
ret = JsGetPropertyIdFromName(L"length", &lengthName);
ret = JsGetProperty(xnm, lengthName, &lengthValue);
int count;
JsNumberToInt(lengthValue, &count);

std::vector si;

for (int i = 0; i < count; i++)
{
JsValueRef index;
JsIntToNumber(i, &index);
JsValueRef IndexedProperty;
ret = JsGetIndexedProperty(xnm, index, &IndexedProperty);

JsValueRef itemref;
JsConvertValueToString(IndexedProperty, &itemref);

WCHAR* cb; UINT len;
JsStringToPointer(itemref, (const wchar_t**) &cb, &len);

si.push_back(cb);
}

for (int i = 0; i < count; i++)
{
JsValueRef index;
JsPointerToString(si[i].c_str(), si[i].length(), &index);

JsValueRef IndexedProperty;
JsGetIndexedProperty(jsobj, index, &IndexedProperty);

map[ si[i] ] = CJsValueRef(IndexedProperty);
}
}
return map;
}