Ответ 1
Visual Studio не имеет возможности выполнить компилятор ресурсов Win32 из задачи MSBuild, и ни одна из встроенных функций для создания ресурсов не создает ресурсы. Из-за этого ваши варианты:
- Создайте файл .res "вручную", как описано в связанной статье, или
- Добавьте задачу сборки, чтобы вы могли вызвать компилятор ресурсов Win32 из вашего .csproj
Сначала я объясню различия между пятью различными "ресурсами", которые могут существовать в файле .exe или .dll, включая "Ресурсы Win32", которые требуется JumpList.
Затем я объясню, как создать задачу пользовательской сборки, которая позволяет встраивать произвольные ресурсы Win32 в исполняемый файл С# или VB.NET.
Пять видов ресурсов в исполняемом файле Win32
Существует пять различных видов "ресурсов", которые могут существовать в файле .exe или .dll:
- Ресурсы Win32
- NET Framework "Встроенные ресурсы"
- Объекты CLR в ResourceSet
- Ресурсы XAML
- Ресурсы WPF (объекты в ResourceDictionary)
Ресурсы Win32
Первоначальный вид ресурса был Win32 "Resource". Этот вид ресурсов определяется в файле .rc и имеет либо нумерованные, либо именованные ресурсы, каждый из которых имеет тип и блок данных.
Компилятор ресурсов Win32, rc.exe, компилирует .rc файл в двоичный файл .res, затем может быть добавлен в результирующий исполняемый файл.
Доступ к ресурсам Win32 осуществляется с помощью функций Win32 FindResource
и LoadResource
.
Ресурсы Win32 встроены в приложения С++, добавив их в файл .rc, который скомпилирован в файл .res и связан с исполняемым файлом. Они также могут быть добавлены после использования программы rc.exe. Для приложений С# и VB.NET MSBuild может добавить предварительно созданный файл .res к исполняемому файлу, который он создает с помощью компилятора Csc или Vbc, или он может создать по умолчанию для вас. Ни С#, ни VB.NET не имеют возможности создавать файлы с расширением .res из-за невыполнения .res файлов, и для вас нет задачи MSBuild.
Вы можете просматривать ресурсы Win32 в файлах .exe или .dll, открыв сам файл .exe или .dll в Visual Studio, используя File → Open.
В типичном приложении C, С++ или MFC будет много ресурсов Win32, например, каждое диалоговое окно будет указано ресурсом.
Типичное приложение WPF будет иметь только три стандартных ресурса Win32, созданных компилятором С# или VB.NET: ресурс версии, RT_MANIFEST и значок приложения. Содержимое этих ресурсов построено из атрибутов Assembly в коде и в элементе <ApplicationIcon>
в файле .csproj или .vbproj.
Это тот ресурс, который ищет JumpList.
Встроенные ресурсы
"Встроенный ресурс" - это ресурс NET Framework. Структура данных, содержащая эти ресурсы, управляется CLR способом, более удобным для доступа управляемым кодом. Каждый ресурс идентифицируется строковым именем, которое по соглашению начинается с пространства имен класса, с которым связан ресурс.
Вложенный ресурс - это всего лишь фрагмент двоичных данных с именем. Фактический тип данных либо известен вызывающему, либо выводится из имени, как файлы в файловой системе. Например, встроенный ресурс с именем, заканчивающимся на ".jpg", скорее всего будет JPEG файлом.
Доступ к встроенным ресурсам осуществляется с помощью Assembly.GetManifestResourceStream
и его братьев и сестер GetManifestResourceInfo
и GetManifestResourceNames
.
Встроенные ресурсы встроены в файлы .exe и .dll, добавив файл в проект и установив действие сборки в "Встроенный ресурс".
Вы можете просмотреть встроенные ресурсы в .exe или .dll, открыв его в NET Reflector и посмотрев папку "Ресурсы".
Встроенные ресурсы обычно используются в WinForms, но почти никогда с WPF.
Наборы ресурсов (.resx/.resources)
Несколько объектов NET Framework, таких как строки и значки, могут быть объединены в единый набор данных "Набор ресурсов", который хранится в .exe как единый встроенный ресурс .NET Framework. Например, это используется WinForms для хранения таких вещей, как значки и строки, которые нелегко включить в сгенерированный код.
Объекты в наборе ресурсов могут быть получены индивидуально с помощью классов ResourceManager
и ResourceSet
, определенных CLR.
Объекты в наборе ресурсов определяются в исходном коде файлом .resx. Данные могут быть непосредственно в файле .resx(как в случае с строками) или ссылаться на файл .resx(как в случае с значками). Когда проект построен, содержимое, указанное каждым файлом .resx, сериализуется в двоичную форму и сохраняется как один встроенный ресурс с расширением ".resx", замененным на ".resources".
Вы можете просмотреть объекты в наборе ресурсов, открыв файлы .exe или .dll в NET Reflector, открыв папку "Ресурсы", щелкнув файл ".resources" и посмотрев на элементы в правой панели.
Многие функции эпохи WinForms обычно используют файлы .resx и ResourceSets аналогично старым файлам Win32.rc для хранения нескольких ресурсов, таких как строки. Они также используются WinForms для хранения настроек в форме, которая не может идти в коде.
Приложения WPF почти никогда не используют произвольные объекты в ResourceSets, хотя WPF сам использует ResourceSets для хранения скомпилированного XAML.
Ресурсы XAML
Ресурс WPF XAML - это скомпилированный файл XAML, который хранится внутри ResourceSet. Имя внутри набора ресурсов - это исходное имя файла с заменой ".xaml" на ".g.baml". Контент может быть любым допустимым XAML, наиболее распространенными типами являются Window, Page, UserControl, ResourceDictionary и
Применение.
Ресурсы WPF можно загружать с помощью Application.LoadComponent()
или путем ссылки на исходное имя файла XAML в контексте WPF. Кроме того, любой ресурс WPF, который имеет код позади (как указано x:Class
), будет автоматически загружен и применен к каждому объекту, созданному из этого класса во время его вызова InitializeComponent
.
Ресурсы WPF создаются путем добавления в проект файла .xaml и установки его действия сборки на "Ресурс", "Страница" или "ApplicationDefinition". Это заставляет компилятор компилировать файл в BAML и добавлять его в соответствующий ResourceSet.
Вы можете просмотреть ресурсы XAML в .exe или .dll, открыв его в NET Reflector с установленной надстройкой BamlViewer, выбрав в меню Tools → BAML Viewer и с помощью BAML Viewer перейти к конкретному. g.baml внутри .resources.
Ресурсы WPF в ResourceDictionary
В WPF почти все так называемые "ресурсы" - это записи в ResourceDictionary. ResourceDictionaries описаны в XAML, либо в других объектах, таких как Windows и UserControls, либо в отдельных файлах XAML, которые содержат только ResourceDictionary. Каждый из них идентифицируется с помощью "x: Key", который может быть любым типом объекта. Сами ресурсы также могут быть любыми типами объектов.
Ресурсы WPF можно ссылаться в XAML с использованием расширений разметки {StaticResource}
и {DynamicResource}
или могут быть загружены в код с помощью FindResource
.
<ResourceDictionary>
и присваивает им атрибут x:Key
.
Ресурсы WPF широко используются в WPF, включая кисти, стили, данные, геометрии, шаблоны и т.д.
Вы можете просмотреть ресурсы WPF в файлах .exe или .dll, просмотрев ресурсы XAML, как описано выше, и для каждого из них, просматривающих теги ResourceDictionary, чтобы просмотреть сами ресурсы.
Включение ресурсов Win32 в исполняемый файл С# или VB.NET
Как легко встраивать произвольные ресурсы Win32 в С# или VB.NET.exe
В приведенном выше обсуждении вы отметите, что легко добавлять каждый тип ресурса в ваше приложение С# или VB.NET, за исключением ресурсов Win32. Чтобы сделать это легко, вы можете добавить дополнительную задачу сборки и задачу. Вот как:
- Создайте проект, содержащий одну задачу сборки "Win32ResourceCompiler" и скомпилируйте ее
- Создайте файл .targets, содержащий одну цель, использующую эту задачу, для автоматической сборки файла .rc в .res
- Задайте проект для использования полученного файла .res
Задача чрезвычайно проста:
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
}
}
Файл .targets также очень прост. Это будет что-то в этом роде:
<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>
Теперь в файле .csproj добавьте ссылку на ваш файл .targets:
<Import Project="Win32ResourceCompiler.targets" />
И, конечно же, вам нужно предоставить вашему файлу .rc файл типа Win32RCFile:
<ItemGroup>
<Win32RCFile Include="MyWin32Resources.rc" />
</ItemGroup>
С помощью этой настройки вы можете создать традиционный файл Win32.rc, чтобы указать все ваши ресурсы Win32, включая вашу версию, манифест, значок приложения и столько дополнительных значков, сколько хотите. Каждый раз, когда вы компилируете, все эти ресурсы Win32 будут добавлены в ваш .exe файл.
Это займет немного времени, чтобы настроить, но гораздо более удовлетворительно и проще в долгосрочной перспективе, чем вручную редактировать файл .res.
Вы можете указать несколько значков в вашем файле .rc следующим образом:
1 ICON ApplicationIcon.ico
2 ICON JumpListIcon.ico
3 ICON AnotherIcon.ico
Здесь - документация для всех операторов определения ресурсов, которые вы можете использовать в файле .rc.
Также обратите внимание, что вышеприведенный файл .targets был напечатан на волне момента и не был протестирован. Документацию по синтаксису файлов MSBuild (.csproj и .targets) можно найти здесь и здесь, а хорошие примеры файлов .targets можно найти в каталоге c:\Windows\Microsoft.NET\Framework\v3.5).