I'm trying to consolidate functions for a very large automation suite using UFT. There are many functions that get called. I'm curious if anyone has a code snippet that uses the UFT object model, or something similar, that would trace functions called into either the output tab, a text file, or something else that could be perused to see which said functions were called during a script run.
A call to write an info row in the test results reviewer, output tab, etc. can be added, but it's obviously a very laborious exercise.
Sub GetAction(piRow,ByRef pstrActionName)
'On Error Resume Next
'Declaration
Dim objxl,objwb,rowno,strAction,objws
Set objxl=CreateObject("Excel.Application")
'Open the Datasheet
Set objwb=objxl.workbooks.open(excelpath)
objxl.visible=False
objxl.displayalerts=False
Set objws=objxl.activeworkbook.worksheets("Sheet1")
'Get the ActionName
strAction=objxl.cells(piRow,1)
pstrActionName=strAction
End If
If Err.Number<>0 Then
Msgbox "GetAction:"&"Error :"&Cstr(Err.Description)
End If
Set objws=Nothing
Set objwb=Nothing
'Close and Quit from Excel
objxl.Quit
End Sub'GetAction
Write all the function names in a excel sheet
Call above function which will read function names from the excel sheet
call function using below step
call pstrActionName
Related
I am not entirely sure if this is possible, but assuming with us being able to set object references I don't see why not.
To start off, the object that contains the subroutine in question is Excel itself. I am wanting to call one of Excel's VBA subroutines using a different program's VB6 script editor.
I have tried the following without success, but hopefully you can see what I am trying to accomplish here:
Sub Excel_Test()
Dim appXL As Object
Set appXL = GetObject(, "Excel.Application")
Call appXL.Project1.Module1.Test()
End Sub
Obviously this code is not working - but what would be the proper Syntax (if one exists) to call the Macro Test, located in Module1 contained in Excel's object?
You can automate other instances of excel if you identify them by some criteria like the workbook name,
try like
Code:
set otherinstance = getobject(,"fullpath\filename.xls")
otherinstance.application.run "macroname"
Relative VBA newbie here. I created a new Module "QCDataRefresh" with a Public Sub "RefreshExcel" that is designed to open an Excel spreadsheet (housed on my network drive) in the background and refresh it. This is done in order to refresh the many data links contained within said spreadsheet.
Here is the code for this Sub:
Public Sub RefreshExcel()
Dim appExcel As Object
Set appExcel = CreateObject("Excel.Application")
appExcel.workbooks.Open ("\\renssfile2\shares\Supply Chain Project Management\QCData.xlsx")
appExcel.activeworkbook.refreshall
Set appExcel = Nothing
End Function
Running this gives a run-time error '1004': "Application Defined or object-defined error. Debugging seems to highlight the line of code "appExcel.activeworkbook.refreshall". Not sure why though?
Additionally, I am also attempting to create a button in Access to run this from my dashboard. To do this, I created a new button, and created a new Event Procedure for this entitled, "Command101_Click".
The following is the code for that Event, which attempts to run my RefreshExcel Sub upon clicking the button:
Private Sub Command101_Click()
QCDataRefresh.RefreshExcel
End Sub
When I run this Event, I would expect it to give me the same error from my refresh Function above. However, instead it opens a window asking me to select a Macro. I'm unsure what my mistake is here, but I'm sure that it must be a simple oversight. Thoughts on this as well?
Thanks all!
I think the problem is that the workbooks.open method returns a workbook.
Try this:
Public Sub RefreshExcel()
Dim appExcel As Object
Dim excelwb As Excel.Workbook
Set appExcel = CreateObject("Excel.Application")
Set excelwb = appExcel.workbooks.Open ("\\renssfile2\shares\Supply Chain Project Management\QCData.xlsx")
excelwb.refreshall
Set excelwb = Nothing
Set appExcel = Nothing
End Sub
Whenever I have unexpected and unusual issue\error for using excel to output to or read from I allways try the following, especially when the code breaks in the middle and doesn't get to the line where you close the spreadsheet and close the Excel object from memory.
So close your spreadsheet and any Excel instances and objects you may have as follow:
Close all Excel files and excel program if you have any open
Go to the Task Manager (by doing Alt+Ctrl+Del) then select Task Manager
Go to processes tab
Sort by process name
Look for any Excel.exe in the list and force close them all one by one
Let us know.
Recently I started getting the error 1004: PasteSpecial method of Range class failed. I know people have said before that it might be that it is trying to paste to the active sheet when there is none, however, as you can see, everything is based on ThisWorkbook so that shouldn't be the problem. It happens extra much when Excel doesn't have the focus.
'references the Microsoft Forms Object Library
Sub SetGlobals()
Set hwb = ThisWorkbook' home workbook
Set mws = hwb.Worksheets("Code Numbers") ' main worksheet
Set hws = hwb.Worksheets("Sheet3") ' home worksheet (Scratch pad)
Set sws = hwb.Worksheets("Status") ' Status sheet
Set aws = hwb.Worksheets("Addresses") ' Addresses sheet
End Sub
Sub Import()
Call SetGlobals
hws.Select
'a bunch of code to do other stuff here.
For Each itm In itms
Set mitm = itm
body = Replace(mitm.HTMLBody, "<img border=""0"" src=""http://www.simplevoicecenter.com/images/svc_st_logo.jpg"">", "")
Call Buf.SetText(body)
Call Buf.PutInClipboard
Call hws.Cells(k, 1).Select
Call hws.Cells(k, 1).PasteSpecial
For Each shape In hws.Shapes
shape.Delete
Next shape
'Some code to set the value of k
'and do a bunch of other stuff.
Next itm
End Sub
Update: mitm and itm have two different types, so I did it for intellisense and who knows what else. This code takes a list of emails and pastes them into excel so that excel parses the html (which contains tables) and pastes it directly into excel. Thus the data goes directly into the sheet and I can sort it and parse it and whatever else I want.
I guess I'm basically asking for anyone who knows another way to do this besides putting it in an html file to post it. Thanks
This probably will not exactly answer your problem - but I noticed a few things in your source code that are too long to place in a comment, so here it is. Some of it is certainly because you omitted it for the example, but I'll mention it anyway, just in case:
Use Option Explicit - this will avoid a lot of errors as it forces you to declare every variable
Call SetGlobals can be simplified to SetGlobals - same for Call Buf.SetText(body) = Bof.SetText Body, etc.
No need to '.Select' anything - your accessing everything directly through the worksheet/range/shape objects (which is best practice), so don't select (hws.Select, hws.Cells(k,1).Select)
Why Set mitm = itm? mitm will therefore be the same object as itm - so you can simply use itm
You're deleteing all shapes in hwsmultiple times - for each element in itms. However, once is enough, so move the delete loop outside of the For Each loop
Instead of putting something in the clipboard and then pasting it to a cell, just assign it directly: hws.Cells(k, 1).Value = body - this should solve your error!
Instead of using global variables for worksheets that you assign in 'SetGlobals', simply use the sheet objects provided by Excel natively: If you look at the right window in the VBE with the project tree, you see worksheet nodes Sheet1 (sheetname), Sheet2 (sheetname), etc.. You can rename these objects - go to their properties (F4) and change it to meaningful names - or your current names (hwb, mws, ...) if you want. Then you can access them throughout your code without any assignment! And it'll work later, even if you change the name of Sheet3to something meaningful! ;-)
Thus, taking it all into account, I end up with the following code, doing the same thing:
Option Explicit
Sub Import()
'a bunch of code to do other stuff here.
For Each shape In hws.Shapes
shape.Delete
Next shape
For Each itm In itms
Call hws.Cells(k, 1) = Replace(itm.HTMLBody, "<img border=""0"" src=""http://www.simplevoicecenter.com/images/svc_st_logo.jpg"">", "")
'Some code to set the value of k
'and do a bunch of other stuff.
Next itm
End Sub
In my Main procedure I want to write a quick if-statement which checks whether the user has made a valid input (user chooses number of project from list of data, see attached screenshot). For that I am checking whether the project number is not part of the list of projects. If that is true, an error message is displayed; if not then a number of other procedures are called.
For some reason though I get error 2015 when I run it, which means that the if-statement is always true, even on correct user entries. Can someone help me understand the error please?
The project number input is a named cell called "IdSelect" and is on a sheet called "Invoice"
The data against which this input is checked is on a sheet called "Input"
The data is stored in column B and called "ProjectList"
Code below (note: I have tried pasting it 5 times but the formatting still won't work this time for some reason - any idea what that could be? The code is properly formatted. Sorry for the messy display; if anyone can tell me what that problem might I would be very grateful!)
Sub Main()
'Turn off screen updating
Application.ScreenUpdating = False
'Define variable for currently active cell to reactivate it afterwards
Dim OldActiveSheet As Object
Dim OldActiveCell As Object
Dim i As Integer
Dim ProjectList As Range
Set OldActiveSheet = ActiveSheet
Set OldActiveCell = ActiveCell
'If-statement to check whether project number is valid or not
Worksheets("Invoice").Activate
'Print to Immediate Window to check value - remove later
Debug.Print Range("IdSelect").Value
If IsError(Application.Match(Range("IdSelect").Value, "ProjectList", 0)) Then
'Print to Immediate Window to check value - remove later
Debug.Print Application.Match(Range("IdSelect").Value, Worksheets("Input").Range("ProjectList"), 0)
MsgBox "Invalid Choice: Project with this number does not exist!"
Exit Sub
Else
'Call procedures to execute
Call SortData
Call Count_Line_Items
Call Count_Total_Rows
Call Write_Services(ServCnt)
Call Write_Expenses(ExpCnt)
End If
'Reactivate previous active cell
OldActiveSheet.Activate
OldActiveCell.Activate
End Sub
Screenshot from "Input" sheet:
The way you refer to range is rather odd.. because you missed out range reference. Oddly enoughbthat you do it correct on the next line at
Debug.Print Application.Match(Range("IdSelect").Value, Worksheets("Input").Range("ProjectList"), 0)
So try this please: (it take me 100 years to format my own post on mobile.....). Make sure to use explicit reference as shown in my sample code below. Set your sheets accordingly.
Dim ws as Worksheet
Set ws = Sheets(1)
IsError(Application.Match(ws.Range("IdSelect").Value, ws.Range("ProjectList"), 0)) Then
And here is for you to read on for error handling on on match.
I have created an Excel Spreadsheet which helps with data analysis from an Oracle database.
The user enters then clicks the "Refresh Query" button which generates a query for Oracle to execute. The query takes a minute or so to complete. Although the VBA code does not hang on ".Refresh", all Excel windows remain frozen until the query completes.
Sub refreshQuery_click()
Dim queryStr as String
' Validate parameters and generate query
' ** Code not included **
'
' Refresh Query
With ActiveWorkbook.Connections("Connection").OLEDBConnection
.CommandText = queryStr
.Refresh
End With
End Sub
Is there a way for the user to manually cancel the query (calling .CancelRefresh) while the Excel user-interface is frozen?
EDIT I don't know if the following is worth noting or regular behavior. While the query is executing, all open Excel windows (including the VBA Editor) become "Not Responding" in Task Manager. Neither pressing Esc nor Ctrl+Break will cancel the script. Also, calling DoEvents (either before or after .Refresh) does not change this behavior.
Here's a method that I know will work. However, there are some complications.
Here's how it's done:
Put the spreadsheet with the data in a separate workbook. This worksheet should execute the refresh query when it's opened and then close once the data is updated.
Create a batch file to call the "Data" Excel file.
Within a different workbook, create a procedure (macro) for the user to call. This procedure will call the batch file, which subsequently calls the Excel file. Since you are calling a batch file and not Excel directly, the Excel procedure will continue because the command shell is released so quickly and opens the other Excel file in a different thread. This allows you to continue working within the main Excel file.
Here are some complications:
I included a method to alert the user that the data has been udpated. There are timing issues where it's possible to try to check if the data has been update when the workbook is not accessible, which forces the user to try to update values. I included a method called my time which pauses the execution of the code so it only checks every so many seconds.
The updated worksheet will pop up in a new window, so the user will need to click on their original worksheet and keep working. You could learn to hide this if you're comfortable with Windows scripting (I haven't learned that yet).
Here are some files and code. Be sure to read the comments in the code for why some things are there.
FILE: C:\DataUpdate.xls
We'll make a workbook called "DataUpdate.xls" and put it in our C:\ folder. In cell A1 of Sheet1, we'll add our QueryTable which grabs external data.
Option Explicit
Sub UpdateTable()
Dim ws As Worksheet
Dim qt As QueryTable
Set ws = Worksheets("Sheet1")
Set qt = ws.Range("A1").QueryTable
qt.Refresh BackgroundQuery:=False
End Sub
Sub OnWorkbookOpen()
Dim wb As Workbook
Set wb = ActiveWorkbook
'I put this If statement in so I can change the file's
'name and then edit the file without code
'running. You may find a better way to do this.
If ActiveWorkbook.Name = "DataUpdate.xls" Then
UpdateTable
'I update a cell in a different sheet once the update is completed.
'I'll check this cell from the "user workbook" to see when the data's been updated.
Sheets("Sheet2").Range("A1").Value = "Update Table Completed " & Now()
wb.Save
Application.Quit
End If
End Sub
In the ThisWorkbook object in Excel, there's a procedure called Workbook_Open(). It should look like the following so it executes the update code when it is opened.
Private Sub Workbook_Open()
OnWorkbookOpen
End Sub
NOTE: I found a bug when this file closed if 1) you accessed the file from the command line or shell and 2) you have the Office Live Add-in installed. If you have the Office Live Add-in installed, it will throw an exception on exit.
FILE: C:\RunExcel.bat
Next, we're going to create a batch file that will open the Excel file we just made. The reason that call the Excel file from within the batch file and not directly from the other Excel file using Shell is because Shell will not continue until the other application closes (at least when using Excel.exe "c:\File.xls"). The batch file, however, runs its code and then immediately closes, thus allowing the original code that called it to continue. This is what will let your uses continue working in Excel.
All this file needs is:
cd "C:\Program Files\Microsoft Office\Office10\"
Excel.exe "C:\DataUpdate.xls"
If you're handy with Windows Scripting, you do fancy things like open the window in a hidden mode or pass a parameter of the file name or Excel location. I kept it simple with a batch file.
FILE: C:\UserWorkbook.xls
This is the file that the user will open to "do their work in." They'll call the code to update the other workbook from within this workbook and they'll still be able to work in this workbook while this one is updating.
You need a cell in this workbook where you'll check the "Update Table Completed" cell from the DataUpdate workbook. I chose cell G1 in Sheet1 for my example.
Add the following code to a VBA module in this workbook:
Option Explicit
Sub UpdateOtherWorkbook()
Dim strFilePath As String
Dim intOpenMode As Integer
Dim strCallPath As String
Dim strCellValue As String
Dim strCellFormula As String
Dim ws As Worksheet
Dim rng As Range
Set ws = Worksheets("Sheet1")
Set rng = ws.Range("G1")
strCellFormula = "='C:\[DataUpdate.xls]Sheet2'!A1"
'This makes sure the formula has the most recent "Updated" value
'from the data file.
rng.Formula = strCellFormula
strFilePath = "C:\RunExcel.bat"
intOpenMode = vbHide
'This will call the batch file that calls the Excel file.
'Since the batch file executes it's code and then closes,
'the Excel file will be able to keep running.
Shell strFilePath, intOpenMode
'This method, defined below, will alert the user with a
'message box once the update is complete. We know that
'the update is complete because the "Updated" value will
'have changed in the Data workbook.
AlertWhenChanged
End Sub
'
Sub AlertWhenChanged()
Dim strCellValue As String
Dim strUpdatedCellValue As String
Dim strCellFormula As String
Dim ws As Worksheet
Dim rng As Range
Set ws = Worksheets("Sheet1")
Set rng = ws.Range("G1")
strCellFormula = "='C:\[DataUpdate.xls]Sheet2'!A1"
strCellValue = rng.Value
strUpdatedCellValue = strCellValue
'This will check every 4 seconds to see if the Update value of the
'Data workbook has been changed. MyWait is included to make sure
'we don't try to access the Data file while it is inaccessible.
'During this entire process, the user is still able to work.
Do While strCellValue = strUpdatedCellValue
MyWait 2
rng.Formula = strCellFormula
MyWait 2
strUpdatedCellValue = rng.Value
DoEvents
Loop
MsgBox "Data Has Been Updated!"
End Sub
'
Sub MyWait(lngSeconds As Long)
Dim dtmNewTime As Date
dtmNewTime = DateAdd("s", lngSeconds, Now)
Do While Now < dtmNewTime
DoEvents
Loop
End Sub
As you can see, I constantly updated the formula in the "Listening Cell" to see when the other cell was updated. Once the data workbook has been updated, I'm not sure how you'd force an update in code without rewriting all the cells. Closing the workbook and reopening it should refresh the values, but I'm not sure of the best way to do it in code.
This whole process works because you're using a batch file to call Excel into a different thread from the original file. This allows you to work in the original file and still be alerted when the other file has been updated.
Good luck!
EDIT: Rather than include a more complete answer in this same answer, I've created a separate answer dedicated entirely to that solution. Check it out below (or above if it gets voted up)
Your users can break the VBA function by pressing Ctrl+Break on the keyboard. However, I've found that this can cause your functions to randomly break until each time any function is run. It goes away when the computer is restarted.
If you open this file in a new instance of Excel (meaning, go to Start > Programs and open Excel from there), I think that the only workbook that will be frozen will be the one executing the code. Other intances of Excel shouldn't be affected.
Lastly, you might research the DoEvents functions, which yields execution back to the Operating System so that it can process other events. I'm not sure if it would work in your case, but you could look into it. That way you can do other things while the process is being completed (It's kind of dangerous because the user can then change the state of your application while the process is working).
I believe I know a way that actually will work, but it's complicated and I don't have the code in front of me. It involves creating a separate instance of the Excel application in code and attaching a handler to the execution of that instance. You include the DoEvents part of the code in a loop that releases once the application closes. The other instantiated Excel application has the sole purpose of opening a file to execute a script and then close itself. I've done something like this before so I know that it works. I'll see if I can find the code tomorrow and add it.
Well, you could consider the old-fashion way -- split the query into smaller batches and use Do Events in between batches.
You could try XLLoop. This lets you write excel functions (UDfs) on an external server. It includes server implementations in many languages (eg. Java, Ruby, Python, PHP).
You could then connect to your oracle database (and potentially add a caching layer) and serve up the data to your spreadsheet that way.
The XLL also has a feature to popup a "busy" GUI that lets the user cancel the function call (which disconnects from the server).
BTW, I work on the project so let me know if you have any questions.