How to adding code to object at runtime ? - Livecode - livecode

everyone.I have any idea to adding code to object at runtime.But I have some problem.
If that object have script and I want to adding code to object by keep old script of object.
How do I do ?
Here my code :
put "on preOpencard" & return & "playani" & return & "end preOpencard" into Ascript[sA]
set the script of the last card of stack stackN to Ascript[sA]
Thank you.

To append the existing script;
put "on preOpencard" & return & "playani" & return & "end preOpencard" into Ascript[sA]
put the script of the last card of stack stackN & return & return & Ascript[sA] into tNewScript
set the script of the last card of stack stackN to tNewScript

The ideas here are sound, but we must be careful to maintain the control structures, that is, to make sure that we start the script with "on" and end it with "end".
So it is important to test this, and generically, to place the new modified code BEFORE the last line of the existing script. That usually entails a generous use of returns, and specifically, the insertion of a return, prepended to the new code snippet, AFTER line "-2" of the existing code:
put return & yourNewCode after line -2 of yourOldScript
set the script of yourObject to yourOldScript
Craig Newman

Related

Error in saving minitab graphs and plots: "...collection is empty and contains no valid output object"

I want to automate GageR&R study in minitab.
I found code but the line mtbProject.Commands.Item(1).Outputs.Item(1).Graph.SaveAs.
Gives
Run time error:"IOutput: IOutput collection is empty and contains no valid output object"
Sub msa_macro()
'
' msa_macro Macro
'
'
Dim MtbApp As Mtb.Application
Dim mtbProject As Mtb.Project
Dim mtbWorksheet As Mtb.Worksheet
Set MtbApp = New Mtb.Application
Set mtbProject = MtbApp.ActiveProject
Set mtbWorksheet = mtbProject.ActiveWorksheet
MtbApp.UserInterface.Visible = True
MtbApp.UserInterface.DisplayAlerts = True
mtbProject.ExecuteCommand "Execute 'C:\Amir\DataAnalysis2\MSA_FixtureMill_STC049\MSA_STC049_BSM\Results_Files\readfileMinitab_test.mtb' 1."
mtbProject.Commands.Item(1).Outputs.Item(1).Graph.SaveAs "C:\Result_Files\grph1.png", True, GFJPEG
End Sub
The problem is, that you want to save the Outputs.Item(1) from Commands.Item(1). So you address the first command that you called, which is "Excecute … ", and this has no Output-Item. Therefore the IOutputs Collection for this Command-Item is empty.
The Output-Collection is defined as the Items of Outputs for each command. What you would want to do, is to save the first Output-Item of the command with which you created the graph.
It would be very helpful, if you could provide some information about your readfileMinitab_test.mtb. What are you doing in this .mtb file, is it also a macro-enabled file? I would guess, that you create the graph in this file?
If you want to save your graph as a .png, I guess you might need the MtbGraphFiletype GFPNGColor instead of GFJPEG. You also don´t need to save the file as grph1.png (just grph1 will suffice), as this is done automatically, because you tell Minitab to save it in a specific filetype.
You could also use the digit-code for the Filetypes (which is a little bit shorter). This would mean GFPNGColor = 3 and GFJPEG = 1. For some further information about this I recommend you the Minitab-Automation-Guide.
An example code could look as following:
'This is the first Command Minitab is executing
mtbProject.ExectueCommand "Execute <something>"
'This is the second Command Minitab is executing
mtbProject.ExecuteCommand "Boxplot C" & CStr(i as Integer)
'We want to Save the Graph, which we created with Command 2. We created one graph with
'this Command, to we only have 1 Output.
mtbProject.Commands.Item(2).Outputs.Item(1).Graph.SaveAs <path as String>, True, 3
Thanks Florian. Yes you are right, I figured it out that I am trying to read the output of the wrong command.
I wanted to execute a sequence of 'Gage R&R' commands and to save an output graph. It is completed now.
Thanks again for the helping answer.

Using strings for network path, not mapped drive, with Shell in VBA

QUESTION UPDATED, PLEASE SEE BELOW
I am trying to use string variables (exedir - the full network drive directory of an exe file, and inputdir - the location of the input file argument) to launch an exe with its argument using shell in VBA.
The commented out line in the script below does not work. If I manually set the drive using a letter I can get it to work, as shown below, but the .exe and .lam input file used here are both on networked drives (the variable comp is the unique name of the users PC, which sets the name of the .lam input file, so the input file name is different for every user).
I'm not too familiar with the syntax and borrowed it from elsewhere. Am I missing a quotation mark or maybe have too many in the commented out row?
Sub CallExeWithInput()
Set wsh = VBA.CreateObject("WScript.Shell")
'Statusnum = wsh.Run(Command:="""" & exedir & """""""" & inputdir & """""", windowstyle:=1, waitonreturn:=False)
SetCurrentDirectory "M:\path\"
Statusnum = wsh.Run(Command:="foo.exe ""M:\path\" & comp & ".lam""", windowstyle:=1, waitonreturn:=False)
End Sub
Example of exedir: \\network\path\foo.exe
Example of inputdir: \\network\path\compname.lam
Example of comp: compname << found using Environ$("computername")
I'm aware of some previous questions, having read many to get this far.
I don't want to provide the letter of the drive, and ideally want to launch the .exe with the input file using string variables to input everything. One major reason I want to only use strings, is that they can be controlled by a single variable, and when the directory changes (say with an upgrade of the .exe) it will be easy to update this script.
UPDATE
Following the comments kindly provided below I arrived here:
SetCurrentDirectory fldr
Statusnum = wsh.Run(Command:="foo.exe " & quote & inputdir & quote, windowstyle:=1, waitonreturn:=False)
Where quote = chr(34) and fldr = \\network\path\
Interestingly, if inputdir is defined as a path to a lettered drive (inputdir = M:\etc), this works. If it is to a network drive path (inputdir = \\network\etc), it launches but the .exe immediately crashes with an invalid floating point operation.
How can I alter this so the input file can be provided as a network path?
If this is not possible I will presumably need a subroutine that locates which letter the user has mapped the network drive onto in order to build my string, such as this:
path = ":\foo\bar\"
dim x as integer
for x = 65 to 90
If CBool(Len(Dir(Chr(x) & path))) Then
msgbox "It's in drive " & Chr(x)
exit for
end if
next x

After a WMI search in VBScript, can I create my search filter BEFORE my "For Each" statement?

I've created an alternative search utility to the Windows search utility with VBScript using a WQL search, but, as it turns out, it's quite slow. I would like to speed it up and I think I can do it, but I would need to place my search filter AFTER my WQL search and BEFORE my For Each statement. Is this even possible?
I've already tested by filtering in the WQL search, but it's about 40% faster if I filter after the WQL search. I've also tested with and without iFlags, but they tend to slow the search quite a bit, even though MS seems to believe otherwise.
Since the user can search by filename, creation date, last modified date and/or file size, if the filter is after the For Each statement then the script has to create the search filter each time it enumerates a file. I'd like to create the filter once in the hope of shaving some time off the search.
This will probably make better sense when you take a look at the snippet of code I've posted. Note that the sub subCreateSearchString will have calls to other search options and functions (ie: convert from UTC to local time, format file sizes, etc.)
Dim strSearchName, strComputer, objSWbemServices, objFile, colFiles
Dim strFileName, strReturnedFileName, strQueryDriveAndPath
strSearchName = "test" 'Text being searched for - change as needed
strQueryDriveAndPath = "PATH = '\\Drop_RW\\' AND DRIVE = 'D:'" 'Path and drive in which to search - change as needed
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colFiles = objSWbemServices.ExecQuery("Select * from CIM_DataFile WHERE " & "" & strQueryDriveAndPath & "")
'* I'd like to place the call to "subCreateSearchString" here
On Error Resume Next
For Each objFile in colFiles
strReturnedFileName = objFile.Name
subCreateSearchString ' Search filter - it works when placed here
If strSearchForString Then
MsgBox "File matches:" & vbCrLf & strReturnedFileName
Else
MsgBox "File DOES NOT match" & vbCrLf & strReturnedFileName
End If
Next
Sub subCreateSearchString
'* Set Filename Variable for search:
strFileName = InStr(LCase(strReturnedFileName), LCase(strSearchName))
strSearchForString = strFileName
End Sub
Since you depend on the names of the files you're iterating over in the For Each loop: no, not possible.
I'd strongly recommend making some adjustments, though.
Use a Function rather than a Sub if you want to return something from a subroutine.
Avoid using global variables. They have a nasty tendency of introducing undesired side effects and also make debugging your code a pain in the rear. Pass values into your subroutines via parameters, and return values as actual return values.
The returned value is an integer (or Null), but you use it like a boolean and named your variables (and sub) as if it were a string. Don't do that. Name your functions/procedures after what they're doing, and name your variables after what they contain. And if you want to use a boolean value make your function actually return a boolean value.
Avoid Hungarian Notation. It's pointless code-bloat the way most people use it. Even more if your naming doesn't even match the actual type.
Do not use global On Error Resume Next. Ever. It simply makes your code fail silently without telling you anything about what actually went wrong. Keep error handling as local as possible. Enable it only for single commands or short code blocks, and only if there is no other way to avoid/handle the error.
Function IsInFilename(searchName, fileName)
IsInFilename = InStr(LCase(fileName), LCase(searchName)) > 0
End Function
For Each objFile in colFiles
If IsInFilename(strSearchName, objFile.Name) Then
MsgBox "..."
Else
MsgBox "..."
End If
Next

Reading AppointmentItem.GlobalAppointmentID of Recurring Event is Causing Issues

I'm finding that when I read the GlobalAppointmentID of a recurring event in Outlook via my Excel-VBA code, things start acting odd.
Here's part of the code that I've been using to try to understand the root cause of this behavior:
For Each otItem In resCal
If otItem.Class = olAppointment Then
Set cItm = otItem
If calItem.Subject = "Coffee Date" Then
Debug.Print "Coffee orig " & cItm.Start
Debug.Print "Coffee orig 1.1 " & cItm.Start
Debug.Print cItm.GlobalAppointmentID
Debug.Print cItm.GlobalAppointmentID
Debug.Print "Coffee orig 1.5 " & cItm.Start
End If
End If
Next otItem
This produces the following output:
Coffee orig 4/16/2015 10:00:00 AM
Coffee orig 1.1 4/16/2015 10:00:00 AM
[Global Appointment ID redacted, but identical]
[Global Appointment ID redacted, but identical]
Coffee orig 1.5 2/19/2015 10:00:00 AM
4/16 is the instance of the recurring event that I would like to record. However, when I call the GlobalAppointmentID property, it changes the value of the .Start property to that of the first instance of the recurring event. I've tested and can implement a workaround that involves me storing the start date in a variable before calling GlobalAppointmentID, however I would like to try to diagnose and fix the root cause of the issue to ensure that it isn't causing any problems that I haven't noticed yet. Can anyone shed some light on what is causing this issue?
Thanks!
the problem does not occur when I call the AppointmentItem by index instead of looping via For Each
I'd recommend using the for loop instead and releasing the object as soon as possible. This is particularly important if your code attempts to enumerate more than 256 Outlook items in a collection that is stored on a Microsoft Exchange Server. If you do not release these objects in a timely manner, you can reach the limit imposed by Exchange on the maximum number of items opened at any one time. Declare an object in the function scope (loop scope) and set it to Nothing to release the reference to the object as soon as possible.
I recently took another look at my code and determined the source of the problem. Here’s the snippets of code that were causing the problem:
With oItms
.Sort "[Start]", False
.IncludeRecurrences = True
End With
Set rCal = oItms.Restrict("[Start] >= '" & CStr(date) & "'")
With rCal
.Sort "[Start]", False
.IncludeRecurrences = True
End With
Specifically, running the “.Sort” and the “.IncludeRecurrances” on rCal without calling the “.Restrict” method caused the problem. I determined that the 2nd “With” was redundant as is, so I removed it. I can now call any property in any order, without having to worry about the values changing.

Applescript file search using data from a spreadsheet

I am currently using this Applescript I found that searches for a file name and returns the file path in a text doc. This works fine for finding 1 or 2 files, but I would like to find 500 files that are spread over hundreds of folders. My ideal script would use data from an excel spreadsheet or csv, perform a search, find the file and make a copy of it in a designated folder on my desktop. Any help is appreciated.
Here is the script I found:
tell application "System Events"
activate
set thePattern to text returned of (display dialog "Search for" default answer "")
end tell
if thePattern = "" then return
try
set foundFiles to do shell script "mdfind -name " & quoted form of thePattern & " | /usr/bin/egrep -i " & quoted form of thePattern & "[^/]*/?$ | /usr/bin/grep -vi " & quoted form of thePattern & ".*" & quoted form of thePattern
on error
set foundFiles to "Nothing Returned"
end try
if foundFiles = "" then set foundFiles to "Nothing Returned"
tell application "TextEdit"
activate
delay 0.5
try
set theDoc to document 1
get text of theDoc
if result is not "" then
make new document
set theDoc to result
end if
on error
make new document
set theDoc to result
end try
set text of theDoc to foundFiles
end tell
You need to read the data from the text file, then turn it into a return or linefeed delimited list and do a repeat over the items of this list. Then turn each item (which is actually a line) into e.g. a tab delimited list and again do a (nested) repeat loop over the items of this list. If you know that e.g. item 3 is the file path, you can set a variable to item 3 of the line as text and use this variable in your shell script.
I think you need to show that you understand the concept of repeat loops by posting your own attempt of implementing this. If you do, I'll be happy to come back and help you with the next step.
Kind regards,
Mark

Resources