VBA cannot create new CXMLHTTPHandler - excel

I'm currently working on late binding due to some issues with macros not working in Excel 2013 when they worked fine in 2010. Obviously, 2010 utilizes 14.0 object library whereas 2013 uses 15.0.
Dim myHttpRequest As Object
Dim myHttpHandler as Object
Set myHttpRequest = CreateObject("MSXML2.XMLHTTP")
Set myHttpHandler = CreateObject("CXMLHTTPHandler")
This yields an ActiveX cannot create object error. I've spent over a day looking into this.
Is there some sort of resource that has to be added in order for these objects to work? Do these objects even exist in Excel's 15.0 Object Library?
I'm completely at a loss of what to do as this usually works.

I strongly suspect, looking at this post http://dailydoseofexcel.com/archives/2006/10/09/async-xmlhttp-calls/
that you are dealing with a user defined class. If that is the case you need to copy across that class, follow the steps outlined in the link, and then simply create a new instance of that class, without need for late binding as no library is involved.
An additional step is to convert code in that class to late bound as required if other libraries are early bound referenced.
As per that link:
Dim MyXmlHttpHandler As CXMLHTTPHandler
' Create an instance of the wrapper class.
Set MyXmlHttpHandler = New CXMLHTTPHandler
The additional steps quoting from that link are:
Export and remove the CXMLHTTPHandler class to a known directory
Open that file with notepad
Find the OnReadyStateChange sub, and add this text after the signature:Attribute OnReadyStateChange.VB_UserMemId = 0
Save, close and reimport the class module into the project

Related

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.

Variable With Multiple Types

I created a couple years ago a few Excel spreadsheets which have VBA macros using a 3rd party API.
That API has been updated, but the changes are so minor that the only things that changed for my spreadsheets are a couple of variable types.
The old version was using those variable types :
Dim ETABSObject As ETABS2016.cOAPI
Dim SapModel As ETABS2016.cSapModel
Set ETABSObject = GetObject(, "CSI.ETABS.API.ETABSObject")
Set SapModel = ETABSObject.SapModel
While the new version uses those types:
Dim ETABSObject As ETABSv17.cOAPI
Dim SapModel As ETABSv17.cSapModel
Set ETABSObject = GetObject(, "CSI.ETABS.API.ETABSObject")
Set SapModel = ETABSObject.SapModel
That's literally the only thing that is changing for me, replacing one by the other allows me to use my old spreadsheet with the new API.
Here's my problem: the software that was using the old API (ETABS16) is still being used as well, and I would like to avoid having to duplicate all my spreadsheets (creating a version for ETABS2016 and one for ETABSv17).
The variable SapModel is extensively used throughout the code, so having a SapModel16 and a SapModel17 variables is not really an option here.
Is there a way to declare SapModel in such a way that it would work for both versions of the API?
I tried declaring it as a Variant and then either setting it as ETABSObject2016.SapModel or ETABSObjectv17.SapModel using on error GoTo, but it didn't work. The on error Goto was able to identify which of the two versions of the API was being used, but the spreadsheet would be stuck at the first use of SapModel.

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.

Vba Excel Trust access to the VBA project model

I need to execute the following lines of code for my client, the problem is that in order to access them I must have activated a certain option within the project, is there any way to avoid that?
Application.VBE.ActiveVBProject.References.AddFromFile "C:\Windows\System32\mshtml.tlb"
Application.VBE.ActiveVBProject.References.AddFromFile "C:\Windows\System32\msxml6.dll"
They are a couple of libraries necessary for the execution of my Macro.
The macro that I am running is as follows:
Sub GetCurrentDate()
Dim S$
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", "http://www.fechadehoy.com/venezuela", False
.send
S = .responseText
End With
With CreateObject("htmlfile")
.body.innerHTML = S
MsgBox .getElementById("fecha").innerText
End With
End Sub
libraries needed for the execution of my macro
Microsoft XML, v6.0
Microsoft HTML Object Library
in order to access them I must have activated a certain option within the project, is there any way to avoid that?
The option isn't within the project, it's at the host application level (Excel): whether programmatic access to the VBIDE API is trusted or not is an important part of macro security settings, and no, there isn't any way around it.
Any programmatic way to circumvent this security setting would make a huge gaping security hole every macro-virus in the world would jump into.
But you don't need to do this. Your code is creating instances of classes located in these libraries using CreateObject, not the New operator: the references are not needed.
With CreateObject("MSXML2.XMLHTTP") ' returns an Object/XMLHTTP reference
.Open ... 'late-bound member call (no intellisense, no compile-time validation)
'...
End With
CreateObject uses the specified ProgID string to find the registration in the Windows Registry, locate the type library, create an instance of the type, and return a reference to that object - everything is resolved at run-time (hence "late" bound), and as long as the ProgID exists in the registry and there's no typo in the late-bound code (Option Explicit can't save you from those), everything "just works".
If you used the New keyword instead...
With New MSXML2.XMLHTTP ' returns an XMLHTTP reference
.Open ... 'early-bound member call (with intelilsense and compile-time validation)
'...
End With
This couldn't be compiled without a project reference to the MSXML2 library.

Excel VBA Compile Error

We have an excel spread sheet which we use and it works for most machines but bombs out with 'Compile Error in Hidden Module - General' on others, and the reason appears to be due to missing References.
We check that Macros is enabled but still doesn't help.
Since we protect this excel spread sheet with a password, we don't want to be giving this password out to our users to check the References, and wondered if anyone had any idea how I can add VBA code to check whether the References required for the excel spread sheet is there and if not then bring up a message box to advise the user.
The References we use are as follows:
Visual Basic For Applications
Microsoft Excel 11.0 Object Library
Microsoft Forms 2.0 Object Library
Microsoft Windows Common Controls 5.0 (SP2)
Alternatively, if anyone has any other suggestions on how to go about this problem, that would be great.
The only reference you have listed that could possibly be missing is the common controls. The rest are default in every version of Excel. The Forms one is only if you have a userform or explicitly set it, but that's not your problem. Common Controls is your problem. It doesn't ship with Office anymore. If you have Visual Studio or VB6 you probably have it. Or an old version of Office like XP Developer Edition.
Anyway, you can check for the existence of the OCX file in the System folder. I don't think it's required to be in that folder, but I've never seen it anywhere else.
It's been quite a while since I've seen a reference to 5.0, so I included how to find 6.0 in the code below. Check to make sure you know what version you're using.
In a standard module:
Private Declare Function GetSystemDirectory Lib "kernel32" Alias "GetSystemDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
Public Function HasCommonControl() As Boolean
Dim sFolder As String
Dim lReturn As Long
Const lSIZE As Long = 255
Const sDLLNAME As String = "COMCTL32.OCX" 'For windows common control 5.0
'Const sDLLNAME As String = "MSCOMCTL.OCX" 'For windows common control 6.0
sFolder = Space(lSIZE)
lReturn = GetSystemDirectory(sFolder, lSIZE)
sFolder = Left$(sFolder, lReturn)
HasCommonControl = Len(Dir(sFolder & Application.PathSeparator & sDLLNAME)) > 0
End Function
Having said all that, why are you using common controls? If it's for a treeview on a userform, then check out this all-vba treeview
http://www.jkp-ads.com/articles/treeview.asp
Since jkp wrote that, I haven't used common controls. So few normal-people PCs have it installed that it's just a pain.
Depending on a reference to a specific Excel or other component version is one possible problem. Switching to late binding would solve that problem, so long as you're careful not to use any commands/objects/methods/properties that are supported in one version and not another.
Following up on RowanC's link (good choice), you can add a reference to Excel, for example and write your code like so:
Dim xlWks as Excel.Worksheet
'Dim xlWks as Object
Once everything's debugged, remove the Excel reference and change the declarations to:
'Dim xlWks as Excel.Worksheet
Dim xlWks as Object
That gives you the benefit of intellisense while coding/debugging but removes the dependency on a specific version of Excel later.
Might be mistaken, but IIRC the Common Controls component is part of Visual Basic, not Office, so unless you distribute it and register it along with your app, it might not be present on some systems.
To try late binding, which doesn't need the references setup (although it may have a performance hit, and it will mean that autocomplete doesn't work in your code) instead of calling excel in the following way:
Dim oExcel As Excel.Application
Set oExcel = CreateObject("Excel.Application")
try calling it this way, and drop the reference to the excel object model.
Dim oExcel As Object
Set oExcel = CreateObject("Excel.Application")

Resources