简体   繁体   中英

In Windows Excel VBA, writing JSON to a 2d variant array

Answering my own question here. It is possible to call into JavaScript running in the Microsoft Script Control and return some JSON data structure. Whilst it is possible to parse the JSON with the Evaluate method of the script control, sometimes one wants to write to a two dimensional (2d) variant array which can then be pasted directly to a sheet or return in a user defined function. This bumps up against marshalling of data structures.

One cannot pass a 2d variant array into a JavaScript function, write to it and then pass it back. [If you have proof that is untrue please post]. So this code fails

'Tools->References->
'Microsoft Script Control 1.0;  {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}; C:\Windows\SysWOW64\msscript.ocx

Private Sub TestJSONtoOleVariantGridFails1()

    Dim oScriptEngine As ScriptControl
    Set oScriptEngine = New ScriptControl
    oScriptEngine.Language = "JScript"

    oScriptEngine.AddCode "function WriteResults1(vGrid) { vGrid(0,0)=1.2;vGrid(0,1)='red';vGrid(1,0)=true;vGrid(1,1)=null; return vGrid;};"

    ReDim vGridBefore(0 To 1, 0 To 1)
    Dim vGridAfter
    vGridAfter = oScriptEngine.Run("WriteResults1", vGridBefore) '<---- FAILS with error "Cannot assign to a function result"

    Debug.Assert vGridAfter(0, 0) = 1.2
    Debug.Assert vGridAfter(0, 1) = "red"
    Debug.Assert vGridAfter(1, 0) = True
    Debug.Assert IsNull(vGridAfter(1, 1))


End Sub

So this begs the question how best to populate a 2d variant array?

I have a solution which I'm posting but I'd be fascinated to know if someone else has figured out the marshalling between JSON and 2d variant arrays.

Here is my solution which works by creating a class to wrap the 2d variant array and then passing in a reference to the class. This is like "boxing".

'Tools->References->
'Microsoft Script Control 1.0;  {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}; C:\Windows\SysWOW64\msscript.ocx

Private Sub TestJSONtoOleVariantGridSucceeds()

    Dim oScriptEngine As ScriptControl
    Set oScriptEngine = New ScriptControl
    oScriptEngine.Language = "JScript"

    oScriptEngine.AddCode "function WriteResults(oGrid) { oGrid.Redimension(2,2); oGrid.Cell(0,0)=1.2;oGrid.Cell(0,1)='red';oGrid.Cell(1,0)=true;oGrid.Cell(1,1)=null;};"

    Dim oGrid As JSONOLEVariant
    Set oGrid = New JSONOLEVariant

    Call oScriptEngine.Run("WriteResults", oGrid)

    Dim vGrid As Variant
    vGrid = oGrid.ExportGridData

    Debug.Assert vGrid(0, 0) = 1.2
    Debug.Assert vGrid(0, 1) = "red"
    Debug.Assert vGrid(1, 0) = True
    Debug.Assert IsNull(vGrid(1, 1))



End Sub

and the class code JSONOLEVariant.cls

Option Explicit
Option Base 0

Private mvGridData As Variant

Public Function ExportGridData()
    ExportGridData = mvGridData
End Function

Public Sub Redimension(ByVal lRows As Long, ByVal lColumns As Long)
    ReDim mvGridData(0 To lRows - 1, 0 To lColumns - 1) 'Zero base
End Sub

Public Property Let Cell(ByVal lRow As Long, ByVal lColumn As Long, ByVal vNewValue As Variant)
    mvGridData(lRow, lColumn) = vNewValue
End Property

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM