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)
Related
I am currently consistently failing at a very simple task:
I want to loop through all currently open Excel-files (Workbooks)
Of course I did the usual googling for code snipes and found quite a bunch of ready-to-use code that should work according to the comments in the discussion threats and ratings. But for me they all just don’t work
I also saw people mentioning releasing COM Objects, but I didn’t really understand it and all the ready-to-go code examples don’t include it neither.
I am using:
Windows 10
Office 16
Visual Studio 2017 (V15.9.41)
COM-Reference 'Microsoft Excel 16.0 Object Library'
I modified the code snippets I found online, so my current code looks like this:
using System;
using Microsoft.Office.Interop.Excel;
private void PrintListOfOpenWB()
{
Microsoft.Office.Interop.Excel.Application xlApp;
xlApp = new Microsoft.Office.Interop.Excel.Application();
foreach (Workbook item in xlApp.Workbooks)
{
Console.WriteLine(item.Name);
}
}
I am using it as part of a WindowsFormsApp, so there is also using System.Windows.Forms etc, but I removed this part, so only the relevant code is shown here.
I do have multiple workbooks open and I do not get any error while compiling nor while running the code. But there is absolutely no output generated, because it directly jumps to the end of the foreach loop.
Any ideas what I am doing wrong?
I looked further into it and found the following solution that works for me.
using System;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
private void PrintListOfOpenWorkbooks()
{
Excel.Application xlApp;
xlApp = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
foreach(Excel.Workbook xlWorkBook in xlApp.Workbooks)
{
Console.WriteLine(xlWorkBook.Name);
}
}
Maybe this will help other people in the future as well.
This probably returns no output because the variable is empty, doing what you did you only created the variable that let you access the library method, and you can't populate that with an actual excel file, to do that do this:
Workbook workBook = xlApp.Workbooks.Open(yourExcelFilePath);
//Cycle through the workBook and display the sheets
workBook.Close(false, yourExcelFilePath, null);
Remember that the hierarchy of working with excel files (and this is practically the same with all the different libraries that helps you in doing this) is structured like this:
test = new Microsoft.Office.Interop.Excel.Application(); : This is used just to interface with the library methods
WorkBook : This is the actual equivalent of the full excel file you want to work on, and you need to populate it first
Worksheet: This is an entity that represent a single excel "page" inside the file
P.S: Re-reading the question I maybe have understood it wrong, can you specify if you want to show the name of excel files inside a folder or show the names of the single sheets inside a sigle excel file
To show the names of different excel files somewhere you can do this:
string[] temp = Directory.GetFiles(directoryPath);
List<string> ExcelFilesInDirectory = new();
foreach (var item in temp)
{
if (item.Contains(".xlsx"))
{
ExcelFilesInDirectory.Add(item);
}
}
Then with that list you can make the user select the file he wants to modify and then you can use the first code sample I sent to make it work
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...
I am working on a web App where user can upload an Excel file and I need to copy data from the user worksheet to a destination worksheet in order to do some calculation. To do so, I have the following code:
public class ExcelCtrl
{
private Excel.Application excelApp = null;
private Excel.Workbook srcworkbook = null;
private Excel.Workbook destworkbook = null;
public void excel_init(String srcpath, String destpath, string copyrange)
{
//Open Excel
this.excelApp = new Excel.Application();
//Open user's file
this.srcworkbook = excelApp.Workbooks.Open(srcpath);
Excel.Worksheet srcworksheet = (Excel.Worksheet)srcworkbook.Worksheets.get_Item(1);
//Open calculation file
this.destworkbook = excelApp.Workbooks.Open(destpath);
Excel.Worksheet destworksheet = (Excel.Worksheet)destworkbook.Worksheets.get_Item(1);
//Range of copy
Excel.Range from = srcworksheet.get_Range(copyrange);
Excel.Range to = destworksheet.get_Range(copyrange);
//Copy
from.Copy(to);
//Close user's file
srcworkbook.Close();
//Open Xla file
excelApp.Workbooks.Open("someXlaFile.xla");
excelApp.Workbooks.Open("AnotherXlaFile.xla");
}
Basically I have to different method to run different calculations and they have the following structure. What differ one calculation method to another are just the macro called, the number of macro and the copy range.
public static string Calculation1(String InputFileName, String CurDir)
{
//The Excel calculation file and its path
string filename = "CalculationFile.xls";
string path_server = ExcelCtrl.DossierCalcs + filename;
ExcelCtrl excel = new ExcelCtrl();
excel.excel_init(CurDir + "\\" + InputFileName, ExcelCtrl.DossierCalcs + filename, "A1:Z105");
//excel.excel_run("Macro1");
//The rest is not important
path_server = CurDir + "\\Resultats - " + InputFileName;
excel.excel_run("AnotherMacro", path_server);
excel.excel_close();
return path_server;
}
Now all work fine, except one calculation (the one above). I am unable to copy data from the user worksheet.
I have tested to :
(normal usage) upload an Excel file with some new data and when I download the file after calculation, it is still the old data.
reduce the range of copy ( I though maybe it is too big) to "A1:Z50" then "A1:A2". However, I have another calculation file where I copy a range of "A1:M730" and it works fine.
copy it manually with Ctrl + C; Ctrl + V (I thought maybe the worksheet is protected from modification or something)
With the first 2 tests, I still got old data (not the user data) and the last one works, I can paste user data; though not very useful if someone need to do it manually everytime an user ask for this calculation.
I hope this is enough for you to understand my problem and hope you can guide me.
Thanks
EDIT
Hello,
Just to clarify a little bit about what I am doing. I have an web app where user can download an Excel xlsx file and they have to fill in with their data. After that, They have to upload their file to the server and choose the calculation they want to run. On the server side, I copy their data (see code above) to the corresponding Excel calculation file. So for each calculation I have one input file for the user and one calculation file to run. In total I have 14 input files and 14 calculations files and 13 of them work fine.
I have done some more tests, the following tests do not copy my data :
(And I am using Excel 2010)
Changing the name of my destination Excel file to something more common because there were a "#" in the file name.
Changing the name of my destination Excel file to one another destination file where the copy works.
Changing the worksheet color (I really don't believe that will solve my problem but I have nothing to lose)
Deleting worksheets from my destination file one by one
And the following tests work (data are copied to the destination file) :
Copying to a new Excel file
Copying to an other Excel calculation file (let's say file B) where I know the copy works
My thought for the last case is because when I open my problematic Excel file, 2 warnings come up. The first one says that the workbook contains link to other data sources and ask me if I want to update it (even after updating, it keeps asking me everytime I open it) and the second one says that the workbook contains links that can not be updated.I have also this 2 warnings when I open file B but with this file the copy works.
So I have tried to delete all links in the file and it does not work either. Futhermore, those links are used in my 13 others files.
I am kind of lost now since I have deleted all worksheet and links from my Excel file and it still won't copy. The only difference I see between my problematic file and a new file is that the former contain Macro.
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)
http://support.microsoft.com/kb/306023 it's the first example: "Use Automation to Transfer Data Cell by Cell" Below are the variables I declared for the example.
Excel.Application m_objExcel;
Excel.Workbooks m_objBooks;
Excel._Workbook m_objBook;
Excel.Sheets m_objSheets;
Excel._Worksheet m_objSheet;
Excel.Range m_objRange;
string m_strSampleFolder = #"C:\VBtest\PRACTICEProgramming\INDIVIDUALprograms\EXCEL";
string m_objOpt = #"C:\VBtest\PRACTICEProgramming\INDIVIDUALprograms\EXCEL";
Excel.Font m_objFont;
Basically everything runs fine. The issue is when the app is running, I get an error message.
"COMException was unhandled
Excel cannot access 'EXCEL'. The document may be read-only or encrypted."
I'm thinking the value I declared for m_objOpt is declared wrong or it doesn't like the value. I tried creating a premade .XLS file but that doesn't work. I also tried putting a name for the xls but the add method wants to find the xls in the default path which I don't want.
I don't know what I can do to fix it.
Looks like you're missing the file extension at the end of m_objOpt... You can try to add .xls or .xlsx to it, or something else regarding the file extension.