To start with, I am new to WixSharp. For several hours now I have been trying to specify a custom file, License.rtf, for my setup project like this:
project.LicenceFile = "License.rtf";
But I keep getting this error:
C# Script execution engine. Version 3.9.4.1.
Copyright (C) 2004-2014 Oleg Shilo.
Error: Specified file could not be executed.
System.Xml.XmlException: The prefix '' cannot be redefined from 'http://schemas. microsoft.com/wix/2006/wi' to '' within the same start element tag.
at System.Xml.XmlWellFormedWriter.PushNamespaceExplicit(String prefix, String ns)
at System.Xml.XmlWellFormedWriter.WriteEndAttribute()
at System.Xml.Linq.ElementWriter.WriteStartElement(XElement e)
at System.Xml.Linq.ElementWriter.WriteElement(XElement e)
at System.Xml.Linq.XElement.WriteTo(XmlWriter writer)
at System.Xml.Linq.XContainer.WriteContentTo(XmlWriter writer)
at System.Xml.Linq.XDocument.WriteTo(XmlWriter writer)
at System.Xml.Linq.XDocument.Save(TextWriter textWriter, SaveOptions options)
at WixSharp.Compiler.BuildWxs(Project project, String path, OutputType type)
at WixSharp.Compiler.BuildWxs(Project project, OutputType type)
at WixSharp.Compiler.Build(Project project, String path, OutputType type)
at WixSharp.Compiler.Build(Project project, OutputType type)
at Script.Main(String[] args)
Please can someone tell me what I am doing wrong. Here is my setup.cs code:
//css_dir ..\..\;
//css_ref Wix_bin\SDK\Microsoft.Deployment.WindowsInstaller.dll;
//css_ref System.Core.dll;
using System;
using System.Xml;
using System.Xml.Linq;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Win32;
using WixSharp;
using WixSharp.CommonTasks;
class Script
{
static public void Main(string[] args)
{
var project =
new Project("myproduct",
new Dir(#"%ProgramFiles%\My Company\myproduct", new DirFiles(#"Files\*.*"),
new Dir("DataModel", new DirFiles(#"Files\Data\*.*"),new Dir("Music", new DirFiles(#"Files\Data\Music\*.*")),new Dir("CardPack", new DirFiles(#"Files\Data\CardPack\*.*")),new Dir("CardSingle", new DirFiles(#"Files\Data\CardSingle\*.*"))),
new ExeFileShortcut("Uninstall MyProduct", "[System64Folder]msiexec.exe", "/x [ProductCode]")),
new Dir(#"%AppDataFolder%\myproduct", new File(#"Files\Config\Configure.json"), new Dir("Folder1", new DirFiles(#"Files\Folder2\*.*"))));
project.LicenceFile = "License.rtf";
project.UI = WUI.WixUI_Minimal;
project.GUID = new Guid();
project.ResolveWildCards();
var exeFile = project.AllFiles.Single(f=>f.Name.EndsWith("myproduct.exe"));
exeFile.Shortcuts = new[] {
new FileShortcut("myproduct.exe", "INSTALLDIR"),
new FileShortcut("myproduct.exe", #"%Desktop%")
};
Compiler.BuildMsi(project);
}
}
Thanks in advance.
Not sure if you found an answer to your question, but Orca is an MSI Table editor that is included in the Windows SDK.
For Windows 7 and .NET 3.5 SP1 - https://www.microsoft.com/en-us/download/confirmation.aspx?id=3138
Once installed, navigate to C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin
and execute the orca.msi. You will then run your Wix# project to generate the msi file. Open the msi file with Orca and navigate to the Binary table. Double click on the data column for WixSharp_LicenseFile and you will be given an option to read or write to a file. If you want to see the contents, select a file name (.rtf format) and write to file. Make any changes you wish, or replace that file, and then use it to read into that binary data row. Once you have read it into the msi table, save the msi file and close.
I am new to WixSharp myself, so I have not found another way (yet!), but this worked for me.
Good luck!
Related
I've been trying to persist a new solution containing a project and a simple cs file with the following code but nothing get saved to the disk. Am I doing something wrong or is Roslyn not the tool to be used to generate solutions project and files?
class Program
{
static void Main(string[] args)
{
var workspace = new AdhocWorkspace();
var solutionInfo = SolutionInfo.Create(SolutionId.CreateNewId(),
VersionStamp.Create(),
#"C:\Seb\SebSol.sln");
var projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(),
VersionStamp.Create(),
"SebProj",
"SebProj.dll",
LanguageNames.CSharp,
#"C:\Seb\SebSol\SebProj\SebProj.csproj");
workspace.AddSolution(solutionInfo);
workspace.AddProject(projectInfo);
var sourceText = SourceText.From("public class A { }");
workspace.CurrentSolution.AddDocument(DocumentId.CreateNewId(projectInfo.Id), "ClassA.cs", sourceText);
workspace.TryApplyChanges(workspace.CurrentSolution);
}
}
You're looking for MsBuildWorkspace, which can actually update sln and csproj files in MSBuild format on disk.
Other than that class, Roslyn APIs are completely agnostic to project formats such as MSBuild.
I wanna generate an exe file with some changes in code from another C# exe.
I know that can easy compile .cs single class using CodeDom.Compiler
The thing I want to know is how to compile a project with 'Resources', 'Settings', 'Forms' and other elements.
CSharpCodeProvider.CompileAssemblyFromSource(CompilerParameters, sources[]);
So, the question is where can I add all resources, settings and form (.resx)?
And can I do it with byte[] streams. Without unpacking project's zip.
Sorry for bad English and mby stupid questions. I wish somebody will help me...
For Example: I have byte[] array of resource file 'pic.png' and I wanna attach it to compiled exe as embedded resource.
You should learn about the new compiler service provided by Microsoft in Microsoft.CodeAnalysis code name "Roslyn".
Roslyn provides you the way to compile the code and everything on the fly including creating and compiling complete solution and projects in-memory.
I think what you're looking for can be achieved via Roslyn. See below sample:
class Program
{
static void Main()
{
var syntaxTree = SyntaxTree.ParseCompilationUnit(
#"using System;
using System.Resources;
namespace ResSample
{
class Program
{
static void Main()
{
ResourceManager resMan = new ResourceManager(""ResSample.Res1"", typeof(Program).Assembly);
Console.WriteLine(resMan.GetString(""String1""));
}
}
}");
var comp = Compilation.Create("ResTest.exe")
.AddReferences(new AssemblyNameReference("mscorlib"))
.AddSyntaxTrees(syntaxTree);
var resourcePath = "ResSample.Res1.resources"; //Provide full path to resource file here
var resourceDescription = new ResourceDescription(
resourceName: "ResSample.Res1.resources",
dataProvider: () => File.OpenRead(resourcePath),
isPublic: false);
var emitResult = comp.Emit(
executableStream: File.Create("ResTest.exe"),
manifestResources: new[] { resourceDescription });
Debug.Assert(emitResult.Success);
}
Original Source here
At line dataProvider: () => File.OpenRead(resourcePath), you can provide your own 'FileStream' like () => return _myResourceStream) for your resource file.
I am creating code generation tool (auto code generation based on table structure) as a Windows forms application in Visual Studio 2012 using .NET Framework 4.0. It's generating the portable object, controller, WCF services and business logic code files.
All code files bundle in the appropriate project and all project bundle in one solution. The solution and projects need to create dynamically through program.
I have tried to create the solution and project using Visual Studio Add-in project. It is working fine in Add-In project (separate solution). The OnConnection method call automatically in Add-in project. Now I want to implements this in my code generation tool. While debugging in Add-In project the application variable shown like COM object.
I am tried to pass the value for OnConnection method from code generation tool, it throws an error (I passed this object for application variable). I really don't know how to call this method from my code generation tool. Anyone help this?
Code
private DTE2 _applicationObject;
private AddIn _addInInstance;
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
createProjectsFromTemplates(_applicationObject);
}
public void createProjectsFromTemplates(DTE2 dte)
{
try
{
Solution2 soln = (Solution2)dte.Solution;
string csTemplatePath;
string csPrjPath = "SamplePath\\TestCreateProject";
csTemplatePath = soln.GetProjectTemplate("WpfApplication.zip", "CSharp");
System.Windows.Forms.MessageBox.Show("C# template path: " + csTemplatePath);
soln.AddFromTemplate(csTemplatePath, csPrjPath, "NewWCFCSharpAutoGeneratorProject", false);
Project prj;
ProjectItem prjItem;
String itemPath;
// Point to the first project (the Visual Basic project).
prj = soln.Projects.Item(1);
prjItem = prj.ProjectItems.AddFromFileCopy("SampelCSharp.cs");
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show("ERROR: " + ex.Message);
}
}
You can instantiate a VS from the host application and generate the files. Hope that will work. The below code works well for me.
Use the following namespaces to get work the below given code.
Namespaces:
using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;
using System.Resources;
using System.Reflection;
Code:
EnvDTE80.DTE2 dte2;
dte2 = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.11.0");
Connect objConnect = new Connect();
Array objArray = null;
objConnect.OnConnection(dte2, ext_ConnectMode.ext_cm_UISetup, null, ref objArray);
I got this reference it is really useful.
http://rcos.rpi.edu/projects/unmake/commit/programmatically-launch-devenv-generate-a-solution-and-save-it/
You can use this. This is for .cs project files and framewwork above .NET 2.0 versions. VB project sources are not compatible.
protected void Build(string project)
{
Engine engine = new Engine();
BuildPropertyGroup properties = new BuildPropertyGroup();
properties.SetProperty(#"Configuration", #"Debug");
// Point to the path that contains the .NET Framework 2.0 CLR and tools
engine.BinPath = #"c:\windows\microsoft.net\framework\v3.5";
// Instantiate a new FileLogger to generate build log
FileLogger logger = new FileLogger();
// Set the logfile parameter to indicate the log destination
string str = #"logfile=D:\temp";
str += project.Substring(project.LastIndexOf("\\"), project.LastIndexOf(".") - project.LastIndexOf("\\")) + ".log";
logger.Parameters = str;
// Register the logger with the engine
engine.RegisterLogger(logger);
// Build a project file
bool success = engine.BuildProjectFile(project, new string[] { "build" }, properties);
//Unregister all loggers to close the log file
engine.UnregisterAllLoggers();
using (BinaryWriter writer = new BinaryWriter(File.Open(#"D:\temp\Prj.log", FileMode.Append)))
{
if (success)
{
writer.Write("\nBuild Success :" + project.Substring(project.LastIndexOf("\\")));
}
else
{
writer.Write("\nBuild Fail :" + project.Substring(project.LastIndexOf("\\")));
}
}
}
I have a set of XSDs that validate against XMLSPY and against Java code. I need to bring this set of XSDs as an embedded resource in Visual Studio 2012 .net. Unfortunately I am getting an error that a global element has already been declared when trying to resolve them with a custom XmlResolver to deal with the xsd:include. Error is strange because the element is declared only once.
Visual Studio Solution
|----------- Visual Studio Project
|----------- Schemas (Embedded Resource)
|----------- Directory A
|------------ set of XSDs that are referenced by XSDs in Directory B and to a globaltype definition file located in this directory
|----------- Directory B
|------------- set of XSDs that reference each other and those in Directory A, the XSD call from the main is located here
Validating Util Class
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
namespace ABC.XYZ.Utils
{
public static class XmlUtil
{
private static bool isValid;
public static bool ValidateXml(string targetNamespace, string schemaUri, string xml)
{
isValid = true;
var schemaReaderSettings = new XmlReaderSettings() { ValidationType = ValidationType.Schema };
schemaReaderSettings.ValidationEventHandler += MyValidationHandler;
schemaReaderSettings.Schemas.XmlResolver = new XmlResourceResolver();
var schemaReader = XmlReader.Create(GetSchemaStream(schemaUri), schemaReaderSettings);
schemaReaderSettings.Schemas.Add(targetNamespace, schemaReader);
var x = XElement.Parse(xml);
var sr = new System.IO.StringReader(x.ToString());
XmlReader validatingReader = XmlReader.Create(sr, schemaReaderSettings);
while (validatingReader.Read())
{
}
validatingReader.Close();
return isValid;
}
private static void MyValidationHandler(object sender, ValidationEventArgs args)
{
Console.WriteLine("***Validation error");
Console.WriteLine("\tSeverity:{0}", args.Severity);
Console.WriteLine("\tMessage:{0}", args.Message);
isValid = false;
}
private static Stream GetSchemaStream(string relativeFileName)
{
var resourceFileName =
Assembly.GetExecutingAssembly()
.GetManifestResourceNames()
.FirstOrDefault(p => p.EndsWith(relativeFileName));
return Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceFileName);
}
}
}
Custom XmlResolver
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace ABC.XYZ.Utils
{
public class XmlResourceResolver : XmlResolver
{
public const string AssemblyDefaultNamespace = "ABC.XYZ";
public const string SchemasNamespace = "Schemas";
public override Uri ResolveUri(Uri baseUri, string relativeUri)
{
var result = new UriBuilder("res://", AssemblyDefaultNamespace, -1, SchemasNamespace.Replace(".", "/"));
result.Path += "/" + relativeUri.Replace("../", "/").TrimStart('/');
return result.Uri;
}
public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
{
if (absoluteUri.Scheme != "res") return null;
Debug.WriteLine("Loading resource based on location {0}", absoluteUri);
var assembly = Assembly.GetExecutingAssembly();
var name = String.Format(CultureInfo.InvariantCulture, "{0}{1}",
absoluteUri.Host,
absoluteUri.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped).Replace("/", "."));
// try for an exact match based on schemaLocation hint path
var resourceName = (from x in assembly.GetManifestResourceNames()
where name.Equals(x, StringComparison.OrdinalIgnoreCase)
select x).FirstOrDefault();
// if not match based on filename alone
if (resourceName == null)
{
var schemaDocumentName = Path.GetFileName(absoluteUri.AbsolutePath);
Debug.WriteLine("Unable to locate exact match, looking for match based on filename {0}", schemaDocumentName);
resourceName = (from x in assembly.GetManifestResourceNames()
where x.Contains(SchemasNamespace) &&
x.EndsWith("." + schemaDocumentName, StringComparison.OrdinalIgnoreCase)
select x).FirstOrDefault();
}
Debug.WriteLine("Loading resource {0}", resourceName);
var stream = assembly.GetManifestResourceStream(resourceName);
return stream;
}
}
}
Any insights into this problem with be greatly appreciated.
XSD 1.0 encourages but does not require validators to detect multiple inclusions (or imports) of the same schema document and include them only once.
The result is that including the same schema document more than once from multiple other schema documents is the simplest way to create interoperability nightmares with XSD. (Not the only way, just the simplest way.) If you own the schema documents, segregate all inclusions and all schema-location information on imports into a driver file and delete all includes and all schema-location hints on imports from the 'normal' schema documents.
The problem is that when you're doing it with XMLSpy, the XSDs are files in the file system; what's happening then, for each file there's a base URI, and therefore resolvers will use that information to ensure that once an XSD is loaded, the same one is not loaded again, based on URI compare.
Now, the way you're doing it by loading as a stream from an assembly, all that information is gone (your stream doesn't have a base URI). Your resolver will keep loading the same XSD over and over again, from different places, thus creating this clash.
All the XSD processors I know, do not employ any other means to filter multiple inclusions of the same XSD content, but base source URI.
In .NET, the easiest way might be (again, depending on how complex your graph is) to try the solution in this post; the whole idea is to provide a base URI, which should give the info required to avoid multiple inclusions.
Another alternative might be to make sure in your custom resolver that for any given URI you're resolving, you only return once a stream (return null in all other cases). This is guaranteed to work as long as you're not using xsd:redefine composition (in which case the solution is to make a topological sort of the schema file graph and ensure all xsd:redefines are loaded first).
To #CMSperbergMcQueen point, an approach that is guaranteed to work is to refactor ALL the XSDs such that there's only one XSD embedded resource per namespace; each XSD would have all imports removed (technique called "dangling"). Add those XSDs to an XML Schema set as independent XSDs and compile. Unless you run into a .NET bug, the result should be a compiled XmlSchemaSet.
I created an empty Visual Studio Solution called Solution.sln which I load into the workspace int the first line. Then I add a project to the solution, and update the workspace to the latest solution which should now contain a project. How do I write out the files for the new stuff I added to the empty solution?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
using Roslyn.Services;
namespace RoslynMainApp
{
class Program
{
static void Main(string[] args)
{
IWorkspace workspace = Workspace.LoadSolution(#"C:\RoslynSolutions\Solution.sln");
ProjectId projectId;
ISolution solution = Solution.Create(SolutionId.CreateNewId("Solution"));
solution.AddCSharpProject("Project1.dll", "Project1", out projectId);
var success = workspace.ApplyChanges(workspace.CurrentSolution, solution);
if(success)
{
//How do I write out all the stuff I just added to Solution.sln to the directory RoslynSolutions?
}
}
}
}
Thanks in advance,
Bob
The act of calling ApplyChanges should write the changes to disk. However, note that in CTP1, only a small set of the changes you can apply to solutions are actually implemented.