Save Method of Application class failed when trying to save an Excel Document - excel

I havea a method in Delphi that saves some data into a ExcelFile. The Program works fine for any kind of Excel except Excel 2013.
Here is the code
try
// If no instance of Word is running, try to Create a new Excel Object
ExcelApp := CreateOleObject('Excel.Application');
except
ShowMessage('Cannot start Excel/Excel not installed ?');
Exit;
end;
ExcelApp.DisplayAlerts := False;
ExcelApp.Workbooks.Add(xlWBatWorkSheet);
// fill the Excel file
ExcelApp.Visible := True;
// Save the Workbook
ExcelApp.save;
if not VarIsEmpty(ExcelApp) then begin
ExcelApp.DisplayAlerts := False; // Discard unsaved files....
ExcelApp.Quit;
end;
So As I said, this worked fine for Excel untill the 2013 Version. When I try to use this on a computer with Excel 2013 I get the error
Save Method of Application class failed.
Any Ideas why is this happening and any possible Workaround?
PS I tried with
ExcelApp.Workbooks[1].SaveAs('c:\test.xlsx', xlWBATWorksheet);
I also get an error :
SaveAS Method of Workbook class failed.
I also read that I could be that I don't have acces to save on that location, but i'm the administrator on the computer.
If I help the time of executing this operation takes a lot more time that It usually did in Excel 2010 or Excel 2007.

According to the documentation, the Excel Application object has no Save method. Use SaveAs from the Workbook object.
You are trying to save a file to the root directory of the system volume, and by default, that is secured so that standard user cannot create files in that location. Even though you are an administrator, UAC means that your process runs with a standard user token.
The other problem I see is that xlWBATWorksheet is not a file format constant. You mean to use xlOpenXMLWorkbook. This should be fine:
Workbook.SaveAs('c:\somedir\test.xlsx', xlOpenXMLWorkbook);
where you replace c:\somedir with some suitable path on your machine.
Switching to early bound COM might alleviate some of your travails but the answers can always be found in the documentation. You don't need to do this blind.

I haven't done any Microsoft Office automation myself but I do remember from the time that I still used Delphi 7 that when you installed it the installer actually asked you for which version of office do you wanna install the extensions for.
So I would gues that there are some differences in COM implementation that different versions of Microsoft Office use so it is posible that components your Delphi use for Microsoft Office Automation are not compatible with Office 2013.

May not be relevant but had same error message in VB6 (yes, 2016 and I still use it for odd things on Windows 10!) because the sheet was selected. Selected another object before saving and it worked.

You need to install KB2830391 HF460904 for Excel 2013 issue for AX 2009. Change in one sysExcel class on how the transfer/save are made!

Related

How to stop from deleting a file/workbook in MS excel when it is already open?

We have designed Microsoft Addins for MS Excel and Word 2019 written in VB.net.
There we have designed a tab, on clicking this tab, we open a Task Pane.
On loading this task pane, we execute a code to launch another Excel File/Word file.
So when I delete a file in MS Word that is already open it shows an exception The file 'Filename' already exists.
Given below is the code snippet I am using to delete an already existing open file named processFile
My.Computer.FileSystem.DeleteFile(processFile)
Now when I run the same code snippet in MS Excel it does not show this exception and deletes the file.
I am not able to understand this behavior.
Kindly suggest if anyone has understanding on it
Here is some more information about which environment I'm working in:
Operating System : Microsoft Windows 10 Pro
Code Editor : Visual Studio 2019
Technology : Vb.net(.Net Framework 4.8)
MS Office Version : 2019(32 bit) : Microsoft Windows 10 Pro
The IOException should be thrown if the file is in use. You need to close any editors first and then delete files.
Check if the file is open. I have a code below that may help.
As import sfile use the fullpath with filename. (eg. "C:\Windows\test.txt")
returns True when file it's open and false when it isn't.
Yu will need "Imports System.IO"
Public Function IsFileInUse(sFile As String) As Boolean
Try
If File.Exists(sFile) Then
Using f As New IO.FileStream(sFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
End Using
End If
Catch Ex As Exception
Return True
End Try
Return False
End Function
As per the information in the comment section, the file is opened in "protected mode" and you are saying that it is deleting while it is still open to the user.
So yes, if the file is engaged and deleted by some program, it should throw an exception and not delete. But if no exception is coming, i.e. some specific handling has been done by Windows/MS Excel so that file has been deleted while it is still kept on buffer and open. Its answer can be given by Microsoft only.
One solution, I can suggest is to close the "protected object" and then delete the file so that no file will be opened to the user and it will be safely deleted.
Snippet to open the file for Add-ins(VSTO):
Dim objProtectedMode As String objProtectedMode = Globals.Connect.Application.ProtectedViewWindows.Open(fileLocation, , False, False)
Snippet to delete the file safely:
If Not (objProtectedMode Is Nothing) Then
objProtectedMode.Close()
End If
My.Computer.FileSystem.DeleteFile(objProtectedMode)
Note: - Solution may vary for other add-ins. Code snippet provided for VSTO Add-ins.

64-bit Excel 365 crashes, 32-bit Excel 365 works fine

I have a question relating to the differences between the 32 bit and 64 bit versions of Excel and VBA.
I am working in Office 365, 64 bit. (I am using 64 bit because I ran into memory issues and as a test, to see if 64 bit works for our company). I am working on an Excel file which has a lot of VBA code used to gather product properties from SQL, calculate parameters from these properties, and output everything to another SQL database. In addition, the Excel file outputs PDF files.
The Excel file is stored as a template, so that users can open the template and save the new file to their respective workspace. At the moment, the users are using Office 365, 32 bit.
When I open the Excel template, Excel closes itself. It seems to crash before calculating the parameters on the new file. There is no error message; in the lower-right message box I can see that Excel doesn't get to the calculating stage.
However, when the other users open the file in 32-bit Excel, everything is fine.
I am not using pointers (no PtrSafe) and no LongLong variables.
I also have no compile errors.
I am currently rebuilding the Excel file by saving it as a file without macro's, and then copying the VBA modules - a different site mentioned the VBA code may be corrupt. I am halfway through adding macro's, and the error pops up again; the VBA code I have added last has been in use for about a year so I am tempted to exclude it as a culprit.
Where would you suggest I look to find the problem?
You're absolutely right of course. I have gone back to the last working version and began adding a text logfile, which would log the start and end of each procedure. I got lucky as the file crashed as I was doing this, and the logfile pointed me towards a procedure seemed to be working, until the right conditions were met for it to crash.
The procedure itself accesses global variables which were not initialised. I didn't catch errors that could occur properly. For some reason, this works fine in x86 Excel, doesn't trigger any problems in the compiler or during debugging but crashes in x64 Excel when enough memory is used.
Gekozen_Assen is the name of a global variable. It is a dictionary which contains information. I had tried to use .Exists as a method to test if the required item in the dictionary exists, but this doesn't work if the dictionary isn't initialized at all.
The errorous code:
GetFromGlobal = ""
If Global_Dictionary.Exists(Answer_Type) Then
GetFromGlobal = Global_Dictionary.Item(Answer_Type)
Else
GetFromGlobal = "Error!"
End If
Instead I should've been using "Is Nothing", the fixed code below:
If Global_Dictionary Is Nothing Then
GetFromGlobal = "Error: Dictionary not initialized"
Else
If Global_Dictionary.Exists(Answer_Type) Then
GetFromGlobal = Global_Dictionary.Item(Answer_Type)
Else
GetFromGlobal = "Error: Dictionary item not found"
End If
End If

Delphi Ole - Sudden Error - Interface not supported

Delphi Tokyo, Office 2016. I have an existing app, been running great for a while. I went this morning to run the application, and all the sudden it is throwing an error. I open the source code and step through it. It is throwing the following error:
'Project ... raised exception class EIntfCastError with message 'Interface not supported'.
The line of code causing the issue is
oExcel := CreateOleObject('Excel.Application') as ExcelApplication;
The source code has not changed. The issue was first found in the executable. Excel appears to be working fine. There is one other fact, which may or may not be relevant... Every time I start Outlook I get a popup Error message 'Failed to load the elevation application'. This started approximately 1 month ago, and to my knowledge, I don't believe I have run my application since I started receiving this message. I cannot find any information about this, but it does not seem to effect Outlook. (I have performed both a Quick Repair as well as an Online Repair for MS Office 2016, but neither effort changes anything.) When I look at Outlook Plugins, I do NOT have any plugIn called 'Elevation'.
The Outlook issue may or may not be related to the Excel issue.
What is going on here? How do I debug this further?
I would split you code into two steps, one to create the Ole object and the other
to extract the ExcelApplication interface. This way, you can easily identify which
of the two steps is geneerating the exception. Something like this
var
oExcel : OleVariant;
...
oExcel := CreateOleObject('Excel.Application');
oExcel := IDispatch(oExcel) as ExcelApplication;
To be honest, when I first saw your code, I was surprised it compiled in the first
place, but I checked it and it did.
However, there is really not a lot of point in assigning the ExcelApplication interface
back to an OleVariant. It would be better to assign it to an interface variable and use
that to make use of the early-binding, type safety and code-completion that is available
in the IDE. So I would do something like this, instead:
var
oExcel : OleVariant;
Excel : ExcelApplication;
...
oExcel := CreateOleObject('Excel.Application');
Excel := IDispatch(oExcel) as ExcelApplication;
// then use the Excel interface instead of oExcel.
Tbh, I am not expert enough in COM/Ole to be sure why splitting the original single step into two makes the difference between it not working and working. Perhaps a COM expert will chip in on that.

MATLAB 2015b broken ActiveX/Excel Controls

Having an issue involving the creation of ActiveX handles using MATLAB 2015b. Before updating (from 2013a) I used to create a new Excel application handle using the following 'try catch':
global Excel
try
Excel = actxGetRunningServer('Excel.Application') ;
catch
Excel = actxserver('Excel.Application');
end
Since updating to 2015b, the code still runs through without error, but now the Excel handle created, whilst still of type Excel_Application, has no properties. Calling Excel.get returns a struct with no fields.
Apart from the update, there haven't been any other changes made to the code, and the version of MS Office hasn't changed.
Have there been any changes in the way MATLAB handles the ActiveX interface, or is there something wrong with my code?

Excel Object SaveAs, error happens when Existing File is Open

Excel_Obj = CREATE OleObject
Excel_Obj.ConnectToNewObject( 'excel.application' )
Excel_Obj.Workbooks.Add
Excel_Obj.Application.ActiveWorkbook.WorkSheets.Add
Excel_Sheet = Excel_Obj.Application.ActiveWorkbook.WorkSheets[1]
//EXAMPLE
Excel_Sheet.Cells[1,1] = 45
Excel_Obj.Application.ActiveWorkbook.SaveAs(ls_file,56) //csv
//where ls_file = the Opened File
error happened after / during saveas.
try catch throw "error calling external object..in click..line.. saveas.."
--
i want to state to the user that the excel file is open therefore cannot be overwritten properly. I used a try catch and throwed a proper message but before the messagebox for the catch event happens, the PB execution error R0035 happens. any solutions or proper way to know if the excel file is open.
You might be able to check if the file is open first, have a look at this answer:
how to check if file is opened in excel using OLE (leaves excel process open)
I'd try a PowerScript FileOpen () call with a LockReadWrite! parameter to see if it can be opened, followed immediately by a FileClose () if it was successful. (I think this is a PowerScript-specific variation on the DXL solution Colin linked to.)
Good luck,
Terry
Have you tried approaches similar to these?
Using Win32 API:
http://www.rgagnon.com/pbdetails/pb-0030.html
Using PB function fileopen()with the (default) exclusive rights set:
http://www.tek-tips.com/viewthread.cfm?qid=1610670
In other words, see if the file can be opened exclusively before connecting to Excel or making the CSV?
You will have to turn off the option to break into the debugger for that exception to see the exception handling work in the IDE. Look for the Help topic "Exception Settings dialog box" for details. Once you see it's working I recommend you set it back to break into the debugger, since you'd normally want to see what threw the error.
You cannot use ole when document is open( even you set lock write) by the user and not by apllication.
my approach, I have been using many times till now:
Check excel is open or not, use use can use api or wsh script in the internet to check app opened. If opened do not run save as and tell user to close excel and not run it for while for while.
if you user run excel and your program still running active workbook and worksheet application will be switch to excel that opened by user ( imagine it wrong written data).
Change your code as below
if Excel_Obj.ConnectToNewObject( 'excel.application' ) <> 0 then
messagebox("warning", "could connect to excel", stopsign!)
RETURN
end if
just for knowledge another technique is DDE call, but not common today and most complicated.
Happy coding From pb developer.

Resources