How can I inject a XAML transformation into my build? - wpf

I'd like to run a custom EXE against my XAML Resource Dictionaries. Let's say this exe that I've got is going to strip out comments, whitespace and unused resources. The original XAML files need to be untouched, but the XAML (silverlight) and BAML (wpf) that ends up in the XAPs and DLLs needs to be transformed. It needs to work on my computer and the build server.
My question is: what's the simplest and most reliable way to run this exe?
My first thought was to have a pre-build event. But this would have to work on the original XAML file. Development would become quite painful.
By the time the post build event has been run, my resources are already compiled into the dlls.
What are my options?

You should implement the "exe" as an MSbuild Task.
Essentially you build a C# class that inherits from the Microsoft.Build.Utilities.Task class, and overide the Execute() method.
Something like
public class CleanXAML : Task
{
}
Then you spefify (either in your build file, or an external .tasks file that you import, the task name and the path to the DLL you just built)
<UsingTask AssemblyFile="C:\customtasks\XamlTasks.dll"
TaskName="Rob.CustomTasks.Xaml.CleanXaml"/>
That enables you to invoke this like any other MsBuild task
<CleanXaml Source="$(PathtoOriginalXaml)"
Destination="$(SourceCodePath)\$(cleanXaml.xaml)" />
From there you need to figure out the best way to "inject" this into your build process. Depending on how you are building (msbuild, vs2010, teambuild, or teambuild workflow) there are different ways to do this. Essentially you need this to happen BEFORE the CoreCompile target is invoked and make sure your "output xaml" properly replaces what CSC.exe is going to expect.
Do some searches on MsBuild tasks for more info, or ask any question you've got here.
I would highly recommend this approach vs. using a CallEXE task in MSBuild, b/c this way the MSBuild properties and items stay in context so you are just moving from build step to build step, vs sidetracking the whole thing to do the transform, then hoping it keeps working.

Related

.NET: How to isolate an anti-debugging class library?

I built a .NET class library and used an obfuscator to obfuscate it with anti-debugging.
I built a testing project using my obfuscated class library. I would have hoped that anti-debugging forbids debugger to step into my class library. But it simply threw exception "Debugger detected" when my class library was invoked when I started the project in debugging mode (by pressing "F5" in Visual Studio).
What this means is that if a project uses my library then the developer simply cannot debug at all. They may have millions of lines of code that has nothing to do with my library. Not being able to debug at all in their project will only mean one thing: they will not use my library.
Is there anyway a developer can do to "isolate" my library, so that they can debug elsewhere?
Specially thanks to #Artem Razin for:
isolate sensitive code to a separate process that runs with the
enabled anti-debugging feature.
Its great and helpful. Also virtualization he specified is good approach. I will post you a good approach if you need exactly working with anti-debug envirnoment. Bceause you mention the exception: Debugger Detected
Am assume you use Eziriz .NET Reactor. When I speak with support. They said you can't provide two anti-debug version for specific HardwareID. Because HardwareID involved in the licensing system and it must not bypassed!
I can tell you a workaround for that by using .NET Reactor CLI and MSBuild targets.
What scenario it should be? (I will show what we need to do before write CLI...)
If you a have a developer team, or friend who need to use your obfuscated library. That's great. But he can't debug because its anti-debugged.
Then we must separate an assembly into two assemblies. One for developer its obfuscated but without anti-debug feature enabled. and other assembly into release folder for consumer or your audience.
So when you build your assembly. or need to create nuget package for it. you need to do a double obfuscation. Firstly you will obfuscate the anti-debug version for consumer into Consumer/AntiDebug folder. Secondly you will obfuscate the original DLL again but for developer without anti-debug feature!
So please use Directory.Build.targets for that. Here's code for obfuscation:
<Target Name="ObfuscateDLL" Condition="'$(Configuration)' == 'Release' AND $(OutputType) == 'Library'"
AfterTargets="AfterBuild">
<PropertyGroup>
<ObfuscatedFolder>$(MSBuildThisFileDirectory)\Anti Debug</ObfuscatedFolder>
<ObfuscatorPath>C:\Program Files (x86)\Eziriz\.NET Reactor\dotNET_Reactor.Console.exe</ObfuscatorPath>
<ObfuscatorParameters>-antitamp 1 -anti_debug 1 -hide_calls 1 -hide_calls_internals 1 -control_flow_obfuscation 1 -flow_level 9 -resourceencryption 1 -antistrong 1 -virtualization 1 -necrobit 1 -mapping_file 1 -mapping_file_overwrite 1 -mapping_filename "<ProtectedAssemblyLocation>\<AssemblyName>.nrmap" </ObfuscatorParameters>
</PropertyGroup>
<!-- Obfuscate with anti-debug to Obfuscated folder or \Release path when GenerateNuget enabled -->
<Exec Command=""$(ObfuscatorPath)" -file "$(TargetPath)" -targetfile "$(ObfuscatedFolder)\$(TargetFileName)" $(ObfuscatorParameters)"/>
<!-- Obfuscate without anti-debug to /Release path for Nuget package for Developers -->
<Exec Command=""$(ObfuscatorPath)" -file "$(TargetPath)" -targetfile "$(TargetPath)" $(ObfuscatorParameters.Replace('-anti_debug 1','').Replace('-mapping_file 1', ''))"/>
</Target>
Please use above code! if you need it as simple as possible. But you need to manually create nuget package for you developer. via MSBuild or by the way you need.
But If you use .NET Framework and want to generate obfuscated debuggable nuget package (for developers). And also provide anti-debug version to your consumer. You can use following MSBuild targets.
It contains ability to create Nuget package with all dependencies automatically.
It obfuscate the consumer library to Anti Debug folder. then It will obfuscate nuget version and packacking it. then copy back Anti Debug version to Release folder.
You can manually turn on/off GenerateNuget property. If you will not generate nuget so anti-debug version only produced.
Change the code depending on your needs...
https://pastebin.com/wmvcWMUp
(See link XML content are large can't posted to StackOverflow)
Anti-debugging is a well-known feature since the times of exe packers. Unfortunately, it is a process-wide thing. Usually, .NET obfuscators check debugger-specific environment variables.
There is no way to prevent a debugger from stepping into your assembly.
I would say that anti-debugging is for those who want to protect their end-user products, not libraries.
You can virtualize your code (modern obfuscators like ArmDot provide this feature), so debugging it would have almost no sense.
Another idea is to isolate sensitive code to a separate process that runs with the enabled anti-debugging feature. On the client-side, you just provide a proxy that redirects all calls to the process.

Application Settings in .Net Core (WPF) and single exe

To migrate an application I want to continue using the plain old settings that still come along with .Net5 (App.Config, Settings.settings and so on).
I need a simple built in solution without additional dependencies.
The proposed way seems to be appsettings.json or similar.
For that to use with WPF you need to add some additonal dependencies which bloat the project when
publishing it as single exe (not self contained). It is over-the-top for simple applications.
I followed the steps here:
Equivalent to UserSettings / ApplicationSettings in WPF dotnet core
The accepted answer from Alexander works for a normal exe built.
These are the generated files
MyApp.dll
MyApp.dll.config
MyApp.exe
Modifying "MyApp.dll.config" with an editor directly reflects the changed data in the code.
MessageBox.Show(Settings.Default.SomeConfigValue);
The used config file can be displayed using
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
MessageBox.Show(config.FilePath);
It displays
C:\Projekte\MyApp\MyApp\bin\Debug\net5.0-windows\MyApp.dll.config
Unfortunately this fails for single exe
These are the generated files (in publish folder)
MyApp.dll.config
MyApp.exe
Modifying "MyApp.dll.config" or "MyApp.exe.config" has no effect. The file does not seem to be used by the framework.
Above messagebox now shows
C:\Projekte\MyApp\Publish<Unknown>.config
How to get the built-in configuration system work with single exe?

What is a good way to build a lot of small tools in Visual Studio?

Suppose you have some source code that comes from the unix world. This source consists of a few files which will create a library and a lot of small .c files (say 20 or so) that are compiled into command-line tools, each with their own main() function, that will use the library.
On unixy systems you can use a makefile to do this easily but the most naive transformation to the windows / Visual Studio world involves making a separate project for each tool which, although it works, is a lot of work to set up and synchronize and more difficult to navigate at both the filesystem and project/solution level. I've thought about using different configurations where all but one .c file are excluded from the build but that would make building all the tools at once impossible.
Is there a nice way of building all the tools from a single "thing" (project, msbuild file, etc.)?
I'm really not interested in using cygwin's gcc/mingw or NAnt. I'd like to stick with the standard Windows toolchain as much as possible.
You don't HAVE to use visual studio to compile code. You can make your own batch file or Powershell script that simply calls the compiler on your source, just like a makefile.
So I've been looking into this for a while now and the solutions all leave much to be desired.
You can...
Create a lot of small projects by hand.
Use MSBuild and deal with its steep learning curve.
Use a build tool that does not integrate well with Visual Studio, like GNU make.
You can't even make a project template like you can with .NET projects! Well, you can make a wizard if you want to wade through the docs on doing that I suppose. Personally, I have decided to go with the "many small projects" solution and just deal with it. It turns out it can be less horrible than I had thought, though it still sucks. Here's what I did in Visual Studio 2008:
Create your first Win32 command line tool project, get all your settings down for all platforms and make sure it works under all circumstances. This is going to be your "template" so you don't want to edit it after you've made 20 copies.
(optional) I set up my paths in the visual studio project files so that everything is built in the project directory, then I have a post-build step copy just the dll/exe/pdb files I need to $(SolutionDir)$(OutDir). That way you can jump into a single directory to test all your tools and/or wrap them up for a binary distribution. VS2008 seems to be insane and drops output folders all over the place, with the default locations of Win32 and x64 output differing. Spending a few minutes to ensure that all platforms are consistent will pay off later.
Clean up your template. Get rid of any user settings files and compiler output.
Copy and paste your project as many times as you need. One project per tool.
Rename each copied project folder and project file to a new tool name. Open up the project file in a text editor like Notepad++. If you have a simple, 1-file project you'll need to change the project name at two places at the beginning of the file and the source code file name(s) at the end of the file. You shouldn't need to touch the configuration stuff in the middle.
You will also need to change the GUID for the project. Pop open guidgen.exe (in the SDK bin directory) and use the last radio button setting. Copy and paste a new GUID into each project file at the top. If you have dependencies, there will be one or more GUIDs at the bottom of the file near the source code. Do NOT change them as they are the GUIDs from the dependencies and have to match!
Go into Visual Studio, open up your main solution and add your tool projects.
Go into the configuration manager and make sure that everything is correct for all supported platforms, then test your build.
It's not beautiful, but it works and it's very much worth the setup time to be able to control your builds from the GUI. Hopefully VS2010 will be better about this, but I'm not too hopeful. It looks like MS is giving a lot more love to the .NET community than the C/C++ community these days.
If you have a makefile you can use a 'makefile' project in Visual Studio (which in misnamed - it simply allows you to specify custom build/debug commands), and use it to invoke GNU make.
You will need to change the makefile to use the VC++ command line tools instead of cc or gcc or whatever it uses, but often these are specified by macros at the top of the makefile.
If the makefile uses other Unix specific commands (such as rm), you may need to make modifications, or create bath files to map commands to Windows equivalents. Another option is to install any necessary tools from GNUWin32 to make it work.
If the build is very complex or involves configure scripts, then you have a harder task. You could generate the makefile from a configure script using MSYS/MinGW, and then modify it as above to make it work with VC++.
Makefile projects will not be as tightly integrated in Visual Studio however. All the build management is down to you and the makefile.
If you're really using Visual Studio, I would suggest creating a project for each tool, and adding these projects to a single solution. From Visual Studio, it's easy to build a complete solution all at once, and MSBuild knows how to build .sln files as well.
msbuild myslnfile.sln
or even:
msbuild
... will build your solution.

g.i.cs file not found with WPF and code contracts

I have a WPF project which compiles just fine. However, when I enable code contracts, I get a lot of errors like the following:
file 'C:\MyProject\obj\Debug\MyFile.g.i.cs' could not be found
Is there workaround?
Just FYI... This bug has been fixed in the latest version of Code Contracts (v1.2.21023.14, released Oct. 22nd).
Can you be a bit more specific about your repro steps? The significance of the files ending in .g.i.cs is they are files generated specifically to enable intellisense in running projects. They are not truly part of the build process and likely should not be consumed by code contracts. I'm not a code contracts expert by any means though so I could be wrong on this point.
I posted a repro and workaround to this problem on the Code Contracts forum. Here's the URL:
http://social.msdn.microsoft.com/Forums/en-US/codecontracts/thread/4f2af748-1db1-4175-abf0-fbcc82f177ee
The short answer is that the error occurs whenever you have multiple projects that reference each other in a Solution, and one of the child projects is a WPF control library. To get around the problem, you can either disable contract verification for the parent project(s) (the ones that reference the other projects), or you can add a post-build event to the offending child project(s) to create the *.g.i.cs files that the Code Contracts rewriter is looking for.
For example, create a blank text file in the root directory of your child project and name it "Blank.txt". Then add the following command as a post-build event in that project:
copy "$(ProjectDir)Blank.txt" "$(ProjectDir)obj\$(Configuration)\GeneratedInternalTypeHelper.g.i.cs"
Copy this line as many times as needed, one for each missing file.

Can I save a FlowDocument to BAML in a programmatic way?

Has anyone found a way to save a FlowDocument as BAML or other compressed format? I can import XML with images to create a new FlowDocument:
<TextRange class instance>.Load(fs, DataFormats.Rtf)
However, I haven't found a good way to save it in a 'native' compressed format. Uncompressed XAML is easy to generate using:
<TextRange class instance>.Save(fs, DataFormats.Xaml);
But is there any programmatic method to save it to a compressed format?
If there isn't an existing method, does anyone know where to find a programmatic XAML compiler? Or even just the BAML specifications? I could programmatically generate an entire XAML window with the FlowDocument embedded, but I'd still want to convert the XAML to BAML for faster load times. I'm using relatively large rtf documents and conversion time using DataFormats.Rtf is significant.
I do not think it is possible... The BamlWriter is marked as internal, this will hopefully open up soon!
I unfortunatly do not know of any XAML compilers
Well, it turns out you can run Visual C# 2008 Express w/o the GUI. And you can modify the final program name via code before you compile as well. I'm sure you can do it via APIs, but here's the hack I found:
The program's is name determined in .csproj, in the xml tag.
Run via code or batch file: "\Common7\IDE\vcsexpress" ".sln" /rebuild Release /projectconfig Release /out errors.txt
I like to examine and then delete the errors.txt after each run to make it easier to see if I got a clean build. This isn't ideal because you have to have a full bought version of Visual C# 2008 on each machine you use this way, but it is a way to create a new executable to display each flow document in a programatic way. Also if you have an error in your XAML, you may generate a program that won't run.
Note that the BAML format does NOT compress the text, only the tags and other 'plumbing'. Even the Margin and Padding information is saved in clear ASCII. This is inherited by the end .exe leaving the text clearly visible in sections to notepad or similar.
The XamlPackage format is compressed:
<TextRange class instance>.Save(fs, DataFormats.Xaml);

Resources