Configuration-COM-API.md (33864B)
1 <!-- TEMPLATE 2 The purpose of this spec is to describe new APIs, in a way 3 that will transfer to docs.microsoft.com (DMC). 4 5 There are two audiences for the spec. The first are people that want to evaluate and 6 give feedback on the API, as part of the submission process. 7 When it's complete it will be incorporated into the public documentation at 8 http://docs.microsoft.com (DMC). 9 Hopefully we'll be able to copy it mostly verbatim. So the second audience is 10 everyone that reads there to learn how and why to use this API. 11 Some of this text also shows up in Visual Studio Intellisense. 12 13 For example, much of the examples and descriptions in the `RadialGradientBrush` API spec 14 (https://github.com/microsoft/microsoft-ui-xaml-specs/blob/master/active/RadialGradientBrush/RadialGradientBrush.md) 15 were carried over to the public API page on DMC 16 (https://docs.microsoft.com/windows/winui/api/microsoft.ui.xaml.media.radialgradientbrush?view=winui-2.5) 17 18 Once the API is on DMC, that becomes the official copy, and this spec becomes an archive. 19 For example if the description is updated, that only needs to happen on DMC and needn't 20 be duplicated here. 21 22 Examples: 23 * New class (RadialGradientBrush): 24 https://github.com/microsoft/microsoft-ui-xaml-specs/blob/master/active/RadialGradientBrush/RadialGradientBrush.md 25 * New member on an existing class (UIElement.ProtectedCursor): 26 https://github.com/microsoft/microsoft-ui-xaml-specs/blob/master/active/UIElement/ElementCursor.md 27 28 Style guide: 29 * Use second person; speak to the developer who will be learning/using this API. 30 (For example "you use this to..." rather than "the developer uses this to...") 31 * Use hard returns to keep the page width within ~100 columns. 32 (Otherwise it's more difficult to leave comments in a GitHub PR.) 33 * Talk about an API's behavior, not its implementation. 34 (Speak to the developer using this API, not to the team implementing it.) 35 * A picture is worth a thousand words. 36 * An example is worth a million words. 37 * Keep examples realistic but simple; don't add unrelated complications. 38 (An example that passes a stream needn't show the process of launching the File-Open dialog.) 39 40 --> 41 42 Microsoft.Management.Configuration API 43 === 44 45 # Background 46 This API is being added to enable the Developer+ configuration scenarios. It enables interacting with 47 configuration sets in three contexts: 48 49 1. Loading an existing configuration set from a stream 50 2. Loading previously applied configuration sets from the local history 51 3. Authoring a new/editing an existing configuration 52 53 These configuration sets are composed of configuration units, which describe the individual configurable 54 items and the values to configure. 55 56 Configuration actions consist of: 57 58 1. Test :: Determining whether the system state matches the described state 59 2. Get :: Extracting the current system state with respect to the configuration scope 60 3. Set :: Applying the described state to the system 61 62 This API is also intended to support multiple processes watching for state changes, both for the 63 configuration set lifetimes and the individual configuration unit states. 64 65 # Conceptual pages (How To) 66 67 _(Add conceptual documentation that will go to docs.microsoft.com "how to" page if needed)_ 68 69 # API Pages 70 71 <!-- TEMPLATE 72 73 Each of the L2 sections in this "API Pages" section corresponds to a page on DMC. 74 75 It's not necessary to have a section for every class member though: 76 * If its purpose and usage is obvious from it's name/type, it's not necessary to 77 create a section for it. 78 * If its purpose and usage is fully explained by brief description, either 79 put it in a table in the "Other [class] members" section 80 put it with /// comments in the IDL section 81 82 Create an L2 section here for each API that needs more description or examples. 83 For a new class with members, the members should go in their own L2 section. 84 85 Example layout 86 ## MyClass 87 ## MyClass.Member1 88 ## MyClass.Member2 89 ## Other MyClass members 90 ## MyOtherClass 91 ## ... 92 93 Notes: 94 * The first line of each of these sections should become that first line on the DMC page, 95 which then becomes the description you see in Intellisense. 96 * Each page can have description, examples, and remarks. 97 Remarks are where the documentation calls out special considerations that the developer 98 should be aware of. 99 * It can be helpful at the top of an API page (or after the Intellisense text) to add the 100 API signature in C# 101 * Add a "_Spec note: ..._" to add a note that's useful in this spec but shouldn't go to DMC. 102 * Show _examples_, not _samples_; an example is a snippet, a sample is a full working app. 103 104 --> 105 106 ## ConfigurationSetState enumeration 107 108 The state of a configuration set in the configuration history. 109 110 | Name | Description | 111 |-|-| 112 | Unknown | Primarily used for a configuration set that has not been applied. | 113 | Pending | The configuration set has been recorded into the history, but has not yet begun applying. | 114 | InProgress | The configuration set has begun being applied to the system. | 115 | Completed | The configuration set has completed being applied. | 116 117 ## ConfigurationUnitState enumeration 118 119 The state of a configuration unit in the configuration history. 120 121 | Name | Description | 122 |-|-| 123 | Unknown | Primarily used for a configuration unit that has not been applied. | 124 | Pending | The configuration unit has been recorded into the history, but has not yet begun applying. | 125 | InProgress | The configuration unit has begun being applied to the system. | 126 | Completed | The configuration unit has completed being applied; the result information will contain additional details. | 127 | Skipped | The configuration unit was skipped; the result information will contain additional details on the reason. | 128 129 ## ConfigurationUnitDetailLevel enumeration 130 131 Defines the level of detail probing that is allowed about a configuration unit. 132 133 | Name | Description | 134 |-|-| 135 | Local | Only reads details from local data. | 136 | Catalog | Will query the catalog information for details, but will not download any modules. | 137 | Download | Will download modules, but not load them. | 138 | Load | Will download and load modules for details. | 139 140 ## ConfigurationUnitResultInformation class 141 142 Information on a result for a single unit of configuration. 143 144 The class is used both in reporting results through the `ConfigurationSet.ConfigurationSetChange` event as they occur 145 and in viewing past results via the `ConfigurationUnit.ResultInformation` property on a historical record. 146 147 ## IConfigurationUnitSettingDetails interface 148 149 Provides information for a specific configuration unit setting. 150 151 The properties on this interface are useful for creating a rich authoring experience. 152 153 ## IConfigurationUnitSettingDetails.Semantics schema 154 155 > _TODO: Define the meaning/schema for this value_ 156 157 ## IConfigurationUnitProcessorDetails interface 158 159 Provides information for a specific configuration unit within the runtime. 160 161 The properties on this interface are useful for informing the user about the provenance of the code that is 162 responsible for processing the configuration unit. 163 164 ## ConfigurationUnit class 165 166 A single unit of configuration. 167 168 Represents the smallest actionable configuration element. 169 170 ## ConfigurationUnit constructor 171 172 Creates an empty configuration unit for authoring purposes. 173 174 ```C# 175 ConfigurationUnit(); 176 ``` 177 178 ## ConfigurationUnit properties 179 180 | Name | Description | 181 |-|-| 182 | UnitName | The name of the unit being configured; not a name for this instance. | 183 | InstanceIdentifier | An identifier used to uniquely identify the instance of a configuration unit on the system. | 184 | Identifier | The identifier name of this instance within the set. This value is referenced by other unit's `Dependencies`. | 185 | Dependencies | The identifiers of the configuration units that this unit depends on. | 186 | Directives | Contains the values that are for use by the configuration system, related to this unit. | 187 | Settings | Contains the values that are for use by the configuration unit itself. | 188 | Details | Contains information on the origin of the configuration unit. You must call `ConfigurationProcessor.Get*DetailsAsync` to populate this value. | 189 | State | The current state of the configuration unit. | 190 | ResultInformation | Contains information on the result of the latest attempt to apply the configuration unit. | 191 | ShouldApply | Allows for control over whether this unit should be applied when the set containing it is applied. | 192 193 ## ConfigurationUnit.Directives known values 194 195 > _TODO: List of well known directives_ 196 197 ## ConfigurationSetChangeEventType enumeration 198 199 The change event type that has occurred for a configuration set change. 200 201 | Name | Description | 202 |-|-| 203 | Unknown | For future use if the caller is not aware of newer change types. | 204 | SetStateChanged | The state of the configuration set has changed. | 205 | UnitStateChanged | The state of a configuration unit has changed. | 206 207 ## ConfigurationSetChangeData class 208 209 The change data sent about changes to a specific set. 210 211 This class is sent to subscribers of the `ConfigurationSet.ConfigurationSetChange` event, containing information 212 about the specific change that occurred. 213 214 ## ConfigurationSet class 215 216 A configuration set contains a collection of configuration units and details about the set. 217 218 Represents a self contained group of configuration units that are operated on together. 219 220 ## ConfigurationSet constructors 221 222 Creates an empty configuration set for authoring purposes. 223 224 ```C# 225 ConfigurationSet(); 226 ``` 227 228 Loads a configuration set from the given stream. 229 230 ```C# 231 ConfigurationSet(Windows.Storage.Streams.IInputStream stream); 232 ``` 233 234 ## ConfigurationSet.ConfigurationSetChange event 235 236 State changes for this set and it's units are sent to subscribers of this event. 237 238 ```C# 239 event Windows.Foundation.TypedEventHandler<ConfigurationSet, ConfigurationSetChangeData> ConfigurationSetChange; 240 ``` 241 242 ## ConfigurationSet.Serialize method 243 244 Serializes the configuration set to the given output stream. 245 246 ```C# 247 void Serialize(Windows.Storage.Streams.IOutputStream stream); 248 ``` 249 250 ## ConfigurationSet.Remove method 251 252 Removes the configuration set from the recorded history, if present. 253 254 ```C# 255 void Remove(); 256 ``` 257 258 You can use this method to remove a configuration set that is no longer relevant. For example, it may have been for 259 a repository that is no longer being used by the user and future conflicts with it's configuration are not important. 260 261 ## ConfigurationSet properties 262 263 | Name | Description | 264 |-|-| 265 | Name | The name of the set; if from a file this could be the file name. | 266 | Origin | The origin of the set; if it came from a repository it could be the remote URL (ex. https://github.com/microsoft/winget-cli.git). | 267 | InstanceIdentifier | An identifier used to uniquely identify the instance of a configuration set on the system. | 268 | State | The state that the set is in. | 269 | InitialIntent | The time that this set was recorded with intent to apply. | 270 | ApplyBegun | The time that this set was last started to be applied. | 271 | ApplyEnded | The time that this set was last finished being applied (does not indicate success). | 272 | ConfigurationUnits | The configuration units that are part of this set. | 273 274 ## IConfigurationUnitProcessor interface 275 276 Provides access to a specific configuration unit within the runtime. 277 278 This interface is the primary mechanism used to actually read and write configuration to the system, 279 but it is not expected that you would use this directly as a consumer of Microsoft.Management.Configuration. 280 281 ## IConfigurationSetProcessor interface 282 283 Contains the lifetime of the processing action for a configuration set. 284 285 This interface is used to contain the lifetime of a processing action, 286 but it is not expected that you would use this directly as a consumer of Microsoft.Management.Configuration. 287 288 ## IConfigurationProcessorFactory interface 289 290 Allows different runtimes to provide specialized handling of configuration processing. 291 292 It is not expected that you would use this interface directly, but rather the `ConfigurationProcessor` class. 293 294 _Spec note: A separate binary (written by us) will contain the implementation(s) of this interface._ 295 296 ## DiagnosticLevel enumeration 297 298 Indicates the importance of diagnostic information. 299 300 | Name | Description | 301 |-|-| 302 | Verbose | Most useful for debugging scenarios; likely too much for general use. | 303 | Informational | Details that can be useful for understanding what is happening. | 304 | Warning | Indicates some abnormal condition, but that is not expected to impact functionality. | 305 | Error | An error has occurred, but this does not necessarily mean that it will halt the operation. | 306 | Critical | A serious, fatal condition has been encountered. | 307 308 ## DiagnosticInformation class 309 310 Contains diagnostic information from the configuration system that can be passed along to the user or log files. 311 This is not intended as primary information, and is thus not localized. 312 313 ## ConfigurationConflictType enumeration 314 315 The type of conflict between configuration sets that was detected. 316 317 | Name | Description | 318 |-|-| 319 | Unknown | For future use if the caller is not aware of newer conflict types. | 320 | MatchingOrigin | Indicates that the first configuration set has a matching name and origin to the second, which has already been applied. | 321 | IdenticalSetApplied | Indicates that the first configuration set is identical to the second, which has already been applied. | 322 | SettingsConflict | Indicates a conflict between the settings of two configuration units. | 323 324 ## ConfigurationConflictSetting class 325 326 Describes a conflict between a setting of two configuration units. 327 328 ## ConfigurationConflict class 329 330 Describes a conflict between two configuration sets. 331 332 ## ApplyConfigurationSetFlags enumeration 333 334 Flags to control how a configuration set should be applied to the system. 335 336 | Name | Description | 337 |-|-| 338 | None | The configuration set should be applied in the default manner. | 339 | DoNotOverwriteMatchingOriginSet | Forces a new configuration set instance to be recorded when the set being applied matches a previous set's origin. The default behavior is to assume that the incoming set is an update to the existing set and overwrite it. | 340 341 ## ConfigurationChangeEventType enumeration 342 343 The configuration set change event type that has occurred. 344 345 | Name | Description | 346 |-|-| 347 | Unknown | For future use if the caller is not aware of newer change types. | 348 | SetAdded | A new configuration set was recorded in the history with the intent to be applied. | 349 | SetStateChanged | A configuration set has changed state. | 350 | SetRemoved | A configuration set has been removed from the history. | 351 352 ## ConfigurationChangeEventType class 353 354 The change data sent about changes to sets. 355 356 ## ConfigurationProcessor class 357 358 The configuration processor is responsible for the interactions with the system. 359 360 You must use this class to do anything beyond reading configuration sets. It is the entrypoint for all actions that 361 will interact with the actual system configuration. 362 363 ## ConfigurationProcessor constructor 364 365 Creates a configuration processor using the given configuration factory. 366 367 ```C# 368 ConfigurationProcessor(IConfigurationProcessorFactory factory); 369 ``` 370 371 > _TODO: Add details on the mechanics of creating the `IConfigurationProcessorFactory` objects that we provide._ 372 373 ## ConfigurationProcessor.CheckForConflicts(Async) method 374 375 Checks for conflicts amongst the configuration sets provided, optionally including the configuration sets already applied to the system. 376 377 ```C# 378 Windows.Foundation.Collections.IVectorView<ConfigurationConflict> CheckForConflicts(Windows.Foundation.Collections.IVectorView<ConfigurationSet> configurationSets, Boolean includeConfigurationHistory); 379 380 Windows.Foundation.IAsyncOperation< Windows.Foundation.Collections.IVectorView<ConfigurationConflict> > CheckForConflictsAsync(Windows.Foundation.Collections.IVectorView<ConfigurationSet> configurationSets, Boolean includeConfigurationHistory); 381 ``` 382 383 This method should be used on any configuration set that is opened in order to determine if it would cause a conflict 384 with previously applied configurations. It should be called *after* setting the `Name` and `Origin` in order to determine 385 if it is a potential update. 386 387 ## ConfigurationProcessor.GetSetDetails(Async) method 388 389 Gets the details for all configuration units in a set. 390 391 ```C# 392 void GetSetDetails(ConfigurationSet configurationSet, ConfigurationUnitDetailLevel detailLevel); 393 394 Windows.Foundation.IAsyncAction GetSetDetailsAsync(ConfigurationSet configurationSet, ConfigurationUnitDetailLevel detailLevel); 395 ``` 396 397 This is a convenience/optimization method that will do the same thing as calling `GetUnitDetails(Async)` on each 398 configuration unit in the set. See `GetUnitDetails(Async)` for more information on what it will do. 399 400 ## ConfigurationProcessor.GetUnitDetails(Async) method 401 402 Gets the details for all configuration units in a set. 403 404 ```C# 405 void GetUnitDetails(ConfigurationUnit unit, ConfigurationUnitDetailLevel detailLevel); 406 407 Windows.Foundation.IAsyncAction GetUnitDetailsAsync(ConfigurationUnit unit, ConfigurationUnitDetailLevel detailLevel); 408 ``` 409 410 This method will get the details about a specific configuration unit and make them available via `ConfigurationUnit.Details`. 411 The `detailLevel` parameter allows control over how deeply to probe for details. It is an analog for the amount of 412 trust to place in the configuration unit processor. 413 414 ## ConfigurationProcessor.ApplySet(Async) method 415 416 Applies the configuration set state to the system. 417 418 ```C# 419 ApplyConfigurationSetResult ApplySet(ConfigurationSet configurationSet, ApplyConfigurationSetFlags flags); 420 421 Windows.Foundation.IAsyncOperationWithProgress<ApplyConfigurationSetResult, ConfigurationSetChangeData> ApplySetAsync(ConfigurationSet configurationSet, ApplyConfigurationSetFlags flags); 422 ``` 423 424 Using the async method and it's progress is more efficient than subscribing to the `ConfigurationSetChange` event before calling this method. 425 426 ## ConfigurationProcessor.TestSet(Async) method 427 428 Tests if the system state matches the state described by the configuration set. 429 430 ```C# 431 TestConfigurationSetResult TestSet(ConfigurationSet configurationSet); 432 433 Windows.Foundation.IAsyncOperationWithProgress<TestConfigurationSetResult, TestConfigurationUnitResult> TestSetAsync(ConfigurationSet configurationSet); 434 ``` 435 436 ## ConfigurationProcessor.GetSettings(Async) method 437 438 Gets the current configuration unit settings from the system state. 439 440 ```C# 441 GetConfigurationUnitSettingsResult GetSettings(ConfigurationUnit unit); 442 443 Windows.Foundation.IAsyncOperation<GetConfigurationUnitSettingsResult> GetSettingsAsync(ConfigurationUnit unit); 444 ``` 445 446 ## ConfigurationProcessor.Diagnostics event 447 448 Enables listening to internal diagnostics events for logging purposes. 449 450 ## ConfigurationProcessor.ConfigurationChange event 451 452 Signals changes to the set of configuration sets in the history, as well as changes to the state of configuration sets in the history. 453 454 ## ConfigurationProcessor.GetConfigurationHistory method 455 456 Gets the configuration sets from the recorded history. 457 458 ```C# 459 Windows.Foundation.Collections.IVectorView<ConfigurationSet> GetConfigurationHistory(); 460 ``` 461 462 Gets the configuration sets that have already been applied or those recorded with the intent to be applied. This may include in progress sets or those that are waiting to be applied. 463 464 # API Details 465 466 [Link to the MIDL3 file.](../../src/Microsoft.Management.Configuration/Microsoft.Management.Configuration.idl) 467 468 # Appendix 469 470 <!-- TEMPLATE 471 Anything else that you want to write down about implementation notes and for posterity, 472 but that isn't necessary to understand the purpose and usage of the API. 473 474 This or the Background section are a good place to describe alternative designs 475 and why they were rejected. 476 --> 477 478 # Sample 479 480 This sample illustrates some of the expected usage patterns. 481 482 ```C# 483 using Microsoft.Management.Configuration; 484 using System; 485 using System.Collections.Generic; 486 using System.IO; 487 using System.Reflection; 488 using Windows.Foundation; 489 using Windows.Foundation.Collections; 490 using Windows.Storage; 491 using Windows.Storage.Streams; 492 493 namespace ConfigurationSample 494 { 495 internal static class Helpers 496 { 497 internal static IConfigurationProcessorFactory CreateIConfigurationProcessorFactory() 498 { 499 throw new NotImplementedException(); 500 } 501 502 internal static ConfigurationSet OpenConfigurationSet(string filePath, ConfigurationProcessor processor) 503 { 504 var fileOperation = FileRandomAccessStream.OpenAsync(filePath, FileAccessMode.Read); 505 fileOperation.AsTask().Wait(); 506 var file = fileOperation.GetResults(); 507 OpenConfigurationSetResult result = processor.OpenConfigurationSet(file); 508 509 if (result.Set != null) 510 { 511 return result.Set; 512 } 513 514 Console.WriteLine($"Failed opening configuration set: 0x{result.ResultCode:X} at {result.Field}"); 515 return null; 516 } 517 518 internal static void SetWatcher(ConfigurationSet set, ConfigurationSetChangeData data) 519 { 520 Console.WriteLine($" - Set: {set.Name} [{set.InstanceIdentifier}]"); 521 Console.WriteLine($" Change: {data.Change}"); 522 Console.WriteLine($" Set State: {data.SetState}"); 523 switch (data.Change) 524 { 525 case ConfigurationSetChangeEventType.UnitStateChanged: 526 Console.WriteLine($" Unit: {data.Unit.UnitName} [{data.Unit.InstanceIdentifier}]"); 527 Console.WriteLine($" Unit State: {data.UnitState}"); 528 if (data.UnitState == ConfigurationUnitState.Completed && data.ResultInformation.ResultCode != null) 529 { 530 Console.WriteLine($" Failure: {data.ResultInformation.Description} [{data.ResultInformation.ResultCode.HResult}]"); 531 } 532 break; 533 } 534 } 535 } 536 537 internal class ApplyProgressWatcher 538 { 539 private bool isFirstProgress = true; 540 541 internal void Watcher(IAsyncOperationWithProgress<ApplyConfigurationSetResult, ConfigurationSetChangeData> operation, ConfigurationSetChangeData data) 542 { 543 if (isFirstProgress) 544 { 545 isFirstProgress = false; 546 547 // If our first progress callback contains partial results, output them as if they had been called through progress 548 ApplyConfigurationSetResult partialResult = operation.GetResults(); 549 550 foreach (ApplyConfigurationUnitResult unitResult in partialResult.UnitResults) 551 { 552 HandleUnitProgress(unitResult.Unit, unitResult.State, unitResult.ResultInformation); 553 } 554 } 555 556 switch (data.Change) 557 { 558 case ConfigurationSetChangeEventType.SetStateChanged: 559 Console.WriteLine($" - Set State: {data.SetState}"); 560 break; 561 case ConfigurationSetChangeEventType.UnitStateChanged: 562 HandleUnitProgress(data.Unit, data.UnitState, data.ResultInformation); 563 break; 564 } 565 } 566 567 private void HandleUnitProgress(ConfigurationUnit unit, ConfigurationUnitState state, ConfigurationUnitResultInformation resultInformation) 568 { 569 switch (state) 570 { 571 case ConfigurationUnitState.Pending: 572 break; 573 case ConfigurationUnitState.InProgress: 574 case ConfigurationUnitState.Completed: 575 case ConfigurationUnitState.Skipped: 576 Console.WriteLine($" - Unit: {unit.UnitName} [{unit.InstanceIdentifier}]"); 577 Console.WriteLine($" Unit State: {state}"); 578 if (resultInformation.ResultCode != null) 579 { 580 Console.WriteLine($" HRESULT: [0x{resultInformation.ResultCode.HResult:X8}]"); 581 Console.WriteLine($" Reason: {resultInformation.Description}"); 582 } 583 break; 584 case ConfigurationUnitState.Unknown: 585 break; 586 } 587 } 588 } 589 590 internal class Program 591 { 592 static void LoadAndOutput(string[] args) 593 { 594 ConfigurationProcessor processor = new ConfigurationProcessor(Helpers.CreateIConfigurationProcessorFactory()); 595 596 // Open the given configuration file 597 ConfigurationSet configSet = Helpers.OpenConfigurationSet(args[1], processor); 598 if (configSet == null) 599 { 600 return; 601 } 602 603 // Output some of the information from the set 604 Console.WriteLine($"Configuration Set: {args[1]}"); 605 606 foreach (ConfigurationUnit unit in configSet.ConfigurationUnits) 607 { 608 Console.WriteLine($" - Configuration Unit: {unit.UnitName}"); 609 if (!string.IsNullOrEmpty(unit.Identifier)) 610 { 611 Console.WriteLine($" Identifier: {unit.Identifier}"); 612 } 613 Console.WriteLine($" Intent: {unit.Intent}"); 614 IReadOnlyList<string> dependencies = unit.Dependencies; 615 if (dependencies.Count > 0) 616 { 617 Console.WriteLine(" Dependencies:"); 618 foreach (string dependency in dependencies) 619 { 620 Console.WriteLine($" {dependency}"); 621 } 622 } 623 ValueSet directives = unit.Directives; 624 if (directives.Count > 0) 625 { 626 Console.WriteLine(" Directives:"); 627 foreach (var directive in unit.Directives) 628 { 629 Console.WriteLine($" {directive.Key}: {directive.Value}"); 630 } 631 } 632 ValueSet settings = unit.Settings; 633 if (settings.Count > 0) 634 { 635 Console.WriteLine(" Settings:"); 636 foreach (var setting in unit.Settings) 637 { 638 Console.WriteLine($" {setting.Key}: {setting.Value}"); 639 } 640 } 641 } 642 } 643 644 static void LoadAndCheckConflicts(string[] args) 645 { 646 // Create the factory and processor 647 ConfigurationProcessor processor = new ConfigurationProcessor(Helpers.CreateIConfigurationProcessorFactory()); 648 649 // Open the given configuration file 650 ConfigurationSet configSet = Helpers.OpenConfigurationSet(args[1], processor); 651 if (configSet == null) 652 { 653 return; 654 } 655 656 // Set a name and origin for this set so that we can see it in the conflict info 657 configSet.Name = Path.GetFileName(args[1]); 658 configSet.Origin = args[1]; 659 660 // Check for conflicts with existing configurations 661 List<ConfigurationSet> configSets = new List<ConfigurationSet>() { configSet }; 662 IList<ConfigurationConflict> conflicts = processor.CheckForConflicts(configSets, true); 663 664 Console.WriteLine($"Conflicts with Configuration Set: {args[1]}"); 665 666 foreach (ConfigurationConflict conflict in conflicts) 667 { 668 Console.WriteLine($" - Conflict: {conflict.Conflict}"); 669 Console.WriteLine($" First Set: {conflict.FirstSet.Name} [{conflict.FirstSet.Origin}]"); 670 Console.WriteLine($" Second Set: {conflict.SecondSet.Name} [{conflict.SecondSet.Origin}]"); 671 if (conflict.Conflict == ConfigurationConflictType.SettingsConflict) 672 { 673 Console.WriteLine($" First Unit: {conflict.FirstUnit.UnitName} [{conflict.FirstUnit.InstanceIdentifier}]"); 674 Console.WriteLine($" Second Unit: {conflict.SecondUnit.UnitName} [{conflict.SecondUnit.InstanceIdentifier}]"); 675 foreach (ConfigurationConflictSetting setting in conflict.Settings) 676 { 677 Console.WriteLine($" - Setting: {setting.Name}"); 678 Console.WriteLine($" First Value: {setting.FirstValue}"); 679 Console.WriteLine($" Second Value: {setting.SecondValue}"); 680 } 681 } 682 } 683 } 684 685 static void LoadAndApply(string[] args) 686 { 687 // Create the factory and processor 688 ConfigurationProcessor processor = new ConfigurationProcessor(Helpers.CreateIConfigurationProcessorFactory()); 689 690 // Open the given configuration file 691 ConfigurationSet configSet = Helpers.OpenConfigurationSet(args[1], processor); 692 if (configSet == null) 693 { 694 return; 695 } 696 697 Console.WriteLine($"Applying Configuration Set: {args[1]}"); 698 699 ApplyProgressWatcher watcher = new ApplyProgressWatcher(); 700 701 var operation = processor.ApplySetAsync(configSet, ApplyConfigurationSetFlags.None); 702 operation.Progress = watcher.Watcher; 703 operation.AsTask().Wait(); 704 ApplyConfigurationSetResult result = operation.GetResults(); 705 706 Console.WriteLine($" - Done: {result.ResultCode.HResult}"); 707 } 708 709 static void GetHistoryAndWatchEverything(string[] args) 710 { 711 Console.WriteLine("Watching all configuration [press Enter to stop]:"); 712 713 // Create the factory and processor 714 ConfigurationProcessor processor = new ConfigurationProcessor(Helpers.CreateIConfigurationProcessorFactory()); 715 716 List<ConfigurationSet> list = new List<ConfigurationSet>(); 717 718 // Attach to the top level change event 719 processor.ConfigurationChange += (ConfigurationSet incomingSet, ConfigurationChangeData data) => 720 { 721 int existingSetIndex = -1; 722 723 lock (list) 724 { 725 for (int i = 0; i < list.Count; ++i) 726 { 727 if (list[i].InstanceIdentifier == data.InstanceIdentifier) 728 { 729 existingSetIndex = i; 730 break; 731 } 732 } 733 734 if (data.Change == ConfigurationChangeEventType.SetAdded || data.Change == ConfigurationChangeEventType.SetStateChanged) 735 { 736 if (existingSetIndex == -1) 737 { 738 incomingSet.ConfigurationSetChange += Helpers.SetWatcher; 739 list.Add(incomingSet); 740 } 741 } 742 else // Removed 743 { 744 if (existingSetIndex != -1) 745 { 746 list[existingSetIndex].ConfigurationSetChange -= Helpers.SetWatcher; 747 list.RemoveAt(existingSetIndex); 748 } 749 } 750 } 751 752 Console.WriteLine($" - Set: {data.InstanceIdentifier}"); 753 Console.WriteLine($" Change: {data.Change}"); 754 }; 755 756 foreach (ConfigurationSet set in processor.GetConfigurationHistory()) 757 { 758 int existingSetIndex = -1; 759 760 lock (list) 761 { 762 for (int i = 0; i < list.Count; ++i) 763 { 764 if (list[i].InstanceIdentifier == set.InstanceIdentifier) 765 { 766 existingSetIndex = i; 767 break; 768 } 769 } 770 771 if (existingSetIndex == -1) 772 { 773 set.ConfigurationSetChange += Helpers.SetWatcher; 774 list.Add(set); 775 } 776 } 777 778 if (existingSetIndex == -1) 779 { 780 Console.WriteLine($" - Set: {set.Name} [{set.InstanceIdentifier}]"); 781 Console.WriteLine($" State: {set.State}"); 782 } 783 } 784 785 // Wait for user to press enter 786 Console.ReadLine(); 787 } 788 789 static void Main(string[] args) 790 { 791 var method = typeof(Program).GetMethod(args[0], BindingFlags.NonPublic | BindingFlags.Static); 792 793 if (method != null) 794 { 795 method.Invoke(null, new object[]{ args }); 796 } 797 else 798 { 799 Console.WriteLine($"{args[0]} is not a sample"); 800 } 801 } 802 } 803 } 804 805 ```