Better option for hosting MS Office documents in custom app? - c#

I am currently hosting an IE Browser control in a .NET (2.0) Form and using it to load Office files such as Excel and Word thusly:
_ieCtrl.Navigate("C:\\test.xls", False);
The hosting and loading works well except whenever I navigate to a file I am presented with a dialog that asks whether I want to save or open the file. (This is standard IE file-download behavior.) I always want to open it of course and I do not want the dialog to show.
Another issue is that when I close the window that hosts the IE control and the Office doc the document does not close and remains open on disk. This means that subsequent attempts to open the same file via my app or the native office app will fail because of the sharing violation.
Is there a programmatic way of avoiding this dialog and cleaning up resources afterward? I am asking for a programmatic answer because web research has only yielded solutions that entail modifying OS-level settings.
Bounty NOTE:
I am open to any solution to this issue that will allow me to:
Host an Excel spreadsheet inside my application
Work rather transparently (avoid usability issues like the one described above)
Avoid having to make any OS-specific changes that may affect other applications (especially icluding IE)
Is zero additional cost (no licensed 3rd party libs please) Code Project and other open source resources are OK
Not mess around with the DSO Framer ActiveX control, unless a stable version is developed/discovered

Is your intention for the user to be able to work with the Excel file in an Excel-ish way (i.e. columns, rows, formulas, etc.), possibly saving it back? If this is the case, I can't see how you can solve this problem well without relying on COM Interop with the Excel object model or by integrating third-party libraries to work with the Excel sheet. I know you said no paid solutions, but there are some feature-rich 3rd-party controls out there just for working with Excel files within applications.
I noticed in your comment to SLaks that the final product is a "dashboard of sorts". If your intention is to design a a custom dashboard application, have you considered parsing the Excel file(s) to extract the data and then presenting it in a logical manner within your application. This removes the need to directly display and work with the Excel file while still allowing you to work with the data inside that file. If you are trying to get the data outside of the file, here are two approaches among many:
You might consider using the Excel object model and COM interop to read the data from the Excel file into your application. Granted, this includes a dependency on Excel being installed, but it is a possibility. This article has some great code for getting started with reading Excel files in this way.
A better way might be to use a library that doesn't have a dependency on Excel being installed on the local system. This answer suggests using the Excel Data Reader library, available on CodePlex.
I know this answer side-steps your original answer of "hosting MS Office documents in [a] custom app," but in case what you're really interested in is the data inside those Excel files, hopefully this answer will prove helpful.

This is a horrible hack and should only be considered as a last resort: SendKeys.Send("{O}");
http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys%28VS.71%29.aspx
Something similar to
_ieCtrl.Navigate("C:\\test.xls", False);
(code to sleep or wait may be needed here)
SendKeys.Send("{O}");
Basically, you send the "o" key to the dialog so it presses the "open" option. You are simulating a keyboard presses to click the "open" button. It is hackey because
1) you may need to wait in between
calls. If you send the o key before
the dialog is up it will be missed.
Hopefully the navigate call is finished when the dialog pops (dont know behavior of control in c#). You may need to experiment with the time since different computers will open faster\slower
2) If the dialog is not shown on a
computer, you will be inserting "o"s
into it. This may cause problems when
exiting because it may popup another dialog to try and save
the changes. May be able to prevent this by opening it in read-only mode
3) Different versions or windows may need different sendkeys commands. For example, you may need to send "o" and them the "{enter}" key
4) Probably more :)

If you want to open the file in a separate Excel instance (not embedded in the WebBrowser control), you can simply call
Process.Start(#"C:\Test.xls");

Office was never meant to run in embedded mode, not in a web page or in an ActiveX Document host. Microsoft had time and time again given us the warning. From pulling dsoframer from the knowledge base to skipping the BrowserFlags registry key in Office 2007.
Move to Office add-ins, Excel Web Access or Office Web Apps as quickly as you can.

Related

Monitor file open c# .Net

I want to build an app that needs to monitor the opening of the files but I don't find any way to can do it.
With FileSystemWatcher there is no option to can monitor the opening of the files. Just the created, removed and modified ones.
So I wonder if there is any functionality implemented in the advanced searches that could give me the infomration of the files opened after a concrete date. (At least in Mac it's possible but I am not sure if Windows has implemented this)
Other solution would be to develop a File System Filter Driver, but I find this way too hard
I cant give you a direct answer (because I dont know) but since Microsoft publish the FileMon tool which does exactly what you are after, it seems that Windows does have a way of notifying file open, close and access. This is discussed here Getting a notification when a local file is accessed in windows but this only covers the change of files, not opening and closing. There is a way of getting all the files opened by a process discussed here Delphi - get what files are opened by an application which is possibly what FileMon is using, but there are caveats (i.e. its an internal OS API).
Hope this helps, sorry cannot give a direct answer.

Replace save file dialog opened by any program by a customized save file dialog

I am working on a Version Control/File Sync System for Windows. It would be great to have a checkbox at the bottom of the classical save file dialog with the option to check/uncheck for my file versioning.
Is it possible to listen for opened save file dialogs by any program (word etc.) and replace/override that dialog with a customized one (with an additional checkbox)?
If the checkbox is checked, another window should pop-up where the user could enter some additional metadata. After that the data is stored in a local database.
I already worked with the approach by dmihailescu (link provided) but it's very complex and I do not know how to modify that example to listen for opened save file dialogs by other programs.
http://www.codeproject.com/Articles/19566/Extend-OpenFileDialog-and-SaveFileDialog-the-easy?msg=4779306#xx4779306xx
Another approach is to use the FileSystemWatcher but that's very expensive to watch the whole system and it's not very comfortable because the user has to be asked for any created file if he/she wants to version control it.
I hope someone could help me to solve that problem or has some additional tips / approaches.
Thank you.
Edit: Use-case
A user has to write a documentation and creates a new word-doc. When he/she clicks the Save as menu entry of word, my customized save file dialog should pop-up with a checkbox at the bottom, if this file should be versioned or not. If the checkbox is "active" a new window should appear where the user could enter additional metadata. After that the data should be stored in local database.
In my case, only the metadata (like the path etc.) should be stored in the database. Let's suppose a user stores the same file in two different directotries (one file is "older" and one file is the current one). If the user opens an older version of this file, my system should recognize that a "newer" one is already stored in another place and synchronize those files.
That should just be a very easy example.
You have two pieces of functionality: save and version-control. Both of the tasks are actually rather complicated. Therefore you shouldn't mix them. You better off using standard Windows API to save file and do not change that. Think about how you'd support several different Windows releases and how painful that would be.
I assume you have your own UI, and do not integrate with, say, Windows Explorer (like Tortoise Svn or Dropbox). In this case you can do version-control magic first and then just save the end file using standard API.
If you do integrate with Windows Explorer, I suggest you to have a look at Tortoise svn source code.

Using Clipboard Copy Paste in Excel (VSTO code) freezes other Microsoft Office application

Operating System : Microsoft Windows SP1 (64 bit)
Office Suite : Microsoft Office 2010
.Net Framework : 4.0
Subject : Microsoft suites of applications (Word, Outlook) does not respond for the time slice when a excel plugin code is running
Details : We have written VSTO (in C#) based add-in for excel application. This add-in is used for refreshing data in current sheet.
Following steps of events occurs on click of a "Refresh" button
•A call is made to internal web service by passing some metadata to download a file
•File is downloaded and stored on windows Temp folder.
•A VSTO code is executed to copy data from downloaded sheet to current sheet using Clipboard Copy / Paste. Data is copied row by row.
At any point in time, we'll have one row of data in Clipboard. Also the number of rows and columns varies between request.
Issue: While refresh functionality is working as expected, we are experiencing issue with other Office suites applications (Word, Outlook).
For the time slice refresh is running, all Office suites of application stops responding.
Can some one help with this issue?
I think you can not control other office suites application. But what you can do is, try to decrease the time slice for refresh button By using different concept like
•A call is made to internal web service by passing some metadata to
download a file
•File is downloaded and stored on windows Temp folder.
I don't know for above two point whether you have used separate thread for that or not? If not use separate thread for that.
You can also use some Optimization trick while copy pasting data from one sheet to another.
Here are some tricks to optimize vba / vsto code
http://tchhabhaiya.blogspot.in/2012/06/17-ways-to-optimize-vba-code-for-faster.html
I think below code will help a lot to you if you haven't used this.
Application.ScreenUpdating = False //To Turn Off at the start of code.
Application.ScreenUpdating = True //To Turn on at the end of the code.

Why would the Excel Interop remove an image after processing a file?

Excel Interop is removing images from processed files.
I’m using the Excel Interop, no third-party components are present (that I'm aware of).
The workflow is -- create a copy (target) of a file (template), populate cells, change radio-button state
Create copy (target) of a pre-existing .xslm file (template)
Open target via Excel Interop
Populate target cells, change radio-button state
The worksheet with an image is not modified
Close target
On my dev machine, the target file looks great -- everything is populated, the image is present. NB: on my dev machine, I'm running the code from the VS2010 IDE.
On the production machine -- everything is populated, but the image is not present.
Instead, the following error appears in its place:
NB: on the production machine, it's running as a service, with the Local Service account.
"The image part with relationship ID rId1 was not found in the file"
The entire workbook is opened via the following code:
var workbook = workbooks.Open(targetPath
0, false, 5, Type.Missing, Type.Missing, false, XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
Please note that the worksheet with the image is not manipulated in the code.
The worksbooks (and individual worksheets) are protected. However, the protected template is processed correctly in dev, but not in production. I don't think the protection has anything to do with it (but who knows, right? This is Interop. ugh).
The file was created by another party, and all components (ie, the image) reside within the .xslm structure, not as links to another server.
I have verified that the image is visible on the production machine in the template file, but not in a processed file.
To confirm that this was not an issue in opening the file within the production, I emailed myself a copy, and the image continued to be not present.
I have also confirmed that, on my development machine, processed files do have a visible image.
I unprotected the worksheet, and unzipped the file structure. The .jpg file is indeed not present in the processed target from the production machine.
One more note -- Office 2010 is installed on my development machine, but Office 2007 on the production machine. As a result, I'm using the Office 12 Interop. No runtime errors are generated in either environment.
I am using the Interop (instead of an OpenXml library) because there are ActiveX controls present that must be populated. Note however, that none of the ActiveX controls have any issues -- they are working fine. It's just image-files that are vanishing from processed files (they render fine in the template file).
UPDATE NOTE: There are four other image-files, all .emf on a different worksheet; they are all stripped as well.
As explained in comments (and eventually in an edit to the question), the code was running in production as a service, with the Local Service account.
I am now unsure why I picked this account -- something I found in passing during my research on getting the Interop to run correctly as a service?
However, once I switched from the Local Service account to the Local System account (and checked "Allow service to interact with desktop") it worked. Automagically.
services.msc
select the service
right-click, select "Properties"
select the "Log On" tab
select "Local System account" and check "Allow service to interact with desktop"
"Allow service to interact with desktop" might not be required; Other notes on automating the Interop suggest that other desktop settings are required, however I did an install where those pre-requisites were set but THIS value unchecked; app still worked...
Interop is not supported in sever-scenarios by MS.
There are many options to read/edit/create Excel files without Interop:
MS provides the free OpenXML SDK V 2.0 - see http://msdn.microsoft.com/en-us/library/bb448854%28office.14%29.aspx (XLSX only)
This can read+write MS Office files (including Excel).
Another free option see http://www.codeproject.com/KB/office/OpenXML.aspx (XLSX only)
IF you need more like handling older Excel versions (like XLS, not only XLSX), rendering, creating PDFs, formulas etc. then there are different free and commercial libraries like ClosedXML (free, XLSX only), EPPlus (free, XLSX only), Aspose.Cells, SpreadsheetGear, LibXL and Flexcel etc.
It is hard to say whether your specific case (ActiveX controls) is fully supported by any of the above... that is something you need to test...
Even if the ActiveX controls are supported by any of the libraries there is a chance that the ActiveX controls themselves don't work within a Windows Service (permissions etc.).
EDIT - as per comment:
I understand the ActiveX problem and I addressed it from 2 points:
Have you really tested all above mentioned libraries ?
Have you checked with the implementor(s) of the ActiveX controls whether the ActiveX controls could even theoretically work in a Windows Service scenario ?
EDIT 3 - after the UPDATE from the OP:
.emf is a vector file format... IIRC GDI+ is used to render it on current Windows versions... .emf has evolved a bit over time so older OS and/or Office versions can sometimes have problems rendering newer .emf files... which in turn means the problem is the "missing desktop" in the Windows Service AND/OR that your .emf files are "too new" for the production machine.
(a) Not supported, don't do it https://support.microsoft.com/en-gb/kb/257757
(b) Anyway, if you have to do it (and cannot give desktop access to your process, as suggested in the accepted answer), you can mess with the contents and permissions in C:\Windows\System32\config\systemprofile, as suggested by this answer.
I had to create and allow permissions to the Desktop and to the INetCache folders. Checking (and solving) failed access attempts in paths beginning with C:\Windows\System32\config\systemprofile with the help of Process Monitor was what got me out of the annoying problem and pointed out at INetCache permissions as the reason of the failed insertion of images.
You just have to add permisions to C:\Windows\SysWOW64\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache or C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache(depends on your system version) folder and images will shown
You're probably on your own, since Excel isn't supported in a server environment as #Yahia correctly points out.
Your mention of ActiveX controls is a red flag - maybe some of your ActiveX controls require Excel to run under an account with a profile?
All you can do is debug this yourself, probably best to proceed by eliminating the possible sources of different behaviour in your dev and production environments.
Try using the same Office version in both environments
Are you using Cassini in your dev environment? (i.e. running under your own login) If so, perhaps try with IIS running under a service account with no profile
Try removing the ActiveX components one by one to see if one of those is having an impact
... etc ...
I'm facing the same issue with powerpoint on Desktop (not a service) by copying a slide with picture from a template. (when getting about 200 copy paste in 1 presentation, but 1300 slides with same picture works fine ???)
It is hard to get this issue, I think it is hardware related, like RAM errors, but not sure
only 1 client of hundred get this error, so i think it is hardware related.
Note that i have a website that provide an Excel automataion and it works PERFECTLY, even "it is not supported by MS blah blah...." !
Your excel file seems to be corrupted, you have to find how.

C# Word automation makes Windows Explorer crash

I have written a C# program which import a product list from a .xlsx file and let the user create an order based on that product list.
When the user is finished, the program builds one or more system specifications based on the order.These specifications is written to a .docx file. I have Office 2007 installed on the computer and are using the Microsoft.Office.Interop.Excel and the Microsoft.Office.Interop.Word namespaces.
The problem:
After I have runned the program, Windows Explorer crashes very often and has to restart. This happens when navigating in folders or when right- clicking on folders etc.
This also happens after the program have been closed and the only solution to make it stop is to restart the computer. It seems like it only happens when I have created the output files (.docx). If i start the program and use it like I normally do, but without creating the word files, the problem don't seem to occur.
After the program have created the output files, Word gets "Visible" to the user for manual editing. The user closes the word application when finished editing the documents.
What can make the Windows Explorer crash when running word automation?
I really need help on this one. Any suggestions are welcome.
After execution, do you have ghost excel.exe and word.exe processes remaining?
These ghost are likely to make the system unstable.
You're likely not releasing properly the COM objects you instantiated via automation.
Use Marshal.ReleaseComObject(yourobj); on each and every COM objects you instantiate. It's a real pain, I know.
Note: be sure that you don't instantiate COM objects without knowing it:
mySheet = myExcelObject.workbooks[0].Sheet[0] won't just instantiate a sheet object, but also a workbook object.
Rule of thumb: never ever use a secondary property on a COM object ( foo.bar.baz ) and release everything.
Final note: don't use office automation at all on the server, it's bad, per Microsoft own words, there are fully managed libraries for that.

Categories