Embedded Windows Scripting (VBScript & JScript) and COM
No temporary files. Full and easy access to COM.
Checkout the official homepage for the latest version, (old) demos, change log, and documentation:
<!-- m -->https://ahknet.autohotkey.com/~easycom<!-- m -->
Note: ws4ahk is made for Autohotkey Basic. It may work with Autohotkey_L, but it is not supported.
------------------------------------
This topic was split off from the old topic "EasyCOM.dll" development.
Original post content is below.
------------------------------------
I've been thinking long and hard about using Microsoft Scripting Control to provide easy COM usage to AHK, and the more I have, the more it became the ultimate choice--far better than anything I could develop myself.
Pros
* Automatic objct management (objects are automatically deallocated--no memory leaks!)
* Able to use either VBScript or JScript to write COM related code
* ByRef argument handling is all taken care of
* Almost all VARIANT handling is taken care of
* Can very easily write compound COM statements (e.g. objExcel.Workbooks.Add().Sheets(1).Cells(1,1).Value = 50)
* There's no need for an extra dll (like EasyCOM.dll). It can be done entirely in AHK.
* Much more easily implemented!
The ONLY disadvantage with using Microsoft Scripting Control is that there may be some computers that do not have it installed (but probably not very many). HOWEVER, not only is it available to download from Microsoft and very easily installed, but thanks to that WS_CreateObjectFromDll() function, it doesn't even have to be installed! If a computer doesn't have Microsoft Scripting Control installed, you just need to supply the msscript.ocx file in the same folder as your script, and it will still work perfectly. No need to register the OCX. Your script remains completely portable!
Once this is better tested and found to really work, I think you can agree that there is no reason to continue making the not-so-easy EasyCOM.dll anymore. This is by far a better solution.
Hmm... Have you tested with this DllGetClassObject?but thanks to that CreateObjectFromDll() function, it doesn't even have to be installed!
Actually MS discourages to call it directly. It's called always indirectly, through CoGetClassObject, probably the most important single function in COM.
Anyway, thanks for this very interesting idea, and I'm tempted to use with it CoLoadLibrary instead of LoadLibrary.
I've been working on using Microsoft Scripting Control for COM, and so far things seem to be ok. I'm not quite sure what to call it, so for now I've named it "EasyScript". The #Include file is looking to be a beefy 1000 lines. Right now the API looks something like this:
LoadEasyScript(Language) UnloadEasyScript() ES_Exec(VB or JS string) ; for no return value ES_Eval(VB or JS string) ; for return value ES_AddDispObject(IDispatchPtr) ES_AddObject(ClsId, Name) ES_AddObjectFromDll(ClsId, Name) VBStr(String) JSStr(String)
ES_AddObject() is useful for creating objects by ClassId, since you can't do that in VBScript/JScript. ES_AddObjectFromDll() is thrown in just because it's easy, but I can't imagine anyone actually using it. ES_AddDispObject() is useful for putting ActiveX controls under the care of VBScript/JScript (assuming that works).
VBStr() and JSStr() wrap strings in quote and escapes any quotes in the actual string.
Here's a short usage example
sFile := "C:\WINDOWS" ES_Exec("Set oFSO = CreateObject('Scripting.FileSystemObject')") IsFolder := ES_Eval( "oFSO.FolderExists(" VBStr(sFile) ")" ) ; IsFolder = 1 ES_Exec("Set ByRefObj = CreateObject('Object.With.Byref.Param')") ES_Exec("ByRefObj.ByRefMethod ", ByRefArg )
As you can see I'm using single quotes (') inside the strings. This isn't normally available in VBScript, but to make things easier I may try to allow for it. No guarantee it will end up in a final version.
ByRef arguments can be passed as variables between strings. After the call, the byref variable will be updated with the new value.
I still haven't looked into how to handle script errors.
All this may be too much encapsulation however. It may be better to just expose the Scripting Control methods and let the scripters write VBScript/JScript however they like.
I dunno, I'm still working on it. I'm curious what others think.
Also, It occurred to me that while this "EasyScript" API is handy for the COM basics, it still lacks support for creating ActiveX controls and handling COM Events. I haven't looked too closely at Sean's ActiveX control related scripts, so maybe those will be fine for handling that. I also haven't looked at COM event handling.
But I think those things are better suited for separate #Includes, and the separate APIs can be written to interface with each other.
In any case, I may have bitten off more than I can chew with all this COM stuff, so I'm going to have to pass on delving into COM Events, at least for now.
Yup, and it has worked flawlessly so far.Hmm... Have you tested with this DllGetClassObject?
Ah, you really are quite a COM master. I didn't even know about that function. I gave it a try, but it wasn't working in my tests. Have you had any luck using it?I'm tempted to use with it CoLoadLibrary instead of LoadLibrary.
Yes, I used it successfully to test DllGetClassObject which worked fine.I didn't even know about that function. I gave it a try, but it wasn't working in my tests. Have you had any luck using it?
One thing you might miss is that you have to use always Unicode string with it.
PS. BTW, no real need to use it. Looks like exactly the same behavior with LoadLibrary.
I think that I'd like to be able to use VBScript instructions internaly in AHK, especially those relative to COM, as I think that (for the moment), VBScript is more easy to use to have access to COM, with a well known syntax, than what I seen for the moment under AHK. But I'd like to be able to execute a full VBScript script (not line by line...) and to get back the result :!: :!: :!: Thanks to all those who work on COM integration in AHK for their work.I dunno, I'm still working on it. I'm curious what others think.
Ah yes, I missed the need for a Unicode path--that got it working, thanks.One thing you might miss is that you have to use always Unicode string with it.
Is it possible that the library is automatically unloaded when CoUninitialize() is called? It would be really nice if it was.PS. BTW, no real need to use it. Looks like exactly the same behavior with LoadLibrary.
Thanks for the feedback Dashboard. It does seem like this is the best approach.I think that I'd like to be able to use VBScript instructions internally in AHK, especially those relative to COM .... But I'd like to be able to execute a full VBScript script (not line by line...) and to get back the result
The functions haven't really changed, but their parameters have. Plus I thought that adding a simple 'printf' style syntax would make the code much easier to write (no need for lots of ugly double quotes and string concatenation).
vbwmp := "oWMP" If (!ES_Exec("Set %v = CreateObject(%s)", vbwmp, "WMPlayer.OCX")) Msgbox % ES_Error() If (!ES_Eval(pwmp, vbwmp)) Msgbox % ES_Error()%v inserts the value, and %s inserts the value wrapped in quotes, with special characters escaped.
ES_Eval() will return the value of most script variables. I don't think I'll implement getting return values for Dates and Currency variables, and especially not for Arrays (you should write a script function to convert the array to something you can use before returning it).
You can create an object in the script, put that same object into a COM control, and then control from the script.
DEdit := "DEdit" If (!ES_Exec("Set %v = CreateObject(%s)", DEdit, "DhtmlEdit.DhtmlEdit")) Msgbox % ES_Error() If (!ES_Eval(ppvDEdit, "DEdit")) Msgbox % ES_Error() hContainerCtrl := AtlAxCreateContainer(hWnd, 0, 25, 800, 575) AtlAxAttachControl(ppvDEdit, hContainerCtrl) DE_LoadUrl(DEdit, "http://www.autohotkey.com") DE_LoadUrl(sDhtmlEdit, url) { If (!ES_Exec("%v.LoadUrl %s", sDhtmlEdit, url)) Msgbox % ES_Error() }You could alternately create an object using one of the EasyScript's or Sean's create/get object functions, then pass the object into the script (via AddObject) to be controlled there.
You can always execute more than one line of code at a time.
DE_BrowseMode(sDHtmlEdit) { sCode = ( If `%v.Browsemode = 0 Then `%v.Browsemode = 1 Else `%v.Browsemode = 0 End If ) If (!ES_Exec(sCode, sDHtmlEdit, sDHtmlEdit, sDHtmlEdit)) Msgbox % ES_Error() }This allows you to add functions inside your script. Heck, you could even create classes inside the script, instantiate it, and return it for use in AHK. I haven't pondered just what this could mean. I wonder if it would help with COM event handling at all...?
But speaking of event handling: There is the VBScript GetRef() function which may be used to insert a script call-back function for objects that allow it. These are usually the "OnClick" kind of functions. From what I've seen, it's still limited to a subset of the available object events. There are many other events I can't get access to.
The code is currently working, but I'm still running tests.
I'm also pondering how this script and Sean's scripts should play together. EasyScript covers everything that his CoHelper.ahk does, but if you want to utilize COM controls then we'd need code from IEControl.ahk, which requires CoHelper.ahk...
So I'm thinking I should just include the core functions from IEControl.ahk in EasyScript. This will keep those functions available to script-writers. I hope no one minds if I rename some of them and maybe change their API a bit. My target script-writer is familiar with VB and has never seen Co* functions or Atl* functions, and my goal is that they never have to.
It is quite clear that EasyScript will be much larger than Sean's scripts, both in code size and memory usage. It will also be slower. BUT it will be easy (I hope). :)
Thanks!
I've been working on "EasyScript" this whole time. Seems like every time I look at the code, there are a dozen things I need to add/change/remove/improve. Even just this morning I made an improvement to the API.
The code has grown into a massive 1500 lines, although it is worth noting that a few hundred of those lines are for comments and error checking.
This script contains a ton of error checking and reporting. While it is really nice for development, not everyone may want to have that extra bulk in their released code. Plus, it seems like most are content with Sean's scripts which have no error checking. So I've designed the EasyScript code so the error checking is easily removed via a simple AHK script (not made yet).
Even so, nothing will ever be as lean and mean as Sean's scripts.
There's still a bunch of things I want to clean up in the script. I would like to make the error handling more consistent between the different parts. Plus there is still more error checking to be added. But the script is fully functional.
So here's the first version: v0.01 beta (21Jul2007) I hope the API doesn't change anymore, but no promises.
I didn't think "EasyScript" was such a good name for it. The most accurate might be "Embedded Microsoft Windows Scripting Host for Autohotkey", but that's just silly. I'm leaning toward "Windows Scripting for AHK", abbreviated as WS4AHK or simply WS. A possible alternative is "COMscript", which emphasis its ability to access COM. Anyone have any thoughts/preferences?
Download
Here is also an example script. It's a conversion of ABCYourWay's DHTML edit program to use this new WS4AHK script.
WS_DEControl.ahk
WS_DEdemo.ahk
When I get around to it, I'll post a fresh new forum topic and include a link to API documentation.
but not with WS4AHK
If you find time to have a look at, please correct my script.
Now I added(working function)
numbered list/bullet list
Font/fontname/fontsize
Justify(left, center, right)
FindText/Cut/Paste/Delete/SelectAll/redo/undo/view properties.
Functions left to implement are only table/cell/row functions.
Row/cell functions are esay to add, but I have a problem with a table function.
Thanks.
WS_DEControl.ahk
#Include ws4ahk.ahk ; designed for ws4ahk.ahk v0.01 ; Command IDs DECMD_BOLD = 5000 DECMD_COPY = 5002 DECMD_CUT = 5003 DECMD_DELETE = 5004 DECMD_DELETECELLS = 5005 DECMD_DELETECOLS = 5006 DECMD_DELETEROWS = 5007 DECMD_FINDTEXT = 5008 DECMD_FONT = 5009 DECMD_GETBACKCOLOR = 5010 DECMD_GETBLOCKFMT = 5011 DECMD_GETBLOCKFMTNAMES = 5012 DECMD_GETFONTNAME = 5013 DECMD_GETFONTSIZE = 5014 DECMD_GETFORECOLOR = 5015 DECMD_HYPERLINK = 5016 DECMD_IMAGE = 5017 DECMD_INDENT = 5018 DECMD_INSERTCELL = 5019 DECMD_INSERTCOL = 5020 DECMD_INSERTROW = 5021 DECMD_INSERTTABLE = 5022 DECMD_ITALIC = 5023 DECMD_JUSTIFYCENTER = 5024 DECMD_JUSTIFYLEFT = 5025 DECMD_JUSTIFYRIGHT = 5026 DECMD_LOCK_ELEMENT = 5027 DECMD_MAKE_ABSOLUTE = 5028 DECMD_MERGECELLS = 5029 DECMD_ORDERLIST = 5030 DECMD_OUTDENT = 5031 DECMD_PASTE = 5032 DECMD_REDO = 5033 DECMD_REMOVEFORMAT = 5034 DECMD_SELECTALL = 5035 DECMD_SEND_BACKWARD = 5036 DECMD_BRING_FORWARD = 5037 DECMD_SEND_BELOW_TEXT = 5038 DECMD_BRING_ABOVE_TEXT = 5039 DECMD_SEND_TO_BACK = 5040 DECMD_BRING_TO_FRONT = 5041 DECMD_SETBACKCOLOR = 5042 DECMD_SETBLOCKFMT = 5043 DECMD_SETFONTNAME = 5044 DECMD_SETFONTSIZE = 5045 DECMD_SETFORECOLOR = 5046 DECMD_SPLITCELL = 5047 DECMD_UNDERLINE = 5048 DECMD_UNDO = 5049 DECMD_UNLINK = 5050 DECMD_UNORDERLIST = 5051 DECMD_PROPERTIES = 5052 ; Enums ;OLECMDEXECOPT OLECMDEXECOPT_DODEFAULT = 0 OLECMDEXECOPT_PROMPTUSER = 1 OLECMDEXECOPT_DONTPROMPTUSER = 2 ; DHTMLEDITCMDF DECMDF_NOTSUPPORTED = 0 DECMDF_DISABLED = 1 DECMDF_ENABLED = 3 DECMDF_LATCHED = 7 DECMDF_NINCHED = 11 ; DHTMLEDITAPPEARANCE DEAPPEARANCE_FLAT = 0 DEAPPEARANCE_3D = 1 ; OLE_TRISTATE OLE_TRISTATE_UNCHECKED = 0 OLE_TRISTATE_CHECKED = 1 OLE_TRISTATE_GRAY = 2 ; Error Return Values ; DE_E_INVALIDARG = 0x5 DE_E_ACCESS_DENIED = 0x46 DE_E_PATH_NOT_FOUND = 0x80070003 DE_E_FILE_NOT_FOUND = 0x80070002 DE_E_UNEXPECTED = 0x8000ffff DE_E_DISK_FULL = 0x80070027 DE_E_NOTSUPPORTED = 0x80040100 DE_E_FILTER_FRAMESET = 0x80100001 DE_E_FILTER_SERVERSCRIPT = 0x80100002 DE_E_FILTER_MULTIPLETAGS = 0x80100004 DE_E_FILTER_SCRIPTLISTING = 0x80100008 DE_E_FILTER_SCRIPTLABEL = 0x80100010 DE_E_FILTER_SCRIPTTEXTAREA = 0x80100020 DE_E_FILTER_SCRIPTSELECT = 0x80100040 DE_E_URL_SYNTAX = 0x800401E4 DE_E_INVALID_URL = 0x800C0002 DE_E_NO_SESSION = 0x800C0003 DE_E_CANNOT_CONNECT = 0x800C0004 DE_E_RESOURCE_NOT_FOUND = 0x800C0005 DE_E_OBJECT_NOT_FOUND = 0x800C0006 DE_E_DATA_NOT_AVAILABLE = 0x800C0007 DE_E_DOWNLOAD_FAILURE = 0x800C0008 DE_E_AUTHENTICATION_REQUIRED = 0x800C0009 DE_E_NO_VALID_MEDIA = 0x800C000A DE_E_CONNECTION_TIMEOUT = 0x800C000B DE_E_INVALID_REQUEST = 0x800C000C DE_E_UNKNOWN_PROTOCOL = 0x800C000D DE_E_SECURITY_PROBLEM = 0x800C000E DE_E_CANNOT_LOAD_DATA = 0x800C000F DE_E_CANNOT_INSTANTIATE_OBJECT = 0x800C0010 DE_E_REDIRECT_FAILED = 0x800C0014 DE_E_REDIRECT_TO_DIR = 0x800C0015 DE_E_CANNOT_LOCK_REQUEST = 0x800C0016 ; ------------------------- General functions --------------------------------------------------------------- DE_Add(hWnd, x, y, w, h) { Return GetComControlInHWND( CreateComControlContainer(hWnd, x, y, w, h, "DhtmlEdit.DhtmlEdit") ) } DE_Move(pwb, x, y, w, h) { WinMove, % "ahk_id " . GetHWNDofComControl(pwb), , x, y, w, h } DE_BrowseMode(sDHtmlEdit) ; toggle between Edit mode and View mode. { sCode = ( If `%v.Browsemode = 0 Then `%v.Browsemode = 1 Else `%v.Browsemode = 0 End If ) If (!WS_Exec(sCode, sDHtmlEdit, sDHtmlEdit, sDHtmlEdit)) Msgbox % A_LineFile ":" ErrorLevel } DE_LoadUrl(sDhtmlEdit, url) ;Load url(e.g. "http://www.autohotkey.com") and ready to edit in a WYSIWIG way { If (!WS_Exec(sDhtmlEdit ".LoadUrl %s", url)) Msgbox % A_LineFile ":" ErrorLevel } DE_NewDocument(sDhtmlEdit) ;clear current document and open blank html document { If (!WS_Exec(sDhtmlEdit ".NewDocument")) Msgbox % A_LineFile ":" ErrorLevel } DE_LoadDocument(sDhtmlEdit, FileDir) ;open file dialog and last parameter is prompt string. { If (!WS_Exec(sDhtmlEdit ".LoadDocument", FileDir, prompt)) Msgbox % A_LineFile ":" ErrorLevel } DE_SaveDocument(sDhtmlEdit, Filedir) ;save contents in html. { If (!WS_Exec(sDhtmlEdit ".SaveDocument %s", FileDir)) Msgbox % A_LineFile ":" ErrorLevel } DE_GetDocumentHtml(sDhtmlEdit) ;get and return DOCUMENT'S htmlcode { If (!WS_Eval(sRet, sDhtmlEdit ".DocumentHtml")) Msgbox % A_LineFile ":" ErrorLevel Return sRet } DE_SetDocumentHtml(sDhtmlEdit, sHtml) ;set document's htmlcode { If (!WS_Exec(sDhtmlEdit ".DocumentHtml = %s", sHtml)) Msgbox % A_LineFile ":" ErrorLevel } DE_Refresh(sDhtmlEdit) ;open file dialog and last parameter is prompt string. { If (!WS_Exec(sDhtmlEdit ".Refresh")) Msgbox % A_LineFile ":" ErrorLevel } ; --- WYSIWYG Edit functions ---------------------------------------------------------------------------------------------- ; Set property --> use ExecCommand(), Command ID ; Get Propery --> use QueryStatus(), command ID DE_SetBOLD(sDhtmlEdit) ; toggle selections bold/normal { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_BOLD)) Msgbox % A_LineFile ":" ErrorLevel } DE_SetUnderline(sDhtmlEdit) ; toggle selections underline { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_UNDERLINE)) Msgbox % A_LineFile ":" ErrorLevel } DE_SetItalic(sDhtmlEdit) ; toggle selections italic { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_ITALIC)) Msgbox % A_LineFile ":" ErrorLevel } DE_SetForeColor(sDhtmlEdit, sColor) ; set font color string, e.g. "#55A0FF", "55A0FF", "Blue", "Red" { global If (!WS_Exec(sDhtmlEdit ".ExecCommand %v, %v, %s" , DECMD_SETFORECOLOR , OLECMDEXECOPT_DODEFAULT , sColor)) Msgbox % A_LineFile ":" ErrorLevel } DE_SetBackColor(sDhtmlEdit, sColor) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand %v, %v, %s" , DECMD_SETBACKCOLOR , OLECMDEXECOPT_DODEFAULT , sColor)) Msgbox % A_LineFile ":" ErrorLevel } DE_Font(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_FONT)) Msgbox % A_LineFile ":" ErrorLevel } DE_SetFontName(sDhtmlEdit, sFont) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand %v, %v, %s" , DECMD_SETFONTNAME , OLECMDEXECOPT_DODEFAULT , sFont)) Msgbox % A_LineFile ":" ErrorLevel } DE_SetFontSize(sDhtmlEdit, iFontSize) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand %v, %v, %s" , DECMD_SETFONTSIZE , OLECMDEXECOPT_DODEFAULT , iFontSize)) Msgbox % A_LineFile ":" ErrorLevel } DE_JustifyLeft(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_JUSTIFYLEFT)) Msgbox % A_LineFile ":" ErrorLevel } DE_JustifyCenter(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_JUSTIFYCENTER)) Msgbox % A_LineFile ":" ErrorLevel } DE_JustifyRight(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_JUSTIFYRIGHT)) Msgbox % A_LineFile ":" ErrorLevel } DE_SetHyperLink(sDhtmlEdit) ; insert hyperlink property in selection { global If (!WS_Exec(sDhtmlEdit ".ExecCommand %v, %v, %s" , DECMD_HYPERLINK , OLECMDEXECOPT_DODEFAULT , "")) Msgbox % A_LineFile ":" ErrorLevel } DE_SetImage(sDhtmlEdit) ; insert image in selection { global If (!WS_Exec(sDhtmlEdit ".ExecCommand %v, %v, %s" , DECMD_IMAGE , OLECMDEXECOPT_DODEFAULT , "")) Msgbox % A_LineFile ":" ErrorLevel } DE_UnLink(sDhtmlEdit) ; insert image in selection { global If (!WS_Exec(sDhtmlEdit ".ExecCommand %v, %v, %s" , DECMD_UNLINK , OLECMDEXECOPT_DODEFAULT , "")) Msgbox % A_LineFile ":" ErrorLevel } DE_SelectAll(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_SELECTALL)) Msgbox % A_LineFile ":" ErrorLevel } DE_Paste(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand %v, %v" , DECMD_HYPERLINK , OLECMDEXECOPT_DODEFAULT)) Msgbox % A_LineFile ":" ErrorLevel } DE_Properties(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_PROPERTIES)) Msgbox % A_LineFile ":" ErrorLevel } DE_UnDo(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_UNDO)) Msgbox % A_LineFile ":" ErrorLevel } DE_ReDo(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_REDO)) Msgbox % A_LineFile ":" ErrorLevel } DE_FindText(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_FINDTEXT)) Msgbox % A_LineFile ":" ErrorLevel } DE_Delete(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_DELETE)) Msgbox % A_LineFile ":" ErrorLevel } DE_Cut(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_CUT)) Msgbox % A_LineFile ":" ErrorLevel } DE_COPY(pDHtmlEdit) ; { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_COPY)) Msgbox % A_LineFile ":" ErrorLevel } ; ------- LIST AND TABLE FUNCTIONS DE_OrderList(pDHtmlEdit) ; NUMBERED LIST { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_ORDERLIST)) Msgbox % A_LineFile ":" ErrorLevel } DE_UnorderList(pDHtmlEdit) ; BULLET LIST { global If (!WS_Exec(sDhtmlEdit ".ExecCommand " DECMD_UNORDERLIST)) Msgbox % A_LineFile ":" ErrorLevel } ;DE_InsertTable(numrows, numcols, TableAttr = "100%", CellAttr = "" , Caption = "") ; DE_InsertTable(numrows, numcols) --> I don't know what's the problem here ; { ; WS_Exec("Set %v = CreateObject(%s)", tParam, "DEInsertTableParam.DEInsertTableParam") ; ; create a table object ; WS_Exec("tParam.NumRows = %v", numrows) -> set the table property. ; WS_Exec("tParam.NumCols = %v", numcols) ; return ; ;WS_Exec("Set tParam.TableAttrs = 100%") ; ; global DECMD_INSERTTABLE, OLECMDEXECOPT_DODEFAULT ; If (!WS_Exec(sDhtmlEdit ".ExecCommand %v, %v, %s" ; , DECMD_INSERTTABLE ; , OLECMDEXECOPT_DODEFAULT ; , tParam)) ; Msgbox % A_LineFile ":" ErrorLevel ; ; } ; } ; --------- USING DOM ------------------------------------------------------------------------------------------ DE_DOM(sDHtmlEdit) { iret := WS_Exec("Set DHTMLDOM = %v.DOM", sDHtmlEdit) return "DHTMLDOM" } ; GetSelection(pDhtmlEdit) --> I don't know what's the problem. I can do it with easycom.ahk but not with ws4ahk ; { ; WS_Exec("Set SelType = %v.DOM.%s.%s", pDhtmlEdit, "selection", "type")) ; if seltype = text ; { ; WS_Exec("Set SelectedText = %v.DOM.%s.%s.%s.%s", ; pDhtmlEdit, ; "selection", ; "CreateRange()", ; "htmltext")) ; return SelectedText ; } ; }
WS_DEDemo
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. SendMode Input ; Recommended for new scripts due to its superior speed and reliability. SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. #include WS_DEControl.ahk If (!WS_Initialize("VBScript")) { Msgbox % "Error initializing EasyScript" ExitApp } InitComControls() Gui, +Resize +LastFound +theme Gui, Add, Button, x0 y0 gSetBold, Bold Gui, Add, Button, xp+40 gSetItalic,italic Gui, Add, Button, xp+50 gSetUnderLine, underline gui, Add, Button, xp+75 gSetBlue, Blue Gui, Add, Button, xp+40 gSetImageLink, Image Gui, Add, Button, xp+50 gSetHyperLink, Link Gui, Add, Button, xp+50 gLoadUrl, LoadURL Gui, Add, Button, xp+70 gGetDocument, GetHtml gui, add, button, xp+70 gSetDocument, SetHtml Gui, Add, button, xp+70 gSaveDocument, SaveHtml Gui, Add, button, xp+80 gBrowseMode, BrowseMode Toggle Gui, add, button, xp+140 gNewDocument, New Gui, add, button, xp+40 gFindText, FindText Gui, add, button, xp+70 gSetBackColor, SetBackColor Gui, add, button, x0 yp+25 gSetFontName, SetFontName Gui, add, button, xp+90 gSetFontSize, SetFontSize Gui, add, button, xp+90 gSetFont, SetFont Gui, add, button, xp+50 gList1, List1 Gui, add, button, xp+50 gList2, List2 gui, Add, Button, xp+50 gInsertTable, InsertTable Gui, Show, w800 h600 Center, DhtmlEdit_Test hWnd := WinExist() DEdit := "DEdit" ; Method #1 ppvDEdit := DE_Add(hWnd, 0, 50, 800, 550) WS_AddObject(ppvDEdit, DEdit) ; Method #2 ; If (!WS_Exec("Set %v = CreateObject(%s)", DEdit, "DhtmlEdit.DhtmlEdit")) ; Msgbox % ErrorLevel ; If (!WS_Eval(ppvDEdit, DEdit)) ; Msgbox % ErrorLevel ; ; hContainerCtrl := CreateComControlContainer(hWnd, 0, 25, 800, 575) ; AttachComControlToHWND(ppvDEdit, hContainerCtrl) Gosub, SetDocument Return ; end of auto-run 1:: ;msgbox, % GetSelection(Dedit) return SetBold: ;iret := Invoke(DEdit, "ExecCommand()", DECMD_BOLD) DE_SetBold(DEdit) Return SetItalic: ;iret := Invoke(DEdit, "ExecCommand()", DECMD_ITALIC) DE_SetItalic(DEdit) Return SetBlue: ;iret := Invoke(DEdit, "ExecCommand()", DECMD_SETFORECOLOR, OLECMDEXECOPT_DODEFAULT, "Blue") ;DE_SetForeColor(DEdit, "0000FF") DE_SetForeColor(DEdit, "Blue") ; possible way ;DE_SetForeColor(pDHtmlEdit, "#0000FF") ; also possible Return SetUnderline: ;iret := Invoke(DEdit, "ExecCommand()", DECMD_UNDERLINE) DE_SetUnderline(DEdit) Return SetImageLink: ;iret := Invoke(DEdit, "ExecCommand()", DECMD_IMAGE, OLECMDEXECOPT_DODEFAULT, "") DE_SetImage(DEdit) Return SetHyperLink: ;iret := Invoke(DEdit, "ExecCommand()", DECMD_HYPERLINK, OLECMDEXECOPT_DODEFAULT, "") DE_SetHyperLink(DEdit) Return LoadUrl: url := "http://www.autohotkey.com" DE_LoadUrl(DEdit, url) Return NewDocument: DE_NewDocument(DEdit) Return SaveDocument: Filedir = %A_ScriptDir%\DhtmlEdit_%A_Now%.htm DE_SaveDocument(DEdit, FileDir) Return GetDocument: msgbox, % DE_GetDocumentHtml(DEdit) Return SetDocument: htmlcode = ( <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"> <title></title> </head> <body style="COLOR: rgb(0,0,0); BACKGROUND-COLOR: rgb(255,204,51)" alink ="#ee0000" link="#0000ee" vlink="#551a8b"> <P> <big style="FONT-FAMILY: Verdana"><big><EM><STRONG>Forgive</STRONG></EM> my <span style="FONT-WEIGHT: bold; COLOR: rgb(51,51,255)" >poor</span> coding style! Yes? </big></big></P> <P><BIG style="FONT-FAMILY: Verdana"><BIG>This File is Edited with <STRONG>DhtmlEdit_Demo</STRONG> . </P></BIG></BIG> <ul style="FONT-FAMILY: Verdana"> <li><STRONG><U>First List</U></STRONG> <li><FONT color=blue>second List</FONT> <li><A href="http://www.autohotkey.com">what now?(</A>click then go to AutohotKey)</li> </ul> <table style="WIDTH: 440px; FONT-FAMILY: Verdana; HEIGHT: 52px; TEXT-ALIGN: left" border="1" cellpadding="2" cellspacing="2"> <tbody> <tr> <td>This is a table and the right image is directly from AutoHotKey Forum.</td> <td><A href="http://www.autohotkey.com"><img style="WIDTH: 228px; HEIGHT: 133px" alt="image cannot be loaed for some reason" src="http://www.autohotkey.com/docs/images/AutoHotkey_logo.gif"></A></td> </tr> </tbody> </table> </body> </html> ) DE_SetDocumentHtml(DEdit, htmlcode) htmlcode = Return BrowseMode: DE_BrowseMode(DEdit) Return FindText: DE_FindText(DEdit) Return SetBackColor: DE_SetBackColor(DEdit, "Yellow") Return SetFontName: DE_SetFontName(DEdit, "Arial Black") Return SetFontSize: DE_SetFontSize(DEdit, "4") Return SetFont: DE_Font(DEdit) Return List1: DE_OrderList(DEdit) Return List2: DE_UnOrderList(DEdit) Return InsertTable: DE_InsertTable(2,2) return GuiSize: DE_Move(ppvDEdit, 0, 50, A_GuiWidth, A_GuiHeight-50) Return GuiClose: Gui, %A_Gui%:Destroy ReleaseObject(ppvDEdit) UninitComControls() WS_Uninitialize() ExitApp
There are a few things you need to correct.
DE_JustifyLeft([color=red]s[/color]DHtmlEdit) ;
DE_JustifyCenter([color=red]s[/color]DHtmlEdit) ;
DE_JustifyRight([color=red]s[/color]DHtmlEdit) ;This same correction needs to be made on these functions as well.
DE_SelectAll
DE_Paste
DE_Properties
DE_UnDo
DE_ReDo
DE_FindText
DE_Delete
DE_Cut
DE_COPY
DE_OrderList
DE_UnorderList
I renamed the variable from pDHtmlEdit to sDHtmlEdit because you need to pass in the name of the object in the scripting environment (which is a string).
DE_InsertTable([color=red]sDhtmlEdit,[/color] numrows, numcols) { [color=red]If (![/color]WS_Exec("Set [color=red]tParam[/color] = CreateObject(%s)", "DEInsertTableParam.DEInsertTableParam")[color=red])[/color] [color=red]Msgbox % A_LineFile ":" ErrorLevel[/color] ; create a table object [color=red]If (![/color]WS_Exec("tParam.NumRows = %v", numrows)[color=red])[/color] ; -> set the table property. [color=red]Msgbox % A_LineFile ":" ErrorLevel[/color] [color=red]If (![/color]WS_Exec("tParam.NumCols = %v", numcols)[color=red])[/color] [color=red]Msgbox % A_LineFile ":" ErrorLevel[/color] ;WS_Exec("Set tParam.TableAttrs = 100%") global DECMD_INSERTTABLE, OLECMDEXECOPT_DODEFAULT If (!WS_Exec(sDhtmlEdit ".ExecCommand %v, %v, [color=red]tParam[/color]" , DECMD_INSERTTABLE , OLECMDEXECOPT_DODEFAULT)) Msgbox % A_LineFile ":" ErrorLevel }
In the GetSelection() function, you seem to be mixing AHK and scripting code, and using %s when you should be using %v. It might be easiest to just change all that code into scripting code. I'll post a fixed function later when I have time.
Since this WS version of the script is a translation from your original code, I kept most of the code structure the same. However, since there is only one DHtml edit control, much of the code could be simplified by removing the sDhtmlEdit variable and just refer to the object's name directly in the scripting code. I'll post a rewrite later for an example.
GetSelection(sDHtmlEdit) { sVBCode = ( SelType = `%v.DOM.Selection.Type If SelType = "Text" Then SelectedText = `%v.DOM.Selection.CreateRange().HtmlText Else SelectedText = "" End If ) ; Execute the VB code If (!WS_Exec(sVBCode, sDHtmlEdit, sDHtmlEdit)) Msgbox % A_LineFile ":" ErrorLevel ; The variable "SelectedText" in the scripting environment holds the ; selected text. This gets the value out of the scripting environment. If (!WS_Eval(SelectedText, "SelectedText")) Msgbox % A_LineFile ":" ErrorLevel Return SelectedText }If you include this, your script should fully work.
I've updated ws4ahk.ahk to fix the bug (now v0.02). See the new very unglamorous site.
I also uploaded new variations of WS_DEControl2.ahk and WS_DEDemo2.ahk that removes the need to pass the object name into every function.
I've reviewed your code and tried the demo. It's all very impressive, and it's obvious you put a lot of thought into the interface. Also, it's great that you included clear, concise documentation at the top of the file.I've been working on "EasyScript" this whole time.
All the candidates have some appeal, but I think I prefer "Windows Scripting for AHK" for its greater accuracy. Another idea is "Windows Scripting and COM (WS+COM)" because the "for AHK" part might not add much value in the contexts it's likely to be mentioned in.I didn't think "EasyScript" was such a good name for it. The most accurate might be "Embedded Microsoft Windows Scripting Host for Autohotkey", but that's just silly. I'm leaning toward "Windows Scripting for AHK", abbreviated as WS4AHK or simply WS. A possible alternative is "COMscript", which emphasis its ability to access COM. Anyone have any thoughts/preferences?
Once you decide on a name, feel free to rename your homepage from ~easycom to the new name (unless it's too much trouble). I can update the links throughout the forum.
Since I still know so little about COM, I'd like to rely on you and Sean for the following (to the extent you have time):Even so, nothing will ever be as lean and mean as Sean's scripts.
1) Can/should COM Helper be merged into this Windows Scripting API in a way that gives the best of both worlds? (Maybe that would cause too many compromises.)
2) I realize that you intend to improve the API and documentation (as time permits). When you're ready, perhaps you or someone else can update the following wiki page (and/or make a new page):
<!-- m -->https://ahknet.autoh...m/~easycom/<!-- m -->)
In an effort to bring more attention to the homepage above, I've linked to it from a couple of old COM/OLE topics. At some point, I'll also add some links to it from the AHK docs (e.g. DllCall).See the new very unglamorous site.
Finally, it might be helpful to put a link on <!-- m -->http://www.autohotke...c21674.html<!-- m --> (i.e. this topic) so that people have a way to contact you and leave feedback.
Thanks for spending all this time to provide this often-requested capability!
Thanks by advance.
I haven't digested your code completely (and there's quite a good chance that I'll understand only a fraction of it :oops:)
My current point of view is (unfortunately) a plain user pespective, therefore my highest priority is the usability in regards of a quite simple to adopt command set. What I remember from the past is a 'embed VB'-syntax used within MacroScheduler (a Shareware).
It looks quite simple, isn't it?
//Put this VBSTART..VBEND block at top of script to declare the functions once
VBSTART
Dim xlApp
Dim xlBook
'Opens the Excel file in Excel
Sub OpenExcelFile(filename)
Set xlApp = CreateObject("Excel.Application")
xlApp.visible = true
Set xlBook = xlApp.Workbooks.open(filename)
end sub
'Use this to close Excel later
Sub CloseExcel
xlApp.quit
Set xlApp = Nothing
End Sub
'Retrieves a cell value from the specified worksheet
Function GetCell(Sheet,Row,Column)
Dim xlSheet
Set xlSheet = xlBook.Worksheets(Sheet)
GetCell = xlSheet.Cells(Row, Column).Value
End Function
'Sets specified cell of specified worksheet
Function SetCell(Sheet,Row,Column,NewValue)
Dim xlSheet
Set xlSheet = xlBook.Worksheets(Sheet)
xlSheet.Cells(Row,Column).Value = NewValue
End Function
VBEND
//Do the business
VBRun>OpenExcelFile,%SCRIPT_DIR%example.xls
VBEval>GetCell("Sheet1",5,4),theValue
MessageModal>Cell value: %thevalue%
VBEval>SetCell("Sheet1",28,2,998),nul
//VBRun>CloseExcel
@ Boo
its about Excel 8)
I thought about to (slightly) improve the GUI of WS_DEDemo2.ahk.
Well, desperately waiting for your sign off
Gui, +Resize +LastFound +theme Gui, Add, Button, x0 y2 w110 h22 gSetBold, Bold Gui, Add, Button, xp+111 yp wp hp gSetItalic,italic Gui, Add, Button, xp+111 yp wp hp gSetUnderLine, underline gui, Add, Button, xp+111 yp wp hp gSetBlue, Blue Gui, Add, Button, xp+111 yp wp hp gSetImageLink, Image Gui, Add, Button, xp+111 yp wp hp gSetHyperLink, Link Gui, Add, Button, xp+111 yp wp hp gLoadUrl, LoadURL Gui, Add, Button, x0 yp+23 wp hp gGetDocument, GetHtml gui, add, button, xp+111 yp wp hp gSetDocument, SetHtml Gui, Add, button, xp+111 yp wp hp gSaveDocument, SaveHtml Gui, Add, button, xp+111 yp wp hp gBrowseMode, BrowseMode Toggle Gui, add, button, xp+111 yp wp hp gNewDocument, New Gui, add, button, xp+111 yp wp hp gFindText, FindText Gui, add, button, xp+111 yp wp hp gSetBackColor, SetBackColor Gui, add, button, x0 yp+23 wp hp gSetFontName, SetFontName Gui, add, button, xp+111 yp wp hp gSetFontSize, SetFontSize Gui, add, button, xp+111 yp wp hp gSetFont, SetFont Gui, add, button, xp+111 yp wp hp gList1, List1 Gui, add, button, xp+111 yp wp hp gList2, List2 gui, Add, Button, xp+111 yp wp hp gInsertTable, InsertTable ShowW = 776 ShowH = 600 Gui, Show, % "w" ShowW " h" ShowH Center, DhtmlEdit_Test hWnd := WinExist() ; Create the COM control ppvDEdit := DE_Add(hWnd, 0, 72, ShowW-1, ShowH-72) . . . GuiSize: DE_Move(ppvDEdit, 0, 72, A_GuiWidth, A_GuiHeight-72) Return