I am creating an application which build the code.But i want to set the Visual studio 2010 properties programmatically.
For example, I want to set INCLUDE Directories, Reference directories, Library Directories this all directories which will be set from the VS GUI but i want this programmatically.
you can see msdn article to do this:http://msdn.microsoft.com/en-us/library/microsoft.build.buildengine.engine.buildprojectfile(v=vs.90).aspx
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Build.BuildEngine;
namespace BuildAProjectCS
{
class Program
{
static void Main(string[] args)
{
// Instantiate a new Engine object
Engine engine = new Engine();
// Point to the path that contains the .NET Framework 2.0 CLR and tools
engine.BinPath = #"c:\windows\microsoft.net\framework\v2.0.xxxxx";
// Instantiate a new FileLogger to generate build log
FileLogger logger = new FileLogger();
// Set the logfile parameter to indicate the log destination
logger.Parameters = #"logfile=C:\temp\build.log";
// Register the logger with the engine
engine.RegisterLogger(logger);
// Build a project file
bool success = engine.BuildProjectFile(#"c:\temp\validate.proj");
//Unregister all loggers to close the log file
engine.UnregisterAllLoggers();
if (success)
Console.WriteLine("Build succeeded.");
else
Console.WriteLine(#"Build failed. View C:\temp\build.log for details");
}
}
}
Related
I am making a service to parse through excel files using C# with Visual Studio 2019 using Dot Net.
I have to open both .xlsx and .xls files. I was going to use OpenXml to read the excel files instead, but OpenXml doesn't read .xls files.
The error I am getting is:
System.Runtime.InteropServices.COMException (0x800A03EC): 0x800A03EC
at Microsoft.Office.Interop.Excel.Workbooks.Open(String Filename, Object UpdateLinks, Object ReadOnly, Object Format, Object Password, Object WriteResPassword, Object IgnoreReadOnlyRecommended, Object Origin, Object Delimiter, Object Editable, Object Notify, Object Converter, Object AddToMru, Object Local, Object CorruptLoad)
The error occurs on the line where the excel file is opened. I have Microsoft Office installed on the machine along with Excel 2016, so I'm unsure of what the issue is. The weird thing is that other people I know can use interop.Excel in their service, but for me it gives an error.
When I couldn't get the file to open in the service I tried making it work using the package topShelf.
I have 3 Classes
Service1.cs
Program.cs
Logger.cs (No issues)
The code for Service1:
using _Excel = Microsoft.Office.Interop.Excel;
using System.Diagnostics;
using System;
using System.Timers;
namespace FileParser
{
class Service1
{
//Version of the program
private const string version = "1.0.1.5";
//Timer to determine how often files are parsed
private System.Timers.Timer myTimer = new System.Timers.Timer();
//Windows Application Log for the application
private static Logger Logger = Logger.Instance;
public Service1()
{
}
public void Start()
{
Logger.UpdateLog($"Starting Service v{version}", EventLogEntryType.Information);
try
{
//Display that the program started correctly
Console.WriteLine("Running");
Logger.UpdateLog("Running", EventLogEntryType.Information);
//Open the excel file
Microsoft.Office.Interop.Excel.Application x1App = new _Excel.Application();
_Excel.Workbook x1Workbook = x1App.Workbooks.Open(#"C:/Users/strongb2/Downloads/test.xls"); //Error happened here
//Display that the excel file has been opened
Console.WriteLine("File has been opened");
Logger.UpdateLog("File has been opened", EventLogEntryType.Information);
}
catch(Exception e)
{
GorillaLogger.UpdateLog(e.ToString(), EventLogEntryType.Error);
Console.WriteLine(e);
}
}
public void Stop()
{
Logger.UpdateLog("Stopping Service", EventLogEntryType.Information);
}
}
}
Code for Program:
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Topshelf;
namespace FileParser
{
class Program
{
private static Logger Logger = Logger.Instance;
public static void Main()
{
var rc = HostFactory.Run(x =>
{
x.Service<Service1>(s =>
{
s.ConstructUsing(name => new Service1());
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc => tc.Stop());
});
x.RunAsLocalSystem();
x.SetDescription("File opening test");
x.SetDisplayName("File Parser");
x.SetServiceName("FileParser");
});
var exitCode = (int)Convert.ChangeType(rc, rc.GetTypeCode());
Environment.ExitCode = exitCode;
}
}
}
What I have done so far:
Made sure the dependencies were installed
[Here is what the Dependencies look like]
https://i.stack.imgur.com/FvS5h.png
Ran the code as a console application
adding the dependencies, the start function in the Console Application was able to open the file.
Ran topShelf as a application as well
Running as application, same code was able to open the file
Used different versions of Dot Net.
I used .Net Core 5.0, and used .Net FrameWork 4, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.7.2. None of them were able to open the file
Registry Editor
I read that you can add DependOnService in the service.
https://i.stack.imgur.com/pUY0R.png
I have tried both with and without the .dll extension.
Checked to make sure the Interop.Microsoft.Office.Interop.Excel file
The file is in the same directory where the FileParser.exe is. It is with all the other .dll files.
Googled the error
Nothing I have seen on the internet has helped with this issue.
I'm not sure what else to try to get the file to open using interop.Excel. Does anyone know of a solution to this problem?
I need to get the path where the solution file (.sln) is located. I try with this lines:
string startupPath = Path.Combine(Directory.GetParent(System.IO.Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName,"abc.txt");
// Read the file as one string.
string text = System.IO.File.ReadAllText(startupPath);
When I run it, I get an "Unauthorized Access Exception". When I put the path "manually": C:\Users\yabej\source\repos\tutoriales\Proyecto 0.1 it works!
However I need an "automatic" solution to be sure that the path will be correct when I run my project on different computers
The proper way to get the right solution path worked for me in Visual Studio 2019 with the EnvDTE100 NuGet Package.
Clarification: Only works with a single VS Instance Open (credits #junliantolovich)
Be sure use the correct ProgId for your Visual Studio:
using System;
using EnvDTE80;
using System.IO;
using System.Runtime.InteropServices;
namespace Test
{
public class Program
{
public static void Main()
{
var di = GetSolutionDirInfo();
Console.WriteLine(di.FullName);
}
public static DirectoryInfo GetSolutionDirInfo()
{
// Use here the ProgId of your Visual Studio
// VS 2010 -> "VisualStudio.DTE.10.0"
// VS 2012 -> "VisualStudio.DTE.11.0"
// VS 2013 -> "VisualStudio.DTE.12.0"
// VS 2015 -> "VisualStudio.DTE.14.0"
// VS 2017 -> "VisualStudio.DTE.15.0"
// VS 2019 -> "VisualStudio.DTE.16.0"
var progId = "VisualStudio.DTE.16.0";
var dte2 = (DTE2)Marshal.GetActiveObject(progId);
return Directory.GetParent(dte2.Solution.FullName);
}
}
}
If you add your file (abc.txt) to your solution, then in the properties for the file, you can set 'Copy to output directory' to 'Copy always'. Make sure the build action is set to 'None'. Then during the build process, it'll be copied to the same location as your executable and you can get the path using
var path = Path.Combine(Directory.GetCurrentDirectory(), "\\abc.txt");
I created some add-in for excel in C#. In it is one public class for using in VBA. On my machine all works ok. When I install add-in on tester computer (I'm using InstallShield 2015 Limited Edition for Visual Studio to create setup file) I can't set object.
C# code
using System;
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace PMTAddin
{
[Guid("B2350EC1-522E-4B75-BB02-86BB0FD1A60E")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class PublicClass
{
public void test()
{
System.Windows.Forms.MessageBox.Show(
"test."
, "test"
, System.Windows.Forms.MessageBoxButtons.OK
, System.Windows.Forms.MessageBoxIcon.Error
);
}
private int GetWorksheetID(Excel.Workbook wb, string worksheetName)
{
int result = 0;
foreach (Excel.Worksheet ws in wb.Worksheets)
{
if (ws.Name == worksheetName)
{
result = ws.Index;
break;
}
}
return result;
}
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("", System.Environment.SystemDirectory + #"\mscoree.dll", RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type, "Programmable"), false);
}
private static string GetSubKeyName(Type type, string subKeyName)
{
System.Text.StringBuilder s = new System.Text.StringBuilder();
s.Append(#"CLSID\{");
s.Append(type.GUID.ToString().ToUpper());
s.Append(#"}\");
s.Append(subKeyName);
return s.ToString();
}
}
}
In VBA project I checked reference to it on the list. It calls PMT.
VBA
Sub dsf()
Dim o As PMT.PublicClass
Set o = New PMT.PublicClass 'at this lane on other computer I got error 429. On my computer all work smoothly and method test is running.
o.test
End Sub
I thought that maybe it was something .NET Framework, but it is installed. Any ideas?
EDIT:
I create two diffrent version for bittnes, but the same error.
But I found some new info. In registry on my computer it looks like this
and on tester machine it looks like this
There are no CodeBase value... Do you think this is the problem? If it is, how I need to modify RegisterFunction method to correct this?
After long seeking I found the solution. It's kind of partial, because for 64 bit Excel we need to register library manually (maybe someone knows, how to add bat file to installation file).
I found the answer on this site.
While creating Install Shield instalation file we need to do two things.
Add .tlb file to application files (this step was done by me, before posting on stackoverflow)
Click right on project.Primary output file and choose properities like in screenshot (for *.tlb file we need to check the same, but without "COM Interop")
Without this the installer will not properlly register add-in in registry.
Install file created like this would register add-in for 32-bit excel only. If you want to use it also in 64-bit Excel you need to register library manually. I created simple bat file like this:
c:
cd C:\Windows\Microsoft.NET\Framework64\v4.0.30319
regasm.exe "[pathToDLL]\AddInName.dll" /tlb:"[pathToDLL]\AddInName.tlb" /codebase
pause
Remember, that you need to run it with admin rights.
I am working on a small c# console application that will check my .net DLL and look for environment specific information from compiled dll.
Basically, I want to check c# Web published project and display any file contain production specific information developer forgot to update...
Issue: I am running into is when a developer switch between environment from Dev to test and test to prod. They forget to switch their environment value either in C# or web.config file.
Is there a way I can open individual DLL and extract the DLL content as a string using C# code and a free decompiler?
Try this:
using System;
using System.Linq;
using System.Reflection;
#if DEBUG
[assembly:AssemblyConfiguration("debug")]
#else
[assembly:AssemblyConfiguration("release")]
#endif
namespace ConsoleApp1
{
internal class Program
{
private static void Main()
{
// this should be the filename of your DLL
var filename = typeof(Program).Assembly.Location;
var assembly = Assembly.LoadFile(filename);
var data = assembly.CustomAttributes.FirstOrDefault(a => a.AttributeType == typeof(AssemblyConfigurationAttribute));
if (data != null)
{
// this will be the argument to AssemblyConfigurationAttribute
var arg = data.ConstructorArguments.First().Value.ToString();
Console.WriteLine(arg);
}
}
}
}
How can I create a command in a VSPackage that creates a new solution with a new project (C# Class Library) in it, containing 1 .cs file?
It is not very straighforward but there is an interesting guide on MSDN that explains how to do it. It is for an Add-in but in a VSPackage you have the same set of Visual Studio DTE objects available (the DTE application).
You can define a method that uses GetProjectTemplate and AddFromTemplate to create two console projects. You can define in the method Initialize of your VSPackage class a OLE menu command (if that is what you are looking for):
protected override void Initialize()
{
//// Create the command for the menu item.
var aCommand = new CommandID(GuidList.GuidCmdSet, (int)PkgCmdIdList.CmdId);
var menuItemEnable = new OleMenuCommand((s, e) => createProjectsFromTemplates(), aCommand);
}
And then define a method associated to the command (createProjectsFromTemplates in this case) that creates a solution with a project:
private DTE2 _mApplicationObject;
public DTE2 ApplicationObject
{
get
{
if (_mApplicationObject != null) return _mApplicationObject;
// Get an instance of the currently running Visual Studio IDE
var dte = (DTE)GetService(typeof(DTE));
_mApplicationObject = dte as DTE2;
return _mApplicationObject;
}
}
public void createProjectsFromTemplates()
{
try
{
// Create a solution with two projects in it, based on project
// templates.
Solution2 soln = (Solution2)ApplicationObject.Solution;
string csTemplatePath;
string csPrjPath = "C:\\UserFiles\\user1\\addins\\MyCSProject";
// Get the project template path for a C# console project.
// Console Application is the template name that appears in
// the right pane. "CSharp" is the Language(vstemplate) as seen
// in the registry.
csTemplatePath = soln.GetProjectTemplate(#"Windows\ClassLibrary\ClassLibrary.vstemplate",
"CSharp");
System.Windows.Forms.MessageBox.Show("C# template path: " +
csTemplatePath);
// Create a new C# console project using the template obtained
// above.
soln.AddFromTemplate(csTemplatePath, csPrjPath, "New CSharp
Console Project", false);
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show("ERROR: " + ex.Message);
}
}
For Visual Studio versions after 10.0 the zip for template projects is not available anymore. The .vstemplate must be referenced and it is possible to find all the project templates under the folder:
C:\Program Files (x86)\Microsoft Visual Studio 1x.0\Common7\IDE\ProjectTemplates\
More info on this MSDN link.
The method should create a solution with one C# project based on the c# project template (e.g. containing class1.cs as initial file).
You can define your own template as well if you wish and create a solution based on that custom template. Here is a guide from MSDN on how to create custom templates.
hope it helps.