How to insert comment with picture into excel using C# - c#

As what I described in title, how to insert a picture as a comment into Excel using C#?
Please offer a sample code or some reference documents.
Following is my code:
using Excel=MicroSoft.Office.Interop.Excel;
publice void ExcelEdit(string Path)
{
Excel.Application xlApp;
Excel.WorkBook xlWorkBook;
Excel.WorkSheet xlWorkSheet;
Excel.Range myRange;
xlApp=new Excel.ApplicationClass();
xlWorkBook=xlApp.WorkBooks.Open(Path, misValue, misValue,misValue, misValue,misValue, misValue,misValue, misValue,misValue, misValue,misValue, misValue,misValue, misValue)
xlApp.Visable=True;
xlWorkSheet=(Excel.WorkSheet)xlWorkBook.Sheets.get_Item(1);
myRange=WorkSheet.Range[WorkSheet.Cells[1,1],WorkSheet.Cells[1,1]);
xlWorkSheet.Cells[1,1]=InstertPictureComment(myRange,Path);
myRange=WorkSheet.Range[WorkSheet.Cells[1,2],WorkSheet.Cells[1,2]);
xlWorkSheet.Cells[1,1]=InstertPictureComment(myRange, Path);
}
public void InstertPictureComment(Excel.Range myrange, string picturepath)
{
myrange.ClearComment();
myrange.AddComment();
myrange.Comment.Shape.Fill.UserPicture(picturepath);
myrange.Comment.Shape.Width=400;
myrange.Comment.Shapes.Height=300;
}
I can successfully insert picture comments into excel. The problem is that: when I copy and paste the cells which I have just inserted comments, save the excel, and close it. The next time When I open the excel, messagebox shows "unreadable content in xxx has found. "
What to do with my code!!

The question seems to be repeat of Insert picture comment with C# Ok while copy content with comments fail
I just now posted an answer there. Copying the same answer here.
I have corrected the code so that it compiles
public void InstertPictureComment(Excel.Range myrange, string picturepath)
{
myrange.Cells.ClearComments();
myrange.AddComment();
myrange.Comment.Shape.Fill.UserPicture(picturepath);
myrange.Comment.Shape.Width = 400;
myrange.Comment.Shape.Height = 300;
}
Part of the problem is with Excel. With your code, you are probably creating a new application instance of Excel. Excel is unable to copy objects across the application instances.
If you open another workbook in the same application instance, the objects will get copied. The only way to copy data across application instances is using Paste Special functionality.
You should fetch the existing Excel application instance. If it is not there, then you may create it.
private Excel.Application GetExcelInstance()
{
Excel.Application instance = null;
try
{
instance = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
}
catch (System.Runtime.InteropServices.COMException ex)
{
instance = new Excel.Application();
appCreatedExcelInstance = true;
}
return instance;
}
You may use the appCreatedExcelInstance flag to decide whether or not to quit the instance during cleanup.
I hope this helps.

Related

C# code that remove all macros from Excel file

I have a Windows form app project (C#).
I am trying unsuccessfully to write code so that when I click a button I created, it will load an excel file that actually has macros in it and delete them all.
I know you can delete macros manually in the excel file itself but I need a way to do it programmatically (I just delete them all for the user).
I know that the macros in Excel files are written in VBA language, so I try to use the related libraries in c# but I get an error when I try to use VBProject, VBComponent.
This what I tried so far:
using Microsoft.Office.Interop.Excel;
namespace MacroRemover
{
public partial class Main : Form
{
private void Btn_Click(object sender, EventArgs e)
{
string filePath = "path\\to\\file.xlsm";
Application excel = new Application();
Workbook workbook = excel.Workbooks.Open(filePath);
VBProject vbProject = workbook.VBProject;
foreach (VBComponent component in vbProject.VBComponents)
{
vbProject.VBComponents.Remove(component);
}
workbook.Save();
workbook.Close();
excel.Quit();
}
}
}
Any way that works will help me, I would appreciate the help
Thanks in advance guys!!!
If you don't need to save xlsm format of the file, you can save this file to xlsx format and all scripts will be removed.
using Aspose.Cells;
var workbook = new Workbook("input.xlsm");
workbook.Save("Output.xlsx");
Thanks for all the replies, #tttony's response helped me to understand more deeply and #Bushuev's response here is definitely a possible and simple solution for deleting the macros.
I finally managed to delete all the macros like this:
string filePath = Path_TxtBox.Text;
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Workbook workbook = excel.Workbooks.Open(filePath);
VBProject project = workbook.VBProject;
for (int i = project.VBComponents.Count; i >= 1; i--)
{
VBComponent component = project.VBComponents.Item(i);
try
{
project.VBComponents.Remove(component);
}
catch (ArgumentException)
{
continue;
}
}
for (int i = project.VBComponents.Count; i >= 1; i--)
{
VBComponent component = project.VBComponents.Item(i);
component.CodeModule.DeleteLines(1, component.CodeModule.CountOfLines);
}
workbook.Save();
workbook.Close();
excel.Quit();
MessageBox.Show("Macros Removed");
It should only be noted that I encountered an error: 'Programmatic access to Visual Basic Project is not trusted'
It was solved after I realized that I had to change the option to access the VBA Project object model in the Trust Center settings.

C# : Close Excel file without popup

So basically my app triggers an excel macro, from a file, that updates the file and then closes it.
When I open the file I set the "DisplayAlerts = false" variable in order to ignore all popups and it works as expected in my computer... however, a colleague of mine tried to use it and for every file, he gets the popup asking if he wants to save all changes...
Checked other questions about the popups in excel but all suggested solutions use "oBook.Saved = true;" or "oBook.Close(false);", but these did not work for me.
my code is as follows:
using Microsoft.Office.Interop.Excel;
public static bool Trigger_Macro_From_File(string path)
{
ApplicationClass oExcel = null;
Workbook oBook = null;
try
{
string filename = Path.GetFileName(path);
string macro_name = "!some_macro";
string macro = #"'" + filename + #"'" + macro_name;
// Create an instance of Microsoft Excel
oExcel = new ApplicationClass
{
DisplayAlerts = false,
Visible = false
};
oBook = oExcel.Workbooks.Open(path);
RunMacro(oExcel, new Object[] { macro });
oBook.Save();
oBook.Saved = true;
return true;
}
catch (Exception ex)
{
return false;
}
finally
{
oBook?.Close(false);
System.Runtime.InteropServices.Marshal.ReleaseComObject(oBook);
oBook = null;
oExcel?.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(oExcel);
oExcel = null;
GC.Collect();
}
}
Does anyone know anything about this?
Thanks in advance.
You could double-check that no other "Microsoft Excel" process is running in the Task Manager.
Let's say at some point in your development process you started your program and open the workbook with something like
xlWorkbook = xlApp.Workbooks.Open(filePath);
Then you encountered an exception for some reason, and killed the program without closing the file properly (workbook.Close(..), app.Quit(..) and so on).
The Microsoft Excel process is still running in the background, and has a handle on the file you want to edit. So you cannot execute an instruction that saves the file under the same name. This is why the popup is appearing.
This scenario is taken from the point of view of the developer, but the same behavior could have happened on your coworker's computer if your app crashed without quitting properly, and gets re-started.
Also, be careful that finally statement might not always be executed, so double-check which scenario could cause your app to close without releasing the COM object.

System.Runtime.InteropServices error when exporting dataGridView to Excel workbook

I have an application that displays certain database data, and includes a function to save that data to an excel workbook on request using the Microsoft.Office.Interop.Excel assembly. One of my users reports the following error when trying to save to an excel workbook:
System.Runtime.InteropServices.COMException (0x8002000B): Invalid index. (Exception from HRESULT: 0x8002000B (DISP_E_BADINDEX))
at Microsoft.Office.Interop.Excel.Sheets.get__Default(Object Index)
at WorkCalendar.Form1.saveBtn_Click(Object sender, EventArgs e)
We've verified that he does have Excel 2013 installed and all of the necessary assemblies came through ok according to the full exception details, so I hope one of you can shed some light on what's going on here.
Here's the saveBtn_Click event method mentioned in the error above (edited for conciseness)
private void saveBtn_Click(object sender, EventArgs e)
{
// creating Excel Application
_Application app = new Microsoft.Office.Interop.Excel.Application();
_Workbook workbook;
_Worksheet worksheet;
string fetchString = fetch.ToString("HH.mm.ss");
try
{
// Check for existing workbook and add new page
}
catch
{
// If no workbook found, create a brand new one
workbook = app.Workbooks.Add(Type.Missing);
worksheet = null;
worksheet = workbook.Sheets["Sheet1"];
}
try
{
// do not show the excel sheet being created
app.Visible = false;
worksheet = workbook.ActiveSheet;
worksheet.Name = fetchString;
// Get dataGridView data, insert it into the excel worksheet and format it
}
catch { }
finally
{
// save the application
// Exit from the application
app.Quit();
}
}
As I said, the application works fine on my and other computers on which it's been tested. Any ideas?
EDIT: Altered code example slightly to show the method looking for an existing workbook, and creating one if no workbook found.

Excel Interop instances won't close

I am using Excel Interop. In the beginning of a method I got, I'm allocating a new instance of the application and at the end of it I'm trying to free it, but when I look at the TaskManager I can still see Excel open.
This is the code:
A class member: private Excel.Application _app;
The usage:
public void MethodApp()
{
_app = new Excel.Application();
....
....
FreeApplicationResources();
}
private void FreeApplicationResources()
{
_app.Quit();
Marshal.ReleaseComObject(_app);
}
MethodApp can run several times and it opens instances at the same quantity as the number of times it's called.
Why won't Excel close?
Try releasing any worksheets and workbooks used also in the order below:
Marshal.ReleaseComObject(_worksheet);
Marshal.ReleaseComObject(_workbook);
Marshal.ReleaseComObject(_app);

Using GetVstoObject and HasVstoObject

I have a console app that creates an excel worksheet using the Interop Library, and then tries to get the vstoObject using the GetVstoObject to use the Microsoft.Office.Tools.Excel Library. When running the code below the HasVstoObject always returns false, not sure if it is not created yet when executing since this is being runned from a simple console app main program. From the documentation of Extensions it seems plausible that this can be done
Microsoft.Office.Interop.Excel.Application excelApp = null;
Microsoft.Office.Interop.Excel.Workbook workbook = null;
Microsoft.Office.Interop.Excel.Sheets sheets = null;
Microsoft.Office.Interop.Excel.Worksheet newSheet = null;
Microsoft.Office.Tools.Excel.Worksheet XLsWorkSheet = null;
excelApp = new Interop.Application();
excelApp.Visible = true;
workbook = excelApp.Workbooks.Add(Type.Missing);
sheets = workbook.Sheets;
newSheet = (Interop.Worksheet)sheets.Add(sheets[1], Type.Missing, Type.Missing, Type.Missing);
newSheet.Name = "My New Sheet";
newSheet.Cells[1, 1] = "BOO!";
if (Excel.Extensions.WorksheetExtensions.HasVstoObject(newSheet)) {
XLsWorkSheet = Excel.Extensions.WorksheetExtensions.GetVstoObject(newSheet);
Microsoft.Office.Tools.Excel.Controls.ComboBox combobox1 = XLsWorkSheet.Controls.AddComboBox(XLsWorkSheet.Range["A1", "A1"], "combobox1");
combobox1.Items.Add("1 Item");
}
I also created a Excel 2007 addin to try this and it dosent work when using Globals.Factory.GetvstoObject
Thanks
I think that HasVstoObject will always return false if you never have called GetVstoObject to "cache" the extended VSTO-Object. So the solution is to call GetVstoObject without the enclosing if and everything will work fine. After that, the method HasVstoObject will also return true.
Regards,
Jörg
P.S.: I also don't really understand the deeper sense of the HasVstoObject method...

Categories