I'm trying add a point in currently opened Autocad drawning. As reference I'm using VBA example from AddPoint manual:
VBA:
RetVal = object.AddPoint(Point)
object
Type: Block, ModelSpace, PaperSpace
The objects this method applies to.
Point
Access: Input-only
Type: Variant (three-element array of doubles)
The coordinates of the point to be created.
Sub Example_AddPoint()
' This example creates a point in model space.
Dim pointObj As AcadPoint
Dim location(0 To 2) As Double
' Define the location of the point
location(0) = 5#: location(1) = 5#: location(2) = 0#
' Create the point
Set pointObj = ThisDrawing.ModelSpace.AddPoint(location)
ZoomAll
End Sub
So far I'm successfully connected to ActiveX object and can get/set many things with it (as long as it requires a string input), except I can't figure out how create a
Variant (three-element array of doubles)
required for AddPoint function
Here is autoit code I'm playing with:
Local $location[3] = [5.0,5.0,0.0]
Local $oAcad = ObjGet("","AutoCAD.Application")
$oAcad.ActiveDocument.Modelspace.AddPoint($location)
It returns error:
"1.au3" (3) : ==> The requested action with this object has failed.:
$oAcad.ActiveDocument.Modelspace.AddPoint($location)
$oAcad.ActiveDocument.Modelspace^ ERROR
There is no details about error even with error handler, so I assume datatype of $location variable is wrong.
Related
I'm currently trying to connect a Lua Script with a GS WebApp. The connection is working but due to my lack of knowledge in GScripting I'm not sure why it isn't saving my data correctly.
In the Lua side I'm just passing in a hard-code a random name and simple numerical userid.
local HttpService = game:GetService("HttpService")
local scriptID = scriptlink
local WebApp
local function updateSpreadSheet ()
local playerData = (scriptID .. "?userid=123&name:Jhon Smith")
WebApp = HttpService:GetAsync(playerData)
end
do
updateSpreadSheet()
end
On the Google Script side i'm only saving the data on the last row and then add the value of the userid and the name.
function doGet(e) {
console.log(e)
// console.log(f)
callName(e.parameter.userid,e.parameter.name);
}
function callName(userid,name) {
// Get the last Row and add the name provided
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(sheet.getLastRow() + 1,1).setValues([userid],[name]);
}
However, the only data the script is saving is the name, bypassing the the userid for reasons I have yet to discover.
setValues() requires a 2D array and range dimensions should correspond to that array. The script is only getting 1 x 1 range and setValues argument is not a 2D array. Fix the syntax or use appendRow
sheet.getRange(sheet.getLastRow() + 1,1,1,2).setValues([[userid,name]]);
//or
sheet.appendRow([userid,name])
References:
appendRow
I have a need to crawl a set of data of indeterminate size and build a table key/value index of it. Since I don't know the dimensions in advance, seems I have to use a recursive function. My Lua skills are very new and superficial. I'm having difficulty understanding how to deal with returning a table from the function call.
Note this is for a Lua 5.1 script processor
API = function(tbl)
local table_api = {}
-- do stuff here with target data and add to table_api
table_api["key"] = value
-- then later there is a need to recurse deeper into target data
table_api["lower"] = API(var)
return table_api
end
result = API(source_data)
In most every other language I know there would be some way to make the recurse line table_api["lower"] = API(var) work but since Lua does table variables by reference, my return sub-table just keeps getting overwritten and my result is a tiny last bit of what it should be.
Just for background on my purpose: there's a commercial application I'm working with that has a weakly documented Lua scripting interface. It's running Lua 5.1 and the API is not well documented and frequently updated. As I understand it, everything is stored in _G, so I wanted to write something to reverse engineer the API. I have a working recursive function (not shown here) that enumerates all of _G. For that return value, it just builds up an annotated string and progressively builds on the string. That all works fine and is really useful, but it shows much more that the API interface; all the actual data elements are included, so I have to sift through like 30,000 records to determine an API set of about 500 terms. In order to determine the API, I am trying to use this sub-table return value recursive function being discussed in this question. The code I'm showing here is just a small distilled subset of the larger function.
I'll go ahead and include the full code here. I was hoping to incrementally build a large'ish table of each API level, any sublevels, and finally whatever keys used at the lowest level.
In the end, I was expecting to have a table that I could address like this:
result["api"]["label"]["api"]["sublabel"]["value"]["valuename"]
Full code:
tableAPIShow = function(tbl, table_track)
table_track = table_track or {}
local table_api = {}
if type(tbl) == 'table' then
-- Check if values are tables.
local parent_table_flag = true
for ind,val in pairs(tbl) do
if type(val) ~= 'table' then
parent_table_flag = false
break
end
end
-- If all children are table type, check each of them for subordinate commonality
local api_flag = false
if parent_table_flag == true then
local child_table = {}
local child_table_flag = false
api_flag = true
for ind,val in pairs(tbl) do
-- For each child table, store the names of the indexes.
for sub_ind,sub_val in pairs(val) do
if child_table_flag == false then -- First time though, create starting template view of typical child table.
child_table[sub_ind] = true -- Store the indexes as a template table.
elseif child_table[sub_ind] == nil then -- Otherwise, test this child table compared to the reference template.
api_flag = false
break
end
end
if api_flag == false then -- need to break out of nested loop
break
end
child_table_flag = true
end
end
if api_flag == true then
-- If everything gets to here, then this level is an API with matching child tables below.
for ind,val in pairs(tbl) do
if table_api["api"] == nil then
table_api["api"] = {}
end
table_api["api"][ind] = tableAPIShow(val, table_track)
end
else
-- This level is not an API level, determine how to process otherwise.
for ind,val in pairs(tbl) do
if type(val) == 'table' then
if table_track[val] ~= nil then -- Have we already recursed this table?
else
table_track[val] = true
if table_api["table"] == nil then
table_api["table"] = {}
end
table_api["table"][ind] = tableAPIShow(val, table_track)
end
else -- The children are not tables, they are values
if table_api["value"] == nil then
table_api["value"] = {}
end
table_api["value"][ind] = val
end
end
end
else
-- It's not a table, just return it.
-- Probably never use this portion because it's caught on upper level recurse and not called
return tbl
end
return table_api
end
And I was calling this function in the main script like this:
local str = tableAPIShow(_G)
I've got another function that recursively shows a table so I can look inside my results and see I only get a return value that contains only the values of the top-level of _G (I have it excluded built-in Lua functions/values because I'm only interested in the Application API):
{
[value] = table: 00000000F22CB700 {
[value][_VERSION] = Application/5.8.1 (x86_64; Windows NT 10.0.16299),
[value][tableAPIShow] = "function: 00000000F22C6DE0, defined in (121-231) C:\\Users\\user\\AppData\\Local\\Temp\\APP\\/~mis00002690 ",
[value][_FINAL_VERSION] = true,
[value][Path] = ./Scripts/Database/elements/,
[value][class] = "function: 00000000F1953C40, defined in (68-81) Scripts/Common/Class.lua ",
[value][db_path] = ./Scripts/Database/,
[value][merge_all_units] = "function: 00000000F20D20C8, defined in (2242-2250) Scripts/Database/db_merge.lua ",
}
You just need to localize the variable you store your table in and it will work as you expect:
local table_api = {}
(note that you are passing table variable that conflicts with the global table variable and is not currently used in the function.)
I am inclined to believe that your tableAPIShow function code is working correctly and the
another function that recursively shows a table
fails to serialize your table fully. Hence you don't see the deeper levels of the table returned by tableAPIShow().
I got your initial and current code (tableAPIShow) to work with my simple table serialize function: the whole _Global table is exported completely and formatted as you implemented it in your tableAPIShow().
Code for testing:
apiMassiveTable = {
api = {
get = {
profile = {"profileID", "format"},
name = {"profileID", "encoding"},
number = {"profileID", "binary"}
},
set = {
name = {"apikey", "profileID", "encoding", "newname"},
number = {"apikey", "profileID", "binary", "newnumber"}
},
retrieve = {}
},
metadata = {version="1.4.2", build="nightly"}
}
-- tableAPIShow implemenation here
table.serialize = dofile("serialize.lua")
print(table.serialize("myNameForAHugeTable", tableAPIShow(_G)))
PS: Whatever serialize function you're using, it should enquote strings like Application/5.8.1 (x86_64; Windows NT 10.0.16299) which it does not.
Like #Paul Kulchenko said, you need to learn to use locals (https://www.lua.org/pil/4.2.html). Global variable post-exist until a new lua_State is loaded (a new environment, could be a new process depending on what interpreter you are using). So a tip is to always use local variables for anything you don't want to leave the function or leave the compilation unit.
Think of tables like dictionaries: a word is attached to a definition. Thusly the definition is the data.
What I think you are trying to do is serialization of a table of data. However, that isn't really necessary. You can either shadow copy or deep copy the given table. A shadow copy is when you don't delve into the depths of tables found in the keys, etc. A deep copy is when you copy tables in keys of tables in keys of tables... etc.
local shallow_copy = function(tab)
local rep_tab = {}
for index, value in pairs(tab)do
rep_tab[index] = value
end
return rep_tab
end
-- because local variable is not defined or declared immediately on a 1-liner,
-- a declaration has to exist so that deep_copy can be used
-- lets metatable execute functions
local deep_copy
deep_copy = function(tab)
local rep_tab = {}
for index, value in pairs(tab)do
if(type(value) == "table")then
rep_tab[index] = deep_copy(value)
else
rep_tab[index] = value
end
end
return rep_tab
end
Deco's deepcopy.lua
https://gist.github.com/Deco/3985043
You can also index tables using periods:
local tab = {}
tab.abc = 123
tab["def"] = 456
print(tab.abc, tab["def"])
To serialize the entire _G, you would just filter out the junk you don't need and recurse each table encountered. Watch out for _G, package, and _ENV because if defined it will recurse back to the start.
-- use cap as a whitelist
enumerate_dir = function(dir, cap)
local base = {}
for i, v in pairs(dir) do
-- skip trouble
if(i ~= "_G" and i ~= "_ENV" and i ~= "package")then
if(type(v) == "table")then -- if we have a table
base[i] = enumerate_dir(v, cap)
else
for k, n in pairs(cap) do
if(type(v) == n)then -- if whitelisted
base[i] = tostring(v)
end
end
end
end
end
return base
end
-- only functions and tables from _G please
local enumeration = enumerate_dir(_G, {"function", "table"})
-- do some cool quips to get a basic tree system
prefix = ""
recursive_print = function(dir)
for i, v in pairs(dir)do
if(type(v) == "table")then
print(prefix, i, v)
prefix = prefix .. ">"
recursive_print(v)
else
print(prefix, i, v)
end
end
if(#prefix > 0)then
prefix = prefix:sub(1, #prefix-1)
end
end
recursive_print(test)
I am using OpenOffice Calc spreadsheet formulas with psuedo-random numbers to generate arrays of arithmetic problems which I can easily update to creating new worksheets (I'm a teacher)
Problems are output as formula mark-ups in string form. OOo Math formulas use these string commands typed into the editor to display nicely formatted maths expressions.
I can do this next step manually:
1) go to source cell and copy string mark-up to clipboard
2) select target cell and clear existing contents and objects
3) create new Math object anchored to target cell
4) open Math editor window and paste in mark-up string
5) exit Math editor window and return cursor to source cell
Result: a nice maths expression of given arithmetic problem.
I need to be able to do this for entire columns of source cells on various sheets.
...even better, to then add a listener to dynamically update as sources are updated.
I found code here: Cell content inside formula that achieves this for a fixed pair of cells, but despite all my best efforts, I have had to admit defeat - generalising this code is simply beyond my expertise!
The absolute ideal would be a macro function that I could call like a spreadsheet function; with input arguments (sourceCell, targetCell, listenerON/OFF) that could run the above algorithm and dynamically update if required.
Can anybody help me? A solution like this, or any kind of workaround would be immensely helpful.
UPDATE 2016/10/27
Thank you Jim K, that did work, but use of the dispacher comes with a whole host of difficulties I hadn't foreseen.
I just found Charlie Young's post in the OpenOffice forum which makes use of the API. I have included my adaptation of his code below.
Can anybody help me to integrate it into a function in a similar way as I've described? I don't know how to solve placement of the Math object in to the target cell.
The API code is great as it will create a new Math object each time the code is updated. Existing ones do need to be deleted though.
I think the limitation of not being able to delete existing objects from within a function is going to persist. Would this be the case even if done by a subroutine called by the function?
function InsertFormula(paraFromCell, paraToCell)
Dim oDoc As Object
Dim oSheet As Object
Dim oShape As Object
oDoc = ThisComponent
oSheet = oDoc.Sheets(0)
oShape = oDoc.createInstance("com.sun.star.drawing.OLE2Shape")
oShape.CLSID = "078B7ABA-54FC-457F-8551-6147e776a997"
oSheet.Drawpage.Add(oShape)
oShape.Model.Formula = paraFromCell
oShape.setSize(oShape.OriginalSize)
end function
NEXT UPDATE
I've been managing to solve my own problems quite quickly now...
I've decided to go with a sub, not a function, so I can access the sheet to delete existing objects. Code is attached - Source cells are in Column C and target cells in matching rows of Column A. So far I am only able to send objects to $A$1.
How do I anchor each new object to a specific cell?
REM ***** BASIC *****
Sub InsertThisFormula
Dim oDoc As Object
Dim oSheet As Object
Dim oShape As Object
Dim sourceCell As Object
Dim targetCell As Object
oDoc = ThisComponent
oSheet = oDoc.Sheets(1)
Dim n As Integer
n = 1 'number of rows of formulas
for i = 0 To n-1
rem loop through cells
sourceCell = oSheet.getCellByPosition(2, i)
targetCell = oSheet.getCellByPosition(0, i)
rem clear target cell object/s
targetCell.ClearContents(128)
oShape = oDoc.createInstance("com.sun.star.drawing.OLE2Shape")
oShape.CLSID = "078B7ABA-54FC-457F-8551-6147e776a997"
oSheet.Drawpage.Add(oShape)
oShape.Model.Formula = sourceCell.string
oShape.setSize(oShape.OriginalSize)
Next i
End Sub
Starting from Mifeet's example, add this to My Macros:
rem ----------------------------------------------------------------------
rem Creates a math formula from text
Function InsertFormulaFromCell(paramCellFrom, paramCellTo)
dim document as object
dim dispatcher as object
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
rem go to cell containing markup and copy it
dim fromCellArgs(0) as new com.sun.star.beans.PropertyValue
fromCellArgs(0).Name = "ToPoint"
fromCellArgs(0).Value = paramCellFrom
dispatcher.executeDispatch(document, ".uno:GoToCell", "", 0, fromCellArgs())
dispatcher.executeDispatch(document, ".uno:Copy", "", 0, Array())
rem go to cell where I want the formula displayed
dim toCellArgs(0) as new com.sun.star.beans.PropertyValue
toCellArgs(0).Name = "ToPoint"
toCellArgs(0).Value = paramCellTo
dispatcher.executeDispatch(document, ".uno:GoToCell", "", 0, toCellArgs())
rem open Star.Math
oDesk = createUnoService ("com.sun.star.frame.Desktop")
dispatcher.executeDispatch(document, ".uno:InsertObjectStarMath", "", 0, Array())
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
rem paste clipboard using Array() as place-holder for variable name
dispatcher.executeDispatch(document, ".uno:Paste", "", 0, Array())
rem exit Star.Math
dispatcher.executeDispatch( _
document, ".uno:TerminateInplaceActivation", "", 0, Array())
InsertFormulaFromCell = "Math Formula updated " & Now()
End Function
To run it, put this formula in cell C5:
=INSERTFORMULAFROMCELL("$C$3","$C$20")
Now when the values get updated, it creates another formula.
Note: I could not get the .uno:Delete section of Mifeet's code to work, perhaps because functions are not supposed to access other cells. This may require manually deleting the formulas before creating new ones.
(Posted solution on behalf of the OP).
This is now solved. After a lot of searching, I found what I needed! Simple really. Future improvements might be to resize cells appropriately. Happy for now. Thanks to Jim K and the rest of the Stack Overflow community!
Complete macro below:
REM ***** BASIC *****
Sub InsertThisFormula
Dim oDoc As Object
Dim oSheet As Object
Dim oShape As Object
Dim sourceCell As Object
Dim targetCell As Object
oDoc = ThisComponent
oSheet = oDoc.Sheets(1)
Dim n As Integer
n = 6 'number of rows of formulas
for i = 0 To n-1
rem loop through cells
sourceCell = oSheet.getCellByPosition(2, i)
targetCell = oSheet.getCellByPosition(3, i)
rem clear target cell object/s
targetCell.ClearContents(128)
oShape = oDoc.createInstance("com.sun.star.drawing.OLE2Shape")
oShape.CLSID = "078B7ABA-54FC-457F-8551-6147e776a997"
oSheet.Drawpage.Add(oShape)
oShape.Model.Formula = sourceCell.string
oShape.setSize(oShape.OriginalSize)
oShape.Anchor = targetCell
oShape.MoveProtect = True
Next i
End Sub
OK so here's the situation. I've got a classic ASP website running inside an MVC 4 application. I need the classic ASP website to be able to get a key from the appsettings section of the web.config file.
Here is the function I've got:
' Imports a site string from an xml file (usually web.config)
Function ImportMySite(webConfig, attrName, reformatMSN)
Dim oXML, oNode, oChild, oAttr, dsn
Set oXML=Server.CreateObject("Microsoft.XMLDOM")
oXML.Async = "false"
oXML.Load(Server.MapPath(webConfig))
Set oNode = oXML.GetElementsByTagName("appSettings").Item(0)
Set oChild = oNode.GetElementsByTagName("add")
' Get the first match
For Each oAttr in oChild
If oAttr.getAttribute("key") = attrName then
dsn = oAttr.getAttribute("mysite")
ImportMySite = dsn
Exit Function
End If
Next
End Function
Here is the function call code:
msn = ImportMySite("web.config", "mysite", false)
So when I call this function the value I get back is always blank or null. I'm not sure where I'm going wrong, I'm a total novice with XML so maybe I'm missing something completely obvious. I have searched the questions but couldn't find anything related to this using classic ASP.
Any help would be much appreciated.
I appreciate Connor's work. It got me well along the way to making this happen. I made some changes that I think might be helpful to others.
I did not want to have to repeat the file name for each call and I have a couple of sections in my config. This seemed more general. Also, I consolidated his changes into a for-sure working example. You can paste this into your app, change the CONFIG_FILE_PATH and get on with your life.
'******************************GetConfigValue*******************************
' Purpose: Utility function to get value from a configuration file.
' Conditions: CONFIG_FILE_PATH must be refer to a valid XML file
' Input: sectionName - a section in the file, eg, appSettings
' attrName - refers to the "key" attribute of an entry
' Output: A string containing the value of the appropriate entry
'***************************************************************************
CONFIG_FILE_PATH="Web.config" 'if no qualifier, refers to this directory. can point elsewhere.
Function GetConfigValue(sectionName, attrName)
Dim oXML, oNode, oChild, oAttr, dsn
Set oXML=Server.CreateObject("Microsoft.XMLDOM")
oXML.Async = "false"
oXML.Load(Server.MapPath(CONFIG_FILE_PATH))
Set oNode = oXML.GetElementsByTagName(sectionName).Item(0)
Set oChild = oNode.GetElementsByTagName("add")
' Get the first match
For Each oAttr in oChild
If oAttr.getAttribute("key") = attrName then
dsn = oAttr.getAttribute("value")
GetConfigValue = dsn
Exit Function
End If
Next
End Function
settingValue = GetConfigValue("appSettings", "someKeyName")
Response.Write(settingValue)
OK I found my answer.
I changed:
For Each oAttr in oChild
If oAttr.getAttribute("key") = attrName then
dsn = oAttr.getAttribute("mysite")
ImportMySite = dsn
Exit Function
End If
Next
To:
For Each oAttr in oChild
If oAttr.getAttribute("key") = attrName then
dsn = oAttr.getAttribute("value")
ImportMySite = dsn
Exit Function
End If
Next
I have the following which is returned from an api call:
<WORST>0</WORST>
<AVERAGE>93</AVERAGE>
<START>1</START>
I need to parse this to just give me the <AVERAGE></AVERAGE> number, 93.
Here's what I'm trying but get error detected:
res = AjaxGet(url)
myArray = split(res,"AVERAGE>")
myArray2 = split(myArray[1],"</AVERAGE>")
response.write myArray2[0]
I'm brand new to ASP, normally code in PHP
VBScript doesn't recognise square brackets [] when accessing Array elements and will produce a Syntax Error in the VBScript Engine.
Try making the following changes to the code snippet to fix this problem;
res = AjaxGet(url)
myArray = split(res,"AVERAGE>")
myArray2 = split(myArray(1),"</AVERAGE>")
response.write myArray2(0)
On a side Note:
Parsing XML data in this way is really inefficient if the AjaxGet() function returns an XML response you could use the XML DOM / XPath to locate the Node and access the value.