I recently installed VS2013 (alongside a previous VS2010 installation) and noticed I no longer receive the compiler warning 'BC42324' (text below) when compiling identical VB.NET code (I recompiled back in VS2010 to confirm warning is still shown):
Using the iteration variable in a query expression may have
unexpected results. Instead, create a local variable within the loop
and assign it the value of the iteration variable.
Documentation on MSDN seems to suggest the warning is still included. I see/don't-see the warning with the following code :
Dim Numbers = {0, 1}
For Each index In Numbers
Dim SumPlusIndex = Aggregate x In Numbers Select x + index Into Sum()
Next
Has this warning genuinely been removed? Is so how come? If not could there be other environmental differences between my VS2010 and VS2013 installation that might cause the difference?
Yes, that's the infamous capture the for loop variable bug. It has bitten many programmers so Microsoft decided to do something about it. They solved it for a For Each loop, but not a For loop. You can still trigger the warning like this:
Sub Main()
For ix As Integer = 1 To 10
Dim dlg = Sub()
Console.WriteLine(ix) '' Eek!
End Sub
'' etc...
Next
End Sub
Related
I'm seeing the good old "System.Runtime.InteropServices.COMException HResult=0x80004005 Message=Error HRESULT E_FAIL has been returned from a call to a COM component" error when attempting to find an item via a for loop as shown below:
For i = 1 to itemList.Count
oObject = itemList.Item(i)
Next
But not if I hardcode the index, this finds item 1 without issue:
oObject = itemList.Item(1)
Obviously I don't want to do that and need to search through all the objects in my "itemList" to find the one I'm looking for.
I'm being intentionally vague because the software I'm working in is Dassault 3D Experience but am writing macros for it through Visual Studio 2017. I'm not sure where to even start debugging this sort of issue so any suggestions would be appreciated. Thanks.
Edit: adding full code of what I'm trying to do here (find an object, display its name, also select it on screen to double check. I will later add a check to make sure the object found in each loop is really what I'm looking for). All variables have been declared before this section.
selactive = CATIA.ActiveEditor.Selection
selactive.Clear()
product1Service = CATIA.ActiveEditor.GetService("PLMProductService")
oRootOcc = product1Service.RootOccurrence
cVPMOccurrences = oRootOcc.Occurrences
For i = 1 to cVPMOccurrences.Count
oVPMOccurrence = cVPMOccurrences.Item(i)
selactive.Add(oVPMOccurrence)
MsgBox(oVPMOccurrence.Name)
Next
The line that fails is oVPMOccurrence = cVPMOccurrences.Item(i)
Can you do something like this with a For Each loop?
For each oVPMOccurrence as oRootOcc.Occurrence in cVPMOccurrences.Items
selactive.Add(oVPMOccurrence)
MsgBox(oVPMOccurrence.Name)
Next
Using a For Each means you don't have to worry at all about the index
Not sure what the type of oVPMOccurrence is as you haven't specified
Most indexes in .net are zero base. I don't know what itemList is but I suspect the index of the first item is 0.
For i = 0 to itemList.Count - 1
oObject = itemList.Item(i)
Next
Not sure why you want to overwrite the value of oObject on every iteration.
I've got a VBA macro in an Excel 2016 workbook (Windows 10) which has existed and worked for years (it was written when I was still using Office 2010). I've since upgraded to Office 2016, but now the macro fails with the error: "Ambiguous name detected: bIgnore". This is the failing line of code
If Not bIgnore(strDesc) Then
The bIgnore function is declared only once across all of my modules, and looks like this:
Function bIgnore(pDesc As String)
'If the description is in the "Ignore List" sheet then return True
Dim nRow As Integer
Set wIgnore = Worksheets("Ignore List")
nRow = 1
While wIgnore.Range("A" & nRow).Value <> ""
If InStr(1, pDesc, wIgnore.Range("A" & nRow).Value) > 0 Then
bIgnore = True
Exit Function
End If
nRow = nRow + 1
Wend
bIgnore = False
End Function
Any idea why it is now being regarded as ambiguous by the compiler?
I'd try replacing all instances of "bIgnore" with "blIgnore" and see if it still conflicts or not.
If the error goes away then surely it is keyword conflict.
An ambiguous name is a compile error that always means VBA is seeing at least two identifiers with the same name, in the same scope.
Normally the compile error should just take you there, and highlight the problematic declaration.
Other than that, you can use the VBE's search (Ctrl+F) functionality and try to locate the faulty declaration, but the tool is rather basic/weak, and won't list all results - it iterates them instead... which can be painful.
Alternatively you could try to use Rubberduck's Find Symbol (Ctrl+T) command (assuming the code can be parsed... Rubberduck mostly assumes the code is compilable in the first place), and see every declaration by that name - and that's if the Code Explorer (Ctrl+R) doesn't already reveal the problem:
Disclaimer: I'm heavily involved with the development of the Rubberduck VBIDE add-in.
Another alternative, since Rubberduck uses a symbol table and scoping rules to resolve identifier references, would be to refactor/rename (Ctrl+Shift+R) the function to, say, IsIgnored, and then use Find Symbol again to locate the bIgnore declaration that remained: that should be your culprit.
I am having a problem. The following code should output a single line describing my local instance of SQL. After lots of poking and prodding I have found that the code succeeds when it is compiled with the "Target Framework" set to v3.5, but it fails to return any instances when the "Target Framework" is set to anything higher. There is no error, exception, warning or other explanation. I know that it is not simply taking longer to find the instance because it reaches the final "Console.Readkey()" within .04 seconds when the target is v3.5.
I suppose what I really want to know is: How can I make this work without changing the Target Framework? I would rather not if I don't have to since I have written the rest of my project under the default (v4.5.2) and don't know what consequences might arise from doing so.
P.S. Bonus points if you can tell me why this doesn't work after v3.5.
Module Module1
Sub Main()
Dim datatable As DataTable = System.Data.Sql.SqlDataSourceEnumerator.Instance.GetDataSources()
For Each row As DataRow In datatable.Rows
For i As Integer = 0 To (datatable.Columns.Count - 1)
Console.Write(row.Item(i) & vbTab)
Next
Console.WriteLine()
Next
Console.ReadKey()
End Sub
End Module
Unfortunately, you appear to be experiencing this reported bug.
If it looks like the bug report matches your problem, consider voting to have it fixed.
I had a line of VBA code that basically looked like this:
MyControls.Add(Factory.CreateMyControl(param1, param2))
Where Factory.CreateMyControl is just a sneaky way to allow the new instance of my class module being returned to have a constructor.
It was working without any issues for several weeks. Suddenly, it begins throwing the error object doesn't support this property or method which is baffling me because everything looks like it always has.
After stepping into and through the code, I finally narrowed it down to the line above, and found the issue. The issue was the pair of parentheses surrounding the parameter(s) for the Add function. When I changed the code to the following:
MyControls.Add Factory.CreateMyControl(param1, param2)
It worked just as it always had before the unexpected break.
I now understand that this is the basic syntax in VBA for calling Sub's with parameters: to simply include all parameters in a comma-separated fashion without any parentheses (unless you're setting a Function's return value to another variable or using it's value for some other purpose).
My real question is, why did this suddenly just stop working?
Is it a common occurrence using VBA in Office 2007 for code that once worked to break without warning?
Or could this have been caused by some kind of patch that happened without my knowledge?
With parentheses around, the Sub's parameters per default were passed ByVal instead of ByRef. Without parentheses around, the default is ByRef
Example:
Dim r As Range
Sub test(v As Variant)
MsgBox TypeName(v)
End Sub
Sub main()
Set r = Range("A1")
test r 'ByRef; TypeName is Range
test (r) 'ByVal; TypeName is not Range but the type of the content of A1
End Sub
We have an Excel-file with a large amount of VBA behind it. The Excel-file works just fine on my computer, but so far 3 of my colleagues (non-IT'ers) have gotten this error:
Runtime error 5:
Invalid procedure call or argument
The error is located on this line, and I don't see why it is throwing an error there because it's just a simple Set (and it works perfectly fine on my computer):
Set MyButton = Application.CommandBars("Attributions").Controls.Add(Type:=msoControlButton, Before:=10)
We all have the exact same Excel-file. I even sent them my version of the file, in which everything is running fine and no errors happen, but even when they open my version of the file they still get the above error on the above line!
What exactly could cause this? We all have Office 2013 and updates are installed automatically. The problem started about 2 weeks ago with one colleague and since this week I heard from two other colleagues that they have the same problem. One even said it suddenly worked again after he moved to a different desk (which I doubt would have an influence) but shortly after, it started getting the error again.
I have absolutely no idea why they get the error, or what might cause it. Seeing as we now all have the same version and they still get the error, I am thinking it might have something to do with Excel itself but that's just my idea.
Does this sound familiar to anyone here? Or does anyone know what might cause this, and how it can be fixed?
Edit: a while ago I checked on my colleagues their computers to see if the CommandBar was present, and it was. Even then the error still happened.
I suggest you to use a function that checks if there is a CommandBar in your Application like this:
Function IsCommandBarValid(cbName As String) As Boolean
Dim i As Long
IsCommandBarValid = True
For i = 1 To Application.CommandBars.Count
If (Application.CommandBars(i).Name = cbName) Then
Exit Function
End If
Next i
IsCommandBarValid = False
End Function
Now, You can use it to see that your user have that CommandBar in his or her Application, then make it like this:
If (Not IsCommandBarValid("Attributions")) Then
Call Application.CommandBars.Add(Name:="Attributions")
End If
' And after this add your code
Set MyButton = Application.CommandBars("Attributions").Controls.Add(Type:=msoControlButton, Before:=10)
Invalid procedure call or argument (Error 5)
Some part of the call can't be completed. This error has the following causes and solutions:
An argument probably exceeds the range of permitted values. For example, the Sin function can only accept values within a certain range. Positive arguments less than 2,147,483,648 are accepted, while 2,147,483,648 generates this error.
Check the ranges permitted for arguments.
This error can also occur if an attempt is made to call a procedure that isn't valid on the current platform. For example, some procedures may only be valid for Microsoft Windows, or for the Macintosh, and so on.
Check platform-specific information about the procedure.
For additional information, select the item in question and press F1 (in Windows) or HELP (on the Macintosh).
MSDN Source Article