Change macros text in Excel programmatically - c#

I've got about thousand of Excel (xls, old format) files spread out across many folders on the hard-drive. These files have the same macros that connects to a database. And the macros contains connection string. Macros is password protected, but luckily I know the password.
Question: what is the best way to change the connection string in macros inside all the files?
I have experience of working with NPOI to create/modify xls files. I have seen Interop libraries unlocking password-protected Word files and doing some editing. But I have never seen examples of programmatically changing of the macros text inside Excel file. Is that even possible?
p.s. I don't have problems writing code. The problem is choosing the right tools.

You might want use the following code as a starting point. This code uses COM Interop to extract the VBA script and perform a find-replace. I tried this out on a password-protected spreadsheet with a very basic script and it worked well. It is, admittedly, basic, but you may be able to extract what you need.
string filename = "Test.xls";
string password = "password";
Excel._Application app = new Excel.Application();
Excel._Workbook workbook = app.Workbooks.Open(Filename: filename, Password: password);
if (workbook.HasVBProject)
{
VBProject project = workbook.VBProject;
foreach (VBComponent component in project.VBComponents)
{
if (component.Type == vbext_ComponentType.vbext_ct_StdModule ||
component.Type == vbext_ComponentType.vbext_ct_ClassModule)
{
CodeModule module = component.CodeModule;
string[] lines =
module.get_Lines(1, module.CountOfLines).Split(
new string[] { "\r\n" },
StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Contains("A1"))
{
lines[i] = lines[i].Replace("A1", "D1");
module.ReplaceLine(i + 1, lines[i]);
}
}
}
}
}
workbook.Save();
workbook.Close();
app.Quit();

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# Run Excel Macro Through IIS Server

I have a C# (using Razor) Web Application that runs through my company's intranet.
I have been using ClosedXML to manage all of my Excel needs and it works great, however, now I need to run Macros inside Excel Files and apparently ClosedXML cannot do this, so I must use Excel Interop.
My code below gives the dreaded:
Microsoft Excel cannot access the file ... 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.
The file name and path DOES exist
I made sure that Excel is not even running on the server
The workbook is not open (see above).
Things I've tried.
I've tried to create security provisions for the C:\Windows\System32\config\systemprofile and SysWOW64\config\systemprofile.
(Side Note: I could not find IIS_USRS when I tried to add the security provisions - this may be the problem.)
I've also tried editing the Excel Application properties via dcomcnfg and I still get the same error.
here's what I'm trying to do:
//C# with Razor Syntax
#using MSExcel = Microsoft.Office.Interop.Excel
#using System.Runtime.InteropServices
#using System.Web
#using System.IO
string worksheetName = "Sheet1";
string[] macros = new string[] { "Module1.Reset_List()", "Module1.Run_Setup()"};
string workbookPath = HttpContext.Current.Server.MapPath(#"~/uploads/test.xlsm");
FileInfo xlsFile = new FileInfo(workbookPath);
string msg = (File.Exists(xlsFile.FullName)) ? "Found It!" : "Can't Find It...";
<p>#msg</p>; // <-- This always returns "Found It!"
//Create the Excel Object
MSExcel.Application xlsApp = new MSExcel.Application();
xlsApp.Visible = true;
try
{
//Identify the workbook (open the file)
// *** the error occurs on the line below *** //
MSExcel.Workbook xlsBook = xlsApp.Workbooks.Open(xlsFile.FullName);
xlsBook.Activate();
//Identify the worksheet
MSExcel.Worksheet xlsSheet = (MSExcel.Worksheet)xlsBook.Sheets[worksheetName];
xlsSheet.Activate();
foreach (string macro in macros)
{
xlsApp.Run(macro);
}
xlsBook.Save();
xlsBook.Close(false, "", false);
xlsApp.Quit();
}
catch (Exception e)
{
<p>#e.Message</p>
Marshal.ReleaseComObject(xlsApp);
xlsApp = null;
}
if (xlsApp != null)
{
Marshal.ReleaseComObject(xlsApp);
xlsApp = null;
}

C# ,Exception from HRESULT: 0x80029C4A (TYPE_E_CANTLOADLIBRARY)

I face this problem when I try the exe at the user's end. The user has MicosoftExcel 2000 and I have execel 2003. Can someone please help me.
I have created this tool in c# and have used COM
if( strDataSheetFile.Trim().EndsWith( ".xls" ) || strDataSheetFile.Trim().EndsWith( ".xlsx" ) )
{
System.IO.StreamWriter file = null;
if (IfAbFile)
{
file = new System.IO.StreamWriter(AbaqusDeckFile.ToString(), true);
}
else
{
string[] strFILEnamesSplit = strDataSheetFile.Split(new Char[] { '\\' });
string ExpFile = "";
int ilnt = 0;
foreach (string strVal in strFILEnamesSplit )
{
if (ilnt < (strFILEnamesSplit.Length - 1))
{
ExpFile += strVal;
ExpFile += "/";
}
else
ExpFile += "Deck.inp";
ilnt += 1;
}
file = new System.IO.StreamWriter(ExpFile.ToString(), true);
}
List<List<double>> List_SheetValues = new List<List<double>>();
Excel.Application objexcel;
Excel.Workbook wbexcel;
Excel.Worksheet wsheet;
objexcel = new Excel.Application();
//strDataSheetFile = #"C:\Ajoy\Demos\IsoMount\IsoMount_Springs_database_updated.xls";
if (File.Exists(strDataSheetFile))
wbexcel = objexcel.Workbooks.Open(strDataSheetFile);
else
{
MessageBox.Show(" Please state the number of springs", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Application.UseWaitCursor = false;
return;
}
This is probably happening in you use early (compile time) binding to the Excel type library.
The user has a different version of the type library (2000 vs 2003 on your machine).
Have you tried installing Excel 2000 on your machine & compiling your app by linking to the 2000 type library.
Alternatively, if you are not using any 2003 specific features AND the the functions & objects you are using have not changed between those 2 versions, you can try late (runtime) binding.
There'll be a slight performance hit & you lose intellisense in the IDE but should make your app portable across all Excel versions that support those objects & functions
i think the problem is you are compiling your Project as 'x64' 64bit instead of that compile it as x86 32 bit Application. Follow the below steps:
->Right click on Project
->Select Properties
->Select Build tab
->Change "Platform Target" to "x86"
->now run the Project.

Excel Template: Merging data and saving workbooks

I am on my first foray into Excel Interop and after a flying start have hit a wall.
I have an Excel template that contains one sheet which is an assessment form and another which contains guidance notes for how to carry out the assessment.
I also have an XML file with the details of the projects being assessed.
I need to merge the project title, application number and company name into the first sheet and then save the sheet with the filename [Application No] - [Project Title].xlsx.
The first part is working fine. I have Loaded the XML and the code is putting the data into the form where it should be.
My problem is the saving part. I found the .SaveAs method and it creates a couple of files... but they won't open. I then get a HRESULT error 0x800A03EC - Searching the web has explained nothing about this. Something is telling me that this.SaveAs() is referring to the worksheet rather than the work book but I am just guessing there.
I am hoping I have done something stupid and it is an easy fix.
For reference here is my code but like I say I am not sure how useful it is.
private void MergeData()
{
doc.Load(#"C:\XML Data\source.xml");
XmlNodeList forms = doc.SelectNodes("//form1");
for (int i = 0; i < forms.Count; i++)
{
XmlNodeList nodes = forms[i].ChildNodes;
string refNo = nodes[0].InnerText.ToString();
string companyName = nodes[3].InnerText.ToString();
string title = nodes[1].InnerText.ToString();
this.Cells[9, 4] = title;
this.Cells[11, 4] = refNo;
this.Cells[14, 4] = companyName;
this.SaveAs(#"C:\Assessment Forms\" + refNo + " - " + title + ".xlsx");
}
}
Does anyone know how to save these files?
Thanks for reading
EDIT--
I have found this article
C# and Excel Interop issue, Saving the excel file not smooth
and changed the code to include its suggestion
Excel.Application app = this.Application;
Excel.Workbook wb = app.Workbooks.Add(missing);
wb.SaveAs(#"C:\Assessment Forms\" + refNo + " - " + title + ".xlsx");
But it is doing the same.
I am on a deadline so think I am going to have to start copying, pasting and saving manually :(
Not sure what object this is here, but if you are correct in assuming this is a worksheet, try this.Parent.SaveAs
Alternatively if this turns out to be a range, try this.Worksheet.Parent.SaveAs

Folder of recovered files missing their names - How can I find the one I am looking for by the contents of the file?

I managed to accidentally delete a backup of files I had which I then later recovered. The recovery has lost the files names and location and I am left with about 3000+ .indd (Adobeb InDesign) files.
My problem is I am trying to find the .indd file that I was working on with out having to open each one manually to check.
I know some of the words that I had and I am wondering if I could maybe read the .indd file using a binary reader looking for one of the keywords...I could build it in c# or whatever
Anyone got any ideas?
If regular search does not work, try the built in scripting, of which you can use Javascript, Visual Basic Script, or AppleScript to code. I'm going with JS...
I'm no expert, but I found this code snippet from page 101 of InDesignCS5_ScriptingGuide_JS.pdf and modified it a bit:
var folder = new Folder("C:/Path/To/Files");
var files = folder.getFiles('*.indd');
for (var i=0; i<files.length; i++) {
var file = files[i];
open(file):
var myDocument = app.activeDocument;
//Clear the find/change text preferences.
app.findTextPreferences = NothingEnum.nothing;
app.changeTextPreferences = NothingEnum.nothing;
//Search the document for the string "Important Text".
app.findTextPreferences.findWhat = "Important Text";
//Set the find options.
app.findChangeTextOptions.caseSensitive = false;
app.findChangeTextOptions.includeFootnotes = true;
app.findChangeTextOptions.includeHiddenLayers = true;
app.findChangeTextOptions.includeLockedLayersForFind = true;
app.findChangeTextOptions.includeLockedStoriesForFind = true;
app.findChangeTextOptions.includeMasterPages = true;
app.findChangeTextOptions.wholeWord = false;
//Perform search
var myFoundItems = myDocument.findText();
if (myFoundItems.length) {
alert("FOUND!");
break;
}
app.findTextPreferences = NothingEnum.nothing;
app.changeTextPreferences = NothingEnum.nothing;
myDocument.close();
}
Don't quote me on that, I did not actually run the code, but that's the idea.

Categories