Difference between Excel.ThisWorkbook and just ThisWorkbook? - excel

I have some VBA code that ran fine in Excel at my desk at work but at home it's crashtastic. Turns out all I had to do was change
Set shtObj = ThisWorkbook.Sheets(1)
to
Set shtObj = Excel.ThisWorkbook.Sheets(1)
Anyone know why? Our organization has just moved to a SharePoint platform, which I suspect is causing all manner of voodoo to creep up, but I'm just guessing.

Does it work if you change it back to ThisWorkbook?
I suspect it will, and the reason would be because the VBA recompiled itself (and didn't compile properly the first time - hence the propensity to crash).
Recompilation occurs when the version details embedded in the file differ from the version of Office/VBA in use, or there's a change from 32 to 64 bit Office. Editing the line is enough to recompile the line, so adding Excel. before ThisWorkbook was enough to make it recompile. Removing Excel. before ThisWorkbook should force it to recompile again.
The only other thing it might be is if there's a variable named ThisWorkbook, but then I'd expect you to get error 91, "Object variable or With block variable not set", or some other error, but not a crash.

ThisWorkbook is a global-scope Workbook object that you can use to refer to the workbook instance that contains the very VBA code that you're looking at.
So in theory, an unqualified ThisWorkbook is exactly the same object as Excel.ThisWorkbook or Application.ThisWorkbook.
Proof:
Sub Test()
Debug.Print ObjPtr(ThisWorkbook), _
ObjPtr(Excel.ThisWorkbook), _
ObjPtr(Application.ThisWorkbook)
End Sub
Outputs 3 times the same pointer address.
Excel.ThisWorkbook is a member (Property Get) of the hidden Excel._Global module, and Application.ThisWorkbook is a member (Property Get) of the Excel.Application class.
Not sure what's up with your file, but there's not supposed to be any difference between the two.

This appears to be a bug in my particular user/profile. Others are now using the code/workbook with no reports of trouble. Yay!!?

Related

VBA EXCEL VBA How to enable (check) specific Type Library in Tools/References programmatically?

That's basically my question. Doing googling didn't return anything that I am looking for, but basically I am running SOLIDWORKS from Excel and for that I need "sldworks 2016 Type Library" and "SOLDIWORKS 2016 Constant Type Library" to be enabled. Of course you'd say to do it manually, BUT my program is being run both, by people with and without Solidworks installed and if a user doesn't have SOLDIWORKS on their PC - the entire thing won't even run. So I am looking to enable and disable those two type libraries upon necessity in the code.
Could, someone, please help me?
P.S. I am not looking for any workarounds etc.
BUT my program is being run both, by people with and without Solidworks installed and if a user doesn't have SOLDIWORKS on their PC - the entire thing won't even run.
Is this what you are trying? The below code will first try to bind with an open instance of SOLIDWORKS. If it is not open, then it will try to create a new instance. Obviously if SOLIDWORKS is not installed then the CreateObject will fail but the code will not crash because of On Error Resume Next. Finally check if objSolid is not nothing. This is late binding and you do not have to set any references.
Dim objSolid As Object
'~~> Establish an SOLIDWORKS application object
On Error Resume Next
Set objSolid = GetObject(, "SldWorks.Application")
'~~> If not found then create new instance
If Err.Number <> 0 Then Set objSolid = CreateObject("SldWorks.Application")
Err.Clear
On Error GoTo 0
If objSolid Is Nothing Then
MsgBox "SOLIDWORKS not installed"
Exit Sub
End If
'
'~~> Rest of your code
'
EDIT
You cannot say Solidworks is not properly documented without putting in the right efforts to search. It took me less than 30 seconds to find this SOLIDWORKS Example of Late Binding. Of course their code will fail if the user doesn't have SOLIDWORKS and that is because they have not done proper error handling. My answer above does that for you.
Their website has all the information that you need. You just need to put in the right efforts to search. As I mentioned in the chat below, when you convert the code into late binding, you will have to search for the value of those constants. No one will give them to you in a platter. :) You can either search Google with swDocPART Constant value or as #FunThomas pointed out, type ?swDocPART in Immediate Window to get the value when the reference to SOLIDWORKS has been established.

Name conflict error pops when creating reference at runtime, but not at design time

I'm having this staggering problem in creating a reference at runtime.
In short: I have an addin referenced in another addins, all created by myself and all working fine (except for some annoying popup which appears on loading Excel). As a workaround to this annoyance, I removed the existing reference to create it later, at runtime. But when I try creating the reference, it returns an "Name conflicts with existing module, project, or object library" error popup, and the reference is not created--which makes no sense, because if I create the reference at design time it works perfectly. There is no module or project with repeated name.
Now explaining a little further.
I have four kinda-complex Excel applications I'd had developed for my job. Each one is a VBA project, distributed as Excel Addins (.xlam).
Additionally, I have a fifth project with functions common to the other four. This fifth project is referenced in the other ones (via Tools -> References). So now, all I have to do is to call them as any API outside referenced function (commonProject.Function (arg1, arg2, arg3 etc)).
Unfortunately, I had some problems with a popup message (here) and the workaround seems to be referencing the fifth project in the other ones at runtime.
In order to do this, I uninstalled three of the other four Addins, remaining only one, and used the following code in its Workbook_Open event:
Private Sub Workbook_Open()
Dim strNamePath As String
Dim bolAddinIsRefered as Boolean
Dim oRef As Variant
strNamePath = "c:\etc\etc\etc\Filename.xlam"
For Each oRef In ThisWorkbook.VBProject.References
If oRef.FullPath = strNamePath Then bolAddinIsRefered = True
Next oRef
If bolAddinIsRefered = False Then ThisWorkbook.VBProject.References.AddFromFile strNamePath
End Sub
The problem is, when I used to create the reference at design time by hand, it worked mostly fine (except for the annoying popup I'm now trying to circumvent). But when I try creating the Reference at runtime, it returns an "Name conflicts with existing module, project, or object library" error popup, and the reference is not created.
I have verified the module and worksheet names and there is no duplicated one.
Does anyone have any idea how to prevent this error?
it seems after one and a half day struggling with a problem, when you ask the question on StackOverflow the solution just pops in your mind.
I'd already tried to change both projects names, even internal functions or subs resembling the same name. But I had not looked upon the FILE NAME!
As my solution is called Sisyphus, the filenames of all addins started with "Sisyphus"--"Sisyphus Common Functions.xlam", "Sisyphus DocMerge.xlam" etc.
The problem was VBA was comparing the first word in filename. I removed spaces and it worked well. Now my filenames are "SisyphusCommonFunctions.xlam", "SisyphusDocMerge.xlam" etc. and the referencing in runtime works all right.
Thank you for your time, I'll let this Question and Answer here, because it can be usefull to someone.

Workbook Subroutines cannot be called directly by name anymore from VB6

I have a vb6 program that calls Macros from an Excel file.
Until recently it worked fine (for years), but now it throws an error.
We get a runtime 438 "Object doesn't support this property or method" error.
As an example you can use this simple vb6 program:
Set App = CreateObject("Excel.Application")
Set wrkbook = App.Workbooks.Open(fileName)
App.visible = True
wrkbook.Test
The above code doesn't work anymore.
Instead, if we replace the last line with this:
wrkbook.Application.Run "ThisWorkbook.Test"
it works.
The Excel reference used for this, was "Microsoft Excel 16.0 Object Library"
This has been tested against Excel 2010, 2013, Excel365 with the same results.
Also security settings are all set off in Excel.
Before changing my entire codebase and use Application.Run, I would know why this is happening.
Also using Application.Run has also some downsides, like calling both private & public subs and exceptions thrown are not propagated back to vb6.
Are there other considerations for using Application.Run?
Did Microsoft changed something lately (Scurity update), or am I doing something wrong?
I found the problem, thanks to #UuDdLrLrSs comment.
Problem was the use of early binding.
All Excel objects should use late binding.
More specific, the workbook should be declared as object:
Dim wrkbook As Object 'New Excel.Workbook
Otherwise it cannot recognize/find your Macro method.

Cannot run common module in xlam file as macro is disabled

VBA / Excel - 2007
I want to create one (possibly many) .xlam file(s) to hold common modules accessible across projects. Along the way I have received a number of errors but through the creation of a "mickey-mouse" scenario I have boiled it down to one error condition (as shown in actual result):-
I have seen several problems reported here related to this which in the end have either not been answered or the solution has not quite hit the mark
As a precursor to this I was able to put my common module into another .xlsm project and successfully execute it by using a reference to that called project. However it would be preferable not to create a workbook for the sole purpose of housing common modules
'Caller VBAProject (Caller.xlsm):
Public Sub Caller()
Dim i As Integer
i = 0
'*** Error in line below***
Application.Run "C:\Users\IT\AppData\Roaming\Microsoft\AddIns\Common.xlam!Test", i
End Sub
'Called Test (Common.xlam) -- different project, obviously
Function Test(ByRef i As Integer) As Boolean
If i = 0 Then
Test = False
Else
Test = True
End If
End Function
Actual Result
Run-time error '1004':
Cannot run the macro
'C:\Users\IT\AppData\Roaming\Mirosoft\AddIns\Common.xlam!Test'
The macro may not be available in this workbook or all macros may
be disabled.
Steps Undertaken (in Excel Options)
Trust Center
a) Macro Settings
-- both i) and ii) (at different times)
i) Disabled all macros with notification
ii) Enabled all macros
iii) set Trust access to the VBA project object model
b) Add-ins -- left as default ie no option ticked
c) Trusted Locations -- have added the following
C:\Users\IT\AppData\Roaming\Microsoft\AddIns\
Add-Ins
As an Active Application Add-in I have
C:\Users\IT\AppData\Roaming\Microsoft\AddIns\Common.xlam
Can anybody please tell me what I might have missed?
So just to summarise I don't have a direct answer to my question thus far, that is how to avoid the 1004 error when calling a macro within a .xlam file. However, I do have a more than adequate alternative which is to import the common file into a different module within the same project. What I'm realising is that as I write this it isn't an import at runtime or late binding as Zac implied. I'm not sure I'm too worried though (at least at the moment).

VBA Dim Object error

If I Run
Sub test()
Dim Template_Excel_Instance As excel.application
Set Template_Excel_Instance = CreateObject("excel.application")
End Sub
my code breaks with an error "Automation Error, Library not registered"
If I run
Sub test()
Dim Template_Excel_Instance As object
Set Template_Excel_Instance = CreateObject("excel.application")
End Sub
It runs fine. Is there any way to fix this? Reason I ask is that this issue only affects one PC, despite having the same references as all other PCs. The first error is not coming up anywhere else
Does that PC have a different version of Excel?
The problem is with As Excel.Application. If you don't have the appropriate reference defined, then the VBA compiler will not recognise the type. Yes, VBA does have a compilation step. If you do have the reference defined, then this is sensitive to the application version (just the major part of the application version I think), so is therefore inherently non-portable.
In your latter example, you are using late binding, so only COM object registration is required, not any specific library to be added to your project. For portability, this is the way to go.
Firstly, have you tried repairing the install?
Secondly, is there a reason you are instantiating a second instance of Excel?
Thirdly, let's get a grip on what is happening, please run this code and report back.
Option Explicit
Sub TestWhatVersionDoesCreateObjectReturn()
Dim obj As Object
Set obj = CreateObject("Excel.Application")
Debug.Print obj.Version
End Sub
Sub TestWhatOtherVersionsAreCreatable()
Dim lLoop As Long
For lLoop = 7 To 16
Dim obj As Object
Set obj = Nothing
On Error Resume Next '///set break on unhadnled errors
Set obj = CreateObject("Excel.Application." & CStr(lLoop))
On Error GoTo 0
If Not obj Is Nothing Then Debug.Print obj.Version
Next
End Sub
Also, look for multiple installations of Excel. The code at this blog page will read your registry and write the results to an Excel worksheet. You say you have repaired the install but there might be other Excel installations interfering. The code in that blog will highlight multiple Excel installs.
Ok, from your feedback you say all the Excel libraries version return 14, implying no multi version installs. Hmmm, we ought to consider that actually the library that error is complaining about isn't Excel but a dependency.
Other possible leads
Social MSDN - automation error. Library not registered - solved by cleaning registry of legacy "Microsoft.Office.Interop.Excel" keys

Resources