I am looking for a way to open the password protected Excel file in Excel from my c# program.
Please notice I just need to open it for my user. I am not looking for something like Excel Interop to modify the file.
For a file that has no password, I can simply launch the process start with the full path file name as a parameter. But this one has password in it, so it can't be done like this.
If I use Excel interope to open it, I can open it, but the Excel process will leave there when user close the Excel window.
var excelApp = new Excel.Application();
excelApp.Visible = true;
var wb = excelApp.Workbooks.Open(#"d:\temp\test.xlsx", Password:"1234");
Since user will be modifying the file in the Excel window and then close the windows. This part is out of my control. I simply just want to launch the file, then I don't have to care about it. But by using Excel interope, the COM is actually referecing back to my c# program, so that the whole Excel process can't be disposed completely.
I think I know a workaround for it.
Create a helper C# console application called OpenExcelWorkbookWithPassword.exe which looks like that:
static void Main(string[] args)
{
var excelapp = new Excel.Application();
excelapp.Visible = true;
Excel.Workbook workbook = excelapp.Workbooks.Open(args[0], Password: args[1]);
}
and use this from your main application with the following code:
string path = #"d:\temp\test.xlsx";
string pw = "1234";
System.Diagnostics.Process.Start("OpenExcelWorkbookWithPassword.exe", path + " " + pw);
When the user is closing Excel the Excel.exe process will be terminated even if your main application is still running.
Related
I have an excel file in my project which is listed as resource.
Now I try to open it with a button click like this:
private void Button_Click_Blist(object sender, RoutedEventArgs e)
{
Excel.Application xl = new Excel.Application();
Excel.Workbook wb = xl.Workbooks.Open("Blist.xlsx");
}
My problem is that it says that it can't find the file and throws this exception:
System.Runtime.InteropServices.COMException
We couldn't find 'Blist.xlsx'. Was the object perhaps moved, renamed,
or deleted?
This code uses OLE Automation to start Excel and tell it to open a file in the relative path Blist.xlsx. The executable in this case is Excel, not your own application. The relative path will be resolved using Excel's working directory.
To avoid this problem, pass the absolute file path to Excel :
var fullPath=Path.GetFullPath("Blist.xlsx");
Excel.Workbook wb = xl.Workbooks.Open(fullPath);
Another possibility, which gives no control of (or dependency on) Excel, is to just "start" the file with Process.Start, eg :
Process.Start("Blist.xlsx");
Or
var fullPath=Path.GetFullPath("Blist.xlsx");
Process.Start(fullPath);
The Windows Shell will find the application that can open this document based on its extension and start it, passing the file path as an argument. This can start Excel, Libre Calc or any other application registered to open this particular file extension.
So I tried this and apparently the .Open() method some extra complexety with relative paths (see #PanagiotisKanavos comment). You can make a work around, by getting the current directory path, and pre-pending it, giving the absolute path of the file:
string filename = "Blist.xlsx";
string currentPath = Directory.GetCurrentDirectory();
var xl = new Microsoft.Office.Interop.Excel.Application();
var wb = xl.Workbooks.Open(currentPath + "\\" + filename);
xl.Visible = true;
However, you should (almost) never use hardcoded file names in your code. So the above solution is just an example, not something to copy into production code...
In my application I open a .xlsm file with a macro (copies data to .xlsm file) and a .xlsx file that executes that macro. Let's say my files are called FileWithMacro.xlsm and FileThatExecutesMacro.xlsx. I need this application on a server but have developed it locally. To debug the application, I put my files to C:\Users\myUser\Documents\.
I'm opening the FileWithMacro.xlsm like this:
Excel.Application excel = new Excel.Application();
Excel.Workbook workbook = excel.Workbooks.Open(serverPath + "FileWithMacro.xlsm");
Excel._Worksheet worksheet = workbook.Sheets["FileThatExecutesMacro"];
After that, I call the method that runs the macro:
RunMacro(serverPath + "FileThatExecutesMacro.xlsx");
My method looks like this:
private static void RunMacro(string source)
{
Excel.Application excel = new Excel.Application();
Excel.Workbook workbook = excel.Workbooks.Open(source);
Excel._Worksheet worksheet = workbook.Sheets[1];
worksheet.Activate();
try
{
excelThatRunsMacro.Run("FileWithMacro.xlsm!MyMacro");
workbook.Save();
excelThatRunsMacro.Quit();
}
// and so on
}
Locally the macros work without any problems. When I change all the paths and copy the output of my code to the server (\\myServer\someUrl...), I'm getting the following exception:
'C:\Users\myServerUser\Documents\FileWithMacro.xlsm' could not be found.
Although I changed all my paths to the correct server location (and I am really sure that there is no local path in my code and in the macro anymore). I even deleted my bin and obj folders and rebuilt the project but that didn't change anything. I even created a new project and built it without using local paths but I got the same error. What am I doing wrong? Is excel.Run by default searching the macro in the Documents folder?
Or is the problem because of the line Windows("FileWithMacro.xlsm").Activate in my macro? When running the macro manually, it works fine. It just doesn't work when running it through the code.
I couldn't find out why I got the exception. However, I've found a workaround. Before executing the macro, I copy the FileWithMacro.xlsm to the location in the error message. When I then used the code like I've had it, I've got a message that the FileWithMacro.xlsm is already in use. To fix this, I just had to pass the Excel.Application to my method and use this instance instead of creating a new one:
private static void RunMacro(Excel.Application excel, string source)
It seems that most questions regarding working with Excel files through C# resolve around doing it in a fully automated way. I have a slightly different issue.
The way the code is supposed to work.
Launches a batch that creates a .txt file in given location, populated by results of a sql query. (Done and works)
Opens the file in Excel (the reason why I use .txt is that .csv messes up my numbers by removing leading zeroes etc) and makes it visible to the user. The code stops working and leaves the rest to the user.
User makes the changes to the file himself and manually saves them and exits Excel.
The problem that I am encountering is that the process does not want to 'leave the file alone'. It opens correctly, I edit the value and then I save it and when I try to close it it asks me if I want to save changes again. I click yes and that immediately brings up another popup asking the same question.
I do not know how to 'release' the file so that its control will be fully up to the user without actually closing Excel.
This is the bit of code that I use:
{
(...)
RunBatch("Manual_adjustment");
string fileName = "Manual_Adjustment.txt";
Excel.Application excel = new Excel.Application();
object misValue = System.Reflection.Missing.Value;
Excel.Workbook excelWorkbook;
excel.Visible = true;
excelWorkbook = excel.Workbooks.Open(ConstantValues.FolderPathInput + + #"\" + fileName);
releaseObject(excelWorkbook);
releaseObject(excel);
}
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Exception Occured while releasing object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
How do I let the user save the changes without making him manually open the file from the OS level?
I think calling to Excell.Application.Quit may works
I'm wanting to import data from an Excel workbook without actually displaying the open workbook.
I could have sworn I had used the following code on a previous project and it had worked:
var excelApp = new Excel.Application { Visible = false };
var workbook = excelApp.Workbooks.Open(filePath);
Unfortunately when the workbook opens it is displayed to the user which is unnecessary for this application.
I'm using Microsoft Excel 15.0 Object Library on this project when previously I think it was version 12 or 13. Maybe this is the problem, or is my memory fading and the code is incorrect?
I know this is old but just in case anybody still needs this answer...
excelApp.Visible = false;
(excelApp being the name of the variable used for the excel application)
Is there a way to save changes to an excel spreadsheet through the excel interop (in this case I am adding a worksheet to it) without having it prompt the user if they want to overwrite the existing file with the changes. I do not want the user to even see the spreadsheet open in my application so having a message box popping up asking them if they want to overwrite the file seems very out of place and possibly confusing to the user.
I am using the workbook.SaveAs(fileloaction) method.
Here is where I am initializing the COM reference objects for the excel interop.
private Excel.Application app = null;
private Excel.Workbook workbook = null;
public Excel.Workbook Workbook
{
get { return workbook; }
set { workbook = value; }
}
private Excel.Worksheet worksheet = null;
private Excel.Range workSheet_range = null;
Below is the code I am using to close/save the excel file. The workbook.close() method line is the one that is reportedly throwing the unhandled exception.
workbook.Close(true, startForm.excelFileLocation, Missing.Value);
Marshal.ReleaseComObject(app);
app = null;
System.GC.Collect();
Basically, all you need is ExcelApp.DisplayAlerts = False - Here's how I do it, though:
ExcelApp.DisplayAlerts = False
ExcelWorkbook.Close(SaveChanges:=True, Filename:=CurDir & FileToSave)
Hope this helps
Only this code will Require for stop override alert or Template already in use
ExcelApp.DisplayAlerts = False
I know this is an old post, but I wanted to share a way to make this work without causing possible frustration in the future.
First what I do not like about using: ExcelApp.DisplayAlerts = False
Setting this flag will set this property on the excel file, not just in your program. This means that if a user makes changes to the file and closes it (by clicking the X), they will not be prompted to save the file and will cause frustration later. It will also disable any other prompts excel would typically post.
I like checking if the file exists before saving it:
if (File.Exists(SaveAsName))
{
File.Delete(SaveAsName);
}