Excel 2016 breaks previously working VBA macro - macos

I have developed a small VBA macro in Excel that's supposed to add the values of cells in row 15 to the values of cells in row 6 during workbook change (in my case entering a number in row 15 and pressing tab).
Initially, I developed and used it in Excel 2013, then I have switched to Mac and have since used it in Excel for Mac 2011. Now, I have installed Excel for Mac 2016 and all of a sudden, the macro doesn't work anymore.
This is the script:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("C15:H15")) > 0 Then
Call copySub
End If
End Sub
Sub copySub()
Sheets("sheet1").Protect , UserInterFaceOnly:=True
For i = 3 To 8
Cells(6, i).Value = Cells(6, i).Value + Cells(15, i).Value
Cells(15, i).Value = 0
Next i
End Sub
When I enter a value and press tab in Excel 2016, I get the runtime error 91 "Object variable or With block variable not set". The error seems to occur in the line:
Cells(6, i).Value = Cells(6, i).Value + Cells(15, i).Value
I have also tried to store the sum in a variable before assigning it to Cells(6, i).Value, but that didn't help either.
Did Microsoft change the logic of the sheet protection, especially with the parameter UserInterFaceOnly set to true? Or what's going on here?
I hope you can help me.
Thanks,
chuky

Are you sure you've copied this code correctly? There's no way it would work in any version of Excel.
Your problems are these:
Intersect returns a Range object so your code would throw a 91 error.
There's most likely a case error in your line Sheets("sheet1").Protect ... as it's probably called "Sheet1". If so, this would throw a 91 error.
If you changed that worksheet name from "sheet1", it'd throw a 91 error.
Why are you only protecting the sheet at Worksheet_Change. This should really be done in Workbook_Open? And if you do that, how does the user change the cells without specific cells being free from protection?
It's unclear which worksheets you're referring to and where the copySub routine is held. I've updated your code as it is to remove the main errors and written in the capacity to nominate your worksheet - you'll have to adjust that as you wish. Good luck.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet
Set ws = Target.Worksheet
If Not Intersect(Target, ws.Range("C15:H15")) Is Nothing Then
Call copySub(ws)
End If
End Sub
Sub copySub(ws As Worksheet)
ws.Protect , UserInterFaceOnly:=True
Application.EnableEvents = False
For i = 3 To 8
ws.Cells(6, i).Value = ws.Cells(6, i).Value + ws.Cells(15, i).Value
ws.Cells(15, i).Value = 0
Next i
Application.EnableEvents = True
End Sub

Related

Barcode in Excel

wondering if someone can help me out with the following problem.
I have staff stock areas with items regularly. As part of the stocking they are required to also charge whatever they send out. The issue is that when they charge they do the repetitive task of data entry for each item they charge out.
In my ideal setup, they can scan a barcode and the task would be completed in seconds since the barcode would contain all the data that needs to be entered.
To automate this, I was thinking of creating one barcode that can capture all the required inputs along with the tab, and enter keys they are required to input And then when the barcode is scanned from a paper print out the info would be automatically charged.
The data driving the barcode is in Excel so I'd like to create the barcode in Excel. This is where I need help, I've tried to add barcode font but it's not working and I have no experience in VBA if that is required.Any guidance would be much appreciated!
You may use barcode generation component to generate barcodes from VBA (as pictures) and insert these pictures into Excel.
Below is the sample code for ByteScout BarCode SDK (commercial component compatible with VBA) sample. Basically, if you want you may replace it with any other component that is capable of creating pictures when called from VBA.
' IMPORTANT: This demo uses VBA so if you have it disabled please temporary enable
' by going to Tools - Macro - Security.. and changing the security mode to ""Medium""
' to Ask if you want enable macro or not. Then close and reopen this Excel document
' You should have evaluation version of the ByteScout SDK installed to get it working - get it from https://bytescout.com
' If you are getting error message like
' "File or assembly named Bytescout SDK, or one of its dependencies, was not found"
' then please try the following:
'
' - Close Excel
' - (for Office 2003 only) download and install this hotfix from Microsoft:
' http://www.microsoft.com/downloads/details.aspx?FamilyId=1B0BFB35-C252-43CC-8A2A-6A64D6AC4670&displaylang=en
'
' and then try again!
'
' If you have any questions please contact us at http://bytescout.com/support/ or at support#bytescout.com
'==============================================
'References used
'=================
'Bytescout Barcode SDK
'
' IMPORTANT:
' ==============================================================
'1) Add the ActiveX reference in Tools -> References
'2) Loop through the values from the Column A for which barcode has to be generated
'3) Parse the value to Bytescout Barcode Object to generate the barcode using QR Code barcode type.
'4) Save the generated Barcode Image
'5) Insert the Barcode Image in the Column B
'6) Repeat the steps 3 to 5 till the last Value in Column A
'
'==================================================================
Option Explicit
' declare function to get temporary folder (where we could save barcode images temporary)
Declare Function GetTempPath _
Lib "kernel32" Alias "GetTempPathA" _
(ByVal nBufferLength As Long, _
ByVal lpBuffer As String) As Long
' function to return path to temporary folder
Public Function fncGetTempPath() As String
Dim PathLen As Long
Dim WinTempDir As String
Dim BufferLength As Long
BufferLength = 260
WinTempDir = Space(BufferLength)
PathLen = GetTempPath(BufferLength, WinTempDir)
If Not PathLen = 0 Then
fncGetTempPath = Left(WinTempDir, PathLen)
Else
fncGetTempPath = CurDir()
End If
End Function
Sub Barcode_Click()
'Fetch the Worksheet
Dim mySheet As Worksheet
Set mySheet = Worksheets(1) 'Barcode_Data Sheet
'temp path to save the Barcode images
Dim filePath As String
filePath = fncGetTempPath() 'Change the Path But should end with Backslash( \ )
'Prepare the Bytescout Barcode Object
'====================================
Dim myBarcode As New Bytescout_BarCode.Barcode
myBarcode.RegistrationName = "demo" 'Change the name for full version
myBarcode.RegistrationKey = "demo" 'Change the key for full version
'Barcode Settings
myBarcode.Symbology = SymbologyType_QRCode ' QR Code barcode, you may change to other barcode types like Code 39, Code 128 etc
' set barcode image quality resolution
myBarcode.ResolutionX = 300 'Resolution higher than 250 is good for printing
myBarcode.ResolutionY = 300 'Resolution higher than 250 is good for printing
myBarcode.DrawCaption = True 'Showing Barcode Captions in the Barcode Image
myBarcode.DrawCaptionFor2DBarcodes = True ' show captions for 2D barcodes like QR Code
' first clean the B column from old images (if any)
Dim Sh As Shape
With mySheet
For Each Sh In .Shapes
If Not Application.Intersect(Sh.TopLeftCell, .Range("B1:B50")) Is Nothing Then
If Sh.Type = msoPicture Then Sh.Delete
End If
Next Sh
End With
' now generate new barcodes and insert into cells in the column B
' Repeat the steps for each row from 2 to 6
Dim myVal As Integer
For myVal = 2 To 6 'change the code to all rows with values
'Parse the Value from the Column A to Bytescout Barcode Object
myBarcode.Value = mySheet.Cells(myVal, 1).Text
'Fit the barcode into 80X30 mm rectangle
myBarcode.FitInto_3 80, 30, 4 '4 refers to units of measurement as millimeter
'Save the barcode image to a file in temporary folder
myBarcode.SaveImage filePath & "myBarcode" & myVal & ".png"
'Insert the Barcode image to the Column B and resize them to fit the cell.
'==========================================================================
With mySheet.Pictures.Insert(filePath & "myBarcode" & myVal & ".png")
.ShapeRange.LockAspectRatio = True ' lock aspect ratio
.Left = mySheet.Cells(myVal, 2).Left + 1 ' set left
.Top = mySheet.Cells(myVal, 2).Top + 1 ' set right
.PrintObject = True ' allow printing this object
.Placement = xlMove ' set placement mode to move but do not resize with the cell
.ShapeRange.ScaleHeight 1, True ' set height scale to 1 (no scale)
.ShapeRange.ScaleWidth 1, True ' set width scale to 1 (no scale)
End With
Next myVal ' move to next cell in the column
' Release the Barcode Object.
Set myBarcode = Nothing
End Sub
Disclaimer: I'm relatd to ByteScout

Dynamic Link in UFT automation?

I want to write a dynamic VBScript for my web automation in UFT 12.02. I would like to pass a dynamic value as part of the link. here is my sample Line code:
set ObjExcel = CreateObject("Excel.application")
ObjExcel.workbooks.open "F:\Automation\Web\Business\WebTestData.xls"
For Curr= 1 To 20
USD = ObjExcel.sheets(1).cells(Curr,1).Value
If Browser("...").Page("...").Exist Then
Browser("...").Page("...").WebElement("WebElement").Click
'Attempt to click on Drop Down Link
Browser("...").Page("...").Link("USD").Click
End If
Next
"USD" will keep changing, i.e. I will be picking it from Excel.
Expected Result:
Generate a script that will attempt to click on different links as below:
Browser("...").Page("...").Link("EURO").Click
Browser("...").Page("...").Link("BP").Click
Browser("...").Page("...").Link("AED").Click
Browser("...").Page("...").Link("KSH").Click
Browser("...").Page("...").Link("IR").Click
Yes, you should use USD without double quote.
Dim currType, ObjExcel
set ObjExcel = CreateObject("Excel.application")
ObjExcel.workbooks.open "F:\Automation\Web\Business\WebTestData.xls"
For Curr= 1 To 20
currType = ObjExcel.sheets(1).cells(Curr,1).Value
If Browser("...").Page("...").Exist Then
Browser("...").Page("...").WebElement("WebElement").Click
'Attempt to click on Drop Down Link
Browser("...").Page("...").Link(currType).Click
End If
Next
set ObjExcel = Nothing
Note: I've changed USD with currType.
I have zero experience with UFT, but shouldn't using the variable USD instead of the string "USD" do what you want?
For Curr= 1 To 20
USD = ObjExcel.sheets(1).cells(Curr,1).Value
If Browser("...").Page("...").Exist Then
Browser("...").Page("...").WebElement("WebElement").Click
'Attempt to click on Drop Down Link
Browser("...").Page("...").Link(USD).Click
End If
Next

VBA written in Excel for Windows not working on Mac

I have a set of macros to hide and unhide columns based on the contents of a specific row. They were all written in Excel 2013 for Windows (running in parallels on my MBA, if that's relevant) and work fine there. But when I open the worksheet in Excel 2011 for Mac, the macros give odd results. The "unhide all columns" macro works fine; the other functions get as far as hiding all columns but not as far as unhiding the ones I want to see.
I can only assume Excel for Mac is having a problem with what's in the FOR EACH loop, but I can't figure out what! I'd appreciate any guidance: I need to get this system working on both Windows and Mac.
Code below.
This function works:
Sub GANTT_Filter_Show_All()
Dim rngDates As Range
Set rngDates = Range("GANTT_Dates")
rngDates.EntireColumn.Hidden = False
End Sub
But this one only hides all the columns:
Sub GANTT_Filter_This_Quarter()
Dim intCurrentMonth As Integer, intCurrentYear As Integer, rngDates As Range, cell As Range
Dim intCurrentQuarterMonths(3) As Integer
Set rngDates = Range("GANTT_Dates")
intCurrentMonth = DatePart("m", Date)
intCurrentYear = DatePart("yyyy", Date)
'loading months of current quarter into an array intCurrentMonth
Select Case intCurrentMonth
Case 1 To 3
intCurrentQuarterMonths(0) = 1
intCurrentQuarterMonths(1) = 2
intCurrentQuarterMonths(2) = 3
Case 4 To 6
intCurrentQuarterMonths(0) = 4
intCurrentQuarterMonths(1) = 5
intCurrentQuarterMonths(2) = 6
Case 7 To 9
intCurrentQuarterMonths(0) = 7
intCurrentQuarterMonths(1) = 8
intCurrentQuarterMonths(2) = 9
Case 10 To 12
intCurrentQuarterMonths(0) = 10
intCurrentQuarterMonths(1) = 11
intCurrentQuarterMonths(2) = 12
End Select
'hiding all columns
rngDates.EntireColumn.Hidden = True
'comparing each column to array of months in current quarter and hiding if false
For Each cell In rngDates
For Each v In intCurrentQuarterMonths
If v = DatePart("m", cell.Value) And DatePart("yyyy", cell.Value) = intCurrentYear Then cell.EntireColumn.Hidden = False
Next v
Next cell
Application.Goto Reference:=Range("a1"), Scroll:=True
End Sub
I'm with #Steven on this one, nothing obviously wrong with the code. I'm not a Mac user, but it's entirely possible that there's some weirdness around the date functions, particularly those that require formatting to resolve.
I would try replacing the calls to DatePart() with calls to Month() and Year() in situations like this - even for non-Mac users. It doesn't rely on parsing the strings for formatting, so it's much more efficient (and easy to read):
Sub Benchmarks()
Dim starting As Double, test As Date, i As Long
test = Now
starting = Timer
For i = 1 To 1000000
Year test
Next i
Debug.Print "Elapsed: " & (Timer - starting)
starting = Timer
For i = 1 To 1000000
DatePart "yyyy", test
Next i
Debug.Print "Elapsed: " & (Timer - starting)
End Sub
Since you likely can't run the benchmark...
Elapsed for Year(): 0.109375
Elapsed for DatePart(): 0.515625
Also note that in addition to this, the dates in the column you're searching are coming through as Variants, it may help to explicitly cast them to dates:
If v = Month(CDate(cell.Value)) And intCurrentYear = Year(CDate(cell.Value)) Then
cell.EntireColumn.Hidden = False
End If

Excel Macro, vlookup function works slow, ways to speed up macro

Hello stackexchange community.
I've built a simple tables converter, the main function of which is to convert the table from
1a Value
1b Value
1c Value
1d Value
to
a b c d
1 Value Value Value Value
Unfortunately, the macro runs pretty slow (~ 3 lines per second for one column).
I'd really appreciate if someone could take a look at my piece of code and suggest the way to speed it up.
Here's the piece of code:
Dim LastFinalList As Integer: LastFinalList = Sheet1.Range("O1000").End(xlUp).Row
For Col = 16 To 19
For c = 2 To LastFinalList
searchrange = Sheet1.Range("J:L")
lookfor = Sheet1.Cells(c, 15) & Sheet1.Cells(1, Col)
CountFor = Application.VLookup(lookfor, searchrange, 3, False)
If IsError(CountFor) Then
Sheet1.Cells(c, Col).Value = "0"
Else
Sheet1.Cells(c, Col).Value = CountFor
End If
Next c
Next Col
Thanks in advance and best regards!
UPD:
The Data in unconverted table looks like this (e.g):
Updated by Macro
Value Number Type Key Count Average Value
10 1 a 1a 2 20
30 1 a 1a 2 20
40 1 b 1b 1 40
50 1 c 1c 1 50
So it is also required to calculate averages of repeating types, create a unique list of Numbers (which is LastFinalList in my case) and finally convert it to this:
Number a b c
1 20 40 50
application.vlookupseraches by Number&Type Key, which is also assigned in the unconverted table by macro. The same time those Keys are counted, in order to calculate average for the repeating ones.
Everything works in a blink of an eye till it comes to 'to update final table part.
Full Code:
Sub ConvertToTable()
Dim LastMeter As Integer: LastMeter = Sheet1.Range("I1000").End(xlUp).Row
Sheet1.Range(Cells(2, 9), Cells(LastMeter, 9)).AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Sheet1.Range("O2"), Unique:=True
Sheet1.Range("O1").Value = "The List"
Sheet1.Range("O2").Delete Shift:=xlUp
' to assign keys
For i = 2 To LastMeter
Set CountOpt = Sheet1.Cells(i, 10)
Sheet1.Cells(i, 10).FormulaR1C1 = "=r[0]c[-1]&r[0]c[-2]"
Sheet1.Cells(i, 11).FormulaR1C1 = "=COUNTIF(c10:c10, r[0]c10)"
Next i
'to calculate averages
For x = 2 To LastMeter
If Sheet1.Cells(x, 11).Value = 1 Then
Sheet1.Cells(x, 12).FormulaR1C1 = "=rc7"
ElseIf Sheet1.Cells(x, 11).Value > 1 Then
If Sheet1.Cells(x, 10).Value <> Sheet1.Cells(x - 1, 10).Value Then
Sheet1.Cells(x, 12).FormulaR1C1 = "=ROUND((SUM(rc7:r[" & Sheet1.Cells(x, 11).Value - 1 & "]c7)/" & Sheet1.Cells(x, 11).Value & "),4)"
Else
Sheet1.Cells(x, 12).FormulaR1C1 = "=r[-1]c12"
End If
End If
Next x
'to update final table
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim LastFinalList As Integer: LastFinalList = Sheet1.Cells(Rows.Count, 15).End(xlUp).Row
For Col = 16 To 19
For c = 2 To LastFinalList
searchrange = Sheet1.Range("J:L")
lookfor = Sheet1.Cells(c, 15) & Sheet1.Cells(1, Col)
CountFor = Application.VLookup(lookfor, searchrange, 3, False)
If IsError(CountFor) Then
Sheet1.Cells(c, Col).Value = "0"
Else
Sheet1.Cells(c, Col).Value = CountFor
End If
Next c
Next Col
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Sheet1.Range("O1").Select
End Sub
Also, initially i had a SUMIF formula instead of application.vlookup to be input in each cell in the converted table. But the code was working as slow as now an was bit bulky, that's why i've decide to switch to VLOOKUP.
The thing is, if it actually the way application.vlookup works (with 0.3sec delay for each row), then i guess there's nothing that can be done, and i'm ok to accept that. Although, if that's not the case, i'd really appreciate if someone could help me out and speed up the process.
Thanks!
You can redefine your LastFinalList variable something like
LastFinalList = Sheets("Sheet1").UsedRange.Rows.Count
OR
LastFinalList = Sheets("Sheet1").Cells(Rows.Count, 2).End(xlUp).Row
instead of explicitly defining used range.
Also use following line of code before your code
Application.ScreenUpdating = False
(Turn screen updating off to speed up macro code. User won't be able to see what the macro is doing, but it will run faster.)
After the whole code runs you can(optional) turn screen updating on with
Application.ScreenUpdating = True
It appears that application.vlookup in my particular case was indeed working very slow (no idea why, though). I've managed to improve macro by replacing vlookup with SUMIF formula in each cell, so now the converted table is updated instantly. Thanks everyone who participated and provided their suggestions!

Call out to script to stop with attribute in wWWHomePage

I'm gettinga n error message in line 8 when I try to call out the script to stop when it finds teh attribute in the Web page: field in AD.
Set objSysInfo = CreateObject("ADSystemInfo")
strUserDN = objSysInfo.UserName
Set objUser = GetObject("LDAP://" & strUserDN)
strwWWHomePage = objItem.Get("wWWHomePage")
If wWWHomePage 6 Then
wscript.quit
Else
Set ppt = CreateObject("PowerPoint.Application")
ppt.Visible = True
ppt.Presentations.Open "\\abngan01\tracking\ppt.pptx"
End If
You have:
If wWWHomePage 6 Then
I'm assuming you want it to say:
If wWWHomePage = 6 Then
Since the missing "=" will cause an error, but since that code really doesn't do anything anyway, other than just abort the script, you could simplify your code by only taking action if that value is not set, for example:
If objItem.Get("wWWHomePage") <> 6 Then
Set ppt = CreateObject("PowerPoint.Application")
ppt.Visible = True
ppt.Presentations.Open "\\abngan01\tracking\ppt.pptx"
End If
I'm also assuming "6" is some sort of flag you've set yourself, you might want to use something a little more descriptive like "PPTSTATUS006", or something along those lines.

Resources