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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
//! # `SetAttr` Statement
//!
//! Sets attribute information for a file.
//!
//! ## Syntax
//!
//! ```vb
//! SetAttr pathname, attributes
//! ```
//!
//! ## Parts
//!
//! - **pathname**: Required. String expression that specifies a file name. May include directory or folder, and drive.
//! - **attributes**: Required. Numeric expression or constant specifying the file attributes. Sum of the values of the file attribute constants.
//!
//! ## File Attribute Constants
//!
//! | Constant | Value | Description |
//! |----------|-------|-------------|
//! | vbNormal | 0 | Normal (no attributes set) |
//! | vbReadOnly | 1 | Read-only file attribute |
//! | vbHidden | 2 | Hidden file attribute |
//! | vbSystem | 4 | System file attribute |
//! | vbArchive | 32 | File has changed since last backup |
//!
//! ## Remarks
//!
//! - **Combining Attributes**: You can combine attributes by adding their values together (e.g., `vbReadOnly + vbHidden = 3`).
//! - **File Must Exist**: A run-time error occurs if the file specified by pathname doesn't exist.
//! - **Pathname Validation**: Pathname can be a fully qualified path or a relative path. Wildcard characters (* and ?) are not supported.
//! - **Cannot Set Directory Attribute**: You cannot use `SetAttr` to set the directory (vbDirectory = 16) attribute. Use `MkDir` and `RmDir` instead.
//! - **Volume Label**: You cannot use `SetAttr` to set the volume label (vbVolume = 8) attribute.
//! - **Read-Only Directories**: `SetAttr` cannot change the read-only status of a directory; it only works with files.
//! - **Error Handling**: Use error handling to trap potential errors like file not found, permission denied, or invalid attributes.
//! - **`GetAttr` Function**: Use `GetAttr` to retrieve current file attributes before modifying them with `SetAttr`.
//! - **Clearing Attributes**: To clear an attribute, set the file to vbNormal (0) or use a combination that excludes the unwanted attribute.
//!
//! ## Examples
//!
//! ### Set File to Read-Only
//!
//! ```vb
//! SetAttr "C:\MyFile.txt", vbReadOnly
//! ```
//!
//! ### Set File to Hidden
//!
//! ```vb
//! SetAttr "C:\Data\Secret.dat", vbHidden
//! ```
//!
//! ### Combine Multiple Attributes
//!
//! ```vb
//! ' Set file to read-only and hidden
//! SetAttr "C:\Config.ini", vbReadOnly + vbHidden
//! ```
//!
//! ### Clear All Attributes (Normal)
//!
//! ```vb
//! SetAttr "C:\MyFile.txt", vbNormal
//! ```
//!
//! ### Set Archive Attribute
//!
//! ```vb
//! SetAttr "C:\Backup\Data.dat", vbArchive
//! ```
//!
//! ### Using Variables
//!
//! ```vb
//! Dim fileName As String
//! Dim attrs As Integer
//!
//! fileName = "C:\Data\MyFile.txt"
//! attrs = vbReadOnly + vbArchive
//! SetAttr fileName, attrs
//! ```
//!
//! ### Toggle Read-Only Attribute
//!
//! ```vb
//! Dim currentAttrs As Integer
//! Dim filePath As String
//!
//! filePath = "C:\MyFile.txt"
//! currentAttrs = GetAttr(filePath)
//!
//! If currentAttrs And vbReadOnly Then
//! ' Remove read-only
//! SetAttr filePath, currentAttrs And Not vbReadOnly
//! Else
//! ' Add read-only
//! SetAttr filePath, currentAttrs Or vbReadOnly
//! End If
//! ```
//!
//! ### Set System File
//!
//! ```vb
//! SetAttr "C:\Windows\system.dat", vbSystem
//! ```
//!
//! ### Set Multiple Files in a Loop
//!
//! ```vb
//! Dim i As Integer
//! For i = 1 To 10
//! SetAttr "C:\Files\File" & i & ".txt", vbReadOnly
//! Next i
//! ```
//!
//! ### With Error Handling
//!
//! ```vb
//! On Error Resume Next
//! SetAttr "C:\MyFile.txt", vbReadOnly
//! If Err.Number <> 0 Then
//! MsgBox "Could not set file attributes: " & Err.Description
//! End If
//! On Error GoTo 0
//! ```
//!
//! ### Using App.Path
//!
//! ```vb
//! SetAttr App.Path & "\Config.ini", vbHidden
//! ```
//!
//! ### Preserve Existing Attributes While Adding New Ones
//!
//! ```vb
//! Dim filePath As String
//! Dim currentAttrs As Integer
//!
//! filePath = "C:\MyFile.txt"
//! currentAttrs = GetAttr(filePath)
//!
//! ' Add hidden attribute while preserving others
//! SetAttr filePath, currentAttrs Or vbHidden
//! ```
//!
//! ### Remove Specific Attribute
//!
//! ```vb
//! Dim filePath As String
//! Dim currentAttrs As Integer
//!
//! filePath = "C:\MyFile.txt"
//! currentAttrs = GetAttr(filePath)
//!
//! ' Remove hidden attribute while preserving others
//! SetAttr filePath, currentAttrs And Not vbHidden
//! ```
//!
//! ### Using Numeric Values
//!
//! ```vb
//! SetAttr "C:\MyFile.txt", 1 ' Same as vbReadOnly
//! SetAttr "C:\MyFile.txt", 3 ' Read-only + Hidden (1 + 2)
//! SetAttr "C:\MyFile.txt", 35 ' Read-only + Hidden + Archive (1 + 2 + 32)
//! ```
//!
//! ### Conditional Attribute Setting
//!
//! ```vb
//! If FileIsImportant Then
//! SetAttr filePath, vbReadOnly + vbArchive
//! Else
//! SetAttr filePath, vbNormal
//! End If
//! ```
//!
//! ## Common Errors
//!
//! - **Error 53**: File not found - occurs if the pathname doesn't exist
//! - **Error 5**: Invalid procedure call or argument - occurs if attributes value is invalid
//! - **Error 70**: Permission denied - occurs if you don't have write access to the file
//! - **Error 75**: Path/File access error - occurs if the file is open or locked
//!
//! ## Important Notes
//!
//! - **File Must Be Closed**: The file should not be open when you use `SetAttr`.
//! - **Permissions Required**: You must have appropriate permissions to change file attributes.
//! - **Network Files**: `SetAttr` works with network files if you have appropriate permissions.
//! - **UNC Paths**: `SetAttr` supports UNC (Universal Naming Convention) paths like "\\\\Server\\Share\\File.txt".
//! - **Attribute Persistence**: File attributes persist after the application closes; they're stored in the file system.
//! - **Read-Only Files**: To modify a read-only file, you must first remove the read-only attribute, make changes, then restore it.
//! - **`GetAttr` Complement**: Always use `GetAttr` to retrieve current attributes before modifying them to avoid unintentionally removing existing attributes.
//!
//! ## Best Practices
//!
//! - Use error handling when working with `SetAttr` as file operations can fail for many reasons
//! - Use `GetAttr` before `SetAttr` to preserve existing attributes you don't want to change
//! - Use symbolic constants (vbReadOnly, etc.) instead of numeric values for better code readability
//! - Check file existence using `Dir()` before calling `SetAttr`
//! - Be cautious when setting system attributes as they can affect system stability
//! - Document why specific attributes are being set, especially for hidden or system files
//! - Consider user permissions when setting attributes on shared or network files
//!
//! ## See Also
//!
//! - `GetAttr` function (retrieve file attributes)
//! - `Dir` function (check if file exists)
//! - `Kill` statement (delete files)
//! - `Name` statement (rename files)
//! - `FileCopy` statement (copy files)
//!
//! ## References
//!
//! - [SetAttr Statement - Microsoft Docs](https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/setattr-statement)
use crate;
use cratefile;
use crateVBVariant;
use err_number;
/// Set attributes for a file.
///
/// # Arguments
///
/// * `pathname` - The file path.
/// * `attributes` - The attributes to set.
///
/// # Returns
///
/// Returns `Ok(())` on success, or `Err(VBError)` on failure.