VB Com Error for Naming Sheets on a Worksheet - vb.net

I keep getting an error that says
"An unhandled exception of type
'System.Runtime.InteropServices.COMException' occurred in
Microsoft.VisualBasic.dll"
Additional information: Exception from HRESULT: 0x800A03EC"
on the line where I'm trying to change the name of the sheets from Workbook reportApp. On my timeWorkbook there are headings in cells A1, then cell D1, and so on.
I want it to loop until there is no more values, but I can't change the name. I can change the name of the sheets in that workbook if I put reportApp.Sheets(s).Name = "Name this sheet", but I don't want to do that. I was wondering if there was any problem with my type or code that would get around this?
Private Sub generateReportButton_Click(sender As Object, e As EventArgs) Handles generateReportButton.Click
Dim timeApp As Excel.Application = New Excel.Application
Dim timeClockPath As String = "C:\Users\njryn_000\Desktop\Project ACC\Clock-In Excel\TimeClock.xlsx"
Dim timeWorkbook As Excel.Workbook = timeApp.Workbooks.Open(timeClockPath, ReadOnly:=False, IgnoreReadOnlyRecommended:=True, Editable:=True)
Dim timeWorksheet As Excel.Worksheet = timeWorkbook.Worksheets("TA")
Dim reportApp As Excel.Application = New Excel.Application
Dim reportPath As String = "C:\Users\njryn_000\Desktop\Project ACC\Report\Blank Timecard Report9.xlsx"
Dim reportWorkbook As Excel.Workbook = reportApp.Workbooks.Open(reportPath, ReadOnly:=False, IgnoreReadOnlyRecommended:=True, Editable:=True)
Dim reportWorksheet As Excel.Worksheet = reportWorkbook.Worksheets("Sheet" & 1)
Dim s As Integer
Dim i As Integer
Dim f As Integer
Dim taName As String
Dim taID As String
i = 0
f = 0
s = 1
With timeWorksheet.Range("A1")
Do
i += 3
s += 1
reportApp.Sheets(s).Name = timeWorksheet.Range("A1").Offset(0, i).Value
Loop Until IsNothing(timeWorksheet.Range("A1").Offset(0, 0).Offset(0, i).Value)

You've already solved your problem but you may not be able to add an answer yet so here is some feedback.
When you use a With block you can then refer to whatever you referenced at the top of that block with a single dot ('.') after that. Its a syntax which reduces writing the same thing over and over. In the snippet below I've removed all references to timeWorksheet.Range("A1") and added a leading dot.
With timeWorksheet.Range("A1")
Do
i += 3
s += 1
' Since you are using a With block this statement is simplified.
reportApp.Sheets(s).Name = .Offset(0, i).Value
' I removed the .Offset(0, 0) as it is redundant.
' If you have it in to solve a bug you can put it back.
Loop Until IsNothing(.Offset(0, i).Value)
' More code here...
End With
Also you've realised that you can use the Val() function to fix your code. Reading the documentation, it explains that this function will take a string and begin reading a number from it, ignoring whitespace. As soon as it reaches a non-numeric, non-whitespace character it stops and returns the number ignoring whatever else is in the string.
It seems that this isn't really solving your problem, it just works around it. I'd look at what other characters are present in the cells you are looping through and deal with them explicitly. Otherwise you might end up with strange results.

Related

Excel 2016 VBA - Compare 2 PivotTables fields for matching values

Hi please can someone help, Excel 2016 VBA PivotTable objects. I rarely develop in Excel VBA.
Overall goal:
Compare a single column [P_ID] value list from PivotTable2 against PivotTable1 if they exist or not to enable filtering on those valid values in PivotTable1.
I have some Excel 2016 VBA code which I have adapted from a previous answer from a different internet source.
Logic is: gather data from PivotTable2 from the ComparisonTable dataset (in PowerPivot model), field [P_ID] list of values. Generate a test line as input into function to test for existence of field and value in PivotTable1 against the Mastertable dataset, if true add the line as valid if not skip the line.
Finally filter PivotTable1 with the VALID P_ID values.
It works to a point until it gets to the bFieldItemExists function which generates an error:
Run-time error '1004'
Unable to get the PivotItems property of the PivotField class
Can someone please correct the way of this not working?
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
Dim MyArray As Variant, _
ar As Variant, _
x As String, _
y As String, _
str As Variant
MyArray = ActiveSheet.PivotTables("PivotTable2").PivotFields("[ComparisonTable].[P_ID].[P_ID]").DataRange
For Each ar In MyArray
x = "[MasterTable].[P_ID].&[" & ar & "]"
If ar <> "" And bFieldItemExists(x) = True Then
If str = "" Then
str = "[MasterTable].[P_ID].&[" & ar & "]"
Else
str = str & "," & "[MasterTable].[P_ID].&[" & ar & "]"
End If
End If
Next ar
Dim str2() As String
str2 = Split(str, ",")
Application.EnableEvents = False
Application.ScreenUpdating = False
ActiveSheet.PivotTables("PivotTable1").PivotFields("[MasterTable].[P_ID].[P_ID]").VisibleItemsList = Array(str2)
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Function bFieldItemExists(strName As String) As Boolean
Dim strTemp As Variant
' This line does not work!?
strTemp = ActiveSheet.PivotTables("PivotTable1").PivotFields("[MasterTable].[P_ID].[P_ID]").PivotItems(strName)
If Err = 0 Then bFieldItemExists = True Else bFieldItemExists = False
End Function
The 1004 error occurred due to the use of square brackets [ ]. Remove those.
You also need to use the key word Set when you set an object equal to something. For example Set MyArray = ActiveSheet.PivotTables("PivotTable2").PivotFields("ComparisonTable.P_ID.[P_ID").DataRange.
If you don't use Set you will get a VBA run-time error dialog that says Run-time error '91': Object variable or With block variable not set
I cannot guarantee that my edits will completely solve your problem since I don't have your data set and cannot fully test your code. You will need to use the Debug mode in the VBA editor and single step through the code. To this set a breakpoint on the Set mDataRange = Active.... To set a breakpoint go to the Debug menu and choose the "Toggle Breakpoint" sub-menu item or you can press F9 to set the breakpoint.
Now when you make a change to the Pivot table, the Worksheet_PivotTableUpdate event will fire and the code will top execution at that point.
After the code stops executing due to the breakpoint, you can press the F8 key to single step through your code. If you want to resume execution to the next breakpoint you can press F5. Also when you get the VBA error dialog box, you can hit Debug and then use the F8 key to single step or use the debug windows to see what your variables and objects contain. I'm sure there are some good youtube videos on VBA debugging.
As you single step through the code, you can observe what each variable/object contains using the Immediate window, the Watches window and the Locals window. To open these windows, go to the menu item View and click on each of these sub-menu items.
Here's how you need to edit your code before debugging.
Option Explicit
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
'Better practice is to not use the underscore character to
'continue a Dim declaration line
Dim mDataRange As Range
Dim ar As Range
Dim x As String
Dim y As String
Dim str As Variant
'Use Set to assign the object mDataRange a reference to the the right
'hand side of the equation. Remove the square brackets
'MyArray = ActiveSheet.PivotTables("PivotTable2").PivotFields("[ComparisonTable].[P_ID].[P_ID]").DataRange
Set mDataRange = ActiveSheet.PivotTables("PivotTable2").PivotFields("ComparisonTable.P_ID.P_ID").DataRange
For Each ar In mDataRange
'You need to specify what proprerty from ar you
'want to assign to x. Assuming the value stored in
'ar.Value2 is a string, this should work.
'We use value2 because it is the unformmated value
'and is slightly quicker to access than the Text or Value
'properties
'x = "[MasterTable].[P_ID].&[" & ar & "]"
x = "MasterTable.P_ID." & ar.Value2
'Once again specify the Value2 property as containing
'what value you want to test
If ar.Value2 <> "" And bFieldItemExists(x) = True Then
If str = "" Then
'Remove the square brackets and use the specific property
'str = "[MasterTable].[P_ID].&[" & ar & "]"
str = "MasterTable.P_ID." & ar.Value2
Else
'Remove the square brackets and use the specific property
'str = str & "," & "[MasterTable].[P_ID].&[" & ar & "]"
str = str & "," & "MasterTable.P_ID." & ar.Value2
End If
End If
Next ar
Dim str2() As String
str2 = Split(str, ",")
Application.EnableEvents = False
Application.ScreenUpdating = False
'Remove square brackets
'ActiveSheet.PivotTables("PivotTable1").PivotFields("[MasterTable].[P_ID].[P_ID]").VisibleItemsList = Array(str2)
ActiveSheet.PivotTables("PivotTable1").PivotFields("MasterTable.P_ID.P_ID").VisibleItemsList = Array(str2)
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Function bFieldItemExists(strName As String) As Boolean
'Declare a PivotItem to accept the return value
Dim pvItem As PivotItem
'Since you want to trap for an error, you'll need to let the VBA runtime know
'The following code is a pseudo Try/Catch. This tells the VBA runtime to skip
'the fact an error occured and continue on to the next statement.
'Your next statement should deal with the error condition
On Error Resume Next
'Use Set whenever assigning an object it's "value" or reference in reality
Set pvItem = ActiveSheet.PivotTables("PivotTable1").PivotFields("MasterTable.P_ID.P_ID").PivotItems(strName)
'Assuming that an error gets thrown when strName is not found in the pivot
'Err is the error object. You should access the property you wish to test
If Err.Number = 0 Then
bFieldItemExists = True
Else
bFieldItemExists = False
End If
'Return to normal error functioning
On Error GoTo 0
End Function
Finally, I realize that some of this should be in the comments section, but there was too much I needed to explain to help Learner74. BUT most importantly, I hope I helped him. I have used so many suggestions, recommendations and explanations from the VBA Stack Overflow exchange through the years, I just want to pay it back by paying it forward.
Additional USEFUL Links:
Chip Pearson is the go to site and person for all things VBA
Paul Kelly's Excel Macro Mastery is another go to site for Excel and VBA questions.
Microsoft Excel Object Model which is sometimes useful, but needs improvement. Too many of the objects lack examples, but can at least point you in the right direction.

Determine if a VBComponent regards a workbook or a worksheet

The following code allows me to go through the workbook and worksheets that have macros:
For Each VBCmp In ActiveWorkbook.VBProject.VBComponents
Msgbox VBCmp.Name
Msgbox VBcmp.Type
Next VBCmp
As this page shows, for a workbook and a sheet, their type are both 100, ie, vbext_ct_Document. But I still want to distinguish them: I want to know which VBCmp is about a workbook, which one is about a worksheet.
Note that VBCmp.Name can be changed, they are not necessarily always ThisWorkbook or Sheet1, so it is not a reliable information for what I am after.
Does anyone know if there exists a property about that?
Worksheet objects and Workbook objects both have a CodeName property which will match the VBCmp.Name property, so you can compare the two for a match.
Sub Tester()
Dim vbcmp
For Each vbcmp In ActiveWorkbook.VBProject.VBComponents
Debug.Print vbcmp.Name, vbcmp.Type, _
IIf(vbcmp.Name = ActiveWorkbook.CodeName, "Workbook", "")
Next vbcmp
End Sub
This is the Function I'm using to deal with exported code (VBComponent's method) where I add a preffix to the name of the resulting file. I'm working on an application that will rewrite, among other statements, API Declares, from 32 to 64 bits. I'm planning to abandon XL 32 bits definitely. After exportation I know from where did the codes came from, so I'll rewrite them and put back on the Workbook.
Function fnGetDocumentTypePreffix(ByRef oVBComp As VBIDE.VBComponent) As String
'ALeXceL#Gmail.com
Dim strWB_Date1904 As String
Dim strWS_EnableCalculation As String
Dim strChrt_PlotBy As String
Dim strFRM_Cycle As String
On Error Resume Next
strWB_Date1904 = oVBComp.Properties("Date1904")
strWS_EnableCalculation = oVBComp.Properties("EnableCalculation")
strChrt_PlotBy = oVBComp.Properties("PlotBy")
strFRM_Cycle = oVBComp.Properties("Cycle")
If strWB_Date1904 <> "" Then
fnGetDocumentTypePreffix = "WB_"
ElseIf strWS_EnableCalculation <> "" Then
fnGetDocumentTypePreffix = "WS_"
ElseIf strChrt_PlotBy <> "" Then
fnGetDocumentTypePreffix = "CH_"
ElseIf strFRM_Cycle <> "" Then
fnGetDocumentTypePreffix = "FR_"
Else
Stop 'This isn't expected to happen...
End If
End Function

Find() results in Object variable or With Block variable not set

Thanks for reading my post. I'm new to Excel VBA and have run into a wall debugging a call to Find(). I've gone through several posts on this site and others but so far each fix I've tried has been unsuccessful.
I am writing code to process elements out of financial reports. Each report contains one or more multi-row & multi-column blocks of cells with details describing a project. The size of each block isn't consistent, but each always begins in the top left with "Client Name". So I want to iterate through these blocks keying off that text, then pulling out needed elements.
There's no while loop here yet, as I'm running into the error just setting up the first condition.
Run-time error '91': Object variable or With block variable not set
Here's the section of code from within the Sub, with the error coming in the final line assigning cursorProject:
' store the next report to process
Dim nextReport As String
Dim sourceSheetName As String
Dim sheetSource As Worksheet
nextReport = rptMedia
' copy the worksheet into rptBurn and get that worksheet's name
sourceSheetName = GetSheet(nextReport)
Set sheetSource = Workbooks(rptBurn).Worksheets(sourceSheetName)
sheetSource.Cells.EntireRow.Hidden = False
sheetSource.Cells.EntireColumn.Hidden = False
Workbooks(rptBurn).Activate
' process the sheetSource into sheetCurrent
' set constants
Const constCursorKey As String = "Client Name"
Const constClientColumn As String = "B"
Const constClientNameOffset As Integer = 2
Const constProjectLeft As Integer = 2
Const constProjectRight As Integer = 52
' get range in Client Name column of project entries
Dim cursorStart As Long
Dim cursorEnd As Long
Dim cursorProject As Range
Dim rangeProject As Range
Dim rangeSearch As Range
cursorStart = sheetSource.Columns(2).Find(constCursorKey).Row + constClientNameOffset
' find the last project entry in the sheet
cursorEnd = sheetSource.Range("B" & Rows.Count).End(xlUp).Row
Set rangeSearch = sheetSource.Range(Cells(cursorStart + 1, constProjectLeft), _
Cells(cursorEnd, constProjectLeft))
cursorProject = rangeSearch.Find(What:=constCursorKey, LookIn:=xlValues, LookAt:=xlPart, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False, _
SearchFormat:=False)
This is very sloppy currently as parts will be moved out to its own Sub called while iterating over the reports (hence nextReport is hardcoded here to a specific report name). The various constants are fixed parameters of the reports. The unlisted values like "rptBurn" are globals. The GetSheet function works well, but if you want to see it:
Private Function GetSheet(rpt As String) As String
Workbooks.Open rootPath + rpt
ActiveSheet.Copy after:=Workbooks(rptBurn).Sheets(Workbooks(rptBurn).Sheets.Count)
GetSheet = ActiveSheet.Name
Workbooks(rpt).Close
End Function
I've tried several variations on this. The Locals all look promising up to the error. I set the Hidden properties to False based on another post. I've tried simplifying the call down to the basics and using With, like this:
Set rangeSearch = Sheets(3).Range("B:B")
rangeSearch.Select
With rangeSearch
cursorProject = .Find("Client Name")
End With
But I'm always getting an error on cursorProject. There are definitely many "Client Name" entries in the worksheet I'm testing. I put in the Select to verify I'm grabbing the correct range; oddly I find that "B:AX" get highlighted (AX is the rightmost used column in the report) in the simple version, but the selection I expect in the original. Regardless there are "Client Name" instances in either selection--I can select B4 and see "Client Name".
What am I doing wrong?
Cursorproject is an object variable (range). You can't simply assign a value to an object variable, you have to set it.
dim strSomeTextVarible as string
dim rngSomeCellsObjectVariable as range
strSomeTextVarible = "abc"
set rngSomeCellsObjectVariable = range("a1:c3")

Runtime error 424 Compile error, Object Required - VBA Excel

I need a simple bit of VBA code to work, however I keep getting runtime error 424.
I have looked over many other posts but found nothing that could help me
All I want to do is Vlookup with the id "individual" and find it in the ApplySublimits Worksheet.
Sub CommandButton1_Click()
Dim individual As String
Dim individualCap As Single
Dim subRange As Range
Set subRange = ApplySublimits.Range("B:D")
individual = "D02065"
Range("C10").Value = individual
individualCap = Application.WorksheetFunction.VLookup(individual, subRange, 2, False)
End Sub
I keep getting this error but i dont understand why. Im very new to excel and would appreciate some help or guidance.
How can a single (a floating point number) hold something starting with D. It's not 0-9. If it's hex the &hD02065 is the way to do it. Plus numbers aren't enclosed in quotes.
Declare and set applysublimits as the worksheet
Change individualCap to String
e.g.
Sub CommandButton1_Click()
Dim individual As String
Dim individualCap As String
Dim subRange As Range
Dim applysublimits As Worksheet
Set applysublimits = Sheets("Sheet1")
Set subRange = applysublimits.Range("B:D")
individual = "D02065"
Range("C10").Value = individual
individualCap = Application.WorksheetFunction.VLookup(individual, subRange, 2, False)
End Sub

Visio VBA: Invalid Parameter in Nested Loop

In Microsoft Visio Professional 2010 I've isolated the error I've been getting to this little code snippet. On the page is a container holding 2 shapes and I want to iterate through those shapes within another loop. But I keep getting an invalid parameter error.
My attempt at a solution is the top block, but it only works with the same definition for the inner loop. It seems like something is changing during the 2nd iteration of the outer loop, but I'm not sure. I feel it has to do with the way a For Each loop is defined.
Sub Nested_Loop_Error()
Dim a As Variant
Dim b As Variant
Dim lngs() As Long
'This Works
lngs = ActiveDocument.Pages(1).Shapes.ItemFromID(1).ContainerProperties.GetMemberShapes(visContainerFlagsDefault)
For a = 0 To 1
For Each b In lngs
'Do nothing
Next b
Next a
'This does not work
For a = 0 To 1
For Each b In ActiveDocument.Pages(1).Shapes.ItemFromID(1).ContainerProperties.GetMemberShapes(visContainerFlagsDefault)
MsgBox "In Loop for a=" & a
Next b
Next a
End Sub
Edit:
I've been playing around with it and got it to work, but what I'm really interested in is why it works. The 2nd block of code fails when a=1, giving an invalid parameter in the line docMyDoc.Pages...
The following is the code showing the difference of using a variant or a document variable to define the ActiveDocument within the loop. Using the debugger I can't see a difference in how docMyDoc or varMyDoc are defined.
Sub Nested_Loop_Error2()
Dim a As Variant
Dim b As Variant
Dim docMyDoc As Visio.Document
Dim varMyDoc As Variant
'This works
For a = 0 To 1
Set varMyDoc = ActiveDocument
For Each b In varMyDoc.Pages(1).Shapes.ItemFromID(1).ContainerProperties.GetMemberShapes(visContainerFlagsDefault)
MsgBox "Using variant, a=" & a
Next b
Next a
'This does not work
For a = 0 To 1
Set docMyDoc = ActiveDocument
For Each b In docMyDoc.Pages(1).Shapes.ItemFromID(1).ContainerProperties.GetMemberShapes(visContainerFlagsDefault)
MsgBox "Using document, a=" & a
Next b
Next a
End Sub
Using the Variant type doesn't help the compiler much: The variable called "b" should be of type Long, and the "a" variable of type Integer.
This said, you're not using the "a" variable but to repeat twice what you do in the inner loop (Msgbox), but nothing else changes.
Moreover, you need to reference the shape whose ID is b, that you're not doing.
And another tip: don't name variables after their type, but after their semantics.
I think that what you intended to do is something like the example in GetMemberShapes method's reference in MSDN:
Sub Nested_Loop()
Dim lngMemberID as Long
Dim vsoShape as Visio.Shape
Dim j as Integer
For j = 0 to 1
For Each lngMemberID In ActiveDocument.Pages(1).Shapes(1).ContainerProperties.GetMemberShapes(visContainerFlagsDefault)
Set vsoShape = ActivePage.Shapes.ItemFromID(memberID)
Debug.Print vsoShape.ID
Next lngMemberID
Next j
End Sub
Here, your vsoShape variable will refer first to one, then to the other of your shapes. And it will work even if you have more shapes in your page.
That's the good thing of Collections and the For Each loop: Collections are special objects made up as a list of other objects. They have their own methods, as Item, or Count, and shortcuts, like using a number between parenthesis to retrieve an individual object from the collection (as in Pages(1)).
What you do with For Each is to iterate through all the objects in the collection (or all the values in an array).
For your purposes, I'd try the following general structure:
dim oPage as Visio.Page
dim oShape as Visio.Shape
dim oInnerShape as Visio.Shape
For each oPage In ActiveDocument.Pages
For each oShape in oPage.Shapes
If oShape.Master.Name = "xxx" Then ' You can check the type of the shape
For each oInnerShape In oShape
' set and compute width and height
Next oInnerShape
' set and compute width and height of the containing shape
End If
Next oShape
' Rearrange shapes
Next oPage
You can construct an array storing the shape IDs, width and height, while iterating through the shapes, then use that array to rearrange the shapes.
Regards,
I don't have Visio on my computer but are you certain that the first nested loop worked?
I have doubt in lngs = ActiveDocument.Pages(1)... with Dim lngs() As Long:
Excel VBA will throw "Type mismatch" error with trying to store arr = Array(1,2) with Dim arr() As Long. Better off Dim lngs As Variant even if you know it's an array of Long being returned.
The second nested loop works in theory.