Send Excel file to printer in batch job - excel

I will print excel file in a AX 2012 batchjob.
I chose this approach because the template is too complex to draw it in SSRS.
So, I already have a class which works with excel COM object without any problems on client. Then I created a similar class which runs on server. I used WinAPIServer instead of WinAPI, COM interopt, etc.
But now I've an error:
"workBooks" method is not supported by Automation Interface of COM-object "Excel.Application"
Note - AOS is installed on another machine.
Why is it happening?
Are there some special things in working with COM on AX-server side ?
I already tried to change properties of "Microsoft excel application" in different ways.

Related

Exception HResult 0x800a03ec when trying to open Excel with Microsoft.Office.Interop.Excel.Workbooks.Open()

Following Exception is thrown if I try to open an excel file on a client machine:
Exception from HRESULT: 0x800A03EC
Inner Exceptions: (empty)
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)
at (own assembly)
This HResult is a very generic Error, I could not find any useful informations by it.
My Setup:
WCF Service running inside a Windows Service. The exact same Setup is working on three other machines.
Things I can rule out:
Wrong Path
File does not exists
File is corrupt
File is write protected
Things I've done:
Created the Desktop folders as seen here (second Answer) https://social.msdn.microsoft.com/Forums/vstudio/en-US/4d6c383a-94eb-4898-9d22-aa4bb69be25b/
Gave the Desktop Folders "Everyone" or "Jeder" Permissions ("Jeder" is the equivalent of "Everyone" in German)
Started the Service with the currenlty active User
Changed the DCOM Config for Excel as advised by Heidi2 (see Link above)
Changed from Office 365 to Office Professional Plus
Locale is set to en-US while trying to open the file
Opened file manually which is supposed to be opened: no errors / warnings / user dialogs from excel
Installed English - US on target machine
Wrote an non WCF Service which starts the dll which executes the Interop request
Wrote an Console Application which starts the dll which executes the Interop request
Some Observations:
If I remove the Desktop folders (see my first "Things I've done"), I get the error as described and resolved here: Microsoft Office Excel cannot access the file 'c:\inetpub\wwwroot\Timesheet\App_Data\Template.xlsx'
Excel is open for a short time in the task manager while the dll tries to open the excel file
while I've had Office 365 installed, Office Click-Once Tasks opped up in Task Manager, sometimes freezing the Application. That's why I've switched to Professional Plus
If the active language is set to English US, this error is not thrown anymore; but images, which are supposed to be rendered by Interop, are rendered blank
What am I missing here?
Sorry - I know this is an indirect answer, although I would recommend you follow on. I personally have very bad experiences with Excel Interop services (ASP.NET application). As I am aware Microsoft does not recommend Interop server automation.
Even if you solve this issue you might stumble into issues with memory leakage, performance etc. In my previous project we were advanced with Excel interop automation until deployment. We stumbled into so many issues (Excel Interop processes not closing properly etc.) that we had to rewrite everything to OpenXML.
If possible use the new OpenXML format. There is a ClosedXML library that makes working with very easy.
Why OpenXML vs Interop?:
Efficiency (OpenXML is lightweight)
No memory leakage risk
Ease of use
Before trying this solution be sure that you read the "Things I've done" paragraph from the question (and tried what applies to you)
The Exception was thrown upon opening the Document; on the machine which generated the Excels, the files were generated invalid.
The solution was to change the Format of the numbers.
Go into System Configuration -> Time, Language and Region -> Language
Tap on the highlighted Hyperlink
Open Advanced Settings
Change the delimiter to a point "."
We have converted our Client / Server solution from 4GL language to C#, where embedded C# code below worked without any issue before, and started to receive same error message.
Excel.Application excelApp = new Excel.Application();
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(fileExcel,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
I have followed all the instructions in this thread, but to no avail, until I have realised that in our case at least fileExcel, which contains the full path with the name of the file and defined as System.String fileExcel had trailing spaces, e.g. instead of "C:\temp\MyTest.xls" it was "C:\temp\MyTest.xls[many many spaces]".
Once I have added Trim() to fileExcel as below, all went back to normal. Hope it will help to someone in the future.
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(fileExcel.Trim(),
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);

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

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!

Error Code 429: Active X Component Cannot Create Object

I have a .Net Class Library which I refer in VBA and all goes well. When I try to use the same Excel file on some other machine the error is: Error Code 429:Active X component Cannot create Object
The error is recd for line
set a = createobject("dllname.classname")
However I am registering the DLL at runtime and it gives no error for the line
Dim a as dllname.classname
This error happens on my Win-7 pc where as works just fine on Win-XP PC. Please help because I need to run my application using the Excel Sheet.
This article has a good writeup on ensuring your assembly is late-bindable, i.e. via createobject().
Takeaways:
Make sure your assembly includes a ProgID attribute
Use regasm on the target (deployment) machine to do the actual registration of the COM class

How to force Excel VBA to use updated COM server

I'm developing a COM server to be used from Excel VBA. When I update the server (edit code, unregister, re-register) Excel seems to carry on using the original version of the COM server, not the updated version. The only way I have found to get it to use the updated version is to close and re-open Excel, which gets a bit irritating. Is there a way to force Excel to use the newly registered version (maybe some kind of "clear cache" option)?
More details:
The server is being developed in Python using win32com.
In VBA I'm doing something like:
set obj=CreateObject("Foo.Bar")
obj.baz()
Where Foo.Bar is the COM server I have registered in the registry.
If I unregister the server then run the VBA code, I get a "can't create object" error from VBA, so it must realise that something is going on. But once I reregister it picks up the old version.
Any hints appreciated!
Thanks,
Andy
I've found a solution to my problem - the general idea is to set things up so that the main COM server class dynamically loads the rest of the COM server code when it is called. So in Python I've created a COM server class that looks something like:
import main_code
class COMInterface:
_public_methods_ = [ 'method1' ]
_reg_progid_ = "My.Test"
_reg_clsid_ = "{D6AA2A12-A5CE-4B6C-8603-7952B711728B}"
def methods(self, input1,input2,input3):
# force python to reload the code that does the actual work
reload(main_code)
return main_code.Runner().go(input1,input2,input3)
The main_code module contains the code that does the actual work and is reloaded each time the COM method is called. This works as long as the inputs don't change. There will presumably be a runtime penalty for this, so might want to remove the reload for the final version, but it works for development purposes.
Just a suggestion, have you tried to Unload the object? Maybe create a button in your excel spredsheat that force to unload the object.
I hope it helps

Scriptom (groovy) leaves Excel process running - am I doing something wrong?

I am using the Scriptom extension to Groovy 1.7.0 to automate some processing using Excel 2007 under Windows XP.
This always seems to leave an Excel process running despite my calling quit on the excel activeX object. (There is a passing reference to this phenomenon in the Scriptom example documentation too.)
Code looks like:
import org.codehaus.groovy.scriptom.ActiveXObject;
def xls = new ActiveXObject("Excel.Application")
xls.Visible = true
// do xls stuff
xls.Quit()
The visible excel window does disappear but an EXCEL process is left in the task manager (and more processes pile up with each run of the script).
There are no error message or exceptions.
Can anyone explain why the Excel process is left behind and is there any way to prevent it from happening?
This works:
xls.Quit()
Scriptom.releaseApartment()
The javadocs state:
In some cases, the JVM can close
before everything is cleaned up, which
can leave automation servers
(especially Excel) hanging. Call this
before your script exits to get
correct behavior from automation
servers.
Looks like you are missing
xls.release();
like it is done here.

Resources