mslnk/header.rs
1use bitflags::bitflags;
2use byteorder::{ByteOrder, LE};
3
4const CLSID: u128 = 0x460000000000_00c0_0000_0000_00021401;
5
6/// A ShellLinkHeader structure (section 2.1), which contains identification
7/// information, timestamps, and flags that specify the presence of optional
8/// structures.
9#[derive(Clone, Copy, Debug)]
10pub struct ShellLinkHeader {
11 /// A LinkFlags structure (section 2.1.1) that specifies information about the shell link and
12 /// the presence of optional portions of the structure.
13 link_flags: LinkFlags,
14 /// A FileAttributesFlags structure (section 2.1.2) that specifies information about the link
15 /// target.
16 file_attributes: FileAttributeFlags,
17 /// A FILETIME structure ([MS-DTYP]section 2.3.3) that specifies the creation time of the link
18 /// target in UTC (Coordinated Universal Time). If the value is zero, there is no creation time
19 /// set on the link target.
20 creation_time: u64,
21 /// A FILETIME structure ([MS-DTYP] section2.3.3) that specifies the access time of the link
22 /// target in UTC (Coordinated Universal Time). If the value is zero, there is no access time
23 /// set on the link target.
24 access_time: u64,
25 /// A FILETIME structure ([MS-DTYP] section 2.3.3) that specifies the write time of the link
26 /// target in UTC (Coordinated Universal Time). If the value is zero, there is no write time
27 /// set on the link target.
28 write_time: u64,
29 /// A 32-bit unsigned integer that specifies the size, in bytes, of the link target. If the
30 /// link target fileis larger than 0xFFFFFFFF, this value specifies the least significant 32
31 /// bits of the link target file size.
32 file_size: u32,
33 /// A 32-bit signed integer that specifies the index of an icon within a given icon location.
34 icon_index: i32,
35 /// A 32-bit unsigned integer that specifies the expected window state of an application
36 /// launched by the link.
37 show_command: ShowCommand,
38 /// A HotkeyFlags structure (section 2.1.3) that specifies the keystrokes used to launch the
39 /// application referenced by the shortcut key. This value is assigned to the application after
40 /// it is launched, so that pressing the key activates that application.
41 hotkey: HotkeyFlags,
42}
43
44impl ShellLinkHeader {
45 /// Get the link flags
46 pub fn link_flags(&self) -> &LinkFlags {
47 &self.link_flags
48 }
49
50 /// Set the link flags
51 pub fn set_link_flags(&mut self, link_flags: LinkFlags) {
52 self.link_flags = link_flags;
53 }
54
55 /// Set some link flags
56 pub fn update_link_flags(&mut self, link_flags: LinkFlags, value: bool) {
57 self.link_flags.set(link_flags, value);
58 }
59
60 /// Get the file attributes
61 pub fn file_attributes(&self) -> &FileAttributeFlags {
62 &self.file_attributes
63 }
64
65 /// Set the file attributes
66 pub fn set_file_attributes(&mut self, file_attributes: FileAttributeFlags) {
67 self.file_attributes = file_attributes;
68 }
69
70 /// Get the file creation time
71 pub fn creation_time(&self) -> u64 {
72 self.creation_time
73 }
74
75 /// Set the file creation time
76 pub fn set_creation_time(&mut self, creation_time: u64) {
77 self.creation_time = creation_time;
78 }
79
80 /// Get the file access time
81 pub fn access_time(&self) -> u64 {
82 self.access_time
83 }
84
85 /// Set the file access time
86 pub fn set_access_time(&mut self, access_time: u64) {
87 self.access_time = access_time;
88 }
89
90 /// Get the file write time
91 pub fn write_time(&self) -> u64 {
92 self.write_time
93 }
94
95 /// Set the file write time
96 pub fn set_write_time(&mut self, write_time: u64) {
97 self.write_time = write_time;
98 }
99
100 /// The file size, or at least the least significant 32-bits of the
101 /// size
102 pub fn file_size(&self) -> u32 {
103 self.file_size
104 }
105
106 /// Set the file size, or if bigger then 32-bits, set the least
107 /// significant 32-bits
108 pub fn set_file_size(&mut self, file_size: u32) {
109 self.file_size = file_size;
110 }
111
112 /// Get the icon index
113 pub fn icon_index(&self) -> i32 {
114 self.icon_index
115 }
116
117 /// Set the icon index
118 pub fn set_icon_index(&mut self, icon_index: i32) {
119 self.icon_index = icon_index;
120 }
121
122 /// Get the show command
123 pub fn show_command(&self) -> &ShowCommand {
124 &self.show_command
125 }
126
127 /// Set the shortcut show command
128 pub fn set_show_command(&mut self, show_command: ShowCommand) {
129 self.show_command = show_command;
130 }
131
132 /// Get the hotkey flags
133 pub fn hotkey(&self) -> &HotkeyFlags {
134 &self.hotkey
135 }
136
137 /// Get a mutable pointer to the hotkey flags
138 pub fn hotkey_mut(&mut self) -> &mut HotkeyFlags {
139 &mut self.hotkey
140 }
141}
142
143impl Default for ShellLinkHeader {
144 /// Create a new, blank, ShellLinkHeader
145 fn default() -> Self {
146 Self {
147 link_flags: LinkFlags::IS_UNICODE,
148 file_attributes: FileAttributeFlags::FILE_ATTRIBUTE_NORMAL,
149 creation_time: 0,
150 access_time: 0,
151 write_time: 0,
152 file_size: 0,
153 icon_index: 0,
154 show_command: ShowCommand::ShowNormal,
155 hotkey: HotkeyFlags::new(HotkeyKey::NoKeyAssigned, HotkeyModifiers::NO_MODIFIER),
156 }
157 }
158}
159
160impl Into<[u8; 0x4c]> for ShellLinkHeader {
161 /// Write the data in this header to a `[u8]` for writing to the output file.
162 fn into(self) -> [u8; 0x4c] {
163 let mut header_data = [0u8; 0x4c];
164 LE::write_u32(&mut header_data[0..], 0x4c);
165 LE::write_u128(&mut header_data[4..], CLSID);
166 LE::write_u32(&mut header_data[20..], self.link_flags.bits);
167 LE::write_u32(&mut header_data[24..], self.file_attributes.bits);
168 LE::write_u64(&mut header_data[28..], self.creation_time);
169 LE::write_u64(&mut header_data[36..], self.access_time);
170 LE::write_u64(&mut header_data[44..], self.write_time);
171 LE::write_u32(&mut header_data[52..], self.file_size);
172 LE::write_i32(&mut header_data[56..], self.icon_index);
173 LE::write_u32(&mut header_data[60..], self.show_command as u32);
174 LE::write_u16(&mut header_data[64..], self.hotkey.to_flags_u16());
175 LE::write_u16(&mut header_data[66..], 0);
176 LE::write_u32(&mut header_data[68..], 0);
177 LE::write_u32(&mut header_data[72..], 0);
178 header_data
179 }
180}
181
182bitflags! {
183 /// The LinkFlags structure defines bits that specify which shell linkstructures are present in
184 /// the file format after the ShellLinkHeaderstructure (section 2.1).
185 pub struct LinkFlags: u32 {
186 /// The shell link is saved with an item ID list (IDList). If this bit is set, a
187 /// LinkTargetIDList structure (section 2.2) MUST follow the ShellLinkHeader. If this bit
188 /// is not set, this structure MUST NOT be present.
189 const HAS_LINK_TARGET_ID_LIST = 0b0000_0000_0000_0000_0000_0000_0000_0001;
190 /// The shell link is saved with link information. If this bit is set, a LinkInfo structure
191 /// (section 2.3) MUST be present. If this bit is not set, this structure MUST NOT be
192 /// present.
193 const HAS_LINK_INFO = 0b0000_0000_0000_0000_0000_0000_0000_0010;
194 /// The shell link is saved with a name string. If this bit is set, a NAME_STRING
195 /// StringData structure (section 2.4) MUST be present. If this bit is not set, this
196 /// structure MUST NOT be present.
197 const HAS_NAME = 0b0000_0000_0000_0000_0000_0000_0000_0100;
198 /// The shell link is saved with a relative path string. If this bit is set, a
199 /// RELATIVE_PATH StringData structure (section 2.4) MUST be present. If this bit is not
200 /// set, this structure MUST NOT be present.
201 const HAS_RELATIVE_PATH = 0b0000_0000_0000_0000_0000_0000_0000_1000;
202 /// The shell link is saved with a relative path string. If this bit is set, a
203 /// WORKING_DIR StringData structure (section 2.4) MUST be present. If this bit is not
204 /// set, this structure MUST NOT be present.
205 const HAS_WORKING_DIR = 0b0000_0000_0000_0000_0000_0000_0001_0000;
206 /// The shell link is saved with a relative path string. If this bit is set, a
207 /// COMMAND_LINE_ARGUMENTS StringData structure (section 2.4) MUST be present. If this bit
208 /// is not set, this structure MUST NOT be present.
209 const HAS_ARGUMENTS = 0b0000_0000_0000_0000_0000_0000_0010_0000;
210 /// The shell link is saved with a relative path string. If this bit is set, a
211 /// ICON_LOCATION StringData structure (section 2.4) MUST be present. If this bit is not
212 /// set, this structure MUST NOT be present.
213 const HAS_ICON_LOCATION = 0b0000_0000_0000_0000_0000_0000_0100_0000;
214 /// The shell link contains Unicode encoded strings. This bit SHOULD be set. If this bit is
215 /// set, the StringData section contains Unicode-encoded strings; otherwise, it contains
216 /// strings that are encoded using the system default code page
217 const IS_UNICODE = 0b0000_0000_0000_0000_0000_0000_1000_0000;
218 /// The LinkInfo structure (section 2.3) is ignored.
219 const FORCE_NO_LINK_INFO = 0b0000_0000_0000_0000_0000_0001_0000_0000;
220 /// The shell link is saved with an EnvironmentVariableDataBlock (section 2.5.4).
221 const HAS_EXP_STRING = 0b0000_0000_0000_0000_0000_0010_0000_0000;
222 /// The target is run in a separate virtual machine when launching a link target that is a
223 /// 16-bit application.
224 const RUN_IN_SEPARATE_PROCESS = 0b0000_0000_0000_0000_0000_0100_0000_0000;
225 /// A bit that is undefined and MUST be ignored.
226 const UNUSED1 = 0b0000_0000_0000_0000_0000_1000_0000_0000;
227 /// The shell link is saved with a DarwinDataBlock(section2.5.3).
228 const HAS_DARWIN_ID = 0b0000_0000_0000_0000_0001_0000_0000_0000;
229 /// The application is run as a different user when the target of the shell link is
230 /// activated.
231 const RUN_AS_USER = 0b0000_0000_0000_0000_0010_0000_0000_0000;
232 /// The shell link is saved with an IconEnvironmentDataBlock (section 2.5.5).
233 const HAS_EXP_ICON = 0b0000_0000_0000_0000_0100_0000_0000_0000;
234 /// The file system location is represented in the shell namespace when the path to an item
235 /// is parsed into an IDList.
236 const NO_PIDL_ALIAS = 0b0000_0000_0000_0000_1000_0000_0000_0000;
237 /// A bit that is undefined and MUST be ignored.
238 const UNUSED2 = 0b0000_0000_0000_0001_0000_0000_0000_0000;
239 /// The shell link is saved with a ShimDataBlock(section2.5.8)
240 const RUN_WITH_SHIM_LAYER = 0b0000_0000_0000_0010_0000_0000_0000_0000;
241 /// The TrackerDataBlock(section2.5.10)is ignored.
242 const FORCE_NO_LINK_TRACK = 0b0000_0000_0000_0100_0000_0000_0000_0000;
243 /// The shell link attempts to collect target properties and store them in the
244 /// PropertyStoreDataBlock(section2.5.7) when the link target is set.
245 const ENABLE_TARGET_METADATA = 0b0000_0000_0000_1000_0000_0000_0000_0000;
246 /// The EnvironmentVariableDataBlock is ignored.
247 const DISABLE_LINK_PATH_TRACKING = 0b0000_0000_0001_0000_0000_0000_0000_0000;
248 /// The SpecialFolderDataBlock(section2.5.9)and the KnownFolderDataBlock(section2.5.6)are
249 /// ignored when loading the shell link. If this bit is set, these extra data blocks SHOULD
250 /// NOT be saved when saving the shell link.
251 const DISABLE_KNOWN_FOLDER_TRACKING = 0b0000_0000_0010_0000_0000_0000_0000_0000;
252 /// If the linkhas a KnownFolderDataBlock(section2.5.6), the unaliased form of the known
253 /// folder IDList SHOULD be used when translating the target IDList at the time that the
254 /// link is loaded.
255 const DISABLE_KNOWN_FOLDER_ALIAS = 0b0000_0000_0100_0000_0000_0000_0000_0000;
256 /// Creating a link that references another link is enabled. Otherwise, specifying a link
257 /// as the target IDList SHOULD NOT be allowed.
258 const ALLOW_LINK_TO_LINK = 0b0000_0000_1000_0000_0000_0000_0000_0000;
259 /// When saving a link for which the target IDList is under a known folder, either the
260 /// unaliased form of that known folder or the target IDList SHOULD be used.
261 const UNALIAS_ON_SAVE = 0b0000_0001_0000_0000_0000_0000_0000_0000;
262 /// The target IDList SHOULD NOT be stored; instead, the path specified in the
263 /// EnvironmentVariableDataBlock(section2.5.4) SHOULD be used to refer to the target.
264 const PREFER_ENVIRONMENT_PATH = 0b0000_0010_0000_0000_0000_0000_0000_0000;
265 /// When the target is a UNC name that refers to a location on a local machine, the local
266 /// path IDList in the PropertyStoreDataBlock(section2.5.7) SHOULD be stored, so it can be
267 /// used when the link is loaded on the local machine.
268 const KEEP_LOCAL_ID_LIST_FOR_UNC_TARGET = 0b0000_0100_0000_0000_0000_0000_0000_0000;
269 }
270}
271
272bitflags! {
273 /// The FileAttributesFlags structure defines bits that specify the file attributes of the link
274 /// target, if the target is a file system item. File attributes can be used if the link target
275 /// is not available, or if accessing the target would be inefficient. It is possible for the
276 /// target items attributes to be out of sync with this value.
277 pub struct FileAttributeFlags: u32 {
278 /// The file or directory is read-only. For a file, if this bit is set, applications can read the file but cannot write to it or delete it. For a directory, if this bit is set, applications cannot delete the directory
279 const FILE_ATTRIBUTE_READONLY = 0b0000_0000_0000_0000_0000_0000_0000_0001;
280 /// The file or directory is hidden. If this bit is set, the file or folder is not included in an ordinary directory listing.
281 const FILE_ATTRIBUTE_HIDDEN = 0b0000_0000_0000_0000_0000_0000_0000_0010;
282 /// The file or directory is part of the operating system or is used exclusively by the operating system.
283 const FILE_ATTRIBUTE_SYSTEM = 0b0000_0000_0000_0000_0000_0000_0000_0100;
284 /// A bit that MUST be zero.
285 const RESERVED1 = 0b0000_0000_0000_0000_0000_0000_0000_1000;
286 /// The link target is a directory instead of a file.
287 const FILE_ATTRIBUTE_DIRECTORY = 0b0000_0000_0000_0000_0000_0000_0001_0000;
288 /// The file or directory is an archive file. Applications use this flag to mark files for
289 /// backup or removal.
290 const FILE_ATTRIBUTE_ARCHIVE = 0b0000_0000_0000_0000_0000_0000_0010_0000;
291 /// A bit that MUST be zero.
292 const RESERVED2 = 0b0000_0000_0000_0000_0000_0000_0100_0000;
293 /// The file or directory has no other flags set. If this bit is 1, all other bits in this
294 /// structure MUST be clear.
295 const FILE_ATTRIBUTE_NORMAL = 0b0000_0000_0000_0000_0000_0000_1000_0000;
296 /// The file is being used for temporary storage.
297 const FILE_ATTRIBUTE_TEMPORARY = 0b0000_0000_0000_0000_0000_0001_0000_0000;
298 /// The file is a sparse file.
299 const FILE_ATTRIBUTE_SPARSE_FILE = 0b0000_0000_0000_0000_0000_0010_0000_0000;
300 /// The file or directory has an associated reparse point.
301 const FILE_ATTRIBUTE_REPARSE_POINT = 0b0000_0000_0000_0000_0000_0100_0000_0000;
302 /// The file or directory is compressed. For a file, this means that all data in the file
303 /// is compressed. For a directory, this means that compression is the default for newly
304 /// created files and subdirectories.
305 const FILE_ATTRIBUTE_COMPRESSED = 0b0000_0000_0000_0000_0000_1000_0000_0000;
306 /// The data of the file is not immediately available.
307 const FILE_ATTRIBUTE_OFFLINE = 0b0000_0000_0000_0000_0001_0000_0000_0000;
308 /// The contents of the file need to be indexed.
309 const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0b0000_0000_0000_0000_0010_0000_0000_0000;
310 /// The file or directory is encrypted. For a file, this means that all data in the file is encrypted. For a directory, this means that encryption is the default for newly created files and subdirectories.
311 const FILE_ATTRIBUTE_ENCRYPTED = 0b0000_0000_0000_0000_0100_0000_0000_0000;
312 }
313}
314
315/// The HotkeyFlags structure specifies input generated by a combination of keyboard keys being
316/// pressed.
317#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
318pub struct HotkeyFlags {
319 low_byte: HotkeyKey,
320 high_byte: HotkeyModifiers,
321}
322
323impl HotkeyFlags {
324 /// Create a new HotkeyFlags instance.
325 pub fn new(low_byte: HotkeyKey, high_byte: HotkeyModifiers) -> Self {
326 Self {
327 low_byte,
328 high_byte,
329 }
330 }
331
332 /// Convert these HotkeyFlags to the u16 representation for saving.
333 fn to_flags_u16(self) -> u16 {
334 self.low_byte as u16 + ((self.high_byte.bits as u16) << 8)
335 }
336
337 /// The primary key assigned to the hotkey
338 pub fn key(&self) -> &HotkeyKey {
339 &self.low_byte
340 }
341
342 /// Set the hotkey primary key
343 pub fn set_key(&mut self, key: HotkeyKey) {
344 self.low_byte = key;
345 }
346
347 /// The modifiers (Shift, Ctrl, Alt) for this hotkey
348 pub fn modifiers(&self) -> &HotkeyModifiers {
349 &self.high_byte
350 }
351
352 /// Set the hotkey modifiers (Shift, Ctrl, Alt)
353 pub fn set_modifiers(&mut self, modifiers: HotkeyModifiers) {
354 self.high_byte = modifiers;
355 }
356}
357
358#[allow(missing_docs)]
359#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
360/// An 8-bit unsigned integer that specifies a virtual key code that corresponds to a key on the
361/// keyboard.
362pub enum HotkeyKey {
363 NoKeyAssigned = 0x00,
364 Key0 = 0x30,
365 Key1,
366 Key2,
367 Key3,
368 Key4,
369 Key5,
370 Key6,
371 Key7,
372 Key8,
373 Key9,
374 KeyA = 0x41,
375 KeyB,
376 KeyC,
377 KeyD,
378 KeyE,
379 KeyF,
380 KeyG,
381 KeyH,
382 KeyI,
383 KeyJ,
384 KeyK,
385 KeyL,
386 KeyM,
387 KeyN,
388 KeyO,
389 KeyP,
390 KeyQ,
391 KeyR,
392 KeyS,
393 KeyT,
394 KeyU,
395 KeyV,
396 KeyW,
397 KeyX,
398 KeyY,
399 KeyZ,
400 F1 = 0x70,
401 F2,
402 F3,
403 F4,
404 F5,
405 F6,
406 F7,
407 F8,
408 F9,
409 F10,
410 F11,
411 F12,
412 F13,
413 F14,
414 F15,
415 F16,
416 F17,
417 F18,
418 F19,
419 F20,
420 F21,
421 F22,
422 F23,
423 F24,
424 NumLock = 0x90,
425 ScrollLock,
426}
427
428bitflags! {
429 /// An 8-bit unsigned integer that specifies bits that correspond to modifier keys on the
430 /// keyboard.
431 pub struct HotkeyModifiers: u8 {
432 /// No modifier key is being used.
433 const NO_MODIFIER = 0x00;
434 /// The "SHIFT" key on the keyboard.
435 const HOTKEYF_SHIFT = 0x01;
436 /// The "CTRL" key on the keyboard.
437 const HOTKEYF_CONTROL = 0x02;
438 /// The "ALT" key on the keyboard.
439 const HOTKEYF_ALT = 0x04;
440 }
441}
442
443/// The expected window state of an application launched by the link.
444#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
445pub enum ShowCommand {
446 /// The application is open and its window is open in a normal fashion.
447 ShowNormal = 0x01,
448 /// The application is open, and keyboard focus is given to the application, but its window is
449 /// not shown.
450 ShowMaximized = 0x03,
451 /// The application is open, but its window is not shown. It is not given the keyboard focus.
452 ShowMinNoActive = 0x07,
453}