I am trying to embed an icon into my my WPF application so that I can pull it out for use as an icon in the Windows 7 JumpList using the following code:
newScene.IconResourcePath = System.Reflection.Assembly.GetEntryAssembly().Location;
newScene.IconResourceIndex = 0;
I've gotten it to work using the following method: http://dennisdel.com/?p=38
However, it doesn't seem like the best approach and it seems like there should be an easier way to embed an icon resource into my application while still leaving the "Icon and Manifest" option checked in the Application properties for my program.
I've tried numerous methods including setting the icon build action as a resource and an embedded resource, but every time I open my .exe in a resource editor, the icon does not appear.
Any suggestions?
Visual Studio does not come with a way to execute the Win32 resource compiler from a MSBuild task, and none of its embedded functionality for creating resources created raw resources. Because of this your choices are:
Create the .res file "by hand" as described in the linked article, or
Add a build task so you can call the Win32 resource compiler from your .csproj
First I will explain the differences between the five different kinds of "resources" that can exist in a .exe or .dll file, including "Win32 Resources" that JumpList requires.
I will then explain how to construct a custom build task that allows you to embed arbitrary Win32 Resources in a C# or VB.NET executable.
The five kinds of resources in a Win32 executable
There are five different kinds of "resources" that can exist in a .exe or .dll file:
Win32 Resources
NET Framework "Embedded Resources"
CLR Objects within a ResourceSet
XAML Resources
WPF Resources (Objects within a ResourceDictionary)
Win32 Resources
The original kind of resource was a Win32 "Resource". This kind of resource is defined in a .rc file and has either numbered or named resources, each of which has a type and a blob of data. The
Win32 resource compiler, rc.exe, compiles the .rc file into a binary .res file can then be added to the resulting executable.
Win32 resources are accessed using the Win32 FindResource and LoadResource functions.
Win32 resources are embedded into C++ applications by adding them to the .rc file, which is compiled to a .res file and linked into the executable. They can also be added after the fact using the rc.exe program. For C# and VB.NET applications, MSBuild can add a prebuilt .res file to the executable it creates via the Csc or Vbc compiler or it can build a default one for you. Neither C# nor VB.NET has the ability to build non-default .res files from .rc files, and there is no MSBuild task to do this for you.
You can view the Win32 Resources in a .exe or .dll by opening the .exe or .dll file itself in Visual Studio using File -> Open.
A typical C, C++ or MFC application will have many Win32 Resources, for example every dialog box will be specified by a resource.
A typical WPF application will have just the three default Win32 resources constructed by the C# or VB.NET compiler: The version resource, the RT_MANIFEST, and the application icon. The contents of these resources are constructed from Assembly attributes in the code and the <ApplicationIcon> element in the .csproj or .vbproj file file.
This is the kind of resource that the JumpList is looking for.
Embedded Resources
An "embedded resource" is a NET Framework resource. The data structure containing these resources is managed by the CLR in a manner more conducive for access by managed code. Each resource is identified by a string name, which by convention begins with the namespace of the class the resource is associated with.
An embedded resource is just a blob of binary data with a name. The actual data type is either known by the caller or inferred from the name, similar to files in a file system. For example, an embedded resource with a name ending in ".jpg" is likely to be a JPEG file.
Embedded resources are accessed using Assembly.GetManifestResourceStream and its siblings GetManifestResourceInfo and GetManifestResourceNames.
Embedded resources are embedded into .exe and .dll files by adding the file to the project and setting the build action to "Embedded Resource".
You can view the Embedded Resources in a .exe or .dll by opening it in NET Reflector and looking at the "Resources" folder.
Embedded resources are commonly used in WinForms but almost never with WPF.
Resource Sets (.resx/.resources)
Multiple NET Framework objects such as strings and icons can be combined together into a single "Resource Set" data struture that is stored in the .exe as a single NET Framework Embedded Resource. For example this is used by WinForms to store things like icons and strings that are not easy to include in the generated code.
Objects in a Resource Set can be retrieved individually using the ResourceManager and ResourceSet classes defined by the CLR.
Objects in a Resource Set are defined in source code by a .resx file. The data can be directly in the .resx file (as in the case of strings) or referenced by the .resx file (as in the case of icons). When the project is built, the content specified by each .resx files is serialized into a binary form and stored as a single Embedded Resource with the extension ".resx" replaced by ".resources".
You can view the objects in a Resource Set by opening the .exe or .dll in NET Reflector, opening the Resources folder, clicking on a ".resources" file, and looking at the items in the right-hand pane.
Many WinForms-era features commonly used .resx files and ResourceSets in a manner similar to the old Win32 .rc files, to store multiple resources such as strings all together. They are also used by WinForms itself for storing settings on a form that cannot go in the code behind.
WPF applications almost never uses arbitrary objects in ResourceSets, though WPF itself uses ResourceSets internally to store compiled XAML.
XAML Resources
A WPF XAML Resource is a compiled XAML file that is stored inside a ResourceSet. The name inside the resource set is the original filename with ".xaml" replaced with ".g.baml". The content can be any valid XAML, the most common types being Window, Page, UserControl, ResourceDictionary, and
Application.
WPF Resources can be loaded using Application.LoadComponent() or by referencing the original XAML file name in a WPF context. In addition, any WPF Resource that has code behind (as specified by x:Class) will automatically be loaded and applied to each object that is created of that class during its InitializeComponent call.
WPF Resources are created by adding a .xaml file to your project and setting its build action to "Resource", "Page", or "ApplicationDefinition". This causes the compiler to compile the file to BAML and add it to the appropriate ResourceSet.
You can view the XAML resources in .exe or .dll by opening it in NET Reflector with the BamlViewer add-in installed, selecting Tools -> BAML Viewer from the menu, and using the BAML Viewer to browse to the specific .g.baml file inside the .resources.
WPF Resources within a ResourceDictionary
In WPF, almost all of what are known as "resources" are entries in a ResourceDictionary. The ResourceDictionaries are described in XAML, either within other objects such as Windows and UserControls, or in separate XAML files that contain only a ResourceDictionary. Each is identified by an "x:Key", which can be any object type. The resources themselves can also be any object type.
WPF resources can be referenced in XAML using the {StaticResource} and {DynamicResource} markup extensions, or can be loaded in code using FindResource.
WPF resources are added to a ResourceDictionary by adding them to the XAML file that contains the ResourceDictionary inside the <ResourceDictionary> element and giving them a x:Key attribute.
WPF resources are used extensively in WPF, including brushes, styles, data, geometries, templates, etc.
You can view the WPF Resources in a .exe or .dll by browsing the XAML Resources as described above and for each one looking inside the ResourceDictionary tags to see the resources themselves.
Including Win32 Resources in a C# or VB.NET executable
How to easily embed arbitrary Win32 Resources into a C# or VB.NET .exe
You will note from the discussion above that it is easy to add every type of resource to your C# or VB.NET application except for Win32 Resources. To make this easy you can add an additional build task and target. Here is how:
Construct a project containing a single "Win32ResourceCompiler" build task and compile it
Create a .targets file that contains a single target that uses this task to automatically build a .rc file into a .res
Set your project to use the resulting .res file
The task is extremely simple:
public class Win32ResourceCompiler : ToolTask
{
public ITaskItem Source { get; set; }
public ITaskItem Output { get; set; }
protected override string ToolName { get { return "rc.exe"; } }
protected override string GenerateCommandLineCommands()
{
return #"/r /fo """ + Output.ItemSpec + #""" """ + Source.ItemSpec + #"""";
}
protected override string GenerateFullPathToTool()
{
// TODO: Return path to rc.exe in your environment
}
}
The .targets file is also very simple. It will be something along these lines:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask TaskName="SomeNamespace.Win32ResourceCompiler" AssemblyFile="Something.dll" />
<PropertyGroup>
<CoreCompileDependsOn>$(CoreCompileDependsOn);CompileWin32RCFile</CoreCompileDependsOn>
</PropertyGroup>
<Target Name="CompileWin32RCFile" Outputs="#(Win32RCFile->'%(filename).res')">
<Win32ResourceCompiler
Source="#(Win32RCFile)"
Output="#(Win32RCFile->'%(filename).res')" />
</Target>
</Project>
Now in your .csproj file, add a reference to your .targets file:
<Import Project="Win32ResourceCompiler.targets" />
And of course you need to give your .rc file a file type of Win32RCFile:
<ItemGroup>
<Win32RCFile Include="MyWin32Resources.rc" />
</ItemGroup>
With this setup you can create a traditional Win32 .rc file to specify all your Win32 resources, including your version, manifest, application icon, and as many additional icons as you want. Every time you compile, all these Win32 resources will be added to your .exe file.
This takes a little while to set up but is much more satisfying and simpler in the long run than manually editing a .res file.
You can specify multiple icons in your .rc file like this:
1 ICON ApplicationIcon.ico
2 ICON JumpListIcon.ico
3 ICON AnotherIcon.ico
Here is the documentation for all the resource definition statements you can use in a .rc file.
Also note that the above .targets file was typed up on the spur of the moment and has not been tested. Documentation on the syntax of MSBuild (.csproj and .targets) files can be found here and here, and good examples of .targets files can be found in the c:\Windows\Microsoft.NET\Framework\v3.5 directory).
Related
I would like to embed compiled XAML into an assembly as BAML2006.
If the Embedded Resource MSBuild action is selected, the XAML file gets embedded into the assembly as a text resource that can be read like any other loose XAML resource. However, loose XAML has some serious limitations when it comes to referenced namespaces, most cripplingly, any namespace referred to by its [XmlnsDefinitionAttribute] must be loaded into the AppDomain before the loose XAML is parsed. In contrast, embedded BAML does not suffer from this, as the assembly containing the namespace is added to the list of referenced assemblies and is loaded by the AppDomain automatically before any code starts running.
If the Page MSBuild task is selected, XAML gets "compiled" into BAML2006 and is embedded to the .resources.g of the containing assembly. However, compilation will fail if the WindowsBase, PresentationCode and PresentationFramework assemblies are not referenced. As I am working on a project which uses XAML but not WPF (we load object graphs with XamlObjectWriter and custom markup extensions, but reuse the Visual Studio some of XAML editor infrastructure for IntelliSense support), I would like to avoid depending on these libraries.
Is there any way to make MSBuild embed BAML and add required assembly references without depending on WPF?
I guess Workflow Foundation uses a similar approach, but I haven't been able to find any information.
Has anyone had experience, or is it even possible to load an external XAML file into a WPF project from a hosted website.
We are wondering because we are defining the XAML file as our "styles". We would like a person not familiar with XAML to edit the file and then we don't have to redeploy the whole application, but next time the application loads it will just reference the changed XAML file.
Or is this not possible because the XAML files are compiled into the project?
Or would an option be to load an external XML file in code behind and populate our "style" properties that way? Is this possible?
We currently are using ResourceDictionary and calling an internal XAML file in the application, but we would like a more dynamic solution.
Using XamlReader.Load you can use the XAML parser. There is a performance hit from parsing XAML instead of BAML, and downloading a file from the network could negatively impact the (in my experience) often already slow startup times for WPF applications. The blog entry below provides a nice explanation of dynamically loading resource dictionaries.
http://blogs.interknowlogy.com/2011/09/02/xamlreader-looseresourcedictionaryfiles-parsercontext/
I create a WPF application and want to add several languages for it. Localization is created via resx-files (smth like Labels.resx and Labels.en-US.resx). After project building a new folder bin\en-US is created. But the concept is that the application should be represented as the only one EXE-file.
So the question: is it possible to store all resx-files (default (Labels.resx) and any localized (e.g. Labels.en-US.resx)) inside EXE-file?
I don't think so, from Microsoft's site:
At compile time, Visual Studio first converts the .resx files in a project to binary resource (.resources) files and stores them in a subdirectory of the project's obj directory. Visual Studio embeds any resource files that do not contain localized resources in the main assembly that is generated by the project. If any resource files contain localized resources, Visual Studio embeds them in separate satellite assemblies for each localized culture. It then stores each satellite assembly in a directory whose name corresponds to thelocalized culture. For example, localized English (United States) resources are stored in a satellite assembly in the en-US subdirectory.
I am trying to merge all the assemblies of an class library in a single .dll file.
I can merge all the assemblies using the Ilmerge but is that when I use the merged dll in a Silverlight application I am having trouble when a template is apply to my control and binding problems if I use a control that inherits with UserControl.
is there any solution to solve this problem?
The problem is that when the initial dlls are built the Xaml in the project is added as a resource in the dll. The code generated to load this xaml will look something like this:-
System.Windows.Application.LoadComponent(this, new System.Uri("/SilverlightLibrary1;component/MyControl.xaml", System.UriKind.Relative));
Note how the name of the dll forms part of the Uri need to fetch the xaml. I doubt IlMerge is able to spot that and fix it up. Hence once merged the Uris cannot be found.
A resolution for this is probably uglier than multiple references or simply creating another project that links all the code files involved.
What is .baml file and what's the use of this file?
Who creates this file?
A compiled XAML file.
Wikipedia says:
A XAML file can be compiled into a
.baml (Binary XAML) file, which may be
inserted as a resource into a .NET
Framework assembly. At run-time, the
framework engine extracts the .baml
file from assembly resources, parses
it, and creates a corresponding WPF
visual tree or workflow.
.baml = Binary Application Markup File, a compiled XAML file.
BAML form is an optimized form of XAML used by the WPF XAML implementation. It is optimized in the sense that it uses internal lookups and tokens for commonly used types or members. The optimization is useful as an implementation detail that addresses packaging size and load time for WPF application scenarios that involve XAML. Full Topic on Msdn
The purpose of BAML is only for checking if generated WPF controls have right values in their properties. Compiled XAML has also its auto-generated *.cs code. You can look at in your app\DEBUG\OBJ directory. Every XAML file has generated cs. Its name is XAMLfileName.g.cs where g means generated.