I need to copy one module (Dictionary from Tim Hall - https://github.com/timhall/VBA-Dictionary) from one workbook to another programatically. For this I am using this piece of code:
Sub CopyMacrosToExistingWorkbook(SourceWB As Workbook, strModuleName As String, TargetWB As Workbook)
Dim SourceVBProject As VBIDE.VBProject, DestinationVBProject As VBIDE.VBProject
Set SourceVBProject = SourceWB.VBProject
Set DestinationVBProject = TargetWB.VBProject
Dim SourceModule As VBIDE.CodeModule, DestinationModule As VBIDE.VBComponent
Set SourceModule = SourceVBProject.VBComponents(strModuleName).CodeModule
Set DestinationModule = DestinationVBProject.VBComponents.Add(SourceModule.Parent.Type)
DestinationModule.Name = strModuleName
With SourceModule
DestinationModule.CodeModule.AddFromString .Lines(1, .CountOfLines)
End With
End Sub
On Windows everything is going well but on Mac (Office 365 version 16.29), the file, where I will import this Dictionary modul is not working. It cant be saved and it writes this Internal error to me:
The interesting thing is, that it is enough to copy this broken file to windows, open it, save it and return it back to Mac. But this is not sufficient solution to me.
I Have found, that if I will remove from Dictionary class module this piece of code, the "Internal Error" is not showing, but I cant use the module without this code:
Public Enum CompareMethod
BinaryCompare = VBA.vbBinaryCompare
TextCompare = VBA.vbTextCompare
DatabaseCompare = VBA.vbDatabaseCompare
End Enum
So I guess, that something its wrong with this Enum class. What or where could be the problem? I cant find it. Thanks for any help.
It is a long shot, but have you tried using Excel 16.28?
I have several macros that worked fine since 16.12, but after upgrading to 16.29 I got some errors and I couldn't understand what was wrong with the code.
I reverted to 16.28 and all good again.
Related
The following code works fine on latest Excel Windows and also on Excel 16.28 on Mac. But on the latest Excel for Mac (16.29 and 16.30) it generates this error: "Compile error: Method or data member not found" on the code line MyShape.Select.
I assume that there is an alternative way to do what I want that the compiler will approve of, but I don't know what it would be. As an alternative, I tried not selecting the shape and just referring to it, but then I get the same error but on the With MyShape.ShapeRange.Fill line.
Dim MyShape As Shape
'Other stuff
Set MyShape = ActiveSheet.Shapes.AddShape(msoShapeRectangle, 400, 400, DistanceBetweenCells, LineWidth)
MyShape.Select
With Selection.ShapeRange.Fill
'stuff here
End With
I'm hoping that a newer version of Mac Excel, when released, will revert to the older version in allowing the above, but assuming that's not the case, any workarounds?
I like that you're explicitly referring to ActiveSheet, kudos!
The problem is that ActiveSheet is an Object, wich means the compiler is helpless: ActiveSheet.Shapes compiles, but so will ActiveSheet.Shapess - even with Option Explicit specified. The entire expression is evaluated at run-time.
Let's fix that first:
Dim sheet As Worksheet
Set sheet = ActiveSheet
Now sheet.Shapes gets intellisense and compile-time validation, along with subsequent the .AddShape member call. You even get parameter tooltips as you type up the argument list!
What happens next is interesting: you declared MyShape as a Shape, but it's not a Shape you're looking at - the Shape class doesn't have a ShapeRange property, so... where does MyShape.ShapeRange come from then?
If you break execution (F9 to set a breakpoint) after the MyShape.Select call, and then bring up the immediate pane (Ctrl+G), the answer appears:
?typename(selection)
Rectangle
If you press Shift+F2 on the word Rectangle...
Dim myRectangle As Excel.Rectangle '<~ here
...the VBE doesn't seem to figure it out ("identifier under cursor is not recognized"). So we press F2, then right-click somewhere and tick the "Show hidden members" option - and sure enough, there it is:
So your code says "let's use the Shape interface", but works with a Rectangle object. And since that works, it means a Rectangle "is a" Shape: the two interfaces simply describe the same object through different lens, so either works... but then Shape.ShapeRange doesn't look quite right, since the Shape class doesn't define that member and that's the interface we explicitly said we were going to be working with.
If we want to invoke the members of Rectangle, we can - and since we're now showing hidden members in the object browser, intellisense displays the hidden types and members too. If the entire With block is early-bound, everything makes much more sense:
With myRectangle.ShapeRange.Fill
...and explains how the late-bound code off ActiveSheet would work at run-time to resolve the member call, and now the compiler needs a completely other strategy to compile the VBA code: maybe that could shake things up enough to get it to work, maybe it won't. At least the type ambiguities and ignored-by-compiler statements are all gone :)
The thing that's surprising here, is that you can't do that with VBA user code. If you made a MyShape class with a DoSomething method:
'#ModuleDescription "A metaphorical Shape"
Option Explicit
Public Sub DoSomething()
MsgBox TypeName(Me)
End Sub
And then a MyRectangle class that implements MyShape and exposes a member on its own public interface, that yields a MyShape object reference:
'#ModuleDescription "A metaphorical Rectangle"
Option Explicit
Private sh As MyShape
Implements MyShape
Public Property Get Thing() As Object
Set Thing = sh
End Property
Private Sub Class_Initialize()
Set sh = New MyShape
End Sub
Private Sub MyShape_DoSomething()
MsgBox TypeName(Me)
End Sub
And now in any standard module, we can test this - first, all early-bound, and we'll have a factory method that returns a MyShape, to mimick Shapes.CreateShape:
Public Sub WorksMaybe()
Dim r As MyShape
Set r = CreateRect
r.Thing.DoSomething
End Sub
Private Function CreateRect() As MyShape
Set CreateRect = New MyRectangle
End Function
So we run this (on Windows), and I expected, the code doesn't compile:
Late binding however...
Public Sub WorksMaybe()
Dim r As Object
Set r = CreateRect
r.Thing.DoSomething
End Sub
Private Function CreateRect() As MyShape
Set CreateRect = New MyRectangle
End Function
...works? Nope:
Are we not looking at a MyRectangle object? No: we're looking at the limits of late-binding polymorphism in VBA - we created a New MyRectangle, but to the compiler CreateRect returns a MyShape object reference. If we place a breakpoint on End Function, run it, and then type ?TypeName(CreateRect) in the immediate pane (Ctrl+G) when the breakpoint is hit, then despite the declared type being MyShape, the runtime type is clearly MyRectangle.
And it should work - but it doesn't. Error 438, member not found: the late-bound/run-time equivalent of the "method or data member not found" compile error.
And if we use the interface we really mean to work with...
Public Sub WorksMaybe()
Dim r As MyRectangle
Set r = CreateRect
r.Thing.DoSomething
End Sub
Private Function CreateRect() As MyShape
Set CreateRect = New MyRectangle
End Function
...then everything "just works":
Now, I'm not running this on a Mac, but this code compiles for me...
Option Explicit
Const DistanceBetweenCells As Long = 50
Const LineWidth As Long = 2
Public Sub WorksMaybe()
Dim r As Excel.Rectangle
Set r = CreateRect
r.ShapeRange.Fill.BackColor.RGB = vbRed
End Sub
Private Function CreateRect() As Excel.Shape
Set CreateRect = Shapes.AddShape(msoShapeRectangle, 40, 40, DistanceBetweenCells, LineWidth)
End Function
...and systematically raises run-time error 13 as soon as CreateRect returns and the Shape reference gets assigned to a Rectangle - error 13 being "type mismatch". In other words, a Rectangle is not a Shape (!!?!??). Proof, if we make CreateRect return a Excel.Rectangle, we now get the type mismatch error as soon as we try to assign the function's return value, and nothing makes sense anymore: there's something weird going on, and, well, I'm out of ideas - there doesn't appear to be any way to work early-bound with a Rectangle, despite what TypeName(Selection) claims the type is (the class is hidden/undocumented for a reason after all!), which... pretty much destroys all hope, especially if neither With Selection.Fill nor With MyShape.Fill work (it does work perfectly fine here on my Windows box though).
Sending a frown with some repro code through the user feedback feature should get you heard from the product team at Microsoft. I doubt they removed anything from anywhere - but it's not impossible something broke how interfaces are resolved, somewhere deep down in some seemingly unrelated piece of internal API :)
Ok, I think it is figured out. In Mac Excel version 16.29 Microsoft has deleted certain class members for, at least, Shapes. For instance "Fill" and "Select" are no longer available. So any code that refers to them will generate an error.
I'm not sure how extensive this is or any other ramifications, but I do know that the code works fine in version 16.28, and also that the member list in 16.28 shows both "fill" and "select" but not in 16.29. Thanks to Mathieu Guindon above for the input and also to a poster who deleted his thread - both of these people really helped. I've reported the issue to Microsoft.
Answer from Steve Rindsberg (MVP):
Iterate through the .ShapeRange collection:
For x = 1 To .ShapeRange.Count
With .ShapeRange(x)
'...stuff....
End With
Next
I've had a few similar weird ones on Mac where perfectly good code (on
Windows) errors or sometimes make the Mac app go POOF! And disappear.
Iterating the collections this way has been the fix.
I've tried searching a few different threads but wasn't able to get a solution.
My macro is going to transfer data from one sheet to another. I need to use the AVERAGE function to get the average of a range (on the other sheet)
I'm getting a RUN TIME ERROR 438 error and can't figure out why. I tried using Application.WorksheetFunction but this doesn't bear the correct result and works on the MAX function but not the AVERAGE. I saw a few solutions that involve creating a loop and variables, but I assumed a simple solution should be possible.
Code below:
Option Explicit
Sub Step8CopytoLean()
Dim wblean As Workbook
Dim wbmaster As Workbook
Set wblean = Workbooks("SLA Reporting Lean.xlsx")
Set wbmaster = Workbooks("SLA Reporting MasterFile.xlsx")
Workbooks("Lean.xlsx").Activate
Worksheets("Data").Delete
Workbooks("MasterFile.xlsx").Activate
Worksheets("Data").Copy After:=Workbooks("Lean.xlsx").Sheets("Summary")
Workbooks("Lean.xlsx").Sheets("Summary").Activate
wblean.Sheets("Summary").Range("E4").Value = wbmaster.Sheets("Summary").Range("K20")
wblean.Sheets("Summary").Range("F4").Value = wbmaster.Sheets("Summary").Range("M20")
wblean.Sheets("Summary").Range("E5:E6").Value = wbmaster.Sheets("Summary").Average(Range("K9:K11")) 'line with error
wblean.Sheets("Summary").Range("F5").Value = wbmaster.Sheets("Summary").Max(Range("M8:M11")) 'line with error
Modify the below and try:
Application.WorksheetFunction.Average(ThisWorkbook.Worksheets("Sheet1").Range("A1:A10"))
Something like this:
wblean.Sheets("Summary").Range("E5:E6").Value = Application.WorksheetFunction.Average(wbmaster.Worksheets("Summary").Range("K9:K11"))
wblean.Sheets("Summary").Range("F5").Value = Application.WorksheetFunction.Max(wbmaster.Worksheets("Summary").Range("M8:M11"))
I have an VBA code where I use many objects from PISDK, which I have to add as reference to my project.
I must explicitly declare the variables otherwise the code won't work. I don't know why. Excel throws an error ("types doesn't match") if I declare, for example, pt as object instead of PIPoint.
Here is part of my code:
Dim srv As Server
Dim pt As PIPoint
Dim pv As PIValue
Dim dt As New PITimeFormat
The problem is: when user doesn't have this reference installed, Excel gives me an compilation error, so it's impossible to catch and handle this error. Since this code runs on a user-defined function, as soon as the user opens the workbook, he gets stuck with compiling errors.
I must be able to catch this error.
I can't find documentations to fully implement late binding on this code. I don't know if it's really possible to do it. I know it could solve my problem.
Also, I know I could check if the reference is installed, thru:
thisworkbook.vbproject.references
But if the user doesn't allow access to the vbaProject object under Excel options, I am not able to do this.
Any idea?
I managed to solve my problem declaring everything as object and then using createobject afterwards.
The main problem doing this was using functions, like this one:
I have the function "arcValue". It takes three arguments:
arcValue(TimeStamp as PITimeFormat, Mode as RetrievelTypeConstants, Optional asynchStatus as PIAyncnStatus)
The way I use it doing early binding is:
dim pt as PIPoint
dim pv as PIValue
set pv = pt.data.arcValue("01/09/2014 17:00:00", rtInterpolated)
This works. But when I do:
Dim myPISDK As Object
Dim srv As Object
Dim pt As Object
Dim pd as Object
Dim pv as Object
Set myPISDK = CreateObject("PISDK.PISDK")
Set pv = CreateObject("PISDK.PIValue")
Set srv = myPISDK.Servers.defaultserver
Set pd = pt.DATA
Set pt = srv.PIPoints("piTAG")
Set pv = pd.ArcValue("01/09/2014 17:00:00", rtInterpolated)
It doesn't work. But why?
There were two problems:
First: When I use late binding (createobject) I don't have access to "rtInterpolated" constant, so I have to use its equivalent number.
Set pv = pd.ArcValue("01/09/2014 17:00:00", 3)
But this still doesn't work. So I had to do this to make it work:
Set pv = pd.ArcValue("01/09/2014 17:00:00", 3, Nothing)
And then everything started working. I don't know why, but VBA makes me write something do all parameters, even if they are optional.
This way, I am able to detect erros in runtime, so I used this code:
If myPISDK Is Nothing Then
piVerified = "Erro PI"
Exit Function
End If
Also, I had to remove all references (they are not used anymore, anyway) because it was causing malfunction on other parts of my code not related to this one when the references were missing.
You can use something like that:
Sub NotUsed()
Dim pt As PIPoint
End Sub
Function ReferenceCheck() As Boolean
On Error GoTo NoRef
pt = Acrobat.AV_DOC_VIEW ' PIPoint
ReferenceCheck = True
Exit Function
NoRef:
ReferenceCheck = False
End Function
Sub Test()
If ReferenceCheck Then NotUsed
End Sub
The function refer to a proprieties of the object. If the reference it's ok return true otherwise false.
In the phase of init you can check like that.
The sub NotUsed, don't create Error because not called...
In my sample I use the ADOBE Object ...
I have a VBA function within a spreadsheet which operates on another spreadsheet that is opened in an earlier stage of my macro. The macro used to work fine but just recently has started causing a 1004 error ("Unable to get RoundDown property of the WorksheetFunction class") when it runs.
I believe I understand what the error would be caused by (a problem running RoundDown) but I cannot see why it is getting triggered in my macro and the odd part is that when I go into Debug mode and step through the code in the VBE the error does not recur (despite nothing obviously changing).
Does anyone have a similar experience of this sort of error occuring inconsistently and know what I could do to resolve it?
I'm reasonably VBA/Excel-savvy, but any suggestions on further steps to diagnose it would be appreciated. I am wondering if there is some issue with the opened spreadsheet not being ready but I cannot see how.
The code is here. The error occurs on the line marked with a comment.
Public Function GetDatesA(sWorkbookname As String, sSheetname As String, sCell As String) As Variant
Dim vDateList() As Variant
Dim currentCell As Range
Dim n As Long
Set currentCell = Workbooks(sWorkbookname).Worksheets(sSheetname).Range(sCell)
n = 0
Do
If Trim(currentCell.Value) = "" Then
Exit Do
Else
ReDim Preserve vDateList(0 To 1, 0 To n)
vDateList(0, n) = WorksheetFunction.RoundDown(currentCell.Value, 0) 'error occcurs on this line
vDateList(1, n) = currentCell.Column
'Debug.Print currentCell.Value
End If
Set currentCell = currentCell.Offset(0, 1)
n = n + 1
Loop While currentCell.Column < XL_LAST_COLUMN
GetDatesA = vDateList
End Function
Other details are:
Excel version: 2010
File being opened resides locally on my C: drive; my macro is in a spreadsheet on the network
File format for both files is .xls (i.e. Excel 2003) - I don't have the option of changing this
Windows 7 (not that I think it would be relevant)
Two points I've tried already are:
Substitute a different worksheet function (e.g. Min(currentCell)) and that also causes the same problem
Having the file open already seems to stop the problem - I wonder if there is some way that the workbook which is being opened (rather than my main workbook with the macro in it) is not enabled for macros and this is interfering. But even if this is the cause I'm not sure how to get around it!
Any ideas?
This error occurs often when any argument passed to the worksheet function is not of the correct type or simply doesn't make sense.
For example, I've had this problem when calling WorksheetFunction.Asin with an argument bigger than 1. In your case, I'd guess currentCell.Value is a non-numeric value or one not according to your region settings regarding numbers.
Yes, the error message is really misguiding.
I got the "Unable to get * property of WorksheetFunction Class" error using Transpose, MMult,MDterm, and MInverse functions.
I was able to get my code to run by putting "Option Base 1" in the Declarations (before the actual code) section of the particular Module in the Editer.
Excel assumes "Option Base 0" which will add an extra row and column of empty cells. This will cause the error to occur and isn't immediately obvious to see.
I have come accross this before, and for me it was becase the criteria range made no sense, as Andre said above.
See example formula below:
.Cells(11, i).Formula = Application.WorksheetFunction.CountIfs(Sheets("Sheet1").Range("AC8:C" & n), "S")
Have a look at the Range... it makes no sense. Amended the range from "AC8:C" to "AC8:AC" and it will work perfectly
Reference Excel VBA to SQL Server without SSIS
After I got the above working, I copied all the global variables/constants from the routine, which included
Const CS As String = "Driver={SQL Server};" _
& "Server=****;" _
& "Database=****;" _
& "UID=****;" _
& "PWD=****"
Dim DB_Conn As ADODB.Connection
Dim Command As ADODB.Command
Dim DB_Status As Stringinto a similar module in another spreadsheet. I also copied into the same module
Sub Connect_To_Lockbox()
If DB_Status <> "Open" Then
Set DB_Conn = New Connection
DB_Conn.ConnectionString = CS
DB_Conn.Open ' problem!
DB_Status = "Open"
End If
End SubI added the same reference (ADO 2.8)
The first spreadsheet still works; the seccond at DB_Conn.Open pops up "Run-time error '-214767259 (80004005)': [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified"
Removing the references on both, saving files, re-opening, re-adding the references doesn't help. The one still works and the other gets the error.
?!?
I observed the same error message and in my case nothing had changed. I wondered if my odbc driver needed to be reinstalled (based on what i read online). In any case, restarting excel did the trick. Sometimes the solution is much simpler. :-)
When the error pops up, check your "locals" windows to see what the CS holds. View > Locals Window
Problem: Your constant isn't found by the compiler.
Solution: With the constant being located in a separate module, you'll need to set it as Public for the other code to see it.
Proof:
In order to prove this theory you can do the following:
Open a new Excel spreadsheet
Go to the VBA designer and add a new module
In this module put:
Const TestString As String = "Test String"
Then add the following code to ThisWorkbook:
Public Sub TestString()
MsgBox (TestString)
End Sub
After adding this return to the workbook and add a button, selecting "TestString" as the macro to run when clicked.
Click the button and a blank message box will appear.
Go back to the VBA designer and change the const in Module1 to Public
Click the button on the spreadsheet and you should now see "Test String" in the message box.
I realize that this question is really old. But for the record I want to document my solutions for the error here: It was a data related error in a spreadsheet! A column was formatted as date and contained a value 3000000. Changing the Format to numbers solved the Error 80004005.