Excel Interlop Error on New Server after migration - excel

I recently migrated a windows service to a new server for my company. This service reads data from a sql table and builds an excel document from it, using a template. Unfortunately, even with all of the same code, I am getting a new error when I try to execute the service.
Exception from HRESULT: 0x800A03EC
Stack Trace:
at Microsoft.Office.Interop.Excel.Workbooks.Open(String Filename, Object
UpdateLinks, Object ReadOnly, Object Format, Object Password, Object
WriteResPassword, Object IgnoreReadOnlyRecommended, Object Origin, Object
Delimiter, Object Editable, Object Notify, Object Converter, Object
AddToMru, Object Local, Object CorruptLoad)
This is the code which executes leading up to the error:
Dim xlApp As Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkSheet As Excel.Worksheet
xlApp = New Excel.ApplicationClass
xlWorkBook = xlApp.Workbooks.Open(System.AppDomain.CurrentDomain.BaseDirectory() & strTemplatePath)
The old server is running Microsoft Windows Server 2003 SP2 and the new server is running Microsoft Windows Server 2012 Datacenter. Both have Excel 2003 installed.
What I've tried:
Prayer
Providing permissions to the user which executes the app
Setting my CurrentCulture to "en-US"
Moving the template file to c:\Templates in case of a weird issue with the program files directory
Matching the two server's settings for the "Microsoft Excel Application" within dcomcnfg and mmc-32 (neither is set to "interactive user")
Replacing the currently utilized Excel Interlop file (11.0.8161.0) with the newest version I could find (15.0.4795.1000)
Any help would be appreciated. Thanks
In response to comments:
Inspecting BaseDirectory and strTemplatePath yield a valid path to my excel workbook. If I paste it directly into the explorer address bar the file opens.

I found the answer, which turned out to be super random at the following url:
https://www.codeproject.com/Questions/574791/COMplusExceptionplushresultplus-x-a-ecplusatplu
All I had to do to get this to start working was create the following directory:
C:\Windows\SysWOW64\config\systemprofile\Desktop

Related

(Excel VBA) Outlook Application CreateItem Fails in Certain Situation

In our company .xlsm, I'm using "standard" macro to send e-mails via Outlook:
Dim olApp As Object, olMail As Object
On Error Resume Next
Set olApp = GetObject(, "Outlook.Application")
If olApp Is Nothing Then
Set olApp = CreateObject("Outlook.Application")
End If
On Error GoTo 0
Set olMail = olApp.CreateItem(0)
With olMail
'properties, methods, events
End With
The thing is, it works on all company computers except for one. On this one:
If Outlook client is closed when running macro, everything works fine;
If Outlook client is opened when running macro, it returns Error '91' (Object variable not set) on Set olMail = olApp.CreateItem(0).
What could be the cause?
Your Excel Application must be run under the same security context with Outlook running to be able to get the running instance.
If Outlook client is opened when running macro, it returns Error '91' (Object variable not set) on Set olMail = olApp.CreateItem(0).
If you run Excel with admin privileges you need to run Outlook as well with admin privileges to be able to connect them together.
Also you may try to use the early-binding technology instead of late-binding one. For that you need to add an Outlook COM reference in the Excel COM References dialog (see the VBA editor). Read more about that in the Using early binding and late binding in Automation article.

Accessing the ‘Body’ of an Outlook email from Excel VBA

The following Excel VBA code stopped working after upgrading from Office 2010 on Windows 7 to Office 365 on Windows 10.
Sub readbodytest()
    Dim OL As Outlook.Application
    Dim DIB As Outlook.Folder
    Dim i As Object 'Outlook.ReportItem
    Dim Filter As String
    Set OL = CreateObject("Outlook.Application")
    Set DIB = OL.Session.GetDefaultFolder(olFolderInbox)
    Const PR_SENT_REPRESENTING_EMAIL_ADDRESS = "http://schemas.microsoft.com/mapi/proptag/0x0065001E"
    Filter = "#SQL=" & _
        """" & PR_SENT_REPRESENTING_EMAIL_ADDRESS & """ ci_phrasematch 'mailer-daemon' OR " & _
        """" & PR_SENT_REPRESENTING_EMAIL_ADDRESS & """ ci_phrasematch 'postmaster' OR " & _
        "urn:schemas:httpmail:subject ci_phrasematch 'undeliverable' OR " & _
        "urn:schemas:httpmail:subject ci_phrasematch 'returned'"
    For Each i In DIB.Items.Restrict(Filter)
        Debug.Print i.Body '<< Code fails here
    Next
    Set i = Nothing
    Set DIB = Nothing
    Set OL = Nothing
End Sub
In Excel, it returns
runtime error -2147467259 “Method 'Body' of object '_MailItem' failed”
The code will work when run directly in Outlook VBA, but not when run externally.
The purpose of the code is to do a bulk review of returned mail items, match information in the body of the email to a record on a database, and update the database to record the failure.
Looking to see if anyone has any suggestions before I re-write the code to run in reverse (from Outlook VBA to Excel; instead of Excel trying to retrieve from Outlook).
It makes sense to use the Logon method of the Application class which logs the user on to MAPI, obtaining a MAPI session. Here is what MSDN says:
Use the Logon method only to log on to a specific profile when Outlook is not already running. This is because only one Outlook process can run at a time, and that Outlook process uses only one profile and supports only one MAPI session. When users start Outlook a second time, that instance of Outlook runs within the same Outlook process, does not create a new process, and uses the same profile.
If Outlook is not running and you only want to start Outlook with the default profile, do not use the Logon method. A better alternative is shown in the following code example, InitializeMAPI: first, instantiate the Outlook Application object, then reference a default folder such as the Inbox. This has the side effect of initializing MAPI to use the default profile and to make the object model fully functional.
Second, I'd suggest checking the item type before accessing any properties. Not all items may contain such properties.
Another possible pitfall and most probably that is a security issue when dealing with the Outlook object model. When you try to access any sensitive property Outlook may trigger a security issue (it may be an error in the code or UI guard/prompt). "Security" in this context refers to the so-called "object model guard" that triggers security prompts and blocks access to certain features in an effort to prevent malicious programs from harvesting email addresses from Outlook data and using Outlook to propagate viruses and spam. You can use the following ways to bridge the gap:
The Security Manager for Outlook component allows to turn prompts off/on at runtime.
Use the low-level code which doesn't generate security prompts. Or any other third-party wrappers around that API (for example, Redemption).
Deploy a group policy to avoid security prompts.
Running an up-to-date antivirus software.

User Defined Functions (UDF) from Access Query to Excel using VBA OpenRecordset failed - Undefined Function

How do I get the results of a query from Access into Excel if it has a UDF?
I receive the following error: "Run-time error '3085': Undefined function 'XXXX' in expression". The error occurs when opening an (access query) recordset from Excel VBA. The query being opened has a user defined function (UDF) which is triggering the error.
The code is in Excel Office 365. The query is in Access Office 365.
I have successfully utilized the query being called (and others with the UDFs) for about twelve months, and "suddenly" it is not working any more. I have googled and tested many options with no success.
Most threads say it can't be done, or to not use a udf but try a built-in that works. I am challenging those responses because it has worked previously. The main udf I am using is one called "iMax" which is written about in other posts. It functions like max() in Excel. (No max(x,y) function in Access)
I have also seen threads that suggest executing this in two steps: 1 - change the query to a make table query. 2 - pull the table results into Excel. While I could maybe get away with this (after much rework), it would result in me making many temporary tables with thousands and thousands of rows and doesn't seem very slick.
I have compiled vba and compacted the db with no impact to my problem.
As a long shot I created a dummy database with a simple udf public function that returned the number 1, a simple query that returns three records and a field for the function results. This gets the same error when pulling into Excel.
Sub RunQuery()
Dim MyDatabase As dao.Database
Dim qdf As dao.QueryDef
Dim rs As dao.Recordset
Dim qryname As object
Dim SheetName As String
Set MyDatabase = DBEngine.OpenDatabase _
("SomePath\SomeFilename.accdb")
For Each qryname In Range("SomeRange")
Set rs = MyDatabase.OpenRecordset(qryname) '<<<ERROR IS HERE
SheetName = "SomeSheetName"
With Sheets(SheetName)
.ListObjects(SomeTableName).DataBodyRange.Rows.ClearContents
.Range("A2").CopyFromRecordset rs
End With
Set rs = Nothing
Set qdf = Nothing
Next qryname
End Sub
For all queries in the For loop that do not have a udf, the results are pulled and dumped into a series of tables in Excel. Any query with a udf errors at the "Set rs = Mydatabase.OpenRecordset(qryname)
If you run the query within an Access application session, as Gustav suggested, the expression service can handle the UDF in your query.
Here is a quick tested Excel VBA snippet which pulls data from a query which includes a UDF:
Const cstrDbFile As String = "C:\share\Access\Database2.accdb"
Dim objAccess As Object
Dim rs As Object
Dim ws As Worksheet
Dim strSelect As String
Set objAccess = CreateObject("Access.Application")
objAccess.Visible = True ' useful during testing '
objAccess.OpenCurrentDatabase "C:\share\Access\Database2.accdb"
strSelect = "SELECT ID, DummyFunction('a', '', 'c') FROM Dual;"
Set rs = objAccess.CurrentDb.OpenRecordset(strSelect)
If Not rs.EOF Then
Set ws = ThisWorkbook.Sheets("Sheet1")
ws.Range("A1").CopyFromRecordset rs
End If
rs.Close
objAccess.Quit
Most threads say it can't be done,
and they are right.
Your only option is to use automation to open an instance of Access and, within this, run the query.
Well, as noted, most are saying this should not work.
However, if you are 100% sure it was and did work at one time?
You need to set the "sandbox" mode of the JET (now ACE) database engine.
The expression service normally does not allow evaluation of VBA functions as a security setting to prevent SQL injection, or code running outside of Access to allow SQL to run + call VBA functions. At one time, this feature did default to "on", but now the default is set to access only.
You have to set the folder where Access application as trusted. This should allow the VBA functions to now work. so, make sure you set the folder as trusted.
If the location (folder) where your access application is NOT trusted, then Access will use sandbox mode, and VBA in the SQL will not run.
If the location is trusted, THEN access uses the registry setting on your computer.
My bets are that the location is not trusted - so you always get sandbox mode for SQL in Access.
If you are 100% sure that the folder location is set as trusted in Access, and you still receive the errors, then you have to change the registry setting for Access "sandbox" mode.
The setting in the registry is outlined here:
https://support.office.com/en-us/article/Turn-sandbox-mode-on-or-off-to-disable-macros-8CC7BAD8-38C2-4A7A-A604-43E9A7BBC4FB
The registry settings are:
for x32 bit access:
Software\Microsoft\Office\ClickToRun\Registry\Machine\Software\
Wow6432Node\Microsoft\Office\16.0\Access Connectivity Engine\Engines
The above is for Office 2016
14 = 2010
15 = 2013
16 = 2016
The key value for sandbox mode is:
0 to 3
0 Sandbox mode is disabled at all times.
1 Sandbox mode is used for Access, but not for non-Access programs.
2 Sandbox mode is used for non-Access programs, but not for Access.
3 Sandbox mode is used at all times. This is the default value, set when you install Access
So, from above, you want a setting of 0.

Accessing outlook message body with excel vba: error 287

We have a lot of emails saved to a folder on the file system to be processed by extracting text from the message bodies. Office 2010.
Dim app As Object
Dim msg As Object
dim msg_body as string
Set app = New Outlook.Application
Set msg = app.CreateItemFromTemplate("c:\path\to\message.msg")
msg_body = msg.body
This code works fine on my laptop however when I use it on the work network it gives error '287'.
While debugging I noticed that I can view msg msg.display and even change the body with msg.body = "some text". However I cannot read the message body. Also tried msg.HTMLbody which could not be read.
The most probable cause is your company's policies.
Check this registry key to solve the SaveAs (change the 16 to your office version).
hkcu\software\policies\microsoft\office\16.0\outlook\security\promptoomsaveas
You can change the value to 2, or ask your system administrator to create a new GPO.
More information on this and other security configurations in:
https://support.microsoft.com/en-za/help/926512/information-for-administrators-about-e-mail-security-settings-in-outlo

ActiveX component can't create object: 'TDApiOle80.TDConnection'

I am trying to connect to QCServer using Excel Macro. I am using a 64-bit operating system with following being done:
Register OTAClient.dll
Installed HP ALM Connectivity tool
Added OTA Library to reference
I am getting the following error:
ActiveX component can't create object: 'TDApiOle80.TDConnection'
But the same is running using VBScript:
C:\Windows\SysWOW64\Wscript.exe "C:\Users****\Desktop\qcConn.vbs"
I have found this solution on some other blog:
If you are on 64 bit machine, by default your script will run with the 64 bit version of wscript.exe. But QC is a 32 bit app, so you need to consume it from a 32 bit version of wscript.exe which is located at c:\Windows\SysWOW64\wscript.exe.
So what can be done to run it, call command line prompt in your macro and run your command:
C:\Windows\SysWOW64\Wscript.exe
C:\Users****\Desktop\qcConn.vbs
which will call that vbs. Eg:
Dim goWS: Set goWS = CreateObject("WScript.Shell")
sCmd = "C:\Windows\SysWOW64\Wscript.exe "C:\Users****\Desktop\qcConn.vbs""""
Set oExec = goWS.Exec(sCmd)
Hope this helps !!
This is due to the COM objects issue, you need to create few Key's in Registry to run it without issues.
1) Locate your COM object (TDAPIOLE80) GUID under the HKey_Classes_Root\Wow6432Node\CLSID[GUID]
Once located (in the parent folder) add a new REG_SZ (string) Value. Name should be AppID and data should be the same COM object GUID (Along with {}) you have just searched for.
2) Add a new key under HKey_Classes_Root\Wow6432Node\AppID\, the new key should be called the same as the com object GUID (Along with {})
3) Under the new key you just added, add a new string (REG_SZ) Value, and call it DllSurrogate, Leave the value empty
4) Create a new Key under HKey_Local_Machine\Software\Classes\AppID\ , Again the new key should be called the same as the COM object’s GUID (Along with {}). No values are necessary to be added under this key.
With this you should be good!!
Cheers!!
You can also try following steps-
1.Open IE as Admin(right click on IE Run as Administrator)
2.Open ALM, Navigating by URL (your url)
3.Click on Tools link
4.Click on ALM Connectivity link (Run your download)
5.again Click on Tools
6.HP ALM Client Registration Link
4.In the pop up scroll down and select ‘Register HP ALM’
5.It’ll do some downloads. Once completed close the window
This will fix the problem.

Resources