I have developed a simple C# Winforms application that loads MS-Word 2007 documents via COM automation.
This is all very simple and straight forward, however depending on the document I need to programamtically Enable or Disable Macros as well as ActiveX controls.
There is probably a way to store this in the registry, but I want to control these settings on an instance by instance basis as multiple concurrent requests may be running at a time.
So my question is 'how do I configure the trust center settings using COM automation'.
I have Googled for hours, but all I have been able to find is the Application.AutomationSecurity property, but this only accepts the following values:
MsoAutomationSecurity.msoAutomationSecurityLow
MsoAutomationSecurity.msoAutomationSecurityForceDisable
MsoAutomationSecurity.msoAutomationSecurityByUI
The Word 2007 Trust Center however exposes the following settings:
Macro Settings:
Disable all macros without notification (matches msoAutomationSecurityForceDisable)
Disable all macros with notifications (I don't need this one)
Disable all macros except digitally signed macros (No equivalent)
Enable all macros (matches msoAutomationSecurityLow)
(source: visguy.com)
ActiveX controls (configured separately, I have not found any way to control these, note that according to the screenshot these settings are shared between all applications)
Disable all controls without notification
Prompt me before enabling UFI controls....
Prompt me before enabling all controls with minimal erstrictions
Enable all controls without restrictions
I have tried the old trick of recording an MS-Word macro while changing these settings, but none of these steps are recorded.
Update:
I have found the following entries for the ActiveX controls settings in the registry. Looks like ActiveX settings are indeed global and cannot be specified for a single MS-Word instance unless someone proves me wrong.
ActiveX Disabled
[HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Security]
"DisableAllActiveX"=dword:00000001
"UFIControls"=dword:00000002
ActiveX Enabled with safe mode
[HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Security]
"DisableAllActiveX"=dword:00000000
"UFIControls"=dword:00000002
ActiveX Enabled without safe mode
[HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Security]
"DisableAllActiveX"=dword:00000000
"UFIControls"=dword:00000001
Still keen to resolve the macro settings problem
Looks like I am going to answer my own question.
I have tested it and can confirm the mappings are as follows:
Macro Settings:
msoAutomationSecurityForceDisable = Disable all macros without
notification
msoAutomationSecurityByUI = Disable all macros except digitally
signed macros
msoAutomationSecurityLow = Enable all macros
To the best of my knowledge the global ActiveX settings can only be configured by directly editing the registry
ActiveX Disabled
[HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Security] "DisableAllActiveX"=dword:00000001 "UFIControls"=dword:00000002
ActiveX Enabled with safe mode
[HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Security] "DisableAllActiveX"=dword:00000000 "UFIControls"=dword:00000002
ActiveX Enabled without safe mode
[HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Security] "DisableAllActiveX"=dword:00000000 "UFIControls"=dword:00000001
I have left a comment in the relevant section of the MSDN website
I know this thread is quite old, but I had to figure it out today so after a quick research I found this registry for the Trust Center Settings:
This applies to Word version 2010 (and probably 2007, but with 12.0 instead of 14.0)
Or in text:
Registry location:
HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Word\Security
Macro Settings:
Name: VBAWarnings
Data:
Disable all macros without notification - 4
Disable all macros with notification - 2
Disable all macros except digitally signed macros - 3
Enable all macros (...) - 1
Developer Macro Settings:
Name: AccessVBOM
Data:
Unchecked - 0
Checked - 1
For the setting for ActiveX controls in office 2010
to DisbaleActiveX without safe mode you only need ...
"HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Security" /v UFIControls /t REG_DWORD /D 1 /F
I've spent a couple of days trying the same thing and finally discovered a very simple way of opening an .xls file containing macros, without messing with the registry or Excel's trust settings. In C#:
Application aXL = new Application();
aXL.FileValidation =
Microsoft.Office.Core.MsoFileValidationMode.msoFileValidationSkip;
try {
Workbook aBook = aXL.Workbooks.Open("K:\\Work\\ExcelTest\\BrokenMacro.xls"
, 0
, true
, Type.Missing
, Type.Missing
, Type.Missing
, true
, Type.Missing
, Type.Missing
, false
, false
, Type.Missing
, false
, false
, Type.Missing
/*,false*/);
}
catch (Exception e) {
Console.WriteLine(e);
}
See MSDN for details.
My Excel trust center setting were all set to default values - "Disable All Macros with Warnings", and "Do Not trust access to the VBA object model. Without the msoFileValidationSkip option an exception was thrown. With the msoFileValidationSkip option the file opened fine.
It seems to me that this is the way to go, since it allows a program to open files with macros, but doesn't open up the Excel application virus ridden spreadsheets.
Note that I'm running Office 2010. I don't know on which version of Office this option was introduced.
Related
I have an application that uses Excel 2013. I need a way to disable all macros. I can not do it on workbook open because I do not have access to the open methods, the workbook is opened by another COM application then passed to me. It needs to happen prior to opening the document. What I am ultimately trying to do is set the setting found in the image below.
The best solution I found was to edit the registry. Shout out to Tim Williams for pointing me in the right direction
The key that needs to be edited is
HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Excel\Security\VBAWarnings
In my case I was to disable all macros by setting the value to 4
More info can be found Here
We have developed a VSTO addin for Excel, which pulls excel sheets from a web server, and allows users to manipulate the data on the sheet. It works with a local copy of the file but we don't really care about that copy. But some of our clients have "iManage Integration for Office" installed as well, and these clients experience odd behaviour. In this environment we are not able to cancel the Close event.
More specifically, if a user opens one of our files and makes changes, then closes the file, our event handler fires and prompts them to save changes (to the data on the server). If they choose Cancel, or if they choose Save and the save fails for some reason, we set Cancel = true in an attempt to keep the file open. Ordinarily this works perfectly.
For those clients with iManage, the file closes anyway. If our code has saved the local copy of the file, then the file just closes. If the local copy has not been saved, the user gets another prompt after our prompt, from iManage, asking if they want to save the file. From here, the user could click Cancel and the file remains open. But the users are reporting that it's confusing to see the second prompt after clicking Cancel on the first. And they are not willing to disable the iManage addin. We would like to be able to keep the file open in this case, preferably without seeing the iManage prompt.
Working in a test environment a client set up for me (Excel 2010), I have tried a few things:
I tried setting Cancel on the workbook level BeforeClose and the applicationlevel WorkbookBeforeClose; neither one worked (file still closes whenever iManage is enabled)
I tried to make sure my handler for WorkbookBeforeClose is registered last, by registering it in the workbook level event handler; no change
I can use the iManage ribbon to manually switch to Local Mode, which makes everything work, but I don't know whether/how I can make that change through code.
I can find the iManage addin in Globals.ThisAddIn.Application.COMAddIns; I tried setting its Connect = false, but this gives an error to the effect that only an administrator can connect/disconnect the addin.
I can save the local file during the Closing event, then do SaveAs to create a second copy; the second copy is now active and iManage closes it; then I reopen the original local file. It looks pretty good to the user, but then I have a bunch of COM references to cells on the old file, and these are all garbage. I can probably loop through and serialize them and recreate them with the new file, but it will be time consuming to code and to run, so I'm looking for other ideas first.
Is there any way I can keep the file open, without making the users do anything extra?
UPDATE
Using iManage 9.3.0.0 and Excel 2010, I created a VBA macro with a reference to Worksite Integration Interfaces Library(Ex). The event fires, but the file still closes. If I don't set the Saved property, and I type on the grid, I always get a prompt from iManage asking if I want to save.
Private WithEvents oWS As iManageExtensibility
Private Sub oWS_DocumentBeforeClose2(ByVal Doc As Variant, IgnoreIManageClose As Boolean, Cancel As Boolean)
IgnoreIManageClose = True
Cancel = True
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Set oWS = Application.COMAddIns("WorkSiteOffice2007Addins.Connect").Object
Cancel = True
ActiveWorkbook.Saved = True
End Sub
You do not need to disable the iManage integration add-in for Office. Your application should detect the presence of the iManage integration add-in and then handle that add-in's own equivalent Close event
To do that, first get an instance of the iManage add-in by examining the Excel Application.COMAddins collection and fetching back the COM add-in instance with a ProgID of either WorkSiteOffice2003Addins.Connect (Excel 2003 or earlier) or WorkSiteOffice2007Addins.Connect (Excel 2007 or later).
Actually there should also be a so-called "backwards compatibility" add-in installed also registered with a ProgID of oUR02k.Connect which you may reference instead. Again, whether that is installed or not depends somewhat on the version of FileSite/DeskSite that is installed on the machine.
That all may seem confusing to you however it's because the add-ins have changed over the years, so it rather depends on how old the iManage client is (i.e. FileSite, DeskSite) as well as the version of Office you're targeting. You may need to compensate for different Excel/iManage client versions in your code
Once you have the right COM add-in reference, examine the COMAddin.Object property. This value represents an instance of the iManage Office integration add-in
From there you can cast that object to the strongly typed COM interface of iManageExtensibility
You're then able to hook into all the Office application events that iManage have hijacked (much like you have done in your application) and respond to those events rather than the native Excel ones.
In your case you will need to monitor the DocumentBeforeClose2 event. Note the character '2' at the end. There is also a legacy event named DocumentBeforeClose but the newer DocumentBeforeClose2 has the following method signature:
DocumentBeforeClose2(object doc, ref bool ignoreimanageclose, ref bool cancel)
Finally, in your DocumentBeforeClose2 event handler add your business logic for cancelling the close event and/or the iManage close event. You do that by setting the ignoreimanageclose and/or cancel Booleans to true/false as appropriate. The doc parameter in this case will be the Excel workbook instance, so you may safely cast it to the Excel.Workbook interface if you wish
PS: if you are developing against the iManage APIs and require support you should consider purchasing the iManage SDK. That SDK contains help on various APIs, code samples, and crucially I believe it gives you access to some dev support.
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.
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.
Excel 2007 uses an updated/custom version of the standard Windows folder browse dialog, which you can see if you navigate to Office Button -> Excel Options -> Save -> Server drafts location -> Browse...
Our client wants us to use that dialog instead of the standard C# FolderBrowserDialog - is this possible (i.e. what Win32 DLLs/API calls would need to be made), and more to the point, would it be legal?
The Application.FileDialog object should give you what you're looking for. You can customise it to allow multi-select, set the initial folder, set a file type filter, etc. No API calls required
MSDN FileDialog Object
MSDN FileDialog Object Members
In Windows 7 (possibly vista) you might be able to find the code in here.
http://code.msdn.microsoft.com/WindowsAPICodePack
I've noticed they finally got rid of the old folder browser in 7 with a new one that looks like an open file dialog, but I'm not sure how to implement it.