-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmanual-russian.txt
207 lines (175 loc) · 12 KB
/
manual-russian.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
Мануал для российских программеров.
NBox - утилита для сжатия множества дотнетовых сборок и файлов приложения в одну управляемую сборку, которая
будет хранить сжатые сборки в себе и при необходимости загружать их динамически. Для чего это может понадобиться ?
Во-первых, для уменьшения размера дистрибутива (файлы сжимаются по алгоритму LZMA, используемому в популярном
архиваторе 7-zip). Во-вторых, иногда для разработчика удобнее предоставлять дистрибутив одним исполняемым файлом
вместо того, чтобы делать полноценный инсталлятор или же распространять множество файлов в одном архиве
(то есть этот инструмент можно использовать в качестве лайт-замены для инсталляторов). В-третьих, загрузка
приложения, в котором много зависимостей, занимает обычно больше времени, чем загрузка одного исполняемого файла
с последующей подгрузкой необходимых модулей прямо в памяти (особенно это заметно на медленных сменных носителях), -
и NBox можно использовать для оптимизации загрузки приложения.
Дополнительные особенности :
- Возможность включать в результирующую сборку не только managed-сборки, но и библиотеки с неуправляемым кодом.
Неуправляемые библиотеки обычно используются через interop, и поэтому они должны быть извлечены перед
запуском приложения. Обычно они извлекаются в ту же директорию, в которой расположен исполняемый файл, либо
в системную директорию.
- Возможность включать любые файлы.
Да, вы можете засунуть любой файл и извлечь его перед запуском приложения в указанную директорию.
Это может быть файл конфигурации приложения, какой-либо бинарник, звуковой файл или что-то совсем другое.
- Корректная работа с WPF-приложениями.
Стандартные WPF-приложения особенным образом работает с ресурсами, поэтому обычный алгоритм для них не работает.
Поэтому приходится слегка похимичить с ресурсами. Либо нужно дублировать ресурсы оригинальной сборки в сжатой,
либо менять привязку к абсолютным путям на относительные в исходном коде и xaml.
Пример создания простого конфига.
Возьмем для примера саму утилиту NBox. Для начала ее необходимо загрузить в VisualStudio и откомпилировать.
Получена директория с файлами
NBox.exe - основная сборка нашего приложения
NBox.exe.config - конфигурационный файл, мы можем также включить его
NBox.pdb - необходим для отладки, не будем его брать
config-file.xsd - это просто копия файла схемы, в исполняемом файле он не нужен, так как уже есть в ресурсах
NLog.dll - одна из сборок-зависимостей, сжимаем
Common.Logging.dll - сжимаем
Common.Logging.NLog.dll - сжимаем
ICSharpCode.SharpZipLib.dll - сжимаем
Помещаем все нужные файлы в директорию src. Здесь же создаем директорию output.
Пути прописываем относительно %configdir% - места, где будет лежать конфиг.
Для нашего приложения конфигурационный файл может быть следующим :
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns="http://www.elwood.su/projects/nbox/schemas/config-file/v1.0">
<!-- Набор настроек для сжатия. Вы можете определить несколько таких опций (например, одна будет сжимать
очень сильно, другая вообще не будет сжимать - и дергать их по id -->
<compression-options-set>
<compression-option id="defaultCompression">
<!-- Пока здесь можно установить только то, сжимать вообще или нет. Уровень не меняется -->
<level value="ultra"/>
</compression-option>
</compression-options-set>
<!-- Определяем сборки, которые будут входить в исполняемый файл. -->
<assemblies default-compression-ref="defaultCompression"
default-include-method="Overlay"
default-generate-partial-aliases="false"
default-lazy-load="false">
<!-- Собственно список сборок. -->
<assembly id="NBox.exe" path="%configdir%/src/NBox.exe"/>
<assembly id="Common.Logging.dll" path="%configdir%/src/Common.Logging.dll"/>
<assembly id="Common.Logging.NLog.dll" path="%configdir%/src/Common.Logging.NLog.dll"/>
<assembly id="NLog.dll" path="%configdir%/src/NLog.dll"/>
<assembly id="ICSharpCode.SharpZipLib.dll" path="%configdir%/src/ICSharpCode.SharpZipLib.dll"/>
</assemblies>
<!-- Далее следуют файлы, которые нам нужны. -->
<files default-include-method="Overlay"
default-compression-ref="defaultCompression"
default-overwrite-on-extracting="CheckExist">
<file id="NBox.exe.config" path="%configdir%/src/NBox.exe.config" extract-to-path="%mainassemblydir%/NBox.exe.config"/>
</files>
<!-- И здесь определяем то, что мы должны получить. assembly-name задает имя новой сборки, оно должно
отличаться от имен всех сборок проекта, чтобы не создавать конфликтов -->
<output path="%configdir%/output/NBox.exe" assembly-name="NBoxBoxed" grab-resources="false"
apptype="Console" apartment="STA" machine="x86" main-assembly-ref="NBox.exe">
<includes>
<assemblies>
<assembly ref="Common.Logging.dll"/>
<assembly ref="Common.Logging.NLog.dll"/>
<assembly ref="NLog.dll"/>
<assembly ref="ICSharpCode.SharpZipLib.dll"/>
</assemblies>
<files>
<!-- При use-shadow-copying = true конфиг-файл будет скопирован во временную директорию, а не в директорию
с приложением. На запуск это не повлияет, AppDomain будет настроен корректно, конфиг-файл будет использован.
-->
<app-config use-shadow-copying="false" ref="NBox.exe.config"/>
<!-- Вместо app-config можно было воспользоваться просто файлом, но в этом случае приложение
не защищено от переименования, после переименования конфиг-файл перестанет подхватываться -->
<!--<file ref="NBox.exe.config"/>-->
</files>
</includes>
<!-- Небольшая оптимизация для компилятора microsoft c# -->
<compiler-options>
<options>/filealign:512</options>
</compiler-options>
</output>
</configuration>
Осталось только запустить NBox командой наподобие следующей :
NBox.exe my-config.xml
Далее по порядку содержимое конфигурационного файла.
1. Определение настроек сжатия.
Здесь все достаточно очевидно, вы определяете способ сжатия, и затем используете ссылки на него,
когда определяете сборки и файлы, внедряемые в проект. Единственное, что стоит отметить - то, что
на данный момент управление степенью сжатия не реализовано.
2. Определение сборок.
Каждая сборка имеет следующие атрибуты :
id - идентификатор сборки, необходим при связывании проекта
path - путь к исходному файлу, возможно, с использованием переменных %configdir% и %root%
compression-ref - ссылка на способ сжатия
copy-compressed-to - NBox сжимает файлы во временную директорию, содержимое которой позже очищается.
И если вы хотите оставить сжатый файл, вы можете задать имя файла, куда он будет скопирован. Это
необходимо, если вы используете метод внедрения "файл", то есть сжатая сборка не будет объединена с
исполняемым файлом, а будет лежать рядом и загружаться из файла.
include-method - может быть file, resource или overlay. При первом способе сжатая сборка лежит рядом с
исполняемым файлом и грузится из файла. Resource - сжатая сборка станет частью ресурсов исполняемого файла.
Overlay - сжатая сборка будет дописана в конец исполняемого файла. Последний способ экономит память,
поскольку оверлеи не загружаются в память загрузчиком Windows.
file-load-from-path - если вы выбрали метод "file", то наш собранных exe-шник должен знать, откуда он
будет грузить сборку. С помощью переменных %mainassemblydir% и %system32dir% вы можете определить путь
к сжатому файлу. Если же вы используете метод внедрения "resource" или "overlay", этот атрибут
не нужен.
overlay-offset и overlay-lenght - эти атрибуты используются лоадером NBox'а в момент загрузки
приложения и на этапе сборки проекта игнорируются.
resource-name - аналогично предыдущему
lazy-load - если равно true, то сборка будет загружена в момент первого обращения к ней.
Иначе - сборка будет принудительно загружена в момент старта приложения.
generate-partial-aliases - генерировать ли частичные алиасы по полному имени сборки. Т.е. при true для
сборки с полным именем "BettyBoxed, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" будут
сгенерированы таже имена "BettyBoxed, Version=1.0.0.0, Culture=neutral",
"BettyBoxed, Version=1.0.0.0" и "BettyBoxed".
aliases - список алиасов, по которым вы можете достучаться до вашей сборки, помимо полного имени и,
если generate-partial-aliases был установлен в true, - частичных алиасов. К примеру, вы можете
добавить свой алиас к сборке так :
<aliases>
<alias value="presentationframework.luna, Culture=neutral"/>
</aliases>
3. Определение файлов
С файлами все аналогично, только отсутствуют алиасы и добавлены следующие 2 атрибуты :
extract-to-path - куда будет помещен файл при распаковке. Если не указывать, файл будет распакован в
ту директорию, откуда стартовало приложение.
overwrite-on-extracting - режим перезаписи. Может принимать значения Always, CheckExists, CheckSize,
Never.
4. Определение результирующей сборки.
Тут, в принципе, тоже все достаточно просто и интуитивно понятно.
Вы отмечаете те сборки и файлы, которые должны быть включены, задаете имя сборки, иконку, дополнительные
опции компилятора. Единственный неочевидный атрибут - grab-resources - его смысл изложен в следующем разделе.
По поводу WPF. В приложениях WPF, создаваемых VisualStudio, содержится следующий код:
<Application x:Class="ExampleWPF_1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
<Application.Resources>
</Application.Resources>
</Application>
И он будет искать Window1.xaml в _исполняемом файле_, а не в сборке, в которой это определено.
Так как у нас исполняемым файлом является сжатая, сгенерированная NBox'ом сборка, которая содержит другие
сборки в сжатом виде и свои собственные ресурсы, то приложение при загрузке падает с ошибкой
"Не могу найти ресурс". Для того, чтобы этого не происходило, можно привязать загрузку ресурсов к конкретной
сборке, например, следующим образом :
<Application x:Class="ExampleWPF_1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="/ExampleWPF_1;component/Window1.xaml">
<Application.Resources>
</Application.Resources>
</Application>
Либо - для тех приложений, код которых менять по каким-либо причинам не следует, - выставить в
конфиге сжатия флаг grabResources в true. При сжатии NBox продублирует все ресурсы из mainAssembly в
свои ресурсы, и обращение к ресурсам будет происходить корректно. Минусы данного способа - результирующая
сборка может сильно распухнуть из-за дублирования толстых ресурсов, и обращения к ресурсам теперь идут на
самом деле к другой сборке, что может в будущем повлиять на поведение приложения, при изменении поведения
подсистемы WPF. Плюс - не нужно модифицировать код.
Основное следствие данной проблемы заключается в том, что вы не можете включать в проект более одной сборки, содержащей
WPF-ресурсы (чтобы узнать об их присутствии, можно поискать рефлектором ресурс с названием AssemblyName.g.resources).
Почему ? Потому что при grabResources = true мы должны продублировать все ресурсы из всех сборок в один
с именем AssemblyNameBoxed.g.resources, но возможности создать несколько ресурсов с одинаковым именем у нас нет.
Что делать в таких случаях ? Например, вы хотите включить темы для оформления WPF - dll, содержащие
WPF-ресурсы. Можно просто добавить их как файлы, чтобы при загрузке они распаковались рядом с приложением.
Конечно, сначала стоит попробовать включить их стандартно - как сборки, возможно, проблемы не возникнет -
если разработчики этой библиотеки использовали относительные пути относительно сборки или обращений к
ресурсам нет вообще.