Excel File created as read only - c#

I have created an Excel Add-in using VSTO in C#. I want to create a new Excel file from a template located on a SharePoint site. A file picker dialog box is used so the user can chose which file to use as a template. Everything works fine exept the new workbook is created as read only. If I copy the template file on my computer, and use the same program to pick that file as a template, the new workbook is not created as read only.
The file on the sharePoint is not being open elseware when creathing the new file. Is there a way to specify the sharePoint library is a safe source? Or to set the newly created workbook readonly property to false?
{
string pathSP= #”\\Business.sharepoint.com#SSL\teams\group\NDC\”;
if (System.IO.Directory.Exists(pathSP))
{
Excel.Application excelObj = Globals.ThisAddIn.Application;
Office.FileDialog fileDialog = excelObj.FileDialog[Office.MsoFileDialogType.msoFileDialogFilePicker];
fileDialog.InitialFileName = initialPath;
fileDialog.AllowMultiSelect = false;
fileDialog.InitialView = Office.MsoFileDialogView.msoFileDialogViewDetails;
fileDialog.Title = "Create Excel file from template";
fileDialog.Filters.Clear();
fileDialog.Filters.Add("Excel template", "*.xls; *.xlsx; *.xlsm; *.xltx; *.xltm; *.xlt", 1);
string TemplatePath;
if (fileDialog.Show() == -1)
{
templatePath = fileDialog.SelectedItems.Item(1);
fileDialog = null;
}
else
{
templatePath=""
fileDialog = null;
}
if (templatePath != "")
{
Excel.Workbook ws= excelObj.Workbooks.Add(templatePath);
}
}
else
{
MessageBox.Show("SharePoint site is not available", "Create Excel file from template", MessageBoxButtons.OK,MessageBoxIcon.Exclamation);
}
}

for the two ways you mentioned:
set the share point library as a safe source - this can be achieved by setting the excel setting: Options -> Trust Centre -> Trust Centre Settings -> Trusted Locations -> add the sharepont location
set the file access (readonly=false) at the end of your process
Actually as a general practice when dealing with template file (not limited to excel), the system should copy the template file to a local temp location (ideally the running user's TEMP folder), use it and then delete it afterwards. this way would avoid all kinds of problems such as file-lock-by-other-user/process problems.

So I think your problem is the Workbooks.Add(). Check out what Microsoft says about it:
[Workbooks.Add()] Determines how the new workbook is created. If this argument is a string specifying the name of an existing Microsoft Excel file, the new workbook is created with the specified file as a template.
I believe the workbook you're creating is a carbon copy of whatever the sharepoint server has, including permissions. The fact it works locally is another clue that sharepoint might be fiddling with permissions.
I suggest try saving a copy of the file locally. You can even use the SaveFileDialog object to give the user a GUI to save their new copy.
SaveFileDialog userSaveFileDialog = new SaveFileDialog();
userSaveFileDialog.Filter = "Excel 2007 and later | *.xlsx, Excel Macro Enabled Worksheet | *.xlsm, I'm guessing this is a 2007 template | *.xltx, Template Macro maybe | *.xltm, I almost definitely think this is a template file | *.xlt";
userSaveFileDialog.Title = "Save an Excel File";
userSaveFileDialog.ShowDialog();
this.Application.ActiveWorkbook.SaveCopyAs(#userSaveFileDialog.FileName);
Once you're done, you can programmatically open the newly saved workbook using userSaveFileDialog.FileName as your filepath.

Related

Can't open bound excel file in C# project

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...

How to open excel file as readonly without any alerts and without using any path or file name?

I'm loading data into excel template stored in server and downloading it using FileStreamResult. I want to download the excel as read only. To make read only as I tried path is asking but I don't know where the user can download it into his system from server. So, how can I make the file read only?
I'm able to download as read only but it was asking prompt like "Do you want save changes or open as Read-Only?" I don't want that prompt and file to be open directly with Read-Only.
I tried using macro
But it is asking prompt to save changes.
As I don't know the path as user will download from server to his particular location. So, how can I make that read Only without using path r filename?
Controller:
System.IO.Stream spreadsheetStream = new System.IO.MemoryStream();
XLWorkbook wb = new XLWorkbook(Server.MapPath("~/XlsReport/Report_Template.xlsm"));
.....(Loading data into worksheets)...
wb.SaveAs(spreadsheetStream);
spreadsheetStream.Position = 0;
return new FileStreamResult(spreadsheetStream,"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") { FileDownloadName = "Report.xlsm" };
Macro:
Private Sub Workbook_Open()
ThisWorkbook.ChangeFileAccess xlReadOnly
End Sub
The downloaded file is asking to save changes. It should be directly open as ReadOnly without any prompts.
I used
ThisWorkbook.Saved = True
ThisWorkbook.ChangeFileAccess xlReadOnly
Now the downloaded file was directly opening in read only.

C# OpenFileDialog: The filename, directory name, or volume label syntax is incorrect

I need to programmatically open a document from Sharepoint in Visio. But when I navigate to the network folder, select a document and click on open, I
get the following error:
The filename, directory name, or volume label syntax is incorrect
When searching for the error, I found the following documentation: https://msdn.microsoft.com/en-us/library/ms832054.aspx. So I guess that the file name contains illegal characters. I tried to use the FileOk event to overwrite the validation of the fileName:
public void openFile() {
OpenFileDialog sf = new OpenFileDialog();
sf.FileOk += openFileDialog_FileOk;
if (sf.ShowDialog() == DialogResult.OK)
{
var app =(Microsoft.Office.Interop.Visio.Application)context.Application;
app.Documents.Open(sf.FileName);
}
}
private void openFileDialog_FileOk(object sender, CancelEventArgs e)
{
var sfd = sender as OpenFileDialog;
var file = new FileInfo(sfd.FileName);
if (file.Name.Contains('#'))
e.Cancel = true;
}
but the event does not fire. Using the standard Visio interface it is possible to open files from Sharepoint but the file dialog looks a bit different:
How can I get a similar file dialog? And so my questions is: how can I programmatically open a Visio document from Sharepoint (network folder)?
Since Visio does not provide app.GetOpenFilename API, you are out of luck. But you could use another office application for the same. Like Excel for example:
var excel = new Excel.Application();
var fileName = excel.GetOpenFilename();
excel.Quit();
var visio = new Visio.Application();
visio.Documents.Open(fileName);
which provides a "similar dialog" and "normal url", that is understood by Visio API without any issues.
The problem probably is that Visio API does not understand UNC DAV file path format with #SSL part, that is provided by the default "built-in" OpenFileDialog (or may be something else as well). Check what is the value of the .FileName returned by the default dialog. BTW, to prevent error messages, it's enough to set sf.CheckFileExists = false, maybe that will be enough.

C# Excel unable to copy worksheet

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.

How to connect to an Excel workbook that lives in SharePoint 2013 and update it

I am creating a command line application and I would like to connect to a SharePoint site that has a workbook that I want to update.
I don't even know where to start but I guess the questions I have are.
What API can I use for this? It has to be something that is already built-in and not a third party API if possible :)
Once the connection is done and I am able to open the spreadsheet, will I be able to also switch from one sheet to another?
I've tried to use some code like this but it did not work.
private static void GetExcelSheetNames(string filename)
{
var xls = new Microsoft.Office.Interop.Excel.Application();
xls.Visible = true;
xls.DisplayAlerts = false;
var workbook = xls.Workbooks.Open(Filename: filename, IgnoreReadOnlyRecommended: true, ReadOnly: false);
try
{
// Refresh the data from data connections
workbook.RefreshAll();
// Wait for the refresh occurs - *wish there was a better way than this.
System.Threading.Thread.Sleep(5000);
// Save the workbook back again
workbook.SaveAs(Filename: filename); // This is when the Exception is thrown
// Close the workbook
workbook.Close(SaveChanges: false);
}
catch (Exception ex)
{
//Exception message is "Cannot save as that name. Document was opened as read-only."
}
finally
{
xls.Application.Quit();
xls = null;
}
}
The Exception that I get was:
Microsoft Excel cannot access the file 'https//url/bla/bla/bla/workbook.xlsx There are several possible reasons:
The file name or path does not exist.
The file is being used by another program.
The workbook you are trying to save has the same name as a currently open workbook.
Actually, it seems like it is trying to open an instance of Excel Desktop in my machine.
Sorry for such an open question but I don't really know how can I connect to a SharePoint site.
Thanks in advance!
If you're using a document in a document library, check to make sure that it is checking out the document before you try to save it. I am working with a similar process but using a report library instead of a document library and am able to save documents without check out/in.

Categories

Resources