ScriptBasic COM IntegrationAuthor: Dave Date: 06.14.14 - 10:35am This is part 3 of the ScriptBasic series. You can download a copy to play with here: Source & Binaries So i have been tinkering with it for the last 3 weekends. All of the major hurtles have been cleared.
Debug UI showing active debugging The rest of this post is mostly on the COM integration. This adds very powerful capabilities without much code. The design i went for uses CreateObject and CallByName which are both familiar to vb6 developers. declare sub CreateObject alias "CreateObject" lib "sb_engine.dll" declare sub CallByName alias "CallByName" lib "sb_engine.dll" declare sub ReleaseObject alias "ReleaseObject" lib "sb_engine.dll" const VbLet = 4 const VbMethod = 1 'you can load objects either by ProgID or CLSID obj = CreateObject("SAPI.SpVoice") if obj = 0 then print "CreateObject failed! " else CallByName(obj, "rate", VbLet, 2) CallByName(obj, "volume", VbLet, 60) CallByName(obj, "speak", VbMethod, "This is my test") ReleaseObject(obj) print "Release called obj reference is now: ", obj, " " end if Next came the problem of how to give scripts access to the host applications objects. ScriptBasic does not have any easy implementation for this. I spent hours looking through the source trying to see how to add symbols to the GlobalVariables table. The easy answer however was not to have the host set global variables at runtime, but instead to let the script query the host application for the values it needs. The resolver idea I had before worked perfectly for this and I cooked up a new extension method. declare sub GetHostObject alias "GetHostObject" lib "sb_engine.dll" declare sub GetHostString alias "GetHostString" lib "sb_engine.dll" obj = GetHostObject("Form1") if obj = 0 then print "GetHostObject failed! Make sure host called AddObject " else CallByName(obj, "caption", VbLet, "this is my form caption!") CallByName(obj, "Alert", VbMethod, "This is my test") end if print "GetHostString(test)=", GetHostString("test") The VB6 host then implements a method AddObject, AddString that allow the extension to look up these live object pointers at runtime through a callback to a resolver. Once you have the objptr (which is just a long value), CallByName can operate freely and access the objects arbitrarily. (because all VB6 form and class objects are COM objects under the hood which already support IDispatch scripting interfaces. In just a couple lines of code, integration with the host app just became seamless and now requires no extra work marshalling data between the native script host and the embedded intrepreter. Pretty slick! The next question that comes up, is how do you deal with complex statements that access multiple objects when using CallByName. Lets look at an Excel example: 'vbscript: Set ExcelWorkbook = ExcelApp.Workbooks.Add 'translates to oWorkBook = CallByName(oExcelApp, "Workbooks", vbGet) oExcelWorkbook = CallByName(oWorkBook, "Add") 'vbscript: ExcelSheet.Cells(i, j).Value = "test" 'translates to oCell = CallByName(oExcelSheet, "Cells", vbGet, i, j) CallByName(oCell, "Value", vbLet, "test") Its tested and works fine, but slightly bulky. Next experiment is going to be a statement parser that automates these steps. Comments: (0) |
About Me More Blogs Main Site |