diff --git a/THIRDPARTYNOTICES.md b/THIRDPARTYNOTICES.md new file mode 100644 index 0000000..646bc50 --- /dev/null +++ b/THIRDPARTYNOTICES.md @@ -0,0 +1,39 @@ +## Third-party notices +This software contains portions or derivative works of the following products + +### CredProvider.NET +https://github.com/SteveSyfuhs/CredProvider.NET + +MIT License + +Copyright (c) 2017 Steve Syfuhs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +### CredNet library +https://github.com/Sajidur78/CredNet +MIT License + +Copyright 2020 Sajid + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 0000000..73c10e1 --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,226 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = true +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = true:suggestion +dotnet_style_qualification_for_field = true +dotnet_style_qualification_for_method = true:suggestion +dotnet_style_qualification_for_property = true:suggestion + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members + +# Expression-level preferences +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true +dotnet_style_explicit_tuple_names = true +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true +dotnet_style_object_initializer = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true +dotnet_style_prefer_compound_assignment = true +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_style_prefer_conditional_expression_over_return = true +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true + +# Parameter preferences +dotnet_code_quality_unused_parameters = all + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = 0 + +# New line preferences +dotnet_style_allow_multiple_blank_lines_experimental = true +dotnet_style_allow_statement_immediately_after_block_experimental = true + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = false + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true +csharp_style_expression_bodied_constructors = false +csharp_style_expression_bodied_indexers = true +csharp_style_expression_bodied_lambdas = true +csharp_style_expression_bodied_local_functions = false +csharp_style_expression_bodied_methods = false +csharp_style_expression_bodied_operators = false +csharp_style_expression_bodied_properties = true + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_extended_property_pattern = true +csharp_style_prefer_not_pattern = true +csharp_style_prefer_pattern_matching = true +csharp_style_prefer_switch_expression = true + +# Null-checking preferences +csharp_style_conditional_delegate_call = true + +# Modifier preferences +csharp_prefer_static_local_function = true +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async +csharp_style_prefer_readonly_struct = true + +# Code-block preferences +csharp_prefer_braces = true +csharp_prefer_simple_using_statement = true +csharp_style_namespace_declarations = block_scoped +csharp_style_prefer_method_group_conversion = true +csharp_style_prefer_top_level_statements = false + +# Expression-level preferences +csharp_prefer_simple_default_expression = true +csharp_style_deconstructed_variable_declaration = true +csharp_style_implicit_object_creation_when_type_is_apparent = true +csharp_style_inlined_variable_declaration = true +csharp_style_prefer_index_operator = true +csharp_style_prefer_local_over_anonymous_function = true +csharp_style_prefer_null_check_over_type_check = true +csharp_style_prefer_range_operator = true +csharp_style_prefer_tuple_swap = true +csharp_style_prefer_utf8_string_literals = true +csharp_style_throw_expression = true +csharp_style_unused_value_assignment_preference = discard_variable +csharp_style_unused_value_expression_statement_preference = discard_variable + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true +csharp_style_allow_embedded_statements_on_same_line_experimental = true + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case diff --git a/src/Lithnet.CredentialProvider.Samples/CredUI.cs b/src/Lithnet.CredentialProvider.Samples/CredUI.cs new file mode 100644 index 0000000..60024b5 --- /dev/null +++ b/src/Lithnet.CredentialProvider.Samples/CredUI.cs @@ -0,0 +1,60 @@ +using System; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Samples +{ + public static class CredUI + { + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public struct CREDUI_INFO + { + public int cbSize; + public IntPtr hwndParent; + public string pszMessageText; + public string pszCaptionText; + public IntPtr hbmBanner; + } + + [DllImport("credui.dll", CharSet = CharSet.Auto)] + public static extern int CredUIPromptForWindowsCredentials( + ref CREDUI_INFO uiInfo, + int authError, + ref uint authPackage, + IntPtr InAuthBuffer, + uint InAuthBufferSize, + out IntPtr refOutAuthBuffer, + out uint refOutAuthBufferSize, + ref bool fSave, + uint flags + ); + + public static void Prompt(string caption, string message) + { + var uiInfo = new CREDUI_INFO() + { + pszCaptionText = caption, + pszMessageText = message + }; + + uiInfo.cbSize = Marshal.SizeOf(uiInfo); + + uint authPackage = 0; + + var save = false; + + CredUIPromptForWindowsCredentials( + ref uiInfo, + 0, + ref authPackage, + IntPtr.Zero, + 0, + out IntPtr outCredBuffer, + out uint outCredSize, + ref save, + 0 + ); + + Marshal.FreeCoTaskMem(outCredBuffer); + } + } +} diff --git a/src/Lithnet.CredentialProvider.Samples/Installing the sample.md b/src/Lithnet.CredentialProvider.Samples/Installing the sample.md new file mode 100644 index 0000000..0afea96 --- /dev/null +++ b/src/Lithnet.CredentialProvider.Samples/Installing the sample.md @@ -0,0 +1,36 @@ +# Using the sample credential provider + +## Installing the sample + +In order to install and run the sample app, you have to register the COM component + +Build the EXE, and from an elevated command prompt, change to the bin folder, and run the following commands + +``` +%windir%\Microsoft.NET\Framework64\v4.0.30319\regasm /codebase "Lithnet.CredentialProvider.Samples.exe" + +REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{1A3993B6-EB2B-44BB-A788-7AB1711DFF16}" /f +REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{1A3993B6-EB2B-44BB-A788-7AB1711DFF16}" /ve /t REG_SZ /f /d "Lithnet.CredentialProvider.Samples.TestCredentialProvider" +``` + +## Disable the sample + +To disable the credential provider, run the following command. + +``` +REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{1A3993B6-EB2B-44BB-A788-7AB1711DFF16}" /v "Disabled" /t REG_DWORD /f /d 1 +``` + +## Re-enable the sample +To enable the provider again after disabling it, run the following command. +``` +REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{1A3993B6-EB2B-44BB-A788-7AB1711DFF16}" /v "Disabled" /t REG_DWORD /f /d 0 +``` + +## Uninstalling the sample +To remove the credential provider, run the following command. + +``` +%windir%\Microsoft.NET\Framework64\v4.0.30319\regasm /u "Lithnet.CredentialProvider.Samples.exe" +REG DELETE "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{1A3993B6-EB2B-44BB-A788-7AB1711DFF16}" /f +``` \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider.Samples/Lithnet.CredentialProvider.Samples.csproj b/src/Lithnet.CredentialProvider.Samples/Lithnet.CredentialProvider.Samples.csproj new file mode 100644 index 0000000..879c78c --- /dev/null +++ b/src/Lithnet.CredentialProvider.Samples/Lithnet.CredentialProvider.Samples.csproj @@ -0,0 +1,35 @@ + + + + Exe + net472 + false + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + diff --git a/src/Lithnet.CredentialProvider.Samples/Program.cs b/src/Lithnet.CredentialProvider.Samples/Program.cs new file mode 100644 index 0000000..3bbdb12 --- /dev/null +++ b/src/Lithnet.CredentialProvider.Samples/Program.cs @@ -0,0 +1,44 @@ +using System; +using Microsoft.Extensions.Logging; +using NLog; +using NLog.Extensions.Logging; + +namespace Lithnet.CredentialProvider.Samples +{ + internal static class Program + { + internal static ILoggerFactory LoggerFactory { get; } + + static Program() + { + /* + This sample uses NLog to capture trace events from the provider, but you can use any + logging system compatible with Microsoft.Extensions.Logging; + */ + + var config = new NLog.Config.LoggingConfiguration(); + var logconsole = new NLog.Targets.ConsoleTarget("logconsole"); + + /* + + Add file based logging if required + + */ + + // var logfile = new NLog.Targets.FileTarget("logfile") { FileName = "c:\\file.txt" }; + //config.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, logfile); + + config.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, logconsole); + + LogManager.Configuration = config; + Program.LoggerFactory = new NLogLoggerFactory(new NLogLoggerProvider(new NLogProviderOptions() { ReplaceLoggerFactory = true }, LogManager.LogFactory)); + } + + static void Main(string[] args) + { + CredUI.Prompt("Login with Cred UI", "Select your favorite credential provider"); + Console.WriteLine("Done! Press any key to exit"); + Console.ReadKey(); + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider.Samples/Resources.Designer.cs b/src/Lithnet.CredentialProvider.Samples/Resources.Designer.cs new file mode 100644 index 0000000..de0a7f4 --- /dev/null +++ b/src/Lithnet.CredentialProvider.Samples/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Lithnet.CredentialProvider.Samples { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Lithnet.CredentialProvider.Samples.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap TileIcon { + get { + object obj = ResourceManager.GetObject("TileIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/src/Lithnet.CredentialProvider.Samples/Resources.resx b/src/Lithnet.CredentialProvider.Samples/Resources.resx new file mode 100644 index 0000000..e6bb7a2 --- /dev/null +++ b/src/Lithnet.CredentialProvider.Samples/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Resources\TileIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider.Samples/Resources/TileIcon.png b/src/Lithnet.CredentialProvider.Samples/Resources/TileIcon.png new file mode 100644 index 0000000..85fb8af Binary files /dev/null and b/src/Lithnet.CredentialProvider.Samples/Resources/TileIcon.png differ diff --git a/src/Lithnet.CredentialProvider.Samples/TestCredentialProvider.cs b/src/Lithnet.CredentialProvider.Samples/TestCredentialProvider.cs new file mode 100644 index 0000000..8c25299 --- /dev/null +++ b/src/Lithnet.CredentialProvider.Samples/TestCredentialProvider.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Microsoft.Extensions.Logging; + +namespace Lithnet.CredentialProvider.Samples +{ + [ComVisible(true)] + [ClassInterface(ClassInterfaceType.None)] + [ProgId("Lithnet.CredentialProvider.Samples.TestCredentialProvider")] + [Guid("1A3993B6-EB2B-44BB-A788-7AB1711DFF16")] + public class TestCredentialProvider : CredentialProviderBase + { + private static readonly ILogger logger = Program.LoggerFactory.CreateLogger(); + + public TestCredentialProvider() + { + } + + public override ILoggerFactory GetLoggerFactory() + { + return Program.LoggerFactory; + } + + public override IEnumerable GetControls(UsageScenario cpus) + { + + var password = new SecurePasswordTextboxControl(TestCredentialProviderControlKeys.Password, "Password"); + + if (cpus == UsageScenario.ChangePassword) + { + var confirmPassword = new SecurePasswordTextboxControl(TestCredentialProviderControlKeys.ConfirmPassword, "Confirm password"); + yield return new TextboxControl(TestCredentialProviderControlKeys.Username, "Username"); + yield return password; + yield return confirmPassword; + yield return new SubmitButtonControl(TestCredentialProviderControlKeys.ButtonSubmit, "Submit", confirmPassword); + } + else + { + yield return new CredentialProviderLabelControl(TestCredentialProviderControlKeys.LabelCredentialProvider, "Login with showcase credential provider"); + yield return new CredentialProviderLogoControl(TestCredentialProviderControlKeys.ImageCredentialProvider, "Credential provider logo", Resources.TileIcon); + yield return new CredentialProviderLogoControl(TestCredentialProviderControlKeys.ImageUserTile, "User tile image", Resources.TileIcon); + + yield return new LargeLabelControl(TestCredentialProviderControlKeys.LabelLargeHeading, "The is our showcase credential provider"); + yield return new SmallLabelControl(TestCredentialProviderControlKeys.LabelSmallHeading, "Let's see what we can do"); + + yield return new CheckboxControl(TestCredentialProviderControlKeys.Checkbox, "A checkbox"); + yield return new SmallLabelControl(TestCredentialProviderControlKeys.LabelCheckboxValue, "The check box is currently unchecked"); + yield return new CommandLinkControl(TestCredentialProviderControlKeys.CommandLinkCheckboxValue, "Click this link to change the check box value in code behind"); + + yield return new ComboboxControl(TestCredentialProviderControlKeys.Combobox, "Items to choose from:"); + yield return new SmallLabelControl(TestCredentialProviderControlKeys.LabelComboboxSelectedItem, "This is the currently selected item: "); + yield return new CommandLinkControl(TestCredentialProviderControlKeys.CommandLinkComboboxAdd, "Add a random item to the combo box"); + yield return new CommandLinkControl(TestCredentialProviderControlKeys.CommandLinkComboboxRemove, "Remove the last item from the combo box"); + + yield return new TextboxControl(TestCredentialProviderControlKeys.Username, "Username"); + yield return new CommandLinkControl(TestCredentialProviderControlKeys.CommandLinkUsername, "Click this link to generate a random username"); + + yield return password; + yield return new SubmitButtonControl(TestCredentialProviderControlKeys.ButtonSubmit, "Submit", password); + } + } + + public override bool IsUsageScenarioSupported(UsageScenario cpus, CredUIWinFlags dwFlags) + { + switch (cpus) + { + case UsageScenario.Logon: + case UsageScenario.UnlockWorkstation: + case UsageScenario.CredUI: + case UsageScenario.ChangePassword: + return true; + + default: + return false; + } + } + + public override bool ShouldIncludeUserTile(CredentialProviderUser user) + { + return true; + } + + public override bool ShouldIncludeGenericTile() + { + return true; + } + + public override CredentialProviderCredential1Tile CreateGenericTile() + { + return new TestCredentialProviderTile(this); + } + + public override CredentialProviderCredential1Tile CreateUserTile(CredentialProviderUser user) + { + return new TestCredentialProviderTile(this, user); + } + } +} diff --git a/src/Lithnet.CredentialProvider.Samples/TestCredentialProviderControlKeys.cs b/src/Lithnet.CredentialProvider.Samples/TestCredentialProviderControlKeys.cs new file mode 100644 index 0000000..aebc473 --- /dev/null +++ b/src/Lithnet.CredentialProvider.Samples/TestCredentialProviderControlKeys.cs @@ -0,0 +1,23 @@ +namespace Lithnet.CredentialProvider.Samples +{ + internal static class TestCredentialProviderControlKeys + { + internal const string LabelCredentialProvider = "LabelCredentialProvider"; + internal const string ImageCredentialProvider = "ImageCredentialProvider"; + internal const string LabelLargeHeading = "LabelHeadingLarge"; + internal const string LabelSmallHeading = "LabelHeadingSmall"; + internal const string Username = "TextUsername"; + internal const string CommandLinkUsername = "CommandLinkUsername"; + internal const string Password = "TextPassword"; + internal const string ConfirmPassword = "TextPasswordConfirm"; + internal const string Checkbox = "Checkbox"; + internal const string LabelCheckboxValue = "LabelCheckbox"; + internal const string CommandLinkCheckboxValue = "CommandLinkCheckbox"; + internal const string ImageUserTile = "UerTileImage"; + internal const string Combobox = "Combobox"; + internal const string LabelComboboxSelectedItem = "ComboSelectedItemLabel"; + internal const string CommandLinkComboboxAdd = "CommandLinkComboboxAdd"; + internal const string CommandLinkComboboxRemove = "CommandLinkComboboxRemove"; + internal const string ButtonSubmit = "SubmitButton"; + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider.Samples/TestCredentialProviderTile.cs b/src/Lithnet.CredentialProvider.Samples/TestCredentialProviderTile.cs new file mode 100644 index 0000000..6449553 --- /dev/null +++ b/src/Lithnet.CredentialProvider.Samples/TestCredentialProviderTile.cs @@ -0,0 +1,192 @@ +using System; +using System.Runtime.InteropServices; +using System.Security; +using Microsoft.Extensions.Logging; + +namespace Lithnet.CredentialProvider.Samples +{ + public class TestCredentialProviderTile : CredentialProviderCredential2Tile + { + private TextboxControl UsernameControl; + private SecurePasswordTextboxControl PasswordControl; + private SecurePasswordTextboxControl PasswordConfirmControl; + private ComboboxControl ComboboxControl; + private CheckboxControl CheckboxControl; + private SmallLabelControl CheckboxStateControl; + private SmallLabelControl ComboboxStateControl; + + private ILogger logger = Program.LoggerFactory.CreateLogger(); + + public TestCredentialProviderTile(CredentialProviderBase credentialProvider) : base(credentialProvider) + { + } + + public TestCredentialProviderTile(CredentialProviderBase credentialProvider, CredentialProviderUser user) : base(credentialProvider, user) + { + } + + public string Username + { + get => UsernameControl.Text; + set => UsernameControl.Text = value; + } + + public SecureString Password + { + get => PasswordControl.Password; + set => PasswordControl.Password = value; + } + + public SecureString ConfirmPassword + { + get => PasswordConfirmControl.Password; + set => PasswordConfirmControl.Password = value; + } + + public string ComboboxSelectedItemLabel + { + get => ComboboxStateControl.Label; + set => ComboboxStateControl.Label = value; + } + + public bool IsChecked + { + get => CheckboxControl.IsChecked; + set => CheckboxControl.IsChecked = value; + } + + public string CheckboxStateLabel + { + get => CheckboxStateControl.Label; + set => CheckboxStateControl.Label = value; + } + + public override void Initialize() + { + if (UsageScenario == UsageScenario.ChangePassword) + { + PasswordConfirmControl = Controls.GetControl(TestCredentialProviderControlKeys.ConfirmPassword); + } + + PasswordControl = Controls.GetControl(TestCredentialProviderControlKeys.Password); + CheckboxControl = Controls.GetControl(TestCredentialProviderControlKeys.Checkbox); + CheckboxStateControl = Controls.GetControl(TestCredentialProviderControlKeys.LabelCheckboxValue); + + Controls.GetControl(TestCredentialProviderControlKeys.CommandLinkCheckboxValue).OnClick = () => + { + CheckboxControl.IsChecked = !CheckboxControl.IsChecked; + }; + + CheckboxControl.PropertyChanged += CheckboxControl_PropertyChanged; + + UsernameControl = Controls.GetControl(TestCredentialProviderControlKeys.Username); + Controls.GetControl(TestCredentialProviderControlKeys.CommandLinkUsername).OnClick = () => + { + Username = Guid.NewGuid().ToString(); + }; + + ComboboxStateControl = Controls.GetControl(TestCredentialProviderControlKeys.LabelComboboxSelectedItem); + + ComboboxControl = Controls.GetControl(TestCredentialProviderControlKeys.Combobox); + ComboboxControl.PropertyChanged += ComboboxControl_PropertyChanged; + ComboboxControl.ComboBoxItems.Add("Item 1"); + ComboboxControl.ComboBoxItems.Add("Item 2"); + ComboboxControl.ComboBoxItems.Add("Item 3"); + ComboboxControl.SelectedItemIndex = 0; + + int count = 3; + Controls.GetControl(TestCredentialProviderControlKeys.CommandLinkComboboxAdd).OnClick = () => + { + ComboboxControl.ComboBoxItems.Add($"Item {++count}"); + }; + + Controls.GetControl(TestCredentialProviderControlKeys.CommandLinkComboboxRemove).OnClick = () => + { + if (ComboboxControl.ComboBoxItems.Count > 0) + { + ComboboxControl.ComboBoxItems.Remove(ComboboxControl.ComboBoxItems[ComboboxControl.ComboBoxItems.Count - 1]); + } + }; + + Username = User?.QualifiedUserName; + } + + private void ComboboxControl_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(ComboboxControl.SelectedItemIndex)) + { + ComboboxSelectedItemLabel = $"Selected item: {(ComboboxControl.SelectedItem ?? "(none)")}"; + } + } + + private void CheckboxControl_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + CheckboxStateControl.Label = $"The check box is {(CheckboxControl.IsChecked ? "checked" : "not checked")}"; + } + + protected override CredentialResponseBase GetCredentials() + { + string username; + string domain; + + if (Username.Contains("\\")) + { + domain = Username.Split('\\')[0]; + username = Username.Split('\\')[1]; + } + else + { + username = Username; + domain = Environment.MachineName; + } + + var spassword = Controls.GetControl(TestCredentialProviderControlKeys.Password).Password; + + if (!IsChecked) + { + logger.LogTrace("Performing secure login"); + + return new CredentialResponseSecure() + { + IsSuccess = true, + Password = spassword, + Domain = domain, + Username = username + }; + } + else + { + logger.LogTrace("Performing insecure login"); + string plainTextPassword = GetPlainTextPasswordFromSecureString(spassword); + + return new CredentialResponseInsecure() + { + IsSuccess = true, + Password = plainTextPassword, + Domain = domain, + Username = username + }; + } + } + + private string GetPlainTextPasswordFromSecureString(SecureString s) + { + string plainTextPassword; + IntPtr pPassword = IntPtr.Zero; + try + { + pPassword = Marshal.SecureStringToGlobalAllocUnicode(s); + plainTextPassword = Marshal.PtrToStringUni(pPassword); + } + finally + { + if (pPassword != IntPtr.Zero) + { + Marshal.FreeHGlobal(pPassword); + } + } + + return plainTextPassword; + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider.sln b/src/Lithnet.CredentialProvider.sln new file mode 100644 index 0000000..a7aa86a --- /dev/null +++ b/src/Lithnet.CredentialProvider.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33205.214 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lithnet.CredentialProvider", "Lithnet.CredentialProvider\Lithnet.CredentialProvider.csproj", "{9C07477C-ABB8-4DE5-B69C-3F8719D952C6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lithnet.CredentialProvider.Samples", "Lithnet.CredentialProvider.Samples\Lithnet.CredentialProvider.Samples.csproj", "{967DF0EB-F85A-4006-A3BF-0C558753A9DC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9E97082E-4E8D-4E8B-A320-40E2A1494C74}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9C07477C-ABB8-4DE5-B69C-3F8719D952C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C07477C-ABB8-4DE5-B69C-3F8719D952C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C07477C-ABB8-4DE5-B69C-3F8719D952C6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C07477C-ABB8-4DE5-B69C-3F8719D952C6}.Release|Any CPU.Build.0 = Release|Any CPU + {967DF0EB-F85A-4006-A3BF-0C558753A9DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {967DF0EB-F85A-4006-A3BF-0C558753A9DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {967DF0EB-F85A-4006-A3BF-0C558753A9DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {967DF0EB-F85A-4006-A3BF-0C558753A9DC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0563C71A-762F-4784-887B-D51D14C92903} + EndGlobalSection +EndGlobal diff --git a/src/Lithnet.CredentialProvider/ChangePasswordResponse.cs b/src/Lithnet.CredentialProvider/ChangePasswordResponse.cs new file mode 100644 index 0000000..13a9d70 --- /dev/null +++ b/src/Lithnet.CredentialProvider/ChangePasswordResponse.cs @@ -0,0 +1,23 @@ +namespace Lithnet.CredentialProvider +{ + /// + /// The object is used to communicate the results of a password change operation to LogonUI + /// + public class ChangePasswordResponse + { + /// + /// Gets or sets a value indicating if the password was successfully changed + /// + public bool IsSuccess { get; set; } + + /// + /// Optional. Gets or sets the icon to use when displaying the status text + /// + public StatusIcon StatusIcon { get; set; } + + /// + /// Options. Details about the result of the password change operation + /// + public string StatusText { get; set; } + } +} diff --git a/src/Lithnet.CredentialProvider/Controls/BitmapControl.cs b/src/Lithnet.CredentialProvider/Controls/BitmapControl.cs new file mode 100644 index 0000000..2137a7b --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/BitmapControl.cs @@ -0,0 +1,102 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Runtime.InteropServices; +using Lithnet.CredentialProvider.Interop; + +namespace Lithnet.CredentialProvider +{ + /// + /// The base class of image-based controls + /// + public abstract class BitmapControl : ControlBase + { + private Bitmap bitmap; + private Color backgroundColor; + + protected BitmapControl(string key, string label, bool isProviderLogo, Bitmap bitmap) : + base(key, label, FieldType.TileImage, isProviderLogo ? Guid.Parse(CredProviderConstants.CPFG_CREDENTIAL_PROVIDER_LOGO) : Guid.Empty) + { + this.bitmap = bitmap; + this.backgroundColor = Color.FromArgb(70, 70, 70); + } + + protected BitmapControl(BitmapControl source) : base(source) { } + + /// + /// Specifies the background color that should replace any transparent elements of the image. This defaults to #707070 + /// + public Color BackgroundColor + { + get { return this.backgroundColor; } + set + { + if (this.backgroundColor != value) + { + this.backgroundColor = value; + this.RaisePropertyChanged(); + } + } + } + + /// + /// The image to be displayed + /// + public Bitmap Bitmap + { + get { return this.bitmap; } + set + { + + if (this.bitmap != value) + { + this.bitmap = value; + + if (this.Events is ICredentialProviderCredentialEvents3 e) + { + var buffer = this.GetBitmapBuffer(out uint size); + e.SetFieldBitmapBuffer(this.Credential, this.Id, size, buffer); + } + + this.RaisePropertyChanged(); + } + } + } + + internal IntPtr GetHBitmap() + { + if (this.bitmap == null) + { + return IntPtr.Zero; + } + + return this.Bitmap.GetHbitmap(this.BackgroundColor); + } + + internal IntPtr GetBitmapBuffer(out uint size) + { + size = 0; + var hbitmap = this.GetHBitmap(); + + if (hbitmap == IntPtr.Zero) + { + return IntPtr.Zero; + } + + var image = Bitmap.FromHbitmap(hbitmap); + + IntPtr buffer = IntPtr.Zero; + using (MemoryStream ms = new MemoryStream()) + { + image.Save(ms, ImageFormat.Bmp); + var bitmapBytes = ms.ToArray(); + size = (uint)bitmapBytes.Length; + buffer = Marshal.AllocCoTaskMem(bitmapBytes.Length); + Marshal.Copy(bitmapBytes, 0, buffer, bitmapBytes.Length); + } + + return buffer; + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/CheckboxControl.cs b/src/Lithnet.CredentialProvider/Controls/CheckboxControl.cs new file mode 100644 index 0000000..6128dfa --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/CheckboxControl.cs @@ -0,0 +1,57 @@ +using Lithnet.CredentialProvider.Interop; + +namespace Lithnet.CredentialProvider +{ + /// + /// A control that renders a check box in the credential UI + /// + public class CheckboxControl : ControlBase + { + private bool isChecked; + + /// + /// Creates a new control + /// + /// The unique key for this control + public CheckboxControl(string key) : this(key, null) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + public CheckboxControl(string key, string label) : base(key, label, FieldType.CheckBox) { } + + /// + /// Gets or sets a value indicating if the checkbox is currently checked + /// + public bool IsChecked + { + get { return this.isChecked; } + set + { + if (this.isChecked != value) + { + this.isChecked = value; + this.Events?.SetFieldCheckbox(this.Credential, this.Id, value ? 1 : 0, this.Label); + this.RaisePropertyChanged(); + } + } + } + + internal void SetIsCheckedInternal(bool value) + { + this.isChecked = value; + this.RaisePropertyChanged(nameof(this.IsChecked)); + } + + private CheckboxControl(CheckboxControl source) : base(source) { } + + internal override ControlBase Clone() + { + var clone = new CheckboxControl(this); + clone.IsChecked = this.IsChecked; + return clone; + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/ComboboxControl.cs b/src/Lithnet.CredentialProvider/Controls/ComboboxControl.cs new file mode 100644 index 0000000..a8c8ef4 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/ComboboxControl.cs @@ -0,0 +1,110 @@ +using Lithnet.CredentialProvider.Interop; + +namespace Lithnet.CredentialProvider +{ + /// + /// A control that renders a comboxbox in the credential UI + /// + public class ComboboxControl : ControlBase + { + private int selectedItemIndex; + + /// + /// Creates a new control + /// + /// The unique key for this control + public ComboboxControl(string key) : this(key, null) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + public ComboboxControl(string key, string label) : base(key, label, FieldType.ComboBox) + { + this.ComboBoxItems = new SimpleList(); + this.ComboBoxItems.ItemAdded += this.ComboBoxItems_ItemAdded; + this.ComboBoxItems.ItemRemoved += this.ComboBoxItems_ItemRemoved; + } + + private void ComboBoxItems_ItemRemoved(object sender, int e) + { + if (e == this.selectedItemIndex) + { + this.SelectedItemIndex = e - 1; + } + + this.Events?.DeleteFieldComboBoxItem(this.Credential, this.Id, (uint)e); + } + + private void ComboBoxItems_ItemAdded(object sender, string item) + { + this.Events?.AppendFieldComboBoxItem(this.Credential, this.Id, item); + if (this.selectedItemIndex == -1) + { + this.SelectedItemIndex = 0; + } + } + + /// + /// Get the list of items in the combobox + /// + public SimpleList ComboBoxItems { get; } + + /// + /// Gets or sets the index of the currently selected item in the combobox + /// + public int SelectedItemIndex + { + get { return this.selectedItemIndex; } + set + { + if (this.selectedItemIndex != value) + { + this.selectedItemIndex = value; + this.Events?.SetFieldComboBoxSelectedItem(this.Credential, this.Id, (uint)this.selectedItemIndex); + this.RaisePropertyChanged(); + this.RaisePropertyChanged(nameof(this.SelectedItem)); + } + } + } + + /// + /// Get the value of the currently selected item in the combobox + /// + public string SelectedItem + { + get + { + if (this.selectedItemIndex >= 0 && this.selectedItemIndex < this.ComboBoxItems.Count) + { + return this.ComboBoxItems[this.selectedItemIndex]; + } + + return null; + } + } + + internal void SetComboboxSelectedItemIndexInternal(int index) + { + this.selectedItemIndex = index; + this.RaisePropertyChanged(nameof(this.SelectedItemIndex)); + this.RaisePropertyChanged(nameof(this.SelectedItem)); + } + + private ComboboxControl(ComboboxControl source) : base(source) + { + this.ComboBoxItems = new SimpleList(); + this.ComboBoxItems.ItemAdded += this.ComboBoxItems_ItemAdded; + this.ComboBoxItems.ItemRemoved += this.ComboBoxItems_ItemRemoved; + } + + internal override ControlBase Clone() + { + var clone = new ComboboxControl(this); + clone.ComboBoxItems.AddRange(this.ComboBoxItems); + clone.SelectedItemIndex = this.SelectedItemIndex; + return clone; + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/CommandLinkControl.cs b/src/Lithnet.CredentialProvider/Controls/CommandLinkControl.cs new file mode 100644 index 0000000..a077f28 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/CommandLinkControl.cs @@ -0,0 +1,38 @@ +using System; +using Lithnet.CredentialProvider.Interop; + +namespace Lithnet.CredentialProvider +{ + /// + /// Represents a control that renders as a clickable text link in the credential UI + /// + public class CommandLinkControl : ControlBase + { + /// + /// Creates a new control + /// + /// The unique key for this control + public CommandLinkControl(string key) : this(key, null) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + public CommandLinkControl(string key, string label) : base(key, label, FieldType.CommandLink) { } + + private CommandLinkControl(CommandLinkControl source) : base(source) { } + + /// + /// Gets or sets an action to take when the link is clicked by the user + /// + public Action OnClick { get; set; } + + internal override ControlBase Clone() + { + var clone = new CommandLinkControl(this); + clone.OnClick = this.OnClick; + return clone; + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/ControlBase.cs b/src/Lithnet.CredentialProvider/Controls/ControlBase.cs new file mode 100644 index 0000000..5887f87 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/ControlBase.cs @@ -0,0 +1,202 @@ +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Lithnet.CredentialProvider.Interop; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Lithnet.CredentialProvider +{ + /// + /// Represents the base of all control types + /// + public abstract class ControlBase : INotifyPropertyChanged + { + private static uint fieldIdCounter; + + private FieldState state; + private FieldInteractiveState interactiveState; + private string label; + private FieldOptions options; + private protected ILogger logger = NullLogger.Instance; + + public event PropertyChangedEventHandler PropertyChanged; + + private protected ControlBase(ControlBase source) + { + this.Id = source.Id; + this.Key = source.Key; + this.Type = source.Type; + this.FieldTypeGuid = source.FieldTypeGuid; + + this.state = source.State; + this.interactiveState = source.InteractiveState; + this.label = source.Label; + this.options = source.options; + } + + private protected ControlBase(string key, FieldType type) + : this(key, null, type, Guid.Empty) { } + + private protected ControlBase(string key, string label, FieldType type) + : this(key, label, type, Guid.Empty) { } + + private protected ControlBase(string key, string label, FieldType type, Guid guidType) + { + this.Id = fieldIdCounter++; + this.Type = type; + this.FieldTypeGuid = guidType; + + this.label = label; + this.state = FieldState.DisplayInSelectedTile; + this.interactiveState = FieldInteractiveState.None; + this.options = FieldOptions.None; + + this.Key = key; + this.logger = CredentialProviderBase.LoggerFactory.CreateLogger(this.GetType()); + } + + internal void AssignCredential(ICredentialProviderCredential credential) + { + this.Credential = credential; + } + + internal void AssignEvents(ICredentialProviderCredentialEvents events) + { + this.Events = events; + } + + internal void UnassignEvents() + { + this.Events = null; + } + + internal ICredentialProviderCredentialEvents Events { get; private set; } + + internal ICredentialProviderCredential Credential { get; private set; } + + /// + /// Gets the unique ID associated with this control + /// + public string Key { get; } + + /// + /// Gets the internal numerical ID associated with this control + /// + public uint Id { get; } + + /// + /// Gets or sets the label text for the control + /// + public string Label + { + get { return this.label; } + set + { + if (this.label != value) + { + this.label = value; + if (this.Type != FieldType.PasswordText && + this.Type != FieldType.EditText) + { + this.Events?.SetFieldString(this.Credential, this.Id, Marshal.StringToCoTaskMemUni(this.label)); + } + + this.RaisePropertyChanged(); + } + } + } + + internal FieldType Type { get; } + + internal Guid FieldTypeGuid { get; } + + /// + /// Gets or sets the options that control the rendering of this field + /// + public FieldOptions Options + { + get + { + return this.options; + } + set + { + if (this.options != value) + { + this.options = value; + + if (this.Events is ICredentialProviderCredentialEvents2 e) + { + e.SetFieldOptions(this.Credential, this.Id, this.options); + } + + this.RaisePropertyChanged(); + } + } + } + + /// + /// Gets or sets the states in which this control should be displayed + /// + public FieldState State + { + get + { + return this.state; + } + set + { + if (this.state != value) + { + this.state = value; + + this.Events?.SetFieldState(this.Credential, this.Id, this.state); + this.RaisePropertyChanged(); + } + } + } + + /// + /// Gets or sets the interactivity status of the control + /// + public FieldInteractiveState InteractiveState + { + get { return this.interactiveState; } + set + { + if (this.interactiveState != value) + { + this.interactiveState = value; + this.Events?.SetFieldInteractiveState(this.Credential, this.Id, this.interactiveState); + this.RaisePropertyChanged(); + } + } + } + + internal FieldDescriptor GetDescriptor() + { + return new FieldDescriptor + { + FieldType = this.Type, + FieldID = this.Id, + FieldTypeGuid = this.FieldTypeGuid, + Label = this.Label + }; + } + + /// + public override string ToString() + { + return $"{this.Id}:{this.Type}:{this.Label}"; + } + + internal void RaisePropertyChanged([CallerMemberName] string name = null) + { + this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); + } + + internal abstract ControlBase Clone(); + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/ControlCollection.cs b/src/Lithnet.CredentialProvider/Controls/ControlCollection.cs new file mode 100644 index 0000000..18068d5 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/ControlCollection.cs @@ -0,0 +1,197 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Lithnet.CredentialProvider.Interop; + +namespace Lithnet.CredentialProvider +{ + /// + /// A collection of control objects + /// + public class ControlCollection : IEnumerable + { + private readonly Dictionary idControls = new Dictionary(); + private readonly Dictionary keyedControls = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly List controls = new List(); + + private ICredentialProviderCredentialEvents events; + private ICredentialProviderCredential credential; + private bool locked; + + internal ControlCollection() { } + + internal ControlCollection(CredentialProviderCredential1Tile credential) + { + this.credential = credential; + } + + internal void SetCredential(ICredentialProviderCredential credential) + { + if (this.credential != null && this.credential != credential) + { + throw new InvalidOperationException("Cannot set credential more than once"); + } + + this.credential = credential; + } + + internal void Add(ControlBase control) + { + if (this.locked) + { + throw new InvalidOperationException("Cannot add controls after the provider has had GetFieldDescriptorCount called"); + } + + if (this.credential != null) + { + control.AssignCredential(this.credential); + } + + if (this.events != null) + { + control.AssignEvents(this.events); + } + + if (this.keyedControls.ContainsKey(control.Key)) + { + throw new ArgumentException("An control with the same key already exists"); + } + + this.idControls.Add(control.Id, control); + this.keyedControls.Add(control.Key, control); + this.controls.Add(control); + } + + internal void AssignEvents(ICredentialProviderCredentialEvents events) + { + if (this.credential == null) + { + throw new InvalidOperationException("Unable to assign events until a credential has been set"); + } + + this.events = events; + + foreach (var control in this.idControls.Values) + { + control.AssignEvents(events); + } + } + + internal void UnassignEvents() + { + this.events = null; + + foreach (var control in this.idControls.Values) + { + control.UnassignEvents(); + } + } + + /// + /// Gets a control from the collection + /// + /// The type of control + /// The unique ID of the control + /// + public T GetControl(string key) where T : ControlBase + { + return (T)this.keyedControls[key]; + } + + internal T GetControl(uint id) where T : ControlBase + { + return (T)this.idControls[id]; + } + + internal bool TryGetControl(uint id, FieldType type, out T control) where T : ControlBase + { + if (this.idControls.ContainsKey(id)) + { + control = this.idControls[id] as T; + + if (control != null) + { + if (control.Type == type) + { + return true; + } + } + } + + control = null; + return false; + } + + internal bool TryGetControl(uint id, out ControlBase control) + { + control = null; + + if (this.idControls.ContainsKey(id)) + { + control = this.idControls[id]; + return true; + } + + return false; + } + + /// + /// Gets the total number of controls in the collection + /// + public int Count => this.idControls.Count; + + internal ControlBase this[int index] + { + get + { + return this.controls[index]; + } + } + + internal void Lock() + { + this.locked = true; + } + + /// + /// Gets a control by its unique ID + /// + /// + /// + public ControlBase this[string key] + { + get + { + return this.keyedControls[key]; + } + } + + /// + /// Get all controls of the specified type + /// + /// + /// + internal IEnumerable GetByType(FieldType type) + { + foreach (var item in this.idControls) + { + if (item.Value.Type == type) + { + yield return item.Value; + } + } + } + + /// + public IEnumerator GetEnumerator() + { + return this.idControls.Values.GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return this.idControls.Values.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/CredentialProviderLabelControl.cs b/src/Lithnet.CredentialProvider/Controls/CredentialProviderLabelControl.cs new file mode 100644 index 0000000..5d1805e --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/CredentialProviderLabelControl.cs @@ -0,0 +1,32 @@ +namespace Lithnet.CredentialProvider +{ + /// + /// Represents a control that provides the credential UI with the name of this credential provider + /// + public class CredentialProviderLabelControl : SmallLabelControl + { + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + public CredentialProviderLabelControl(string key) : this(key, null) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + public CredentialProviderLabelControl(string key, string label) : base(key, label, true) + { + this.State = FieldState.DisplayInDeselectedTile; + } + + private CredentialProviderLabelControl(CredentialProviderLabelControl source) : base(source) { } + + internal override ControlBase Clone() + { + return new CredentialProviderLabelControl(this); + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/CredentialProviderLogoControl.cs b/src/Lithnet.CredentialProvider/Controls/CredentialProviderLogoControl.cs new file mode 100644 index 0000000..0f93a27 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/CredentialProviderLogoControl.cs @@ -0,0 +1,44 @@ +using System.Drawing; + +namespace Lithnet.CredentialProvider +{ + /// + /// Represents a control that provides the credential UI with the logo of this credential provider + /// + public class CredentialProviderLogoControl : BitmapControl + { + /// + /// Creates a new control + /// + /// The unique key for this control + public CredentialProviderLogoControl(string key) : this(key, null, null) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control. This value is not displayed to the user + public CredentialProviderLogoControl(string key, string label) : this(key, label, null) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + /// The bitmap to use as the logo + public CredentialProviderLogoControl(string key, string label, Bitmap bitmap) : base(key, label, true, bitmap) + { + this.State = FieldState.DisplayInDeselectedTile; + } + + private CredentialProviderLogoControl(CredentialProviderLogoControl source) : base(source) { } + + internal override ControlBase Clone() + { + var clone = new CredentialProviderLogoControl(this); + clone.Bitmap = this.Bitmap; + clone.BackgroundColor = this.BackgroundColor; + return clone; + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/InsecurePasswordTextboxControl.cs b/src/Lithnet.CredentialProvider/Controls/InsecurePasswordTextboxControl.cs new file mode 100644 index 0000000..3082f01 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/InsecurePasswordTextboxControl.cs @@ -0,0 +1,69 @@ +using System; +using System.Runtime.InteropServices; +using Lithnet.CredentialProvider.Interop; +using Microsoft.Extensions.Logging; + +namespace Lithnet.CredentialProvider +{ + /// + /// A masked password text box, with a Password property that provides the password in plain text + /// + public class InsecurePasswordTextboxControl : ControlBase + { + private string password; + + /// + /// Creates a new control + /// + /// The unique key for this control + public InsecurePasswordTextboxControl(string key) : this(key, null) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + public InsecurePasswordTextboxControl(string key, string label) : base(key, label, FieldType.PasswordText) { } + private InsecurePasswordTextboxControl(InsecurePasswordTextboxControl source) : base(source) { } + + /// + /// Gets or sets the password value in plain text + /// + public string Password + { + get { return this.password; } + set + { + if (this.password != value) + { + this.password = value; + if (this.password?.Length > 0) + { + var ptr = Marshal.StringToCoTaskMemUni(this.password); + this.logger.LogTrace($"0x:{ptr.ToString("X16")} - Created ptr for outgoing SetFieldString"); + this.Events?.SetFieldString(this.Credential, this.Id, ptr); + } + else + { + this.Events?.SetFieldString(this.Credential, this.Id, IntPtr.Zero); + } + + this.RaisePropertyChanged(nameof(this.Password)); + } + } + } + + internal void SetPasswordInternal(string s) + { + this.password = s; + this.RaisePropertyChanged(nameof(this.Password)); + } + + internal override ControlBase Clone() + { + var clone = new InsecurePasswordTextboxControl(this); + clone.password = this.password; + return clone; + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/LargeLabelControl.cs b/src/Lithnet.CredentialProvider/Controls/LargeLabelControl.cs new file mode 100644 index 0000000..5a9c294 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/LargeLabelControl.cs @@ -0,0 +1,30 @@ +using Lithnet.CredentialProvider.Interop; + +namespace Lithnet.CredentialProvider +{ + /// + /// A text label that appears in a larger font size + /// + public class LargeLabelControl : ControlBase + { + /// + /// Creates a new control + /// + /// The unique key for this control + public LargeLabelControl(string key) : this(key, null) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + public LargeLabelControl(string key, string label) : base(key, label, FieldType.LargeText) { } + + private LargeLabelControl(LargeLabelControl source) : base(source) { } + + internal override ControlBase Clone() + { + return new LargeLabelControl(this); + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/SecurePasswordTextboxControl.cs b/src/Lithnet.CredentialProvider/Controls/SecurePasswordTextboxControl.cs new file mode 100644 index 0000000..1a5ef8f --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/SecurePasswordTextboxControl.cs @@ -0,0 +1,71 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Security; +using Lithnet.CredentialProvider.Interop; + +namespace Lithnet.CredentialProvider +{ + /// + /// A masked password text box, with a Password property that provides the password as a secure string + /// + public class SecurePasswordTextboxControl : ControlBase + { + private SecureString password; + + /// + /// Creates a new control + /// + /// The unique key for this control + public SecurePasswordTextboxControl(string key) : this(key, null) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + public SecurePasswordTextboxControl(string key, string label) : base(key, label, FieldType.PasswordText) { } + + /// + /// Gets or sets the password value as a secure string + /// + public SecureString Password + { + get { return this.password; } + set + { + if (this.password != value) + { + this.password = value; + if (this.password?.Length > 0) + { + var ptr = Marshal.SecureStringToCoTaskMemUnicode(this.password); + Trace.WriteLine($"0x:{ptr.ToString("X16")} - CONTROL: Created ptr for outgoing SetFieldString"); + this.Events?.SetFieldString(this.Credential, this.Id, ptr); + } + else + { + this.Events?.SetFieldString(this.Credential, this.Id, IntPtr.Zero); + } + + this.RaisePropertyChanged(nameof(this.Password)); + } + } + } + + internal void SetPasswordInternal(SecureString s) + { + this.password = s; + this.RaisePropertyChanged(nameof(this.Password)); + } + + private SecurePasswordTextboxControl(SecurePasswordTextboxControl source) : base(source) { } + + internal override ControlBase Clone() + { + var clone = new SecurePasswordTextboxControl(this); + clone.password = this.password; + return clone; + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/SimpleList.cs b/src/Lithnet.CredentialProvider/Controls/SimpleList.cs new file mode 100644 index 0000000..b019ef9 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/SimpleList.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Lithnet.CredentialProvider +{ + /// + /// Represents a simple list of strings with events + /// + public class SimpleList : IEnumerable + { + private readonly List backingList = new List(); + + public event EventHandler ItemAdded; + public event EventHandler ItemRemoved; + + /// + /// Adds the specified value to the list + /// + /// A string value to add to the list + public void Add(string value) + { + this.backingList.Add(value); + this.ItemAdded?.Invoke(this, value); + } + + /// + /// Removes the specified value to the list, if found + /// + /// A string value to remove from the list + public void Remove(string value) + { + var index = this.backingList.IndexOf(value); + if (index >= 0) + { + this.backingList.RemoveAt(index); + this.ItemRemoved?.Invoke(this, index); + } + } + + /// + /// Adds the specified values to the list + /// + /// Items to add to the list + public void AddRange(IEnumerable items) + { + foreach (var item in items) + { + this.Add(item); + } + } + + /// + /// Gets the total number of items in the list + /// + public int Count => this.backingList.Count; + + /// + public IEnumerator GetEnumerator() + { + return this.backingList.GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return this.backingList.GetEnumerator(); + } + + /// + /// Gets an item from the list based on its index + /// + /// The index of the item to get + /// The item matching the index provided + public string this[int index] + { + get + { + return this.backingList[index]; + } + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/SmallLabelControl.cs b/src/Lithnet.CredentialProvider/Controls/SmallLabelControl.cs new file mode 100644 index 0000000..5be1e7a --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/SmallLabelControl.cs @@ -0,0 +1,40 @@ +using System; +using Lithnet.CredentialProvider.Interop; + +namespace Lithnet.CredentialProvider +{ + /// + /// A text label that appears in a smaller font size + /// + public class SmallLabelControl : ControlBase + { + /// + /// Creates a new control + /// + /// The unique key for this control + public SmallLabelControl(string key) : this(key, null, false) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + public SmallLabelControl(string key, string label) : this(key, label, false) { } + + private protected SmallLabelControl(SmallLabelControl source) : base(source) { } + + private protected SmallLabelControl(string key, string label, bool isProviderLabel) : + base(key, label, FieldType.SmallText, isProviderLabel ? Guid.Parse(CredProviderConstants.CPFG_CREDENTIAL_PROVIDER_LABEL) : Guid.Empty) + { + if (isProviderLabel) + { + this.State = FieldState.DisplayInDeselectedTile; + } + } + + internal override ControlBase Clone() + { + return new SmallLabelControl(this); + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/SubmitButtonControl.cs b/src/Lithnet.CredentialProvider/Controls/SubmitButtonControl.cs new file mode 100644 index 0000000..eb60da3 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/SubmitButtonControl.cs @@ -0,0 +1,47 @@ +using Lithnet.CredentialProvider.Interop; + +namespace Lithnet.CredentialProvider +{ + /// + /// The submit button for the login form. This button is ignored when the credential provider is invoked via CredUI. Note, there can only be one submit button. + /// + public class SubmitButtonControl : ControlBase + { + /// + /// Creates a new control + /// + /// The unique key for this control + /// The control that the submit button should appear adjacent to + public SubmitButtonControl(string key, ControlBase adjacentToControl) : this(key, null, adjacentToControl) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + /// The control that the submit button should appear adjacent to + public SubmitButtonControl(string key, string label, ControlBase adjacentToControl) : base(key, label, FieldType.Submit) + { + this.AdjacentToId = adjacentToControl.Id; + this.AdjacentToKey = adjacentToControl.Key; + this.State = FieldState.DisplayInSelectedTile; + } + + /// + /// Gets the unique ID of the control that the button is adjacent to + /// + public string AdjacentToKey { get; } + + internal uint AdjacentToId { get; private set; } + + private SubmitButtonControl(SubmitButtonControl source) : base(source) { } + + internal override ControlBase Clone() + { + var clone = new SubmitButtonControl(this); + clone.AdjacentToId = this.AdjacentToId; + + return clone; + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/TextboxControl.cs b/src/Lithnet.CredentialProvider/Controls/TextboxControl.cs new file mode 100644 index 0000000..046f6a5 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/TextboxControl.cs @@ -0,0 +1,61 @@ +using System.Runtime.InteropServices; +using Lithnet.CredentialProvider.Interop; + +namespace Lithnet.CredentialProvider +{ + /// + /// A text box control used to capture use input + /// + public class TextboxControl : ControlBase + { + private string text; + + private TextboxControl(TextboxControl source) : base(source) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + public TextboxControl(string key) : this(key, null) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + public TextboxControl(string key, string label) : base(key, label, FieldType.EditText) + { + } + + /// + /// Gets or sets the text value of the text box + /// + public string Text + { + get { return this.text; } + set + { + if (this.text != value) + { + this.text = value; + this.Events?.SetFieldString(this.Credential, this.Id, Marshal.StringToCoTaskMemUni(value)); + this.RaisePropertyChanged(); + } + } + } + + internal void SetTextInternal(string text) + { + this.text = text; + this.RaisePropertyChanged(nameof(this.Text)); + } + + internal override ControlBase Clone() + { + var clone = new TextboxControl(this); + clone.Text = this.Text; + + return clone; + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/Controls/UserTileControl.cs b/src/Lithnet.CredentialProvider/Controls/UserTileControl.cs new file mode 100644 index 0000000..92eb0cf --- /dev/null +++ b/src/Lithnet.CredentialProvider/Controls/UserTileControl.cs @@ -0,0 +1,42 @@ +using System.Drawing; + +namespace Lithnet.CredentialProvider +{ + /// + /// A control that displays the user's tile image + /// + public class UserTileControl : BitmapControl + { + /// + /// Creates a new control + /// + /// The unique key for this control + public UserTileControl(string key) : this(key, null, null) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + public UserTileControl(string key, string label) : this(key, label, null) { } + + /// + /// Creates a new control + /// + /// The unique key for this control + /// The label associated with the control + /// The bitmap to use as the user's tile image + public UserTileControl(string key, string label, Bitmap bitmap) : base(key, label, false, bitmap) { } + + private UserTileControl(UserTileControl source) : base(source) { } + + internal override ControlBase Clone() + { + var clone = new UserTileControl(this); + clone.Bitmap = this.Bitmap; + clone.BackgroundColor = this.BackgroundColor; + + return clone; + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/CredentialProviderBase.ICredentialProvider.cs b/src/Lithnet.CredentialProvider/CredentialProviderBase.ICredentialProvider.cs new file mode 100644 index 0000000..2248941 --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialProviderBase.ICredentialProvider.cs @@ -0,0 +1,214 @@ +using System; +using System.Linq; +using System.Runtime.InteropServices; +using Lithnet.CredentialProvider.Interop; +using Microsoft.Extensions.Logging; + +namespace Lithnet.CredentialProvider +{ + public abstract partial class CredentialProviderBase : ICredentialProvider + { + int ICredentialProvider.SetUsageScenario(UsageScenario cpus, CredUIWinFlags dwFlags) + { + try + { + this.logger.LogTrace($"SetUsageScenario: Usage: {cpus} flags: {dwFlags}"); + + this.UsageScenario = cpus; + + if (this.IsUsageScenarioSupported(cpus, (CredUIWinFlags)dwFlags)) + { + return HRESULT.S_OK; + } + else + { + return HRESULT.E_NOTIMPL; + } + } + catch (Exception ex) + { + this.logger.LogError(ex, "SetUsageScenario failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProvider.SetSerialization(ref CredentialSerialization pcpcs) + { + try + { + this.InboundSerialization = pcpcs; + this.OnSetSerialization(pcpcs); + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "UnAdvSetSerializationise failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProvider.Advise(ICredentialProviderEvents pcpe, IntPtr upAdviseContext) + { + try + { + this.logger.LogTrace($"Advise: {upAdviseContext}"); + if (pcpe != null) + { + this.credentialProviderEventsAdviseContext = upAdviseContext; + this.CredentialProviderEvents = pcpe; + var intPtr = Marshal.GetIUnknownForObject(pcpe); + Marshal.AddRef(intPtr); + } + + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "Advise failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProvider.UnAdvise() + { + try + { + this.logger.LogTrace($"Unadvise"); + + if (this.CredentialProviderEvents != null) + { + var intPtr = Marshal.GetIUnknownForObject(this.CredentialProviderEvents); + Marshal.Release(intPtr); + this.CredentialProviderEvents = null; + this.credentialProviderEventsAdviseContext = IntPtr.Zero; + } + + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "UnAdvise failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProvider.GetFieldDescriptorCount(out uint pdwCount) + { + pdwCount = 0; + + try + { + this.logger.LogTrace("GetFieldDescriptorCount"); + this.BuildControls(); + this.Controls.Lock(); + + pdwCount = (uint)this.Controls.Count; + this.logger.LogTrace($"GetFieldDescriptorCount return {pdwCount}"); + + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetFieldDescriptorCount failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProvider.GetFieldDescriptorAt(uint dwIndex, out IntPtr ppcpfd) + { + ppcpfd = IntPtr.Zero; + + try + { + this.logger.LogTrace($"GetFieldDescriptorAt {dwIndex}"); + + if (dwIndex >= this.Controls.Count) + { + return HRESULT.E_INVALIDARG; + } + + var item = this.Controls[(int)dwIndex].GetDescriptor(); + var size = Marshal.SizeOf(); + var ptr = Marshal.AllocCoTaskMem(size); + Marshal.StructureToPtr(item, ptr, false); + ppcpfd = ptr; + + this.logger.LogTrace($"GetFieldDescriptorAt {dwIndex}: returning {item}"); + + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetFieldDescriptorAt failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProvider.GetCredentialCount(out uint pdwCount, out uint pdwDefault, out int pbAutoLogonWithDefault) + { + pdwCount = 0; + pdwDefault = 0; + pbAutoLogonWithDefault = 0; + + try + { + this.logger.LogTrace($"GetCredentialCount"); + + if (this.Tiles == null) + { + this.logger.LogTrace($"GetCredentialCount is enumerating tiles"); + this.SetupTiles(); + this.logger.LogTrace($"{this.Tiles.Count} tiles enumerated. {this.Tiles.Count(t => t.IsGenericTile)} generic and {this.tiles.Count(t => !t.IsGenericTile)} personalized"); + } + + this.notifyOnTileCollectionChange = true; + + var autoLogonTile = this.Tiles.FirstOrDefault(t => t.IsAutoLogon); + var defaultTile = this.Tiles.FirstOrDefault(t => t.IsDefault); + + int defaultIndex = 0; + if (autoLogonTile != null) + { + defaultIndex = this.tiles.IndexOf(autoLogonTile); + } + else if (defaultTile != null) + { + defaultIndex = this.tiles.IndexOf(defaultTile); + } + + pdwCount = (uint)this.Tiles.Count; + pdwDefault = (uint)defaultIndex; + pbAutoLogonWithDefault = autoLogonTile == null ? 0 : 1; + + this.logger.LogTrace($"GetCredentialCount returning pdwCount: {pdwCount}, pdwDefault: {pdwDefault}, pbAutoLogonWithDefault: {pbAutoLogonWithDefault}"); + + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetCredentialCount failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProvider.GetCredentialAt(uint dwIndex, out ICredentialProviderCredential ppcpc) + { + ppcpc = null; + + try + { + this.logger.LogTrace($"GetCredentialAt {dwIndex}"); + + var tile = this.Tiles[(int)dwIndex]; + + ppcpc = (ICredentialProviderCredential)tile; + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetCredentialAt failed"); + return HRESULT.E_FAIL; + } + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/CredentialProviderBase.ICredentialProviderSetUserArray.cs b/src/Lithnet.CredentialProvider/CredentialProviderBase.ICredentialProviderSetUserArray.cs new file mode 100644 index 0000000..f5d21cf --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialProviderBase.ICredentialProviderSetUserArray.cs @@ -0,0 +1,33 @@ +using System; +using Lithnet.CredentialProvider.Interop; +using Microsoft.Extensions.Logging; + +namespace Lithnet.CredentialProvider +{ + public abstract partial class CredentialProviderBase : ICredentialProviderSetUserArray + { + int ICredentialProviderSetUserArray.SetUserArray(ICredentialProviderUserArray users) + { + try + { + this.logger.LogTrace($"SetUserArray"); + + if (users.GetCount(out uint count) != HRESULT.S_OK) + { + this.logger.LogTrace($"ICredentialProviderUserArray.GetCount failed"); + return HRESULT.S_FALSE; + } + + this.logger.LogTrace($"SetUserArray called with {count} users"); + + this.credentialProviderUsers = users; + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "SetUserArray failed"); + return HRESULT.E_FAIL; + } + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/CredentialProviderBase.cs b/src/Lithnet.CredentialProvider/CredentialProviderBase.cs new file mode 100644 index 0000000..248d2a2 --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialProviderBase.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using Lithnet.CredentialProvider.Interop; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Lithnet.CredentialProvider +{ + /// + /// This class represents the base of a credential provider. Inherit from this class to create a new credential provider. + /// + public abstract partial class CredentialProviderBase + { + internal static ILoggerFactory LoggerFactory { get; set; } = NullLoggerFactory.Instance; + + private readonly ILogger logger; + private readonly ILoggerFactory loggerFactory; + + private ICredentialProviderEvents CredentialProviderEvents; + private ICredentialProviderUserArray credentialProviderUsers; + + private IntPtr credentialProviderEventsAdviseContext; + private bool notifyOnTileCollectionChange; + private List tiles; + + /// + /// Gets the GUID of the credential provider + /// + public Guid CredentialProviderId { get; private set; } + + /// + /// Gets the list of users that were supplied to the credential provider from LogonUI + /// + public IReadOnlyList SuppliedUsers { get; private set; } + + /// + /// Gets the usage scenario communicated by LogonUI or CreDUI + /// + public UsageScenario UsageScenario { get; private set; } + + /// + /// Gets the list of controls used by this credential provider + /// + public ControlCollection Controls { get; private set; } + + /// + /// Gets a list of the tiles created for this credential provider + /// + public IReadOnlyList Tiles { get; private set; } + + /// + /// Provides access to the serialized input data provided by CredUI + /// + public CredentialSerialization InboundSerialization { get; private set; } + + protected CredentialProviderBase() + { + this.loggerFactory = this.GetLoggerFactory(); + + if (CredentialProviderBase.LoggerFactory != this.loggerFactory) + { + CredentialProviderBase.LoggerFactory = this.loggerFactory; + } + + this.logger = this.loggerFactory.CreateLogger(this.GetType()); + var guidAttribute = (GuidAttribute)(this.GetType().GetCustomAttribute(typeof(GuidAttribute))); + + if (guidAttribute == null) + { + throw new InvalidOperationException("The Credential Provider must have a [Guid(\"xxx\")] attribute assigned to its class"); + } + + this.CredentialProviderId = Guid.Parse(guidAttribute.Value); + } + + /// + /// Gets a logger factory. Override this method and provide an implementation of to enable credential provider logging + /// + /// An ILoggerFactory instance + public virtual ILoggerFactory GetLoggerFactory() { return NullLoggerFactory.Instance; } + + /// + /// Gets a value indicating if the credential provider supports the provided by LogonUI or CredUI + /// + /// The usage scenario + /// Additional flags provided by CredUI + /// True, if the credential provider can handle the specified usage scenario, or false if it cannot + public abstract bool IsUsageScenarioSupported(UsageScenario cpus, CredUIWinFlags dwFlags); + + /// + /// Gets the set of controls used by this provider to render the UI + /// + /// The usage scenario to obtain the controls for + /// A collection of ControlBase objects + public abstract IEnumerable GetControls(UsageScenario cpus); + + /// + /// Gets a value that indicates if the specified user should have a tile rendered for them by this UI + /// + /// Details of the user provided by LogonUI or CredUI + /// A value indicating if this credential provider should show a tile for this user + public abstract bool ShouldIncludeUserTile(CredentialProviderUser user); + + /// + /// Gets a value that indicates if the credential provider should show a generic tile. That is, a tile that is not associated with a specific user. + /// + public abstract bool ShouldIncludeGenericTile(); + + /// + /// Adds additional user tiles to the collection, and notifies LogonUI that new tiles are available + /// + /// One or more credential tiles to add + public void AddAdditionalUserTiles(params CredentialProviderCredential1Tile[] tiles) + { + if (tiles == null) + { + return; + } + + foreach (var tile in tiles) + { + if (!this.tiles.Contains(tile)) + { + this.tiles.Add(tile); + tile.Initialize(); + } + } + + this.NotifyHostOfTileCollectionChange(); + } + + /// + /// Removes one or more user tiles, and notifies LogonUI that tiles have been removed + /// + /// The crendential tiles to remove + public void RemoveUserTiles(params CredentialProviderCredential1Tile[] tiles) + { + if (tiles == null) + { + return; + } + + foreach (var tile in tiles) + { + this.tiles.Remove(tile); + } + + this.NotifyHostOfTileCollectionChange(); + } + + /// + /// This method is used to generate the generic tile for this credential provider. This is called when return true + /// + public abstract CredentialProviderCredential1Tile CreateGenericTile(); + + /// + /// Creates a credential tile for the specified user + /// + /// The user to create the tile for + public abstract CredentialProviderCredential1Tile CreateUserTile(CredentialProviderUser user); + + /// + /// This method is called when the LogonUI or CredUI provides inbound credential data. Override this method to respond to the incoming data. + /// + /// The inbound serialized credential + public virtual void OnSetSerialization(CredentialSerialization inboundSerialization) { } + + private void BuildControls() + { + if (this.Controls == null) + { + this.Controls = new ControlCollection(); + + foreach (var control in this.GetControls(this.UsageScenario)) + { + this.Controls.Add(control); + } + + this.Controls.Lock(); + } + } + + private List GenerateSuppliedUserTiles() + { + this.BuildControls(); + + var tiles = new List(); + + var users = new List(); + + this.credentialProviderUsers.GetCount(out var count); + + for (uint i = 0; i < count; i++) + { + var result = this.credentialProviderUsers.GetAt(i, out var user); + if (result != HRESULT.S_OK) + { + this.logger.LogError($"Could not get user at index {i}"); + continue; + } + + user.GetSid(out var sid); + + this.logger.LogTrace($"Got supplied user {i}: with name {user.GetQualifiedUserName()} and SID {sid}"); + + var credentialProviderUser = new CredentialProviderUser(user); + users.Add(credentialProviderUser); + + if (this.ShouldIncludeUserTile(credentialProviderUser)) + { + var userTile = this.CreateUserTile(credentialProviderUser); + if (userTile != null) + { + tiles.Add(userTile); + userTile.Initialize(); + } + } + } + + if (this.ShouldIncludeGenericTile()) + { + var genericTile = this.CreateGenericTile(); + if (genericTile != null) + { + tiles.Add(genericTile); + genericTile.Initialize(); + } + } + + this.SuppliedUsers = users.AsReadOnly(); + + return tiles; + } + + private void SetupTiles() + { + this.tiles = new List(this.GenerateSuppliedUserTiles()); + this.Tiles = this.tiles.AsReadOnly(); + } + + private void NotifyHostOfTileCollectionChange() + { + if (this.notifyOnTileCollectionChange) + { + this.CredentialProviderEvents?.CredentialsChanged(this.credentialProviderEventsAdviseContext); + } + } + } +} \ No newline at end of file diff --git a/src/Lithnet.CredentialProvider/CredentialProviderCredential1Tile.ICredentialProviderCredential.cs b/src/Lithnet.CredentialProvider/CredentialProviderCredential1Tile.ICredentialProviderCredential.cs new file mode 100644 index 0000000..e91a4e2 --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialProviderCredential1Tile.ICredentialProviderCredential.cs @@ -0,0 +1,481 @@ +using System; +using System.Runtime.InteropServices; +using Lithnet.CredentialProvider.Interop; +using Microsoft.Extensions.Logging; + +namespace Lithnet.CredentialProvider +{ + public partial class CredentialProviderCredential1Tile : ICredentialProviderCredential + { + int ICredentialProviderCredential.Advise(ICredentialProviderCredentialEvents pcpce) + { + try + { + this.logger.LogTrace("Advise"); + + if (pcpce != null) + { + this.Controls.AssignEvents(pcpce); + this.events = pcpce; + this.events2 = pcpce as ICredentialProviderCredentialEvents2; + + var intPtr = Marshal.GetIUnknownForObject(pcpce); + Marshal.AddRef(intPtr); + } + + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "Advise failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.UnAdvise() + { + try + { + this.logger.LogTrace("Unadvise"); + + if (this.events != null) + { + this.Controls.UnassignEvents(); + var intPtr = Marshal.GetIUnknownForObject(this.events); + Marshal.Release(intPtr); + this.events = null; + } + + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "UnAdvise failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.SetSelected(out int pbAutoLogon) + { + pbAutoLogon = 0; + + try + { + this.logger.LogTrace("SetSelected"); + this.IsSelected = true; + pbAutoLogon = this.IsAutoLogon ? 1 : 0; + this.OnSelected(); + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "SetSelected failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.SetDeselected() + { + try + { + this.logger.LogTrace("SetDeselected"); + this.IsSelected = false; + this.OnDeselected(); + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "SetDeselected failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.GetFieldState(uint dwFieldID, out FieldState pcpfs, out FieldInteractiveState pcpfis) + { + pcpfis = FieldInteractiveState.None; + pcpfs = FieldState.Hidden; + + try + { + this.logger.LogTrace($"GetFieldState: field {dwFieldID}"); + + if (this.Controls.TryGetControl(dwFieldID, out var instance)) + { + pcpfs = instance.State; + pcpfis = instance.InteractiveState; + + this.logger.LogTrace($"GetFieldState on [{instance}] returning state {instance.State} and interactive state {instance.InteractiveState}"); + return HRESULT.S_OK; + } + + this.logger.LogError($"GetFieldState failed to find a field match for {dwFieldID}"); + + + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetFieldState failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.GetStringValue(uint dwFieldID, out IntPtr ppsz) + { + ppsz = IntPtr.Zero; + + try + { + this.logger.LogTrace($"GetStringValue: field {dwFieldID}"); + + if (this.Controls.TryGetControl(dwFieldID, out var instance)) + { + if (instance is TextboxControl t) + { + ppsz = Marshal.StringToCoTaskMemUni(t.Text); + return HRESULT.S_OK; + } + + if (instance is SecurePasswordTextboxControl p) + { + if (p.Password == null || p.Password.Length == 0) + { + ppsz = IntPtr.Zero; + } + else + { + ppsz = Marshal.SecureStringToCoTaskMemUnicode(p.Password); + this.logger.LogCritical($"0x{ppsz.ToString("X16")} - Put password for outbound GetStringValue"); + } + + return HRESULT.S_OK; + } + + if (instance is InsecurePasswordTextboxControl i) + { + if (i.Password == null || i.Password.Length == 0) + { + ppsz = IntPtr.Zero; + } + else + { + ppsz = Marshal.StringToCoTaskMemUni(i.Password); + this.logger.LogCritical($"0x{ppsz.ToString("X16")} - Put password for outbound GetStringValue"); + } + + return HRESULT.S_OK; + } + + ppsz = Marshal.StringToCoTaskMemUni(instance.Label); + return HRESULT.S_OK; + } + + this.logger.LogError($"GetStringValue failed to find a field match for {dwFieldID}"); + + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetStringValue failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.GetBitmapValue(uint dwFieldID, out IntPtr phbmp) + { + phbmp = IntPtr.Zero; + + try + { + this.logger.LogTrace($"GetBitmapValue: field {dwFieldID}"); + + if (this.Controls.TryGetControl(dwFieldID, FieldType.TileImage, out var instance)) + { + phbmp = instance.GetHBitmap(); + return HRESULT.S_OK; + } + + this.logger.LogError($"GetBitmapValue was incorrectly called on field {instance}"); + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetBitmapValue failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.GetCheckboxValue(uint dwFieldID, out int pbChecked, out string ppszLabel) + { + pbChecked = 0; + ppszLabel = null; + + try + { + this.logger.LogTrace($"GetCheckboxValue: field {dwFieldID}"); + + + if (this.Controls.TryGetControl(dwFieldID, FieldType.CheckBox, out var instance)) + { + ppszLabel = instance.Label; + pbChecked = instance.IsChecked ? 1 : 0; + return HRESULT.S_OK; + } + + this.logger.LogError($"GetCheckboxValue was incorrectly called on field {instance}"); + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetCheckboxValue failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.GetSubmitButtonValue(uint dwFieldID, out uint pdwAdjacentTo) + { + pdwAdjacentTo = 0; + + try + { + this.logger.LogTrace($"GetSubmitButtonValue: field {dwFieldID}"); + + if (this.Controls.TryGetControl(dwFieldID, FieldType.Submit, out var instance)) + { + pdwAdjacentTo = instance.AdjacentToId; + return HRESULT.S_OK; + } + + this.logger.LogError($"GetSubmitButtonValue was incorrectly called on field {instance}"); + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetSubmitButtonValue failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.GetComboBoxValueCount(uint dwFieldID, out uint pcItems, out uint pdwSelectedItem) + { + pcItems = 0; + pdwSelectedItem = 0; + + try + { + this.logger.LogTrace($"GetComboBoxValueCount: field {dwFieldID}"); + + if (this.Controls.TryGetControl(dwFieldID, FieldType.ComboBox, out var instance)) + { + pcItems = (uint)instance.ComboBoxItems.Count; + pdwSelectedItem = (uint)instance.SelectedItemIndex; + return HRESULT.S_OK; + } + + this.logger.LogError($"GetComboBoxValueCount was incorrectly called on field {instance}"); + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetComboBoxValueCount failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.GetComboBoxValueAt(uint dwFieldID, uint dwItem, out string ppszItem) + { + ppszItem = null; + + try + { + this.logger.LogTrace($"GetComboBoxValueAt: field {dwFieldID}"); + if (this.Controls.TryGetControl(dwFieldID, FieldType.ComboBox, out var instance)) + { + if (dwItem < instance.ComboBoxItems.Count) + { + ppszItem = instance.ComboBoxItems[(int)dwItem]; + return HRESULT.S_OK; + } + else + { + return HRESULT.E_FAIL; + } + } + + this.logger.LogError($"GetComboBoxValueAt was incorrectly called on field {instance}"); + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetComboBoxValueAt failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.SetStringValue(uint dwFieldID, IntPtr psz) + { + try + { + this.logger.LogTrace($"0x{psz.ToString("X16")} - Incoming SetStringValue: field {dwFieldID}"); + + if (this.Controls.TryGetControl(dwFieldID, out var instance)) + { + if (instance.Type == FieldType.EditText && instance is TextboxControl b) + { + b.SetTextInternal(Marshal.PtrToStringUni(psz)); + return HRESULT.S_OK; + } + + if (instance.Type == FieldType.PasswordText && instance is SecurePasswordTextboxControl p) + { + this.logger.LogCritical($"0x{psz.ToString("X16")} - Incoming password in SetStringValue"); + + p.SetPasswordInternal(psz.IntPtrToSecureString()); + PInvoke.SecureZeroMemory(psz, (uint)(psz.Wcslen() * 2)); + return HRESULT.S_OK; + } + + if (instance.Type == FieldType.PasswordText && instance is InsecurePasswordTextboxControl i) + { + this.logger.LogCritical($"0x{psz.ToString("X16")} - Incoming password in SetStringValue"); + + i.SetPasswordInternal(Marshal.PtrToStringUni(psz)); + PInvoke.SecureZeroMemory(psz, (uint)(psz.Wcslen() * 2)); + return HRESULT.S_OK; + } + } + + this.logger.LogError($"SetStringValue was incorrectly called on field {instance}"); + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "SetStringValue failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.SetCheckboxValue(uint dwFieldID, int bChecked) + { + try + { + this.logger.LogTrace($"SetCheckboxValue: field {dwFieldID}"); + + if (this.Controls.TryGetControl(dwFieldID, FieldType.CheckBox, out var instance)) + { + instance.SetIsCheckedInternal(bChecked != 0); + return HRESULT.S_OK; + } + + this.logger.LogError($"SetCheckboxValue was incorrectly called on field {instance}"); + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "SetCheckboxValue failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.SetComboBoxSelectedValue(uint dwFieldID, uint dwSelectedItem) + { + try + { + this.logger.LogTrace($"SetComboBoxSelectedValue: field {dwFieldID}"); + + if (this.Controls.TryGetControl(dwFieldID, FieldType.ComboBox, out var instance)) + { + instance.SetComboboxSelectedItemIndexInternal((unchecked((int)dwSelectedItem))); + return HRESULT.S_OK; + } + + this.logger.LogError($"SetComboBoxSelectedValue was incorrectly called on field {instance}"); + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "SetComboBoxSelectedValue failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.CommandLinkClicked(uint dwFieldID) + { + try + { + this.logger.LogTrace($"CommandLinkClicked: field {dwFieldID}"); + + if (this.Controls.TryGetControl(dwFieldID, FieldType.CommandLink, out var instance)) + { + instance.OnClick?.Invoke(); + return HRESULT.S_OK; + } + + this.logger.LogError($"CommandLinkClicked was incorrectly called on field {instance}"); + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "CommandLinkClicked failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.GetSerialization(out SerializationResponse pcpgsr, out CredentialSerialization pcpcs, out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon) + { + pcpgsr = SerializationResponse.NoCredentialNotFinished; + pcpcs = default; + ppszOptionalStatusText = null; + pcpsiOptionalStatusIcon = StatusIcon.None; + + try + { + this.logger.LogTrace($"GetSerialization called"); + NativeSerializationResponse response = this.OnGetSerialization(); + + pcpgsr = response.SerializationResponse; + pcpcs = response.SerializedCredentials; + ppszOptionalStatusText = response.OptionalStatusText; + pcpsiOptionalStatusIcon = response.OptionalStatusIcon; + + + this.logger.LogTrace($"GetSerialization is returning {pcpgsr}, with auth provider {pcpcs.AuthenticationPackage}, status {pcpsiOptionalStatusIcon}: {ppszOptionalStatusText}"); + + return response.HResult; + } + catch (Exception ex) + { + ppszOptionalStatusText = "Unexpected error"; + pcpsiOptionalStatusIcon = StatusIcon.Error; + this.logger.LogError(ex, "GetSerialization failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential.ReportResult(int ntsStatus, int ntsSubstatus, out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon) + { + ppszOptionalStatusText = null; + pcpsiOptionalStatusIcon = StatusIcon.None; + + try + { + this.logger.LogTrace($"ReportResult"); + + this.OnLogonStatusReported(ntsStatus, ntsSubstatus, out ppszOptionalStatusText, out pcpsiOptionalStatusIcon); + + if (ppszOptionalStatusText == null && pcpsiOptionalStatusIcon == StatusIcon.None) + { + pcpsiOptionalStatusIcon = 0; + return HRESULT.E_NOTIMPL; + } + + return HRESULT.S_OK; + } + catch (Exception ex) + { + this.logger.LogError(ex, "ReportResult failed"); + return HRESULT.E_FAIL; + } + } + } +} diff --git a/src/Lithnet.CredentialProvider/CredentialProviderCredential1Tile.ICredentialProviderCredentialWithFieldOptions.cs b/src/Lithnet.CredentialProvider/CredentialProviderCredential1Tile.ICredentialProviderCredentialWithFieldOptions.cs new file mode 100644 index 0000000..c441d24 --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialProviderCredential1Tile.ICredentialProviderCredentialWithFieldOptions.cs @@ -0,0 +1,36 @@ +using System; +using Lithnet.CredentialProvider.Interop; +using Microsoft.Extensions.Logging; + +namespace Lithnet.CredentialProvider +{ + public abstract partial class CredentialProviderCredential1Tile : ICredentialProviderCredentialWithFieldOptions + { + int ICredentialProviderCredentialWithFieldOptions.GetFieldOptions(uint dwFieldID, out FieldOptions options) + { + options = FieldOptions.None; + + try + { + this.logger.LogTrace($"GetFieldOptions: field {dwFieldID}"); + + if (this.Controls.TryGetControl(dwFieldID, out var instance)) + { + options = instance.Options; + + this.logger.LogTrace($"GetFieldOptions on [{instance}] returning options {instance.Options}"); + return HRESULT.S_OK; + } + + this.logger.LogError($"GetFieldOptions failed to find a field match for {dwFieldID}"); + + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetFieldOptions failed"); + return HRESULT.E_FAIL; + } + } + } +} diff --git a/src/Lithnet.CredentialProvider/CredentialProviderCredential1Tile.cs b/src/Lithnet.CredentialProvider/CredentialProviderCredential1Tile.cs new file mode 100644 index 0000000..281d7a2 --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialProviderCredential1Tile.cs @@ -0,0 +1,254 @@ +using System; +using System.Runtime.InteropServices; +using Lithnet.CredentialProvider.Interop; +using Microsoft.Extensions.Logging; + +namespace Lithnet.CredentialProvider +{ + /// + /// Represents a 'v1' user credential tile that implements the minimum functionality required by the credential provider framework + /// + /// Inheriting from this class enables you to provide a v1 credential tile. V1 credential tiles were introduced in Windows Vista. These tiles are not personalized. See the Microsoft documentation on ICredentialProviderCredential for more information + public abstract partial class CredentialProviderCredential1Tile + { + private protected readonly ILogger logger; + + private protected ICredentialProviderCredentialEvents events; + private protected ICredentialProviderCredentialEvents2 events2; + + private protected ControlCollection controls; + + protected CredentialProviderCredential1Tile(CredentialProviderBase credentialProvider) + { + this.CredentialProvider = credentialProvider; + this.logger = CredentialProviderBase.LoggerFactory.CreateLogger(this.GetType()); + } + + internal CredentialProviderBase CredentialProvider { get; } + + /// + /// Gets a value indicating if this is a generic, as opposed to a personalized tile + /// + public virtual bool IsGenericTile => true; + + /// + /// Gets a value that indicates if this tile is currently selected by the user + /// + public bool IsSelected { get; private set; } + + /// + /// Gets a value that indicates if the user should be automatically logged on when the tile is selected. The tile must also have IsDefault set to true. + /// + public bool IsAutoLogon { get; set; } + + /// + /// Gets a value indicating if this should be the default time + /// + public bool IsDefault { get; set; } + + /// + /// Gets the current usage scenario + /// + public UsageScenario UsageScenario => this.CredentialProvider.UsageScenario; + + /// + /// Gets a list of controls assigned to this tile + /// + public ControlCollection Controls + { + get + { + if (this.controls == null) + { + this.controls = this.GenerateCredentialControls(); + } + + return this.controls; + } + } + + private ControlCollection GenerateCredentialControls() + { + ControlCollection list = new ControlCollection(this); + + foreach (var control in this.CredentialProvider.Controls) + { + list.Add(control.Clone()); + } + + list.Lock(); + return list; + } + + /// + /// Gets the HWND of the parent of the credential provider, and notifies LogonUI or CredUI that we need to create a Window + /// + /// A HWND to the parentobject + /// The method was called before the host has advised that is ready to rpovide events + /// The request to obtain the parent window HWND failed + public IntPtr CreateParentWindowHwnd() + { + if (this.events == null) + { + throw new InvalidOperationException("The Advise method has not yet been called by the host"); + } + + var result = this.events.OnCreatingWindow(out IntPtr phwndOwner); + if (result == HRESULT.S_OK) + { + return phwndOwner; + } + + throw new COMException("Unable to obtain parent window handle", result); + } + + /// + /// Indicates to the host that multiple updates need to be made to the fields, and that it should delay updating the UI until + /// + /// + public void BeginBulkFieldUpdate() + { + if (this.events2 == null) + { + throw new InvalidOperationException("The credential provider has not provided an ICredentialProviderCredentialEvents2 interface"); + } + + this.events2.BeginFieldUpdates(); + + } + + /// + /// Indicates to the host that the bulk update to fields has completed, and it can now update the UI according to the new values + /// + /// + + public void EndBulkFieldUpdate() + { + if (this.events2 == null) + { + throw new InvalidOperationException("The credential provider has not provided an ICredentialProviderCredentialEvents2 interface"); + } + + this.events2.EndFieldUpdates(); + } + + /// + /// Called after the tile has been initialized. Override this method to perform post-initialization actions. + /// + public virtual void Initialize() { } + + /// + /// Called when the user selects this tile + /// + protected virtual void OnSelected() { } + + /// + /// Called when a user deselects this tile + /// + protected virtual void OnDeselected() { } + + /// + /// Called just before credentials are serialized and returned to the host + /// + protected virtual void OnBeforeSerialize() { } + + /// + /// Constructs the credential set from tile for serialization + /// + /// Override this method, and provide either a or response. + /// + /// The credential set ready to be serialized and returned to LogonUI/CredUI + protected abstract CredentialResponseBase GetCredentials(); + + /// + /// This method is called when the is set to and the user clicks the submit button. If you are supporting this scenario, you should override this method, and perform the password change operation using the information in the tile controls. Return a object to indicate if the operation was successful or not. + /// + /// A object + protected virtual ChangePasswordResponse ChangePassword() + { + return null; + } + + /// + /// Called by LogonUI to translates a received error status code into the appropriate user-readable message. The Credential UI does not call this method. + /// + /// The NTSTATUS value that reflects the return value of the Winlogon call to LsaLogonUser. + /// The NTSTATUS value that reflects the value pointed to by the SubStatus parameter of LsaLogonUser when that function returns after being called by Winlogon. + /// Optional. The error message that will be displayed to the user. + /// Optional. An icon that will shown on the credential + protected virtual void OnLogonStatusReported(int ntStatusCode, int ntSubstatusCode, out string optionalStatusText, out StatusIcon optionalStatusIcon) + { + optionalStatusText = null; + optionalStatusIcon = StatusIcon.None; + } + + /// + /// Performs serialization of the credentials by first calling and then serializing the response for return to LogonUI/CredUI. You may override this method to perform the serialization yourself. In that case, will not be called and does not need to be implemented. + /// + /// returned an invalid response + protected virtual NativeSerializationResponse OnGetSerialization() + { + this.OnBeforeSerialize(); + + var response = new NativeSerializationResponse(); + + if (this.UsageScenario == UsageScenario.Logon || this.UsageScenario == UsageScenario.UnlockWorkstation || this.UsageScenario == UsageScenario.CredUI || this.UsageScenario == UsageScenario.PLAP) + { + var credentials = this.GetCredentials(); + + response.OptionalStatusText = credentials?.StatusText; + response.OptionalStatusIcon = credentials?.StatusIcon ?? StatusIcon.None; + + if (credentials?.IsSuccess != true) + { + response.SerializationResponse = SerializationResponse.NoCredentialNotFinished; + response.HResult = HRESULT.S_OK; + return response; + } + + CredentialSerializer.Logger = this.logger; + + if (credentials is CredentialResponseSecure s) + { + response.SerializedCredentials = CredentialSerializer.GenerateCredentialSerialization(credentials.Domain, credentials.Username, s.Password, this.UsageScenario == UsageScenario.UnlockWorkstation, this.CredentialProvider.CredentialProviderId); + } + else if (credentials is CredentialResponseInsecure i) + { + response.SerializedCredentials = CredentialSerializer.GenerateCredentialSerialization(credentials.Domain, credentials.Username, i.Password, this.UsageScenario == UsageScenario.UnlockWorkstation, this.CredentialProvider.CredentialProviderId); + } + else + { + throw new InvalidOperationException($"Unknown response type from {nameof(GetCredentials)}"); + } + + response.HResult = HRESULT.S_OK; + response.SerializationResponse = SerializationResponse.ReturnCredentialFinished; + return response; + } + else if (this.UsageScenario == UsageScenario.ChangePassword) + { + var result = this.ChangePassword(); + + if (result?.IsSuccess == true) + { + response.SerializationResponse = SerializationResponse.NoCredentialFinished; + response.HResult = HRESULT.S_OK; + } + else + { + response.SerializationResponse = SerializationResponse.NoCredentialNotFinished; + response.HResult = HRESULT.S_OK; + } + + response.OptionalStatusText = result?.StatusText; + response.OptionalStatusIcon = result?.StatusIcon ?? StatusIcon.None; + + return response; + } + + response.HResult = HRESULT.E_NOTIMPL; + return response; + } + + } +} diff --git a/src/Lithnet.CredentialProvider/CredentialProviderCredential2Tile.cs b/src/Lithnet.CredentialProvider/CredentialProviderCredential2Tile.cs new file mode 100644 index 0000000..5b49b2f --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialProviderCredential2Tile.cs @@ -0,0 +1,135 @@ +using System; +using Lithnet.CredentialProvider.Interop; +using Microsoft.Extensions.Logging; + +namespace Lithnet.CredentialProvider +{ + /// + /// Represents a 'v2' user credential tile that implements the functionality of , and includes support for personalized tile, where a single user tile is shown, with multiple logon options grouped within it. + /// + /// Inheriting from this class enables you to provide a v2 credential tile. V2 credential tiles were introduced in Windows 8. See the Microsoft documentation on ICredentialProviderCredential2 for more information + /// + public abstract class CredentialProviderCredential2Tile : CredentialProviderCredential1Tile, ICredentialProviderCredential2 + { + public CredentialProviderUser User { get; } + + public override bool IsGenericTile => this.User == null; + + public GenericTileDisplayMode GenericTileDisplayMode { get; set; } + + protected CredentialProviderCredential2Tile(CredentialProviderBase credentialProvider) : this(credentialProvider, null) { } + + protected CredentialProviderCredential2Tile(CredentialProviderBase credentialProvider, CredentialProviderUser user) : base(credentialProvider) + { + this.User = user; + } + + int ICredentialProviderCredential2.GetUserSid(out string sid) + { + sid = null; + + try + { + this.logger.LogTrace("GetUserSid"); + + if (this.IsGenericTile) + { + this.logger.LogTrace("GetUserSid: Tile is generic so returning no SID"); + return this.GenericTileDisplayMode == GenericTileDisplayMode.DisplayUnderOtherUser ? HRESULT.S_FALSE : HRESULT.E_NOTIMPL; + } + + return this.User.User.GetSid(out sid); + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetUserSid failed"); + return HRESULT.E_FAIL; + } + } + + int ICredentialProviderCredential2.SetSelected(out int pbAutoLogon) + { + return ((ICredentialProviderCredential)this).SetSelected(out pbAutoLogon); + } + + int ICredentialProviderCredential2.SetDeselected() + { + return ((ICredentialProviderCredential)this).SetDeselected(); + } + + int ICredentialProviderCredential2.GetFieldState(uint dwFieldID, out FieldState pcpfs, out FieldInteractiveState pcpfis) + { + return ((ICredentialProviderCredential)this).GetFieldState(dwFieldID, out pcpfs, out pcpfis); + } + + int ICredentialProviderCredential2.GetStringValue(uint dwFieldID, out IntPtr ppsz) + { + return ((ICredentialProviderCredential)this).GetStringValue(dwFieldID, out ppsz); + } + + int ICredentialProviderCredential2.GetBitmapValue(uint dwFieldID, out IntPtr phbmp) + { + return ((ICredentialProviderCredential)this).GetBitmapValue(dwFieldID, out phbmp); + } + + int ICredentialProviderCredential2.GetCheckboxValue(uint dwFieldID, out int pbChecked, out string ppszLabel) + { + return ((ICredentialProviderCredential)this).GetCheckboxValue(dwFieldID, out pbChecked, out ppszLabel); + } + + int ICredentialProviderCredential2.GetSubmitButtonValue(uint dwFieldID, out uint pdwAdjacentTo) + { + return ((ICredentialProviderCredential)this).GetSubmitButtonValue(dwFieldID, out pdwAdjacentTo); + } + + int ICredentialProviderCredential2.GetComboBoxValueCount(uint dwFieldID, out uint pcItems, out uint pdwSelectedItem) + { + return ((ICredentialProviderCredential)this).GetComboBoxValueCount(dwFieldID, out pcItems, out pdwSelectedItem); + } + + int ICredentialProviderCredential2.GetComboBoxValueAt(uint dwFieldID, uint dwItem, out string ppszItem) + { + return ((ICredentialProviderCredential)this).GetComboBoxValueAt(dwFieldID, dwItem, out ppszItem); + } + + int ICredentialProviderCredential2.SetCheckboxValue(uint dwFieldID, int bChecked) + { + return ((ICredentialProviderCredential)this).SetCheckboxValue(dwFieldID, bChecked); + } + + int ICredentialProviderCredential2.SetStringValue(uint dwFieldID, IntPtr psz) + { + return ((ICredentialProviderCredential)this).SetStringValue(dwFieldID, psz); + } + + int ICredentialProviderCredential2.CommandLinkClicked(uint dwFieldID) + { + return ((ICredentialProviderCredential)this).CommandLinkClicked(dwFieldID); + } + + int ICredentialProviderCredential2.SetComboBoxSelectedValue(uint dwFieldID, uint dwSelectedItem) + { + return ((ICredentialProviderCredential)this).SetComboBoxSelectedValue(dwFieldID, dwSelectedItem); + } + + int ICredentialProviderCredential2.GetSerialization(out SerializationResponse pcpgsr, out CredentialSerialization pcpcs, out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon) + { + return ((ICredentialProviderCredential)this).GetSerialization(out pcpgsr, out pcpcs, out ppszOptionalStatusText, out pcpsiOptionalStatusIcon); + } + + int ICredentialProviderCredential2.UnAdvise() + { + return ((ICredentialProviderCredential)this).UnAdvise(); + } + + int ICredentialProviderCredential2.Advise(ICredentialProviderCredentialEvents pcpce) + { + return ((ICredentialProviderCredential)this).Advise(pcpce); + } + + int ICredentialProviderCredential2.ReportResult(int ntsStatus, int ntsSubstatus, out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon) + { + return ((ICredentialProviderCredential)this).ReportResult(ntsStatus, ntsSubstatus, out ppszOptionalStatusText, out pcpsiOptionalStatusIcon); + } + } +} diff --git a/src/Lithnet.CredentialProvider/CredentialProviderCredential3Tile.cs b/src/Lithnet.CredentialProvider/CredentialProviderCredential3Tile.cs new file mode 100644 index 0000000..f77dc02 --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialProviderCredential3Tile.cs @@ -0,0 +1,135 @@ +using System; +using Lithnet.CredentialProvider.Interop; +using Microsoft.Extensions.Logging; + +namespace Lithnet.CredentialProvider +{ + /// + /// Represents a user credential tile that implements the functionality of and , but includes support for dynamically updating bitmap images. + /// + /// This interface is public, but undocumented by Microsoft. It is recommended to use tiles unless this specific functionality is needed + public abstract class CredentialProviderCredential3Tile : CredentialProviderCredential2Tile, ICredentialProviderCredential3 + { + protected CredentialProviderCredential3Tile(CredentialProviderBase credentialProvider) : this(credentialProvider, null) { } + + protected CredentialProviderCredential3Tile(CredentialProviderBase credentialProvider, CredentialProviderUser user) : base(credentialProvider, user) { } + + int ICredentialProviderCredential3.GetBitmapBufferValue(uint dwFieldID, out uint pImageBufferSize, out IntPtr ppImageBuffer) + { + this.logger.LogTrace($"Called GetBitmapBufferValue {dwFieldID}"); + + ppImageBuffer = IntPtr.Zero; + pImageBufferSize = 0; + + try + { + this.logger.LogTrace($"GetBitmapBufferValue: field {dwFieldID}"); + + if (this.Controls.TryGetControl(dwFieldID, FieldType.TileImage, out var instance)) + { + var hbitmap = instance.GetBitmapBuffer(out pImageBufferSize); + return HRESULT.S_OK; + } + + this.logger.LogError($"GetBitmapValue was incorrectly called on field {instance}"); + return HRESULT.E_FAIL; + } + catch (Exception ex) + { + this.logger.LogError(ex, "GetBitmapValue failed"); + return HRESULT.E_FAIL; + } + } + + /// + int ICredentialProviderCredential3.GetUserSid(out string sid) + { + return ((ICredentialProviderCredential2)this).GetUserSid(out sid); + } + + /// + int ICredentialProviderCredential3.SetSelected(out int pbAutoLogon) + { + return ((ICredentialProviderCredential)this).SetSelected(out pbAutoLogon); + } + + /// + + int ICredentialProviderCredential3.SetDeselected() + { + return ((ICredentialProviderCredential)this).SetDeselected(); + } + + int ICredentialProviderCredential3.GetFieldState(uint dwFieldID, out FieldState pcpfs, out FieldInteractiveState pcpfis) + { + return ((ICredentialProviderCredential)this).GetFieldState(dwFieldID, out pcpfs, out pcpfis); + } + + int ICredentialProviderCredential3.GetStringValue(uint dwFieldID, out IntPtr ppsz) + { + return ((ICredentialProviderCredential)this).GetStringValue(dwFieldID, out ppsz); + } + + int ICredentialProviderCredential3.GetBitmapValue(uint dwFieldID, out IntPtr phbmp) + { + return ((ICredentialProviderCredential)this).GetBitmapValue(dwFieldID, out phbmp); + } + + int ICredentialProviderCredential3.GetCheckboxValue(uint dwFieldID, out int pbChecked, out string ppszLabel) + { + return ((ICredentialProviderCredential)this).GetCheckboxValue(dwFieldID, out pbChecked, out ppszLabel); + } + + int ICredentialProviderCredential3.GetSubmitButtonValue(uint dwFieldID, out uint pdwAdjacentTo) + { + return ((ICredentialProviderCredential)this).GetSubmitButtonValue(dwFieldID, out pdwAdjacentTo); + } + + int ICredentialProviderCredential3.GetComboBoxValueCount(uint dwFieldID, out uint pcItems, out uint pdwSelectedItem) + { + return ((ICredentialProviderCredential)this).GetComboBoxValueCount(dwFieldID, out pcItems, out pdwSelectedItem); + } + + int ICredentialProviderCredential3.GetComboBoxValueAt(uint dwFieldID, uint dwItem, out string ppszItem) + { + return ((ICredentialProviderCredential)this).GetComboBoxValueAt(dwFieldID, dwItem, out ppszItem); + } + + int ICredentialProviderCredential3.SetCheckboxValue(uint dwFieldID, int bChecked) + { + return ((ICredentialProviderCredential)this).SetCheckboxValue(dwFieldID, bChecked); + } + + int ICredentialProviderCredential3.SetStringValue(uint dwFieldID, IntPtr psz) + { + return ((ICredentialProviderCredential)this).SetStringValue(dwFieldID, psz); + } + + int ICredentialProviderCredential3.CommandLinkClicked(uint dwFieldID) + { + return ((ICredentialProviderCredential)this).CommandLinkClicked(dwFieldID); + } + + int ICredentialProviderCredential3.SetComboBoxSelectedValue(uint dwFieldID, uint dwSelectedItem) + { + return ((ICredentialProviderCredential)this).SetComboBoxSelectedValue(dwFieldID, dwSelectedItem); + } + + int ICredentialProviderCredential3.GetSerialization(out SerializationResponse pcpgsr, out CredentialSerialization pcpcs, out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon) + { + return ((ICredentialProviderCredential)this).GetSerialization(out pcpgsr, out pcpcs, out ppszOptionalStatusText, out pcpsiOptionalStatusIcon); + } + int ICredentialProviderCredential3.UnAdvise() + { + return ((ICredentialProviderCredential)this).UnAdvise(); + } + int ICredentialProviderCredential3.Advise(ICredentialProviderCredentialEvents pcpce) + { + return ((ICredentialProviderCredential)this).Advise(pcpce); + } + int ICredentialProviderCredential3.ReportResult(int ntsStatus, int ntsSubstatus, out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon) + { + return ((ICredentialProviderCredential)this).ReportResult(ntsStatus, ntsSubstatus, out ppszOptionalStatusText, out pcpsiOptionalStatusIcon); + } + } +} diff --git a/src/Lithnet.CredentialProvider/CredentialProviderUser.cs b/src/Lithnet.CredentialProvider/CredentialProviderUser.cs new file mode 100644 index 0000000..eef8b72 --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialProviderUser.cs @@ -0,0 +1,151 @@ +using System; +using System.Runtime.InteropServices; +using Lithnet.CredentialProvider.Interop; +using Microsoft.Extensions.Logging; + +namespace Lithnet.CredentialProvider +{ + /// + /// Represents a user provided by the credential framework + /// + public class CredentialProviderUser + { + internal readonly ICredentialProviderUser User; + private readonly ILogger logger; + private string qualifiedUserName; + private string sid; + private string userName; + private string displayName; + private string logonStatus; + private string providerId; + + internal CredentialProviderUser(ICredentialProviderUser user) + { + this.User = user; + this.logger = CredentialProviderBase.LoggerFactory.CreateLogger(); + } + + /// + /// Gets the qualified username of the user. This name is used to pack an authentication buffer + /// + public string QualifiedUserName + { + get + { + if (this.qualifiedUserName == null) + { + this.qualifiedUserName = this.TryGetValueOrDefault(PropertyKeys.PKEY_Identity_QualifiedUserName); + } + + return this.qualifiedUserName; + } + } + + /// + /// Gets the SID of the user + /// + public string Sid + { + get + { + if (this.sid == null) + { + this.sid = this.TryGetValueOrDefault(PropertyKeys.PKEY_Identity_PrimarySid); + } + + return this.sid; + } + } + + /// + /// Gets the username of the user + /// + public string UserName + { + get + { + if (this.userName == null) + { + this.userName = this.TryGetValueOrDefault(PropertyKeys.PKEY_Identity_UserName); + } + + return this.userName; + } + } + + /// + /// Gets the display name of the user + /// + public string DisplayName + { + get + { + if (this.displayName == null) + { + this.displayName = this.TryGetValueOrDefault(PropertyKeys.PKEY_Identity_DisplayName); + } + + return this.displayName; + } + } + + /// + /// Gets the logon status of the user. Does not apply to the CredUI scenario. + /// + /// For example, "Signed-in", "Locked" + public string LogonStatus + { + get + { + if (this.logonStatus == null) + { + this.logonStatus = this.TryGetValueOrDefault(PropertyKeys.PKEY_Identity_LogonStatusString); + } + + return this.logonStatus; + } + } + + /// + /// The user's provider ID + /// + public string ProviderID + { + get + { + if (this.providerId == null) + { + this.providerId = this.TryGetValueOrDefault(PropertyKeys.PKEY_Identity_ProviderID); + } + + return this.providerId; + } + } + + private string GetValue(PropertyKey key) + { + var result = this.User.GetStringValue(key, out var value); + + if (result != HRESULT.S_OK) + { + throw new COMException("Could not get user SID", result); + } + + return value; + } + + private string TryGetValueOrDefault(PropertyKey key) + { + try + { + return this.GetValue(key); + } + catch (Exception ex) + { + this.logger.LogError(ex, $"Unable to get property value for key {key.PropertyID}"); + } + + return null; + } + } +} diff --git a/src/Lithnet.CredentialProvider/CredentialResponse.cs b/src/Lithnet.CredentialProvider/CredentialResponse.cs new file mode 100644 index 0000000..c366f77 --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialResponse.cs @@ -0,0 +1,33 @@ +namespace Lithnet.CredentialProvider +{ + /// + /// A base class used to provide credentials for serialization + /// + public abstract class CredentialResponseBase + { + /// + /// Gets or sets a value indicating if the credentials were sucessfully obtained + /// + public bool IsSuccess { get; set; } + + /// + /// An optional status icon + /// + public StatusIcon StatusIcon { get; set; } + + /// + /// An optional status message describing any errors that occurred + /// + public string StatusText { get; set; } + + /// + /// The domain of the user who's credentials are to be serialized + /// + public string Domain { get; set; } + + /// + /// The username of the user who's credentials are to be serialized + /// + public string Username { get; set; } + } +} diff --git a/src/Lithnet.CredentialProvider/CredentialResponseInsecure.cs b/src/Lithnet.CredentialProvider/CredentialResponseInsecure.cs new file mode 100644 index 0000000..6025593 --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialResponseInsecure.cs @@ -0,0 +1,13 @@ +namespace Lithnet.CredentialProvider +{ + /// + /// A representation of a set of credentials to serialize back to LogonUI/CredUI. Consider using the class, which uses a SecureString for the password. + /// + public class CredentialResponseInsecure : CredentialResponseBase + { + /// + /// The plain-text password of the user who's credentials are to be serialized + /// + public string Password { get; set; } + } +} diff --git a/src/Lithnet.CredentialProvider/CredentialResponseSecure.cs b/src/Lithnet.CredentialProvider/CredentialResponseSecure.cs new file mode 100644 index 0000000..a0ef4a9 --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialResponseSecure.cs @@ -0,0 +1,15 @@ +using System.Security; + +namespace Lithnet.CredentialProvider +{ + /// + /// A representation of a set of credentials to serialize back to LogonUI/CredUI. + /// + public class CredentialResponseSecure : CredentialResponseBase + { + /// + /// The password of the user who's credentials are to be serialized + /// + public SecureString Password { get; set; } + } +} diff --git a/src/Lithnet.CredentialProvider/CredentialSerialization.cs b/src/Lithnet.CredentialProvider/CredentialSerialization.cs new file mode 100644 index 0000000..7035b81 --- /dev/null +++ b/src/Lithnet.CredentialProvider/CredentialSerialization.cs @@ -0,0 +1,32 @@ +using System; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider +{ + /// + /// A native credential serialization structure used to pass logon information back to LogonUI/CredUI + /// + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct CredentialSerialization + { + /// + /// The unique identifier of the authentication package. This parameter is required when calling LsaLogonUser. In a Credential UI scenario, this value is set before a serialization is sent through SetSerialization. This is the same as the authentication package value returned by LsaLookupAuthenticationPackage. Content providers can use this parameter to determine if they are able to return credentials for this authentication package. Developers who write their own authentication package may supply their own value. + /// + public uint AuthenticationPackage; + + /// + /// The CLSID of the credential provider. Credential providers assign their own CLSID to this member during serialization. Credential UI ignores this member. + /// + public Guid ProviderClassGuid; + + /// + /// The size, in bytes, of the credential pointed to by . + /// + public uint SerializationSize; + + /// + /// A pointer to an array of bytes containing serialized credential information. The exact format of this data depends on the authentication package targeted by a credential provider. + /// + public IntPtr SerializationData; + } +} diff --git a/src/Lithnet.CredentialProvider/Enums/CredUIWinFlags.cs b/src/Lithnet.CredentialProvider/Enums/CredUIWinFlags.cs new file mode 100644 index 0000000..182f8ad --- /dev/null +++ b/src/Lithnet.CredentialProvider/Enums/CredUIWinFlags.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lithnet.CredentialProvider +{ + [Flags] + public enum CredUIWinFlags + { + /// + /// The caller is requesting that the credential provider return the user name and password in plain text. + /// This value cannot be combined with SECURE_PROMPT. + /// + CREDUIWIN_GENERIC = 0x1, + /// + /// The Save check box is displayed in the dialog box. + /// + CREDUIWIN_CHECKBOX = 0x2, + /// + /// Only credential providers that support the authentication package specified by the authPackage parameter should be enumerated. + /// This value cannot be combined with CREDUIWIN_IN_CRED_ONLY. + /// + CREDUIWIN_AUTHPACKAGE_ONLY = 0x10, + /// + /// Only the credentials specified by the InAuthBuffer parameter for the authentication package specified by the authPackage parameter should be enumerated. + /// If this flag is set, and the InAuthBuffer parameter is NULL, the function fails. + /// This value cannot be combined with CREDUIWIN_AUTHPACKAGE_ONLY. + /// + CREDUIWIN_IN_CRED_ONLY = 0x20, + /// + /// Credential providers should enumerate only administrators. This value is intended for User Account Control (UAC) purposes only. We recommend that external callers not set this flag. + /// + CREDUIWIN_ENUMERATE_ADMINS = 0x100, + /// + /// Only the incoming credentials for the authentication package specified by the authPackage parameter should be enumerated. + /// + CREDUIWIN_ENUMERATE_CURRENT_USER = 0x200, + /// + /// The credential dialog box should be displayed on the secure desktop. This value cannot be combined with CREDUIWIN_GENERIC. + /// Windows Vista: This value is not supported until Windows Vista with SP1. + /// + CREDUIWIN_SECURE_PROMPT = 0x1000, + /// + /// The credential provider should align the credential BLOB pointed to by the refOutAuthBuffer parameter to a 32-bit boundary, even if the provider is running on a 64-bit system. + /// + CREDUIWIN_PACK_32_WOW = 0x10000000, + } +} diff --git a/src/Lithnet.CredentialProvider/Enums/FieldInteractiveState.cs b/src/Lithnet.CredentialProvider/Enums/FieldInteractiveState.cs new file mode 100644 index 0000000..d608b20 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Enums/FieldInteractiveState.cs @@ -0,0 +1,28 @@ +namespace Lithnet.CredentialProvider +{ + /// + /// Describes the state of a field and how it a user can interact with it. Fields can be displayed by a credential provider in a variety of different interactive states. + /// + public enum FieldInteractiveState + { + /// + /// The field can be edited if the field type supports editing. It also contains none of the other available interactive states. + /// + None, + + /// + /// Reserved and not used. + /// + ReadOnly, + + /// + /// The field is disabled. The user can see it but not interact with it. This support was added starting with Windows 10. + /// + Disabled, + + /// + /// Credential providers use this field interactive state to indicate that the field should receive initial keyboard focus. This interactive state may not be specified for field types that the user cannot edit. If several editable fields specify this state, the last of them based on dwIndex order receives focus. On systems before Windows 10, it was the first of editable fields based on dwIndex order. This field interactive state is obeyed only during initial enumeration. + /// + Focused + } +} diff --git a/src/Lithnet.CredentialProvider/Enums/FieldOptions.cs b/src/Lithnet.CredentialProvider/Enums/FieldOptions.cs new file mode 100644 index 0000000..9743218 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Enums/FieldOptions.cs @@ -0,0 +1,41 @@ +using System; + +namespace Lithnet.CredentialProvider +{ + /// + /// Provides customization options for a single field in a logon or credential UI + /// + [Flags] + public enum FieldOptions + { + /// + /// Default. Don't show the "password reveal" glyph, and use the standard on-screen keyboard layout. + /// + None = 0, + + /// + /// Display the "password reveal" glyph in a password entry box. When this glyph is held down by the user, the entry in the password box is shown in plain text. The glyph is shown here: + /// + PasswordReveal = 1, + + /// + /// The field will contain an e-mail address. The on-screen keyboard should be optimized for that input (showing the .com and @ keys on the primary keyboard layout). This option is used with Microsoft account credentials. + /// + Email = 2, + + /// + /// When enabled, the touch keyboard will be automatically invoked. This should be set only on the CPFG_CREDENTIAL_PROVIDER_LOGO field. + /// + TouchKeyboardAutoInvoke = 4, + + /// + /// The field will only allow numerals to be entered. The on-screen keyboard should be optimized for that input (showing only a number keypad on the primary keyboard layout). This should be set only on the CPFT_PASSWORD_TEXT field + /// + NumbersOnly = 8, + + /// + /// Show the English keyboard. + /// + ShowEnglishKeyboard = 16 + } +} diff --git a/src/Lithnet.CredentialProvider/Enums/FieldState.cs b/src/Lithnet.CredentialProvider/Enums/FieldState.cs new file mode 100644 index 0000000..59bc0ee --- /dev/null +++ b/src/Lithnet.CredentialProvider/Enums/FieldState.cs @@ -0,0 +1,28 @@ +namespace Lithnet.CredentialProvider +{ + /// + /// Specifies the state of a single field in the Credential UI + /// + public enum FieldState + { + /// + /// Do not show the field in any state. One example of this would be a password edit control that should not be displayed until the user authenticates a thumb print. Until the thumb print has been authenticated, the state of the password field would be CPFS_HIDDEN. + /// + Hidden, + + /// + /// Show the field when in the selected state. + /// + DisplayInSelectedTile, + + /// + /// Show the field when in the deselected state. This value is only valid for a UsageScenario set to CredUI. + /// + DisplayInDeselectedTile, + + /// + /// Show the field both when the credential tile is selected and when it is not selected. + /// + DisplayInBoth + } +} diff --git a/src/Lithnet.CredentialProvider/Enums/GenericTileDisplayMode.cs b/src/Lithnet.CredentialProvider/Enums/GenericTileDisplayMode.cs new file mode 100644 index 0000000..cf1519d --- /dev/null +++ b/src/Lithnet.CredentialProvider/Enums/GenericTileDisplayMode.cs @@ -0,0 +1,26 @@ +namespace Lithnet.CredentialProvider +{ + /// + /// Specifies how a generic tile should be dispalyed in LogonUI + /// + public enum GenericTileDisplayMode + { + /// + /// Specifies that the generic tile should be displayed as a logon provider under the generic 'Other User' tile. + /// + /// + /// This applies only to scenarios involving LogonUI. This value is ignored for CredUI. + /// This scenario is only supported in Windows 8 and above. + /// + DisplayUnderOtherUser = 0, + + /// + /// Specifies that the generic tile should be displayed as it's own dedicated credential tile. Note this applies to LogonUI scenarios only. + /// + /// + /// This applies only to scenarios involving LogonUI. This value is ignored for CredUI. + /// Selecting this option emulates the behaviour of a pre-Windows 8 credential provider. + /// + DisplayAsDedicatedTile = 1 + } +} diff --git a/src/Lithnet.CredentialProvider/Enums/SerializationResponse.cs b/src/Lithnet.CredentialProvider/Enums/SerializationResponse.cs new file mode 100644 index 0000000..d6a6927 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Enums/SerializationResponse.cs @@ -0,0 +1,25 @@ +namespace Lithnet.CredentialProvider +{ + public enum SerializationResponse + { + /// + ///No credential was serialized because more information is needed. One example of this would be if a credential requires both a PIN and an answer to a secret question, but the user has only provided the PIN. This signals the caller should be given a chance to alter its response. + /// + NoCredentialNotFinished, + + /// + /// The credential provider has not serialized a credential but has completed its work. This response has multiple meanings. It can mean that no credential was serialized and that the user should not try again. This response can also mean that no credential was submitted but the credential's work is complete. For example, in the Change Password scenario, this response implies success. + /// + NoCredentialFinished, + + /// + /// A credential was serialized. This response implies that a serialization structure was passed back. + /// + ReturnCredentialFinished, + + /// + /// The credential provider has not serialized a credential, but has completed its work. The difference between this value and is that this flag will force the logon UI to return, which will call UnAdvise for all the credential providers. + /// + ReturnNoCredentialFinished + } +} diff --git a/src/Lithnet.CredentialProvider/Enums/StatusIcon.cs b/src/Lithnet.CredentialProvider/Enums/StatusIcon.cs new file mode 100644 index 0000000..5b4291b --- /dev/null +++ b/src/Lithnet.CredentialProvider/Enums/StatusIcon.cs @@ -0,0 +1,32 @@ +namespace Lithnet.CredentialProvider +{ + /// + /// Indicates which status icon should be displayed. + /// + /// + /// CREDENTIAL_PROVIDER_STATUS_ICON is not used starting in Windows 10. + /// As part of ReportResult, a credential provider may specify a status icon to display.It is important to not that only Logon UI calls ReportResult. Credential UI does not. + /// + public enum StatusIcon + { + /// + /// No icon indicated. + /// + None, + + /// + /// Display the error icon. + /// + Error, + + /// + /// Display the warning icon. + /// + Warning, + + /// + /// Reserved + /// + Success + } +} diff --git a/src/Lithnet.CredentialProvider/Enums/UsageScenario.cs b/src/Lithnet.CredentialProvider/Enums/UsageScenario.cs new file mode 100644 index 0000000..9f43157 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Enums/UsageScenario.cs @@ -0,0 +1,43 @@ +namespace Lithnet.CredentialProvider +{ + /// + /// Declares the scenarios in which a credential provider is supported. A credential provider usage scenario (CPUS) enables the credential provider to provide distinct enumeration behavior and UI field setup across scenarios. + /// + public enum UsageScenario + { + /// + /// No usage scenario has been set for the Credential Provider + /// + Invalid, + + /// + /// Workstation logon or unlock. Credential providers that implement this scenario should be prepared to serialize credentials to the local authority for authentication. Starting in Windows 10, the CPUS_LOGON and CPUS_UNLOCK_WORKSTATION user scenarios have been combined. + /// + Logon, + + /// + /// Workstation unlock. Credential providers that implement this scenario should be prepared to serialize credentials to the local authority for authentication. These credential providers also need to enumerate the currently logged-in user as the default tile. + /// + /// Starting in Windows 10, the CPUS_LOGON and CPUS_UNLOCK_WORKSTATION user scenarios have been combined. This enables the system to support multiple users logging into a machine without creating and switching sessions unnecessarily. Any user on the machine can log into it once it has been locked without needing to back out of a current session and create a new one. Because of this, CPUS_LOGON can be used both for logging onto a system or when a workstation is unlocked. However, CPUS_LOGON cannot be used in all cases. Because of policy restrictions imposed by various systems, sometimes it is necessary for the user scenario to be CPUS_UNLOCK_WORKSTATION. Your credential provider should be robust enough to create the appropriate credential structure based on the scenario given to it. Windows will request the appropriate user scenario based on the situation. Some of the factors that impact whether or not a CPUS_UNLOCK_WORKSTATION scenario must be used include the following. Note that this is just a subset of possibilities. + /// - The operating system of the device. + /// - Whether this is a console or remote session. + /// - Group policies such as hiding entry points for fast user switching, or interactive logon that does not display the user's last name. + /// + UnlockWorkstation, + + /// + /// Password change. This enables a credential provider to enumerate tiles in response to a user's request to change the password. Do not implement this scenario if you do not require some secret information from the user such as a password or PIN. These credential providers also need to enumerate the currently logged-in user as the default tile. + /// + ChangePassword, + + /// + /// Credential UI. This scenario enables you to use credentials serialized by the credential provider to be used as authentication on remote machines. This is also the scenario used for over-the-shoulder prompting in User Access Control. This scenario uses a different instance of the credential provider than the one used for , , and , so the state of the credential provider cannot be maintained across the different scenarios. + /// + CredUI, + + /// + /// Pre-Logon-Access Provider. + /// + PLAP + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/AccountOptions.cs b/src/Lithnet.CredentialProvider/Interop/AccountOptions.cs new file mode 100644 index 0000000..13f10ad --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/AccountOptions.cs @@ -0,0 +1,9 @@ +namespace Lithnet.CredentialProvider.Interop +{ + internal enum AccountOptions + { + None, + EmptyLocal, + EmptyConnected + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/CredProviderConstants.cs b/src/Lithnet.CredentialProvider/Interop/CredProviderConstants.cs new file mode 100644 index 0000000..f753d2a --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/CredProviderConstants.cs @@ -0,0 +1,11 @@ +namespace Lithnet.CredentialProvider.Interop +{ + internal static class CredProviderConstants + { + public const string CPFG_CREDENTIAL_PROVIDER_LOGO = "2d837775-f6cd-464e-a745-482fd0b47493"; + public const string CPFG_CREDENTIAL_PROVIDER_LABEL = "286bbff3-bad4-438f-b007-79b7267c3d48"; + public const string MICROSOFT_KERBEROS_NAME_A = "Kerberos"; + public const string NEGOSSP_NAME_A = "Negotiate"; + public const string MSV1_0_PACKAGE_NAME = "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0"; + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/CredentialSerializer.cs b/src/Lithnet.CredentialProvider/Interop/CredentialSerializer.cs new file mode 100644 index 0000000..19237c6 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/CredentialSerializer.cs @@ -0,0 +1,152 @@ +using System; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Lithnet.CredentialProvider.Interop +{ + internal static class CredentialSerializer + { + internal static ILogger Logger { get; set; } = NullLogger.Instance; + + public static CredentialSerialization GenerateCredentialSerialization(string domain, string username, SecureString password, bool isWorkstationUnlock, Guid providerId) + { + var authPackage = PInvoke.LookupAuthenticationPackage(CredProviderConstants.NEGOSSP_NAME_A); + var pData = SerializeKerbLogon(domain, username, password, isWorkstationUnlock ? KerbLogonSubmitType.WorkstationUnlockLogon : KerbLogonSubmitType.InteractiveLogon, out int size); + + Logger.LogTrace($"0x{pData.ToString("X16")} - Serializer: Password got packed into "); + + return new CredentialSerialization() + { + AuthenticationPackage = authPackage, + SerializationData = pData, + ProviderClassGuid = providerId, + SerializationSize = (uint)size + }; + } + + public static CredentialSerialization GenerateCredentialSerialization(string domain, string username, string password, bool isWorkstationUnlock, Guid providerId) + { + var authPackage = PInvoke.LookupAuthenticationPackage(CredProviderConstants.NEGOSSP_NAME_A); + var pData = SerializeKerbLogon(domain, username, password, isWorkstationUnlock ? KerbLogonSubmitType.WorkstationUnlockLogon : KerbLogonSubmitType.InteractiveLogon, out int size); + + Logger.LogTrace($"0x{pData.ToString("X16")}: Password got packed"); + + return new CredentialSerialization() + { + AuthenticationPackage = authPackage, + SerializationData = pData, + ProviderClassGuid = providerId, + SerializationSize = (uint)size + }; + } + + private static unsafe IntPtr SerializeKerbLogon(string domain, string username, string password, KerbLogonSubmitType type, out int size) + { + size = sizeof(KerberosInteractiveUnlockLogon) + + Encoding.Unicode.GetMaxByteCount(domain.Length) + + Encoding.Unicode.GetMaxByteCount(username.Length) + + Encoding.Unicode.GetMaxByteCount(password.Length); + + IntPtr pBuffer = Marshal.AllocCoTaskMem(size); + byte* buffer = (byte*)pBuffer; + + var logon = (KerberosInteractiveUnlockLogon*)buffer; + + logon->SubmitType = type; + logon->LogonDomainName.MaxLength = (ushort)Encoding.Unicode.GetMaxByteCount(domain.Length); + logon->LogonDomainName.Length = (ushort)(domain.Length * sizeof(char)); + logon->LogonDomainName.Buffer = (IntPtr)sizeof(KerberosInteractiveUnlockLogon); + fixed (char* domainBuffer = domain) + { + Encoding.Unicode.GetBytes(domainBuffer, domain.Length, + buffer + logon->LogonDomainName.Buffer.ToInt64(), logon->LogonDomainName.Length); + } + + logon->Username.Length = (ushort)(username.Length * sizeof(char)); + logon->Username.MaxLength = (ushort)Encoding.Unicode.GetMaxByteCount(username.Length); + logon->Username.Buffer = (IntPtr)(sizeof(KerberosInteractiveUnlockLogon) + logon->LogonDomainName.MaxLength); + fixed (char* usernameBuffer = username) + { + Encoding.Unicode.GetBytes(usernameBuffer, username.Length, + buffer + logon->Username.Buffer.ToInt64(), logon->Username.Length); + } + + logon->Password.MaxLength = (ushort)Encoding.Unicode.GetMaxByteCount(password.Length); + logon->Password.Length = (ushort)(password.Length * sizeof(char)); + logon->Password.Buffer = (IntPtr)(sizeof(KerberosInteractiveUnlockLogon) + logon->LogonDomainName.MaxLength + logon->Username.MaxLength); + fixed (char* passwordBuffer = password) + { + Encoding.Unicode.GetBytes(passwordBuffer, password.Length, + buffer + logon->Password.Buffer.ToInt64(), logon->Password.Length); + } + + return pBuffer; + } + + private static unsafe IntPtr SerializeKerbLogon(string domain, string username, SecureString password, KerbLogonSubmitType type, out int size) + { + size = sizeof(KerberosInteractiveUnlockLogon) + + Encoding.Unicode.GetMaxByteCount(domain.Length) + + Encoding.Unicode.GetMaxByteCount(username.Length) + + Encoding.Unicode.GetMaxByteCount(password.Length); + + + IntPtr pBuffer = Marshal.AllocCoTaskMem(size); + byte* buffer = (byte*)pBuffer; + + var logon = (KerberosInteractiveUnlockLogon*)buffer; + + logon->SubmitType = type; + logon->LogonDomainName.MaxLength = (ushort)Encoding.Unicode.GetMaxByteCount(domain.Length); + logon->LogonDomainName.Length = (ushort)(domain.Length * sizeof(char)); + logon->LogonDomainName.Buffer = (IntPtr)sizeof(KerberosInteractiveUnlockLogon); + fixed (char* domainBuffer = domain) + { + Encoding.Unicode.GetBytes(domainBuffer, domain.Length, + buffer + logon->LogonDomainName.Buffer.ToInt64(), logon->LogonDomainName.Length); + } + + logon->Username.Length = (ushort)(username.Length * sizeof(char)); + logon->Username.MaxLength = (ushort)Encoding.Unicode.GetMaxByteCount(username.Length); + logon->Username.Buffer = (IntPtr)(sizeof(KerberosInteractiveUnlockLogon) + logon->LogonDomainName.MaxLength); + fixed (char* usernameBuffer = username) + { + Encoding.Unicode.GetBytes(usernameBuffer, username.Length, + buffer + logon->Username.Buffer.ToInt64(), logon->Username.Length); + } + + logon->Password.MaxLength = (ushort)Encoding.Unicode.GetMaxByteCount(password.Length); + logon->Password.Length = (ushort)(password.Length * sizeof(char)); + logon->Password.Buffer = (IntPtr)(sizeof(KerberosInteractiveUnlockLogon) + logon->LogonDomainName.MaxLength + logon->Username.MaxLength); + + IntPtr buff = IntPtr.Zero; + + try + { + buff = Marshal.SecureStringToCoTaskMemUnicode(password); + Logger.LogTrace($"0x{buff.ToString("X16")} - Serializer: Unprotected password"); + + IntPtr targetPositionToCopyTo = (IntPtr)(buffer + logon->Password.Buffer.ToInt64()); + + Buffer.MemoryCopy(buff.ToPointer(), targetPositionToCopyTo.ToPointer(), logon->Password.Length, password.Length * sizeof(char)); + + Logger.LogTrace($"0x{targetPositionToCopyTo.ToString("X16")} - Serializer: Copied unprotected password into LSA string buffer"); + } + finally + { + if (buff != IntPtr.Zero) + { + Marshal.ZeroFreeCoTaskMemUnicode(buff); + Logger.LogTrace($"0x{buff.ToString("X16")} - Serializer: Freed Unprotected password"); + } + } + + Logger.LogTrace($"0x{((IntPtr)buffer).ToString("X16")} - Serializer: Put password"); + + return pBuffer; + } + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/FieldDescriptor.cs b/src/Lithnet.CredentialProvider/Interop/FieldDescriptor.cs new file mode 100644 index 0000000..0380e34 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/FieldDescriptor.cs @@ -0,0 +1,18 @@ +using System; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct FieldDescriptor + { + public uint FieldID; + + public FieldType FieldType; + + [MarshalAs(UnmanagedType.LPWStr)] + public string Label; + + public Guid FieldTypeGuid; + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/FieldType.cs b/src/Lithnet.CredentialProvider/Interop/FieldType.cs new file mode 100644 index 0000000..e0a388e --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/FieldType.cs @@ -0,0 +1,16 @@ +namespace Lithnet.CredentialProvider.Interop +{ + internal enum FieldType + { + Invalid, + LargeText, + SmallText, + CommandLink, + EditText, + PasswordText, + TileImage, + CheckBox, + ComboBox, + Submit + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/HResult.cs b/src/Lithnet.CredentialProvider/Interop/HResult.cs new file mode 100644 index 0000000..249e76d --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/HResult.cs @@ -0,0 +1,21 @@ +namespace Lithnet.CredentialProvider.Interop +{ + internal static class HRESULT + { + public const int S_OK = 0x00000000; + public const int S_FALSE = 0x00000001; + + public const int E_ACCESSDENIED = unchecked((int)0x80070005); + public const int E_FAIL = unchecked((int)0x80004005); + public const int E_INVALIDARG = unchecked((int)0x80070057); + public const int E_OUTOFMEMORY = unchecked((int)0x8007000E); + public const int E_POINTER = unchecked((int)0x80004003); + public const int E_UNEXPECTED = unchecked((int)0x8000FFFF); + + + public const int E_ABORT = unchecked((int)0x80004004); + public const int E_HANDLE = unchecked((int)0x80070006); + public const int E_NOINTERFACE = unchecked((int)0x80004002); + public const int E_NOTIMPL = unchecked((int)0x80004001); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/InnerPropertyValue.cs b/src/Lithnet.CredentialProvider/Interop/InnerPropertyValue.cs new file mode 100644 index 0000000..fe2f49f --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/InnerPropertyValue.cs @@ -0,0 +1,149 @@ +using System; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [StructLayout(LayoutKind.Explicit, Pack = 8, Size = 8)] + internal struct InnerPropertyValue + { + [FieldOffset(0)] + public sbyte cVal; + + [FieldOffset(0)] + public byte bVal; + + [FieldOffset(0)] + public short iVal; + + [FieldOffset(0)] + public ushort uiVal; + + [FieldOffset(0)] + public int lVal; + + [FieldOffset(0)] + public uint ulVal; + + [FieldOffset(0)] + public int intVal; + + [FieldOffset(0)] + public uint uintVal; + + [FieldOffset(0)] + public LargeInteger hVal; + + [FieldOffset(0)] + public ULargeInteger uhVal; + + [FieldOffset(0)] + public float fltVal; + + [FieldOffset(0)] + public double dblVal; + + [FieldOffset(0)] + public short boolVal; + + [FieldOffset(0)] + public short __OBSOLETE__VARIANT_BOOL; + + [FieldOffset(0)] + [MarshalAs(UnmanagedType.Error)] + public int scode; + + [FieldOffset(0)] + [MarshalAs(UnmanagedType.Currency)] + public decimal cyVal; + + [FieldOffset(0)] + public DateTime date; + + [FieldOffset(0)] + public System.Runtime.InteropServices.ComTypes.FILETIME filetime; + + [FieldOffset(0)] + public UnmanagedBlob bstrblobVal; + + [FieldOffset(0)] + public UnmanagedBlob blob; + + [FieldOffset(0)] + public UnmanagedArray cac; + + [FieldOffset(0)] + public UnmanagedArray caub; + + [FieldOffset(0)] + public UnmanagedArray cai; + + [FieldOffset(0)] + public UnmanagedArray caui; + + [FieldOffset(0)] + public UnmanagedArray cal; + + [FieldOffset(0)] + public UnmanagedArray caul; + + [FieldOffset(0)] + public UnmanagedArray caflt; + + [FieldOffset(0)] + public UnmanagedArray cadbl; + + [FieldOffset(0)] + public UnmanagedArray cabool; + + [FieldOffset(0)] + public UnmanagedArray cascode; + + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pcVal; + + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pbVal; + + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr piVal; + + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr puiVal; + + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr plVal; + + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pulVal; + + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pintVal; + + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr puintVal; + + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pfltVal; + + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pdblVal; + + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pboolVal; + + [ComConversionLoss] + [FieldOffset(0)] + public IntPtr pscode; + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/IConnectableCredentialProviderCredential.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/IConnectableCredentialProviderCredential.cs new file mode 100644 index 0000000..eff4cc9 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/IConnectableCredentialProviderCredential.cs @@ -0,0 +1,89 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("9387928B-AC75-4BF9-8AB2-2B93C4A55290")] + [ComImport] + internal interface IConnectableCredentialProviderCredential : ICredentialProviderCredential + { + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int Advise([MarshalAs(UnmanagedType.Interface)] [In] ICredentialProviderCredentialEvents pcpce); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int UnAdvise(); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetSelected(out int pbAutoLogon); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetDeselected(); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetFieldState([In] uint dwFieldID, out FieldState pcpfs, out FieldInteractiveState pcpfis); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetStringValue([In] uint dwFieldID, out IntPtr ppsz); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetBitmapValue([In] uint dwFieldID, out IntPtr phbmp); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetCheckboxValue([In] uint dwFieldID, out int pbChecked, [MarshalAs(UnmanagedType.LPWStr)] out string ppszLabel); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetSubmitButtonValue([In] uint dwFieldID, out uint pdwAdjacentTo); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetComboBoxValueCount([In] uint dwFieldID, out uint pcItems, out uint pdwSelectedItem); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetComboBoxValueAt([In] uint dwFieldID, uint dwItem, [MarshalAs(UnmanagedType.LPWStr)] out string ppszItem); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetStringValue([In] uint dwFieldID, [In] IntPtr psz); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetCheckboxValue([In] uint dwFieldID, [In] int bChecked); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetComboBoxSelectedValue([In] uint dwFieldID, [In] uint dwSelectedItem); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int CommandLinkClicked([In] uint dwFieldID); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetSerialization(out SerializationResponse pcpgsr, out CredentialSerialization pcpcs, [MarshalAs(UnmanagedType.LPWStr)] out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int ReportResult([In] int ntsStatus, [In] int ntsSubstatus, [MarshalAs(UnmanagedType.LPWStr)] out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int Connect([MarshalAs(UnmanagedType.Interface)] [In] IQueryContinueWithStatus pqcws); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int Disconnect(); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProvider.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProvider.cs new file mode 100644 index 0000000..e65476a --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProvider.cs @@ -0,0 +1,93 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("D27C3481-5A1C-45B2-8AAA-C20EBBE8229E")] + [ComImport] + internal interface ICredentialProvider + { + /// + /// Defines the scenarios for which the credential provider is valid. Called whenever the credential provider is initialized. + /// + /// The scenario the credential provider has been created in. This is the usage scenario that needs to be supported. See the Remarks for more information. + /// A value that affects the behavior of the credential provider. This value can be a bitwise-OR combination of one or more of the following values defined in Wincred.h. See CredUIPromptForWindowsCredentials for more information. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetUsageScenario([In] UsageScenario cpus, [In] CredUIWinFlags dwFlags); + + + /// + /// Sets the serialization characteristics of the credential provider. + /// + /// A CredentialSerialization structure that stores the serialization characteristics of the credential provider + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetSerialization([In] ref CredentialSerialization pcpcs); + + + /// + /// Allows a credential provider to initiate events in the Logon UI or Credential UI through a callback interface. + /// + /// An ICredentialProviderEvents callback interface to be used as the notification mechanism. + /// A pointer to an integer that uniquely identifies which credential provider has requested re-enumeration. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int Advise([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderEvents pcpe, IntPtr upAdviseContext); + + /// + /// Used by the Logon UI or Credential UI to advise the credential provider that event callbacks are no longer accepted. + /// + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int UnAdvise(); + + /// + /// Retrieves the count of fields in the needed to display this provider's credentials. + /// + /// The field count. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetFieldDescriptorCount(out uint pdwCount); + + /// + /// Gets metadata that describes a specified field. + /// + /// The zero-based index of the field for which the information should be retrieved. + /// A pointer to a CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR structure which receives the information about the field. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetFieldDescriptorAt([In] uint dwIndex, out IntPtr ppcpfd); + + + /// + /// Gets the number of available credentials under this credential provider. + /// + /// A DWORD value that receives the count of credentials. + /// A DWORD value that receives the index of the credential to be used as the default. If no default value has been set, this value should be set to CREDENTIAL_PROVIDER_NO_DEFAULT. + /// A BOOL value indicating if the default credential identified by pdwDefault should be used for an auto logon attempt. An auto logon attempt means the Logon UI or Credential UI will immediately call GetSerialization on the provider's default tile. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetCredentialCount(out uint pdwCount, out uint pdwDefault, out int pbAutoLogonWithDefault); + + + /// + /// Gets a specific credential. + /// + /// The zero-based index of the credential within the set of credentials enumerated for this credential provider. + /// An ICredentialProviderCredential instance representing the credential. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetCredentialAt([In] uint dwIndex, [MarshalAs(UnmanagedType.Interface)] out ICredentialProviderCredential ppcpc); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredential.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredential.cs new file mode 100644 index 0000000..0230939 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredential.cs @@ -0,0 +1,190 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + /// + /// Exposes methods that enable the handling of a credential. + /// + /// + /// ICredentialProviderCredential is implemented by outside parties providing a Logon UI or Credential UI prompting for user credentials. Enumeration of user tiles cannot be done without an implementation of this interface. + /// + [Guid("63913A93-40C1-481A-818D-4072FF8C70CC")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + internal interface ICredentialProviderCredential + { + /// + /// Enables a credential to initiate events in the Logon UI or Credential UI through a callback interface. This method should be called before other methods in interface. + /// + /// An callback interface to be used as the notification mechanism. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int Advise([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredentialEvents pcpce); + + /// + /// Used by the Logon UI or Credential UI to advise the credential that event callbacks are no longer accepted. + /// + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int UnAdvise(); + + /// + /// Called when a credential is selected. Enables the implementer to set logon characteristics. + /// + /// When this method returns, contains TRUE if selection of the credential indicates that it should attempt to logon immediately and automatically, otherwise FALSE. For example, a credential provider that enumerates an account without a password may want to return this as true. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetSelected(out int pbAutoLogon); + + /// + /// Called when a credential loses selection. + /// + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetDeselected(); + + /// + /// Retrieves the field state. The Logon UI and Credential UI use this to gain information about a field of a credential to display this information in the user tile. + /// + /// The identifier for the field. + /// The credential provider field state. This indicates when the field should be displayed on the user tile. + /// The credential provider field interactive state. This indicates when the user can interact with the field. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetFieldState([In] uint dwFieldID, out FieldState pcpfs, out FieldInteractiveState pcpfis); + + /// + /// Enables retrieval of text from a credential with a text field. + /// + /// The identifier for the field. + /// A pointer to a null-terminated Unicode string to return to the Logon UI or Credential UI. + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetStringValue([In] uint dwFieldID, out IntPtr ppsz); + + /// + /// Enables retrieval of bitmap data from a credential with a bitmap field. + /// + /// The identifier for the field. + /// Contains a pointer to the handle of the bitmap. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetBitmapValue([In] uint dwFieldID, out IntPtr phbmp); + + /// + /// Retrieves the checkbox value. + /// + /// The identifier for the field. + /// Indicates the state of the checkbox. TRUE indicates the checkbox is checked, otherwise FALSE. + /// Points to the label on the checkbox. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetCheckboxValue([In] uint dwFieldID, out int pbChecked, [MarshalAs(UnmanagedType.LPWStr)] out string ppszLabel); + + /// + /// Retrieves the identifier of a field that the submit button should be placed next to in the Logon UI. The Credential UI does not call this method. + /// + /// The identifier for the field a submit button value is needed for. + /// The field ID of the field that the submit button should be placed next to. + /// Note to implementers: Do not return the field ID of a bitmap in this parameter. It is not good UI design to place the submit button next to a bitmap, and doing so can cause a failure in the Logon UI. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetSubmitButtonValue([In] uint dwFieldID, out uint pdwAdjacentTo); + + /// + /// Gets a count of the items in the specified combo box and designates which item should have initial selection. + /// + /// The identifier for the combo box to gather information about. + /// A pointer to the number of items in the given combo box. + /// Contains a pointer to the item that receives initial selection. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetComboBoxValueCount([In] uint dwFieldID, out uint pcItems, out uint pdwSelectedItem); + + /// + /// Gets the string label for a combo box entry at the given index. + /// + /// The identifier for the combo box to query. + /// The index of the desired item. + /// A string value that receives the combo box label. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetComboBoxValueAt([In] uint dwFieldID, uint dwItem, [MarshalAs(UnmanagedType.LPWStr)] out string ppszItem); + + /// + /// Enables a Logon UI or Credential UI to update the text for a CPFT_EDIT_TEXT fields as the user types in them. + /// + /// The identifier for the field that needs to be updated. + /// A pointer to a buffer containing the new text. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetStringValue([In] uint dwFieldID, [In] IntPtr psz); + + /// + /// Enables a Logon UI and Credential UI to indicate that a checkbox value has changed. + /// + /// The identifier for the field to update. + /// Indicates the new value for the checkbox. TRUE means the checkbox should be checked, FALSE means unchecked. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetCheckboxValue([In] uint dwFieldID, [In] int bChecked); + + /// + /// Enables a Logon UI and Credential UI to indicate that a combo box value has been selected. + /// + /// The identifier for the combo box that is affected. + /// The specific item selected. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetComboBoxSelectedValue([In] uint dwFieldID, [In] uint dwSelectedItem); + + /// + /// Enables the Logon UI and Credential UI to indicate that a link was clicked. + /// + /// The identifier for the field clicked on. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int CommandLinkClicked([In] uint dwFieldID); + + /// + /// Called in response to an attempt to submit this credential to the underlying authentication engine. + /// + /// Indicates the success or failure of the attempt to serialize credentials. + /// A pointer to the credential. Depending on the result, there may be no valid credential. + /// A pointer to a Unicode string value that will be displayed by the Logon UI after serialization. May be NULL. + /// A pointer to an icon that will be displayed by the credential after the call to GetSerialization returns. This value can be NULL. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetSerialization(out SerializationResponse pcpgsr, out CredentialSerialization pcpcs, [MarshalAs(UnmanagedType.LPWStr)] out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon); + + /// + /// Translates a received error status code into the appropriate user-readable message. The Credential UI does not call this method. + /// + /// The NTSTATUS value that reflects the return value of the Winlogon call to LsaLogonUser. + /// The NTSTATUS value that reflects the value pointed to by the SubStatus parameter of LsaLogonUser when that function returns after being called by Winlogon. + /// A pointer to the error message that will be displayed to the user. May be NULL. + /// A pointer to an icon that will shown on the credential. May be NULL. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int ReportResult([In] int ntsStatus, [In] int ntsSubstatus, [MarshalAs(UnmanagedType.LPWStr)] out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredential2.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredential2.cs new file mode 100644 index 0000000..f865855 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredential2.cs @@ -0,0 +1,116 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + /// + /// Extends the ICredentialProviderCredential interface by adding a method that retrieves the security identifier (SID) of a user. The credential is associated with that user and can be grouped under the user's tile. + /// + /// This class is required for creating a V2 credential provider. V2 credential providers provide a personalized log on experience for the user. This occurs by the credential provider telling the Logon UI what sign in options are available for a user. It is recommended that new credential providers should be V2 credential providers. + /// In order to create an ICredentialProviderCredential2 instance, a valid SID needs to be returned by the GetUserSid function.Valid is defined by the returned SID being for one of the users currently enumerated by the Logon UI. + /// A useful tool for getting the available users and determining which ones you want to associate with is the ICredentialProviderUserArray object. This object contains a list of ICredentialProviderUser objects that can be queried to gain information about the users that will be enumerated.For example you could gain the user's SID or username using GetStringValue with a passed in parameter of PKEY_Identity_PrimarySid or PKEY_Identity_USerName respectively. You can even filter the results using SetProviderFilter to only display a subset of available users. + /// Using the ICredentialProviderUserArray is optional, but it is a convenient way to get the necessary information to make valid SID values.In order to get a list of users that will be enumerated by the Logon UI, implement the ICredentialProviderSetUserArray interface to get the ICredentialProviderUserArray object from SetUserArray.Logon UI calls SetUserArray before GetCredentialCount, so the ICredentialProviderUserArray object is ready when a credential provider is about to return credentials. + /// A V2 credential provider is represented by an icon displayed underneath the "Sign-in options" link.In order to provide an icon for your credential provider, define a CREDENTIAL_PROVIDER_FIELD_TYPE of CPFT_TILE_IMAGE in the credential itself.Then make sure the guidFieldType of the CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR is set to CPFG_CREDENTIAL_PROVIDER_LOGO.The recommended size for an icon is 72 by 72 pixels. + /// Similar to specifying an icon for your credential provider, you can also specify a text string to identify your credential provider.This string appears in a pop-up window when a user hovers over the icon.To do this, define a CREDENTIAL_PROVIDER_FIELD_TYPE of CPFT_SMALL_TEXT in the credential itself.Then make sure the guidFieldType of the CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR is set to CPFG_CREDENTIAL_PROVIDER_LABEL.This string should supplement the credential provider icon described above and be descriptive enough that users understand what it is. For example, the picture password provider's description is "Picture Password". + [Guid("FD672C54-40EA-4D6E-9B49-CFB1A7507BD7")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + internal interface ICredentialProviderCredential2 : ICredentialProviderCredential + { + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int Advise([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredentialEvents pcpce); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int UnAdvise(); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetSelected(out int pbAutoLogon); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetDeselected(); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetFieldState([In] uint dwFieldID, out FieldState pcpfs, out FieldInteractiveState pcpfis); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetStringValue([In] uint dwFieldID, out IntPtr ppsz); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetBitmapValue([In] uint dwFieldID, out IntPtr phbmp); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetCheckboxValue([In] uint dwFieldID, out int pbChecked, [MarshalAs(UnmanagedType.LPWStr)] out string ppszLabel); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetSubmitButtonValue([In] uint dwFieldID, out uint pdwAdjacentTo); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetComboBoxValueCount([In] uint dwFieldID, out uint pcItems, out uint pdwSelectedItem); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetComboBoxValueAt([In] uint dwFieldID, uint dwItem, [MarshalAs(UnmanagedType.LPWStr)] out string ppszItem); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetStringValue([In] uint dwFieldID, [In] IntPtr psz); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetCheckboxValue([In] uint dwFieldID, [In] int bChecked); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetComboBoxSelectedValue([In] uint dwFieldID, [In] uint dwSelectedItem); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int CommandLinkClicked([In] uint dwFieldID); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetSerialization(out SerializationResponse pcpgsr, out CredentialSerialization pcpcs, [MarshalAs(UnmanagedType.LPWStr)] out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int ReportResult([In] int ntsStatus, [In] int ntsSubstatus, [MarshalAs(UnmanagedType.LPWStr)] out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon); + + /// + /// Retrieves the security identifier (SID) of the user that is associated with this credential. + /// + /// The address of a pointer to a buffer that, when this method returns successfully, receives the user's SID. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + /// The Logon UI will use the returned SID from this method to associate the credential tile with a user tile. To associate the credential with the "Other user" user tile in the Logon UI, this method should return S_FALSE and a null SID. The "Other user" tile is normally only valid when the PC is joined to a domain. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetUserSid([MarshalAs(UnmanagedType.LPWStr)] out string sid); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredential3.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredential3.cs new file mode 100644 index 0000000..6dc8bd5 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredential3.cs @@ -0,0 +1,117 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + /// + /// Exposes methods that enable the handling of a credential. + /// + /// ICredentialProviderCredential is implemented by outside parties providing a Logon UI or Credential UI prompting for user credentials. Enumeration of user tiles cannot be done without an implementation of this interface. + [Guid("64A5010E-4363-41F8-9738-19045C20DABC")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + internal interface ICredentialProviderCredential3 : ICredentialProviderCredential2 + { + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int Advise([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredentialEvents pcpce); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int UnAdvise(); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetSelected(out int pbAutoLogon); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetDeselected(); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetFieldState([In] uint dwFieldID, out FieldState pcpfs, out FieldInteractiveState pcpfis); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetStringValue([In] uint dwFieldID, out IntPtr ppsz); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetBitmapValue([In] uint dwFieldID, out IntPtr phbmp); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetCheckboxValue([In] uint dwFieldID, out int pbChecked, [MarshalAs(UnmanagedType.LPWStr)] out string ppszLabel); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetSubmitButtonValue([In] uint dwFieldID, out uint pdwAdjacentTo); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetComboBoxValueCount([In] uint dwFieldID, out uint pcItems, out uint pdwSelectedItem); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetComboBoxValueAt([In] uint dwFieldID, uint dwItem, [MarshalAs(UnmanagedType.LPWStr)] out string ppszItem); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetStringValue([In] uint dwFieldID, [In] IntPtr psz); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetCheckboxValue([In] uint dwFieldID, [In] int bChecked); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetComboBoxSelectedValue([In] uint dwFieldID, [In] uint dwSelectedItem); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int CommandLinkClicked([In] uint dwFieldID); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetSerialization(out SerializationResponse pcpgsr, out CredentialSerialization pcpcs, [MarshalAs(UnmanagedType.LPWStr)] out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int ReportResult([In] int ntsStatus, [In] int ntsSubstatus, [MarshalAs(UnmanagedType.LPWStr)] out string ppszOptionalStatusText, out StatusIcon pcpsiOptionalStatusIcon); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int GetUserSid([MarshalAs(UnmanagedType.LPWStr)] out string sid); + + /// + /// Gets a buffer containing the image data + /// + /// The field ID to get + /// The size of the bitmap buffer + /// A pointer to the bitmap buffer + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetBitmapBufferValue([In] uint fieldID, [Out] out uint pImageBufferSize, [Out] out IntPtr ppImageBuffer); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredentialEvents.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredentialEvents.cs new file mode 100644 index 0000000..5b55458 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredentialEvents.cs @@ -0,0 +1,124 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + /// + /// Provides an asynchronous callback mechanism used by a credential to notify it of state or text change events in the Logon UI or Credential UI. + /// + [Guid("FA6FA76B-66B7-4B11-95F1-86171118E816")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + internal interface ICredentialProviderCredentialEvents + { + /// + /// Communicates to the Logon UI or Credential UI that a field state has changed and that the UI should be updated. + /// + /// The credential containing a field whose interactivity state is being set. This value should be set to this. See ICredentialProviderCredentialEvents for more information. + /// The unique ID of the field. + /// The value from the CREDENTIAL_PROVIDER_FIELD_STATE enumeration that specifies the new field state. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetFieldState([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] FieldState cpfs); + + /// + /// Communicates to the Logon UI or Credential UI that the interactivity state of a field has changed and that the UI should be updated. + /// + /// The credential containing a field whose interactivity state is being set. This value should be set to this. See ICredentialProviderCredentialEvents for more information. + /// The unique ID of the field. + /// + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetFieldInteractiveState([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] FieldInteractiveState cpfis); + + /// + /// Communicates to the Logon UI or Credential UI that the string associated with a field has changed and that the UI should be updated. + /// + /// The credential containing a field whose interactivity state is being set. This value should be set to this. See ICredentialProviderCredentialEvents for more information. + /// The unique ID of the field. + /// A pointer to the new string for the field. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetFieldString([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] IntPtr psz); + + /// + /// Communicates to the Logon UI or Credential UI that a checkbox field has changed and that the UI should be updated. + /// + /// The credential containing the checkbox field that is being set. This value should be set to this. See ICredentialProviderCredentialEvents for more information. + /// The unique field ID for the checkbox. + /// The new state of the checkbox. TRUE indicates the checkbox should be checked, FALSE indicates it should not. + /// The new string for the checkbox label. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetFieldCheckbox([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] int bChecked, [MarshalAs(UnmanagedType.LPWStr)][In] string pszLabel); + + /// + /// Communicates to the Logon UI or Credential UI that a tile image field has changed and that the UI should be updated. + /// + /// The credential containing the tile image field that is being set. This value should be set to this. See ICredentialProviderCredentialEvents for more information. + /// The unique ID of the tile image field. + /// The new tile image. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetFieldBitmap([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] IntPtr hbmp); + + /// + /// Communicates to the Logon UI or Credential UI that the selected item in a combo box has changed and that the UI should be updated. + /// + /// The credential containing the combo box being set. This value should be set to this. See ICredentialProviderCredentialEvents for more information. + /// The unique ID of the combo box. + /// The index of the item to select in the combo box. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetFieldComboBoxSelectedItem([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] uint dwSelectedItem); + + /// + /// Communicates to the Logon UI or Credential UI that an item should be deleted from a combo box and that the UI should be updated. + /// + /// The credential containing the combo box that needs to be updated. This value should be set to this. See ICredentialProviderCredentialEvents for more information. + /// The unique ID of the combo box. + /// The index of the item that is deleted. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int DeleteFieldComboBoxItem([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] uint dwItem); + + /// + /// Communicates to the Logon UI or Credential UI that a combo box needs an item appended and that the UI should be updated. + /// + /// The credential containing the combo box that needs an item added. This value should be set to this. See ICredentialProviderCredentialEvents for more information. + /// The unique ID of the combo box. + /// The string that will be appended to the combo box as a new option. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int AppendFieldComboBoxItem([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [MarshalAs(UnmanagedType.LPWStr)][In] string pszItem); + + /// + /// Enables credentials to set the field that the submit button appears adjacent to. + /// + /// The credential containing a field whose interactivity state is being set. This value should be set to this. See ICredentialProviderCredentialEvents for more information. + /// The unique ID of the field. + /// The unique field ID of the field that the submit button should be adjacent to when this method completes. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetFieldSubmitButton([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] uint dwAdjacentTo); + + /// + /// Called when the window is created. Enables credentials to retrieve the HWND of the parent window after Advise is called. + /// + /// A pointer to the handle of the parent window. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int OnCreatingWindow(out IntPtr phwndOwner); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredentialEvents2.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredentialEvents2.cs new file mode 100644 index 0000000..23966ab --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredentialEvents2.cs @@ -0,0 +1,101 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + /// + /// Extends the ICredentialProviderCredentialEvents interface by adding methods that enable batch updating of fields in theLogon UI or Credential UI. + /// + /// + /// In Windows 7 and Windows Vista, many credential providers used ICredentialProviderEvents::CredentialsChanged to update UI. While this works, it causes a re-enumeration of all the credentials from the calling credential provider. The processing of this event can, under some circumstances, lead to flashing or focus changes in the UI due to this re-enumeration. Therefore, using ICredentialProviderEvents::CredentialsChanged solely for UI updates is discouraged. The new recommendation is as follows: + /// + /// Use ICredentialProviderEvents::CredentialsChanged only if a credential provider needs to do automatically logon a user or change the number of credentials it is enumerating. + ///Use ICredentialProviderCredentialEvents2 to update a credential provider's UI. + /// + /// ICredentialProviderCredentialEvents2 includes all of the methods inherited from ICredentialProviderCredentialEvents.This includes all of the inherited methods except OnCreatingWindow. + /// When interacting with a background thread, the use of ICredentialProviderCredentialEvents2 is similar to the use of ICredentialProviderCredentialEvents, in that proper inter-thread communication methods must be used. + /// + [Guid("B53C00B6-9922-4B78-B1F4-DDFE774DC39B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + internal interface ICredentialProviderCredentialEvents2 : ICredentialProviderCredentialEvents + { + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldState([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] FieldState cpfs); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldInteractiveState([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] FieldInteractiveState cpfis); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldString([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] IntPtr psz); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldCheckbox([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] int bChecked, [MarshalAs(UnmanagedType.LPWStr)][In] string pszLabel); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldBitmap([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] IntPtr hbmp); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldComboBoxSelectedItem([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] uint dwSelectedItem); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int DeleteFieldComboBoxItem([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] uint dwItem); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int AppendFieldComboBoxItem([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [MarshalAs(UnmanagedType.LPWStr)][In] string pszItem); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldSubmitButton([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] uint dwAdjacentTo); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int OnCreatingWindow(out IntPtr phwndOwner); + + /// + /// Starts a batch update to fields in the logon or credential UI. + /// + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int BeginFieldUpdates(); + + /// + /// Finishes and commits the batch updates started by BeginFieldUpdates. + /// + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int EndFieldUpdates(); + + /// + /// Specifies whether a specified field in the logon or credential UI should display a "password reveal" glyph or is expected to receive an e-mail address. + /// + /// An ICredentialProviderCredential interface pointer to the credential object. + /// The ID of the field in the logon or credential UI for which this option applies. + /// One or more of the CREDENTIAL_PROVIDER_CREDENTIAL_FIELD_OPTIONS values, which specify the field options. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetFieldOptions([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential credential, [In] uint fieldID, [In] FieldOptions options); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredentialEvents3.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredentialEvents3.cs new file mode 100644 index 0000000..bf8c3e5 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredentialEvents3.cs @@ -0,0 +1,87 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [Guid("2D8DEEB8-1322-4973-8DF9-B282F2468290")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + internal interface ICredentialProviderCredentialEvents3 : ICredentialProviderCredentialEvents2 + { + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldState([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] FieldState cpfs); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldInteractiveState([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] FieldInteractiveState cpfis); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldString([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] IntPtr psz); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldCheckbox([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] int bChecked, [MarshalAs(UnmanagedType.LPWStr)][In] string pszLabel); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldBitmap([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] IntPtr hbmp); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldComboBoxSelectedItem([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] uint dwSelectedItem); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int DeleteFieldComboBoxItem([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] uint dwItem); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int AppendFieldComboBoxItem([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [MarshalAs(UnmanagedType.LPWStr)][In] string pszItem); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldSubmitButton([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, [In] uint dwFieldID, [In] uint dwAdjacentTo); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int OnCreatingWindow(out IntPtr phwndOwner); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int BeginFieldUpdates(); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int EndFieldUpdates(); + + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int SetFieldOptions([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential credential, [In] uint fieldID, [In] FieldOptions options); + + /// + /// Communicates to the Logon UI or Credential UI that a bitmap field should be updated + /// + /// An ICredentialProviderCredential interface pointer to the credential object. + /// The ID of the field to update + /// The image buffer size + /// A pointer to the image buffer + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + int SetFieldBitmapBuffer([MarshalAs(UnmanagedType.Interface)][In] ICredentialProviderCredential pcpc, uint fieldID, uint imageBufferSize, IntPtr pImageBuffer); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredentialWithFieldOptions.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredentialWithFieldOptions.cs new file mode 100644 index 0000000..a55038e --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderCredentialWithFieldOptions.cs @@ -0,0 +1,28 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + /// + /// Provides a method that enables the credential provider framework to determine whether you've made a customization to a field's option in a logon or credential UI. + /// + /// + /// Implement this interface if your credential provider overrides the default field options through ICredentialProviderCredentialEvents2::SetFieldOptions. This enables the credential provider framework to determine the field options that you've specified . + /// + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("DBC6FB30-C843-49E3-A645-573E6F39446A")] + [ComImport] + internal interface ICredentialProviderCredentialWithFieldOptions + { + /// + /// Retrieves the current option set for a specified field in a logon or credential UI. Called by the credential provider framework. + /// + /// The ID of the field in the logon or credential UI. + /// A pointer to an CREDENTIAL_PROVIDER_CREDENTIAL_FIELD_OPTIONS value that, when this method returns successfully, receives one or more flags that specify the current options for the field. + /// Provides a method that enables the credential provider framework to determine whether you've made a customization to a field's option in a logon or credential UI. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetFieldOptions([In] uint fieldID, out FieldOptions options); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderEvents.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderEvents.cs new file mode 100644 index 0000000..c7a8a5d --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderEvents.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + /// + /// Provides an asynchronous callback mechanism used by a credential provider to notify it of changes in the list of credentials or their fields. + /// + /// + /// An implementation of ICredentialProviderEvents is provided for use by outside parties implementing a credential provider. + /// + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("34201E5A-A787-41A3-A5A4-BD6DCF2A854E")] + [ComImport] + internal interface ICredentialProviderEvents + { + /// + /// Signals the Logon UI or Credential UI that the enumerated list of credentials has changed. This happens when the number of credentials change, the individual credentials change, or the number of fields available change. This is an asynchronous method. + /// + /// A pointer to an integer that uniquely identifies which credential provider has requested re-enumeration. The credential provider should pass back the interface pointer it received from Advise in this parameter. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int CredentialsChanged(IntPtr upAdviseContext); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderFilter.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderFilter.cs new file mode 100644 index 0000000..9113adf --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderFilter.cs @@ -0,0 +1,20 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("A5DA53F9-D475-4080-A120-910C4A739880")] + [ComImport] + internal interface ICredentialProviderFilter + { + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int Filter([In] UsageScenario cpus, [In] CredUIWinFlags dwFlags, IntPtr rgclsidProviders, IntPtr rgbAllow, [In] uint cProviders); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int UpdateRemoteCredential([In] ref CredentialSerialization pcpcsIn, ref CredentialSerialization pcpcsOut); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderSetUserArray.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderSetUserArray.cs new file mode 100644 index 0000000..05349ed --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderSetUserArray.cs @@ -0,0 +1,26 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + /// + /// Provides a method that enables a credential provider to receive the set of users that will be shown in the logon or credential UI. + /// + /// + /// Implement this interface for credential providers that have a need to know which users will appear in the logon or credential UI. + /// + [Guid("095C1484-1C0C-4388-9C6D-500E61BF84BD")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + internal interface ICredentialProviderSetUserArray + { + /// + /// Called by the system during the initialization of a logon or credential UI to retrieve the set of users to show in that UI. + /// + /// A pointer to an array object that contains a set of ICredentialProviderUser objects, each representing a user that will appear in the logon or credential UI. This array enables the credential provider to enumerate and query each of the user objects for their SID, their associated credential provider's ID, various forms of the user name, and their logon status string. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetUserArray([MarshalAs(UnmanagedType.Interface)] [In] ICredentialProviderUserArray users); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderUser.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderUser.cs new file mode 100644 index 0000000..524aa93 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderUser.cs @@ -0,0 +1,48 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + /// + /// Provides methods used to retrieve certain properties of an individual user included in a logon or credential UI. + /// + /// Windows 8 introduces the ability to group credential providers by user. The logon UI can display a set of users rather than a set of multiple credential providers for each user. Selecting a user then displays the individual credential provider options associated with that user. + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("13793285-3EA6-40FD-B420-15F47DA41FBB")] + [ComImport] + internal interface ICredentialProviderUser + { + /// + /// Retrieves the user's security identifier (SID). + /// + /// The address of a pointer to a buffer that, when this method returns successfully, receives the user's SID. It is the responsibility of the caller to free this resource by calling the CoTaskMemFree function. + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetSid([MarshalAs(UnmanagedType.LPWStr)] out string sid); + + /// + /// Retrieves string properties from the ICredentialProviderUser object based on the input value. + /// + /// + /// + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetProviderID(out Guid providerID); + + /// + /// One of the following values that specify the property to retrieve. + /// + /// One of the following values that specify the property to retrieve - PKEY_Identity_DisplayName, PKEY_Identity_LogonStatusString, PKEY_Identity_PrimarySid, PKEY_Identity_ProviderID, PKEY_Identity_QualifiedUserName or KEY_Identity_UserName + /// The address of a pointer to a buffer that, when this method returns successfully, receives the requested string. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetStringValue([In] ref PropertyKey key, [MarshalAs(UnmanagedType.LPWStr)] out string stringValue); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetValue([In] ref PropertyKey key, out PropertyValue value); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderUserArray.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderUserArray.cs new file mode 100644 index 0000000..19421b5 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/ICredentialProviderUserArray.cs @@ -0,0 +1,53 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + /// + /// Represents the set of users that will appear in the logon or credential UI. This information enables the credential provider to enumerate the set to retrieve property information about each user to populate fields or filter the set. + /// + /// This object is provided by the Windows credential provider framework to your credential provider through the ICredentialProviderSetUserArray::SetUserArray method. Ownership of this object remains with the credential provider framework. + [Guid("90C119AE-0F18-4520-A1F1-114366A40FE8")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + internal interface ICredentialProviderUserArray + { + /// + /// Limits the set of users in the array to either local accounts or Microsoft accounts. + /// + /// Set this parameter to Identity_LocalUserProvider for the local accounts credential provider; otherwise set it to the GUID of the Microsoft account provider. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetProviderFilter([In] ref Guid guidProviderToFilterTo); + + /// + /// Retrieves a value that indicates whether the "Other user" tile for local or Microsoft accounts is shown in the logon or credential UI. This information can be used by a credential provider to show the same behavior as the password or Microsoft account provider. + /// + /// A pointer to a value that, when this method returns successfully, receives one or more flags that specify which empty tiles are shown by the logon or credential UI. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetAccountOptions(out AccountOptions credentialProviderAccountOptions); + + /// + /// Retrieves the number of ICredentialProviderUser objects in the user array. + /// + /// A pointer to a value that, when this method returns successfully, receives the number of users in the array. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetCount(out uint userCount); + + /// + /// Retrieves a specified user from the array. + /// + /// The 0-based array index of the user. The size of the array can be obtained through the GetCount method. + /// The address of a pointer to an object that, when this method returns successfully, represents the specified user. It is the responsibility of the caller to free this object when it is no longer needed by calling its Release method. + /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int GetAt([In] uint userIndex, [MarshalAs(UnmanagedType.Interface)] out ICredentialProviderUser user); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/IQueryContinue.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/IQueryContinue.cs new file mode 100644 index 0000000..24130d0 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/IQueryContinue.cs @@ -0,0 +1,15 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [Guid("7307055C-B24A-486B-9F25-163E597A28A9")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + internal interface IQueryContinue + { + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int QueryContinue(); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/Interfaces/IQueryContinueWithStatus.cs b/src/Lithnet.CredentialProvider/Interop/Interfaces/IQueryContinueWithStatus.cs new file mode 100644 index 0000000..9bdda86 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/Interfaces/IQueryContinueWithStatus.cs @@ -0,0 +1,19 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("9090BE5B-502B-41FB-BCCC-0049A6C7254B")] + [ComImport] + internal interface IQueryContinueWithStatus : IQueryContinue + { + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + new int QueryContinue(); + + [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.Error)] + int SetStatusMessage([MarshalAs(UnmanagedType.LPWStr)] [In] string psz); + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/InternalExtensions.cs b/src/Lithnet.CredentialProvider/Interop/InternalExtensions.cs new file mode 100644 index 0000000..cd0f242 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/InternalExtensions.cs @@ -0,0 +1,69 @@ +using System; +using System.Security; +using Lithnet.CredentialProvider.Interop; + +namespace Lithnet.CredentialProvider.Interop +{ + internal static class InternalExtensions + { + internal static unsafe int Wcslen(this IntPtr addr) + { + const int maxLength = int.MaxValue; + + var c = (char*)(addr); + + for (int i = 0; i < maxLength; i++) + { + if (c[i] == '\0') + { + return i; + } + } + + throw new ArgumentException("End of string not found"); + } + + internal static unsafe SecureString IntPtrToSecureString(this IntPtr psz) + { + var length = psz.Wcslen(); + var charArray = (char*)psz; + return new SecureString(charArray, length); + } + + internal static string GetUserName(this ICredentialProviderUser user) + { + user.GetStringValue(PropertyKeys.PKEY_Identity_UserName, out var value); + return value; + } + + internal static string GetQualifiedUserName(this ICredentialProviderUser user) + { + user.GetStringValue(PropertyKeys.PKEY_Identity_QualifiedUserName, out var value); + return value; + } + + internal static string GetDisplayName(this ICredentialProviderUser user) + { + user.GetStringValue(PropertyKeys.PKEY_Identity_DisplayName, out var value); + return value; + } + + internal static string GetLogonStatus(this ICredentialProviderUser user) + { + user.GetStringValue(PropertyKeys.PKEY_Identity_LogonStatusString, out var value); + return value; + } + + internal static string GetPrimarySid(this ICredentialProviderUser user) + { + user.GetStringValue(PropertyKeys.PKEY_Identity_PrimarySid, out var value); + return value; + } + + internal static string GetProviderID(this ICredentialProviderUser user) + { + user.GetStringValue(PropertyKeys.PKEY_Identity_ProviderID, out var value); + return value; + } + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/KerbLogonSubmitType.cs b/src/Lithnet.CredentialProvider/Interop/KerbLogonSubmitType.cs new file mode 100644 index 0000000..85a30c1 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/KerbLogonSubmitType.cs @@ -0,0 +1,19 @@ +namespace Lithnet.CredentialProvider.Interop +{ + internal enum KerbLogonSubmitType : uint + { + InteractiveLogon = 2, + SmartCardLogon = 6, + WorkstationUnlockLogon = 7, + SmartCardUnlockLogon = 8, + ProxyLogon = 9, + TicketLogon = 10, + TicketUnlockLogon = 11, + S4ULogon = 12, + CertificateLogon = 13, + CertificateS4ULogon = 14, + CertificateUnlockLogon = 15, + NoElevationLogon = 83, + LuidLogon = 84, + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/KerberosInteractiveUnlockLogon.cs b/src/Lithnet.CredentialProvider/Interop/KerberosInteractiveUnlockLogon.cs new file mode 100644 index 0000000..3919e7b --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/KerberosInteractiveUnlockLogon.cs @@ -0,0 +1,15 @@ +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [StructLayout(LayoutKind.Sequential)] + internal struct KerberosInteractiveUnlockLogon + { + public KerbLogonSubmitType SubmitType; + public LsaStringUni LogonDomainName; + public LsaStringUni Username; + public LsaStringUni Password; + + public long LoginId; + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/LargeInteger.cs b/src/Lithnet.CredentialProvider/Interop/LargeInteger.cs new file mode 100644 index 0000000..facfaf1 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/LargeInteger.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct LargeInteger + { + public long QuadPart; + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/LsaHandle.cs b/src/Lithnet.CredentialProvider/Interop/LsaHandle.cs new file mode 100644 index 0000000..129d0f0 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/LsaHandle.cs @@ -0,0 +1,40 @@ +using System; +using System.ComponentModel; + +namespace Lithnet.CredentialProvider.Interop +{ + internal struct LsaHandle : IDisposable + { + public IntPtr Handle; + + public LsaHandle(IntPtr handle) + { + this.Handle = handle; + } + + public static implicit operator LsaHandle(IntPtr handle) => new LsaHandle(handle); + public static implicit operator IntPtr(LsaHandle handle) => handle.Handle; + + public static LsaHandle ConnectUntrusted() + { + var result = PInvoke.LsaConnectUntrusted(out var handle); + + if (result != 0) + { + throw new Win32Exception((int)result); + } + + return handle; + } + + public bool IsValid() + { + return this.Handle != IntPtr.Zero; + } + + public void Dispose() + { + PInvoke.LsaDeregisterLogonProcess(this.Handle); + } + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/LsaString.cs b/src/Lithnet.CredentialProvider/Interop/LsaString.cs new file mode 100644 index 0000000..86f9eaf --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/LsaString.cs @@ -0,0 +1,33 @@ +using System; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [StructLayout(LayoutKind.Sequential)] + internal struct LsaString : IDisposable + { + public ushort Length; + public ushort MaxLength; + public IntPtr Buffer; + + public LsaString(string value) + { + this.Length = (ushort)value.Length; + this.MaxLength = this.Length; + this.Buffer = Marshal.StringToHGlobalAnsi(value); + } + + public static implicit operator LsaString(string value) => new LsaString(value); + public static implicit operator string(LsaString value) => value.ToString(); + + public override string ToString() + { + return Marshal.PtrToStringAnsi(this.Buffer) ?? string.Empty; + } + + public void Dispose() + { + Marshal.FreeHGlobal(this.Buffer); + } + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/LsaStringUni.cs b/src/Lithnet.CredentialProvider/Interop/LsaStringUni.cs new file mode 100644 index 0000000..38863f2 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/LsaStringUni.cs @@ -0,0 +1,32 @@ +using System; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [StructLayout(LayoutKind.Sequential)] + internal struct LsaStringUni : IDisposable + { + public ushort Length; + public ushort MaxLength; + public IntPtr Buffer; + + public LsaStringUni(string value) + { + this.Length = (ushort)(value.Length * sizeof(ushort)); + this.MaxLength = this.Length; + this.Buffer = Marshal.StringToHGlobalUni(value); + } + + public static implicit operator LsaStringUni(string value) => new LsaStringUni(value); + public static implicit operator string(LsaStringUni value) => value.ToString(); + + public override string ToString() + { + return Marshal.PtrToStringUni(this.Buffer) ?? string.Empty; + } + public void Dispose() + { + Marshal.FreeHGlobal(this.Buffer); + } + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/PInvoke.cs b/src/Lithnet.CredentialProvider/Interop/PInvoke.cs new file mode 100644 index 0000000..cb23cf4 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/PInvoke.cs @@ -0,0 +1,65 @@ +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace Lithnet.CredentialProvider.Interop +{ + internal static class PInvoke + { + [DllImport("secur32.dll", SetLastError = false)] + public static extern uint LsaConnectUntrusted(out IntPtr LsaHandle); + + [DllImport("secur32.dll", SetLastError = false)] + public static extern IntPtr LsaDeregisterLogonProcess([In] IntPtr handle); + + [DllImport("secur32.dll", SetLastError = false)] + public static extern uint LsaLookupAuthenticationPackage(IntPtr lsaHandle, ref LsaString packageName, out uint authenticationPackage); + + [DllImport("advapi32.dll", SetLastError = true)] + public static extern uint LsaNtStatusToWinError(uint status); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool GetComputerName(StringBuilder buffer, ref uint size); + + [DllImport("gdi32.dll")] + public static extern bool DeleteObject(IntPtr hObject); + + public static string GetComputerName(uint bufferSize = 25) + { + var buffer = new StringBuilder((int)bufferSize); + + if (GetComputerName(buffer, ref bufferSize)) + { + return buffer.ToString(); + } + + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + + public static uint LookupAuthenticationPackage(LsaString packageName) + { + using (var handle = LsaHandle.ConnectUntrusted()) + { + var result = LsaLookupAuthenticationPackage(handle, ref packageName, out var package); + + if (result != 0) + { + throw new Win32Exception((int)result); + } + + return package; + } + } + + [MethodImplAttribute(MethodImplOptions.NoOptimization)] + public static unsafe void SecureZeroMemory(IntPtr ptr, uint length) + { + for (int i = 0; i < length; i++) + { + *((byte*)ptr + i) = 0; + } + } + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/PropertyKey.cs b/src/Lithnet.CredentialProvider/Interop/PropertyKey.cs new file mode 100644 index 0000000..cf7541c --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/PropertyKey.cs @@ -0,0 +1,37 @@ +using System; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal struct PropertyKey + { + public Guid FormatID; + + public uint PropertyID; + + public PropertyKey(string format, uint property) + { + FormatID = new Guid(format); + PropertyID = property; + } + + public PropertyKey(uint propertyId, + uint a, + ushort b, + ushort c, + byte d, + byte e, + byte f, + byte g, + byte h, + byte i, + byte j, + byte k) + { + PropertyID = propertyId; + FormatID = new Guid(a, b, c, d, e, f, g, h, i, j, k); + } + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/PropertyKeys.cs b/src/Lithnet.CredentialProvider/Interop/PropertyKeys.cs new file mode 100644 index 0000000..2367503 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/PropertyKeys.cs @@ -0,0 +1,1044 @@ +namespace Lithnet.CredentialProvider.Interop +{ + internal static class PropertyKeys + { + #region Properties + + public static PropertyKey PKEY_Address_Country = new PropertyKey(100, 0xC07B4199, 0xE1DF, 0x4493, 0xB1, 0xE1, 0xDE, 0x59, 0x46, 0xFB, 0x58, 0xF8); + public static PropertyKey PKEY_Address_CountryCode = new PropertyKey(101, 0xC07B4199, 0xE1DF, 0x4493, 0xB1, 0xE1, 0xDE, 0x59, 0x46, 0xFB, 0x58, 0xF8); + public static PropertyKey PKEY_Address_Region = new PropertyKey(102, 0xC07B4199, 0xE1DF, 0x4493, 0xB1, 0xE1, 0xDE, 0x59, 0x46, 0xFB, 0x58, 0xF8); + public static PropertyKey PKEY_Address_RegionCode = new PropertyKey(103, 0xC07B4199, 0xE1DF, 0x4493, 0xB1, 0xE1, 0xDE, 0x59, 0x46, 0xFB, 0x58, 0xF8); + public static PropertyKey PKEY_Address_Town = new PropertyKey(104, 0xC07B4199, 0xE1DF, 0x4493, 0xB1, 0xE1, 0xDE, 0x59, 0x46, 0xFB, 0x58, 0xF8); + public static PropertyKey PKEY_Audio_ChannelCount = new PropertyKey(7, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Audio_Compression = new PropertyKey(10, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Audio_EncodingBitrate = new PropertyKey(4, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Audio_Format = new PropertyKey(2, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Audio_IsVariableBitRate = new PropertyKey(100, 0xE6822FEE, 0x8C17, 0x4D62, 0x82, 0x3C, 0x8E, 0x9C, 0xFC, 0xBD, 0x1D, 0x5C); + public static PropertyKey PKEY_Audio_PeakValue = new PropertyKey(100, 0x2579E5D0, 0x1116, 0x4084, 0xBD, 0x9A, 0x9B, 0x4F, 0x7C, 0xB4, 0xDF, 0x5E); + public static PropertyKey PKEY_Audio_SampleRate = new PropertyKey(5, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Audio_SampleSize = new PropertyKey(6, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Audio_StreamName = new PropertyKey(9, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Audio_StreamNumber = new PropertyKey(8, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Calendar_Duration = new PropertyKey(100, 0x293CA35A, 0x09AA, 0x4DD2, 0xB1, 0x80, 0x1F, 0xE2, 0x45, 0x72, 0x8A, 0x52); + public static PropertyKey PKEY_Calendar_IsOnline = new PropertyKey(100, 0xBFEE9149, 0xE3E2, 0x49A7, 0xA8, 0x62, 0xC0, 0x59, 0x88, 0x14, 0x5C, 0xEC); + public static PropertyKey PKEY_Calendar_IsRecurring = new PropertyKey(100, 0x315B9C8D, 0x80A9, 0x4EF9, 0xAE, 0x16, 0x8E, 0x74, 0x6D, 0xA5, 0x1D, 0x70); + public static PropertyKey PKEY_Calendar_Location = new PropertyKey(100, 0xF6272D18, 0xCECC, 0x40B1, 0xB2, 0x6A, 0x39, 0x11, 0x71, 0x7A, 0xA7, 0xBD); + public static PropertyKey PKEY_Calendar_OptionalAttendeeAddresses = new PropertyKey(100, 0xD55BAE5A, 0x3892, 0x417A, 0xA6, 0x49, 0xC6, 0xAC, 0x5A, 0xAA, 0xEA, 0xB3); + public static PropertyKey PKEY_Calendar_OptionalAttendeeNames = new PropertyKey(100, 0x09429607, 0x582D, 0x437F, 0x84, 0xC3, 0xDE, 0x93, 0xA2, 0xB2, 0x4C, 0x3C); + public static PropertyKey PKEY_Calendar_OrganizerAddress = new PropertyKey(100, 0x744C8242, 0x4DF5, 0x456C, 0xAB, 0x9E, 0x01, 0x4E, 0xFB, 0x90, 0x21, 0xE3); + public static PropertyKey PKEY_Calendar_OrganizerName = new PropertyKey(100, 0xAAA660F9, 0x9865, 0x458E, 0xB4, 0x84, 0x01, 0xBC, 0x7F, 0xE3, 0x97, 0x3E); + public static PropertyKey PKEY_Calendar_ReminderTime = new PropertyKey(100, 0x72FC5BA4, 0x24F9, 0x4011, 0x9F, 0x3F, 0xAD, 0xD2, 0x7A, 0xFA, 0xD8, 0x18); + public static PropertyKey PKEY_Calendar_RequiredAttendeeAddresses = new PropertyKey(100, 0x0BA7D6C3, 0x568D, 0x4159, 0xAB, 0x91, 0x78, 0x1A, 0x91, 0xFB, 0x71, 0xE5); + public static PropertyKey PKEY_Calendar_RequiredAttendeeNames = new PropertyKey(100, 0xB33AF30B, 0xF552, 0x4584, 0x93, 0x6C, 0xCB, 0x93, 0xE5, 0xCD, 0xA2, 0x9F); + public static PropertyKey PKEY_Calendar_Resources = new PropertyKey(100, 0x00F58A38, 0xC54B, 0x4C40, 0x86, 0x96, 0x97, 0x23, 0x59, 0x80, 0xEA, 0xE1); + public static PropertyKey PKEY_Calendar_ResponseStatus = new PropertyKey(100, 0x188C1F91, 0x3C40, 0x4132, 0x9E, 0xC5, 0xD8, 0xB0, 0x3B, 0x72, 0xA8, 0xA2); + public static PropertyKey PKEY_Calendar_ShowTimeAs = new PropertyKey(100, 0x5BF396D4, 0x5EB2, 0x466F, 0xBD, 0xE9, 0x2F, 0xB3, 0xF2, 0x36, 0x1D, 0x6E); + public static PropertyKey PKEY_Calendar_ShowTimeAsText = new PropertyKey(100, 0x53DA57CF, 0x62C0, 0x45C4, 0x81, 0xDE, 0x76, 0x10, 0xBC, 0xEF, 0xD7, 0xF5); + public static PropertyKey PKEY_Communication_AccountName = new PropertyKey(9, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Communication_DateItemExpires = new PropertyKey(100, 0x428040AC, 0xA177, 0x4C8A, 0x97, 0x60, 0xF6, 0xF7, 0x61, 0x22, 0x7F, 0x9A); + public static PropertyKey PKEY_Communication_Direction = new PropertyKey(100, 0x8E531030, 0xB960, 0x4346, 0xAE, 0x0D, 0x66, 0xBC, 0x9A, 0x86, 0xFB, 0x94); + public static PropertyKey PKEY_Communication_FollowupIconIndex = new PropertyKey(100, 0x83A6347E, 0x6FE4, 0x4F40, 0xBA, 0x9C, 0xC4, 0x86, 0x52, 0x40, 0xD1, 0xF4); + public static PropertyKey PKEY_Communication_HeaderItem = new PropertyKey(100, 0xC9C34F84, 0x2241, 0x4401, 0xB6, 0x07, 0xBD, 0x20, 0xED, 0x75, 0xAE, 0x7F); + public static PropertyKey PKEY_Communication_PolicyTag = new PropertyKey(100, 0xEC0B4191, 0xAB0B, 0x4C66, 0x90, 0xB6, 0xC6, 0x63, 0x7C, 0xDE, 0xBB, 0xAB); + public static PropertyKey PKEY_Communication_SecurityFlags = new PropertyKey(100, 0x8619A4B6, 0x9F4D, 0x4429, 0x8C, 0x0F, 0xB9, 0x96, 0xCA, 0x59, 0xE3, 0x35); + public static PropertyKey PKEY_Communication_Suffix = new PropertyKey(100, 0x807B653A, 0x9E91, 0x43EF, 0x8F, 0x97, 0x11, 0xCE, 0x04, 0xEE, 0x20, 0xC5); + public static PropertyKey PKEY_Communication_TaskStatus = new PropertyKey(100, 0xBE1A72C6, 0x9A1D, 0x46B7, 0xAF, 0xE7, 0xAF, 0xAF, 0x8C, 0xEF, 0x49, 0x99); + public static PropertyKey PKEY_Communication_TaskStatusText = new PropertyKey(100, 0xA6744477, 0xC237, 0x475B, 0xA0, 0x75, 0x54, 0xF3, 0x44, 0x98, 0x29, 0x2A); + public static PropertyKey PKEY_Computer_DecoratedFreeSpace = new PropertyKey(7, 0x9B174B35, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71); + public static PropertyKey PKEY_Contact_AccountPictureDynamicVideo = new PropertyKey(2, 0x0B8BB018, 0x2725, 0x4B44, 0x92, 0xBA, 0x79, 0x33, 0xAE, 0xB2, 0xDD, 0xE7); + public static PropertyKey PKEY_Contact_AccountPictureLarge = new PropertyKey(3, 0x0B8BB018, 0x2725, 0x4B44, 0x92, 0xBA, 0x79, 0x33, 0xAE, 0xB2, 0xDD, 0xE7); + public static PropertyKey PKEY_Contact_AccountPictureSmall = new PropertyKey(4, 0x0B8BB018, 0x2725, 0x4B44, 0x92, 0xBA, 0x79, 0x33, 0xAE, 0xB2, 0xDD, 0xE7); + public static PropertyKey PKEY_Contact_Anniversary = new PropertyKey(100, 0x9AD5BADB, 0xCEA7, 0x4470, 0xA0, 0x3D, 0xB8, 0x4E, 0x51, 0xB9, 0x94, 0x9E); + public static PropertyKey PKEY_Contact_AssistantName = new PropertyKey(100, 0xCD102C9C, 0x5540, 0x4A88, 0xA6, 0xF6, 0x64, 0xE4, 0x98, 0x1C, 0x8C, 0xD1); + public static PropertyKey PKEY_Contact_AssistantTelephone = new PropertyKey(100, 0x9A93244D, 0xA7AD, 0x4FF8, 0x9B, 0x99, 0x45, 0xEE, 0x4C, 0xC0, 0x9A, 0xF6); + public static PropertyKey PKEY_Contact_Birthday = new PropertyKey(47, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_BusinessAddress = new PropertyKey(100, 0x730FB6DD, 0xCF7C, 0x426B, 0xA0, 0x3F, 0xBD, 0x16, 0x6C, 0xC9, 0xEE, 0x24); + public static PropertyKey PKEY_Contact_BusinessAddress1Country = new PropertyKey(119, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress1Locality = new PropertyKey(117, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress1PostalCode = new PropertyKey(120, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress1Region = new PropertyKey(118, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress1Street = new PropertyKey(116, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress2Country = new PropertyKey(124, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress2Locality = new PropertyKey(122, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress2PostalCode = new PropertyKey(125, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress2Region = new PropertyKey(123, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress2Street = new PropertyKey(121, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress3Country = new PropertyKey(129, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress3Locality = new PropertyKey(127, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress3PostalCode = new PropertyKey(130, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress3Region = new PropertyKey(128, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddress3Street = new PropertyKey(126, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_BusinessAddressCity = new PropertyKey(100, 0x402B5934, 0xEC5A, 0x48C3, 0x93, 0xE6, 0x85, 0xE8, 0x6A, 0x2D, 0x93, 0x4E); + public static PropertyKey PKEY_Contact_BusinessAddressCountry = new PropertyKey(100, 0xB0B87314, 0xFCF6, 0x4FEB, 0x8D, 0xFF, 0xA5, 0x0D, 0xA6, 0xAF, 0x56, 0x1C); + public static PropertyKey PKEY_Contact_BusinessAddressPostalCode = new PropertyKey(100, 0xE1D4A09E, 0xD758, 0x4CD1, 0xB6, 0xEC, 0x34, 0xA8, 0xB5, 0xA7, 0x3F, 0x80); + public static PropertyKey PKEY_Contact_BusinessAddressPostOfficeBox = new PropertyKey(100, 0xBC4E71CE, 0x17F9, 0x48D5, 0xBE, 0xE9, 0x02, 0x1D, 0xF0, 0xEA, 0x54, 0x09); + public static PropertyKey PKEY_Contact_BusinessAddressState = new PropertyKey(100, 0x446F787F, 0x10C4, 0x41CB, 0xA6, 0xC4, 0x4D, 0x03, 0x43, 0x55, 0x15, 0x97); + public static PropertyKey PKEY_Contact_BusinessAddressStreet = new PropertyKey(100, 0xDDD1460F, 0xC0BF, 0x4553, 0x8C, 0xE4, 0x10, 0x43, 0x3C, 0x90, 0x8F, 0xB0); + public static PropertyKey PKEY_Contact_BusinessEmailAddresses = new PropertyKey(100, 0xF271C659, 0x7E5E, 0x471F, 0xBA, 0x25, 0x7F, 0x77, 0xB2, 0x86, 0xF8, 0x36); + public static PropertyKey PKEY_Contact_BusinessFaxNumber = new PropertyKey(100, 0x91EFF6F3, 0x2E27, 0x42CA, 0x93, 0x3E, 0x7C, 0x99, 0x9F, 0xBE, 0x31, 0x0B); + public static PropertyKey PKEY_Contact_BusinessHomePage = new PropertyKey(100, 0x56310920, 0x2491, 0x4919, 0x99, 0xCE, 0xEA, 0xDB, 0x06, 0xFA, 0xFD, 0xB2); + public static PropertyKey PKEY_Contact_BusinessTelephone = new PropertyKey(100, 0x6A15E5A0, 0x0A1E, 0x4CD7, 0xBB, 0x8C, 0xD2, 0xF1, 0xB0, 0xC9, 0x29, 0xBC); + public static PropertyKey PKEY_Contact_CallbackTelephone = new PropertyKey(100, 0xBF53D1C3, 0x49E0, 0x4F7F, 0x85, 0x67, 0x5A, 0x82, 0x1D, 0x8A, 0xC5, 0x42); + public static PropertyKey PKEY_Contact_CarTelephone = new PropertyKey(100, 0x8FDC6DEA, 0xB929, 0x412B, 0xBA, 0x90, 0x39, 0x7A, 0x25, 0x74, 0x65, 0xFE); + public static PropertyKey PKEY_Contact_Children = new PropertyKey(100, 0xD4729704, 0x8EF1, 0x43EF, 0x90, 0x24, 0x2B, 0xD3, 0x81, 0x18, 0x7F, 0xD5); + public static PropertyKey PKEY_Contact_CompanyMainTelephone = new PropertyKey(100, 0x8589E481, 0x6040, 0x473D, 0xB1, 0x71, 0x7F, 0xA8, 0x9C, 0x27, 0x08, 0xED); + public static PropertyKey PKEY_Contact_ConnectedServiceDisplayName = new PropertyKey(100, 0x39B77F4F, 0xA104, 0x4863, 0xB3, 0x95, 0x2D, 0xB2, 0xAD, 0x8F, 0x7B, 0xC1); + public static PropertyKey PKEY_Contact_ConnectedServiceIdentities = new PropertyKey(100, 0x80F41EB8, 0xAFC4, 0x4208, 0xAA, 0x5F, 0xCC, 0xE2, 0x1A, 0x62, 0x72, 0x81); + public static PropertyKey PKEY_Contact_ConnectedServiceName = new PropertyKey(100, 0xB5C84C9E, 0x5927, 0x46B5, 0xA3, 0xCC, 0x93, 0x3C, 0x21, 0xB7, 0x84, 0x69); + public static PropertyKey PKEY_Contact_ConnectedServiceSupportedActions = new PropertyKey(100, 0xA19FB7A9, 0x024B, 0x4371, 0xA8, 0xBF, 0x4D, 0x29, 0xC3, 0xE4, 0xE9, 0xC9); + public static PropertyKey PKEY_Contact_DataSuppliers = new PropertyKey(100, 0x9660C283, 0xFC3A, 0x4A08, 0xA0, 0x96, 0xEE, 0xD3, 0xAA, 0xC4, 0x6D, 0xA2); + public static PropertyKey PKEY_Contact_Department = new PropertyKey(100, 0xFC9F7306, 0xFF8F, 0x4D49, 0x9F, 0xB6, 0x3F, 0xFE, 0x5C, 0x09, 0x51, 0xEC); + public static PropertyKey PKEY_Contact_DisplayBusinessPhoneNumbers = new PropertyKey(100, 0x364028DA, 0xD895, 0x41FE, 0xA5, 0x84, 0x30, 0x2B, 0x1B, 0xB7, 0x0A, 0x76); + public static PropertyKey PKEY_Contact_DisplayHomePhoneNumbers = new PropertyKey(100, 0x5068BCDF, 0xD697, 0x4D85, 0x8C, 0x53, 0x1F, 0x1C, 0xDA, 0xB0, 0x17, 0x63); + public static PropertyKey PKEY_Contact_DisplayMobilePhoneNumbers = new PropertyKey(100, 0x9CB0C358, 0x9D7A, 0x46B1, 0xB4, 0x66, 0xDC, 0xC6, 0xF1, 0xA3, 0xD9, 0x3D); + public static PropertyKey PKEY_Contact_DisplayOtherPhoneNumbers = new PropertyKey(100, 0x03089873, 0x8EE8, 0x4191, 0xBD, 0x60, 0xD3, 0x1F, 0x72, 0xB7, 0x90, 0x0B); + public static PropertyKey PKEY_Contact_EmailAddress = new PropertyKey(100, 0xF8FA7FA3, 0xD12B, 0x4785, 0x8A, 0x4E, 0x69, 0x1A, 0x94, 0xF7, 0xA3, 0xE7); + public static PropertyKey PKEY_Contact_EmailAddress2 = new PropertyKey(100, 0x38965063, 0xEDC8, 0x4268, 0x84, 0x91, 0xB7, 0x72, 0x31, 0x72, 0xCF, 0x29); + public static PropertyKey PKEY_Contact_EmailAddress3 = new PropertyKey(100, 0x644D37B4, 0xE1B3, 0x4BAD, 0xB0, 0x99, 0x7E, 0x7C, 0x04, 0x96, 0x6A, 0xCA); + public static PropertyKey PKEY_Contact_EmailAddresses = new PropertyKey(100, 0x84D8F337, 0x981D, 0x44B3, 0x96, 0x15, 0xC7, 0x59, 0x6D, 0xBA, 0x17, 0xE3); + public static PropertyKey PKEY_Contact_EmailName = new PropertyKey(100, 0xCC6F4F24, 0x6083, 0x4BD4, 0x87, 0x54, 0x67, 0x4D, 0x0D, 0xE8, 0x7A, 0xB8); + public static PropertyKey PKEY_Contact_FileAsName = new PropertyKey(100, 0xF1A24AA7, 0x9CA7, 0x40F6, 0x89, 0xEC, 0x97, 0xDE, 0xF9, 0xFF, 0xE8, 0xDB); + public static PropertyKey PKEY_Contact_FirstName = new PropertyKey(100, 0x14977844, 0x6B49, 0x4AAD, 0xA7, 0x14, 0xA4, 0x51, 0x3B, 0xF6, 0x04, 0x60); + public static PropertyKey PKEY_Contact_FullName = new PropertyKey(100, 0x635E9051, 0x50A5, 0x4BA2, 0xB9, 0xDB, 0x4E, 0xD0, 0x56, 0xC7, 0x72, 0x96); + public static PropertyKey PKEY_Contact_Gender = new PropertyKey(100, 0x3C8CEE58, 0xD4F0, 0x4CF9, 0xB7, 0x56, 0x4E, 0x5D, 0x24, 0x44, 0x7B, 0xCD); + public static PropertyKey PKEY_Contact_GenderValue = new PropertyKey(101, 0x3C8CEE58, 0xD4F0, 0x4CF9, 0xB7, 0x56, 0x4E, 0x5D, 0x24, 0x44, 0x7B, 0xCD); + public static PropertyKey PKEY_Contact_Hobbies = new PropertyKey(100, 0x5DC2253F, 0x5E11, 0x4ADF, 0x9C, 0xFE, 0x91, 0x0D, 0xD0, 0x1E, 0x3E, 0x70); + public static PropertyKey PKEY_Contact_HomeAddress = new PropertyKey(100, 0x98F98354, 0x617A, 0x46B8, 0x85, 0x60, 0x5B, 0x1B, 0x64, 0xBF, 0x1F, 0x89); + public static PropertyKey PKEY_Contact_HomeAddress1Country = new PropertyKey(104, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress1Locality = new PropertyKey(102, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress1PostalCode = new PropertyKey(105, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress1Region = new PropertyKey(103, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress1Street = new PropertyKey(101, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress2Country = new PropertyKey(109, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress2Locality = new PropertyKey(107, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress2PostalCode = new PropertyKey(110, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress2Region = new PropertyKey(108, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress2Street = new PropertyKey(106, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress3Country = new PropertyKey(114, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress3Locality = new PropertyKey(112, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress3PostalCode = new PropertyKey(115, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress3Region = new PropertyKey(113, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddress3Street = new PropertyKey(111, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_HomeAddressCity = new PropertyKey(65, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_HomeAddressCountry = new PropertyKey(100, 0x08A65AA1, 0xF4C9, 0x43DD, 0x9D, 0xDF, 0xA3, 0x3D, 0x8E, 0x7E, 0xAD, 0x85); + public static PropertyKey PKEY_Contact_HomeAddressPostalCode = new PropertyKey(100, 0x8AFCC170, 0x8A46, 0x4B53, 0x9E, 0xEE, 0x90, 0xBA, 0xE7, 0x15, 0x1E, 0x62); + public static PropertyKey PKEY_Contact_HomeAddressPostOfficeBox = new PropertyKey(100, 0x7B9F6399, 0x0A3F, 0x4B12, 0x89, 0xBD, 0x4A, 0xDC, 0x51, 0xC9, 0x18, 0xAF); + public static PropertyKey PKEY_Contact_HomeAddressState = new PropertyKey(100, 0xC89A23D0, 0x7D6D, 0x4EB8, 0x87, 0xD4, 0x77, 0x6A, 0x82, 0xD4, 0x93, 0xE5); + public static PropertyKey PKEY_Contact_HomeAddressStreet = new PropertyKey(100, 0x0ADEF160, 0xDB3F, 0x4308, 0x9A, 0x21, 0x06, 0x23, 0x7B, 0x16, 0xFA, 0x2A); + public static PropertyKey PKEY_Contact_HomeEmailAddresses = new PropertyKey(100, 0x56C90E9D, 0x9D46, 0x4963, 0x88, 0x6F, 0x2E, 0x1C, 0xD9, 0xA6, 0x94, 0xEF); + public static PropertyKey PKEY_Contact_HomeFaxNumber = new PropertyKey(100, 0x660E04D6, 0x81AB, 0x4977, 0xA0, 0x9F, 0x82, 0x31, 0x31, 0x13, 0xAB, 0x26); + public static PropertyKey PKEY_Contact_HomeTelephone = new PropertyKey(20, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_IMAddress = new PropertyKey(100, 0xD68DBD8A, 0x3374, 0x4B81, 0x99, 0x72, 0x3E, 0xC3, 0x06, 0x82, 0xDB, 0x3D); + public static PropertyKey PKEY_Contact_Initials = new PropertyKey(100, 0xF3D8F40D, 0x50CB, 0x44A2, 0x97, 0x18, 0x40, 0xCB, 0x91, 0x19, 0x49, 0x5D); + public static PropertyKey PKEY_Contact_JA_CompanyNamePhonetic = new PropertyKey(2, 0x897B3694, 0xFE9E, 0x43E6, 0x80, 0x66, 0x26, 0x0F, 0x59, 0x0C, 0x01, 0x00); + public static PropertyKey PKEY_Contact_JA_FirstNamePhonetic = new PropertyKey(3, 0x897B3694, 0xFE9E, 0x43E6, 0x80, 0x66, 0x26, 0x0F, 0x59, 0x0C, 0x01, 0x00); + public static PropertyKey PKEY_Contact_JA_LastNamePhonetic = new PropertyKey(4, 0x897B3694, 0xFE9E, 0x43E6, 0x80, 0x66, 0x26, 0x0F, 0x59, 0x0C, 0x01, 0x00); + public static PropertyKey PKEY_Contact_JobInfo1CompanyAddress = new PropertyKey(120, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo1CompanyName = new PropertyKey(102, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo1Department = new PropertyKey(106, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo1Manager = new PropertyKey(105, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo1OfficeLocation = new PropertyKey(104, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo1Title = new PropertyKey(103, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo1YomiCompanyName = new PropertyKey(101, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo2CompanyAddress = new PropertyKey(121, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo2CompanyName = new PropertyKey(108, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo2Department = new PropertyKey(113, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo2Manager = new PropertyKey(112, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo2OfficeLocation = new PropertyKey(110, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo2Title = new PropertyKey(109, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo2YomiCompanyName = new PropertyKey(107, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo3CompanyAddress = new PropertyKey(123, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo3CompanyName = new PropertyKey(115, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo3Department = new PropertyKey(119, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo3Manager = new PropertyKey(118, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo3OfficeLocation = new PropertyKey(117, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo3Title = new PropertyKey(116, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobInfo3YomiCompanyName = new PropertyKey(114, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_JobTitle = new PropertyKey(6, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_Label = new PropertyKey(100, 0x97B0AD89, 0xDF49, 0x49CC, 0x83, 0x4E, 0x66, 0x09, 0x74, 0xFD, 0x75, 0x5B); + public static PropertyKey PKEY_Contact_LastName = new PropertyKey(100, 0x8F367200, 0xC270, 0x457C, 0xB1, 0xD4, 0xE0, 0x7C, 0x5B, 0xCD, 0x90, 0xC7); + public static PropertyKey PKEY_Contact_MailingAddress = new PropertyKey(100, 0xC0AC206A, 0x827E, 0x4650, 0x95, 0xAE, 0x77, 0xE2, 0xBB, 0x74, 0xFC, 0xC9); + public static PropertyKey PKEY_Contact_MiddleName = new PropertyKey(71, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_MobileTelephone = new PropertyKey(35, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_NickName = new PropertyKey(74, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_OfficeLocation = new PropertyKey(7, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_OtherAddress = new PropertyKey(100, 0x508161FA, 0x313B, 0x43D5, 0x83, 0xA1, 0xC1, 0xAC, 0xCF, 0x68, 0x62, 0x2C); + public static PropertyKey PKEY_Contact_OtherAddress1Country = new PropertyKey(134, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress1Locality = new PropertyKey(132, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress1PostalCode = new PropertyKey(135, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress1Region = new PropertyKey(133, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress1Street = new PropertyKey(131, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress2Country = new PropertyKey(139, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress2Locality = new PropertyKey(137, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress2PostalCode = new PropertyKey(140, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress2Region = new PropertyKey(138, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress2Street = new PropertyKey(136, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress3Country = new PropertyKey(144, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress3Locality = new PropertyKey(142, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress3PostalCode = new PropertyKey(145, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress3Region = new PropertyKey(143, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddress3Street = new PropertyKey(141, 0xA7B6F596, 0xD678, 0x4BC1, 0xB0, 0x5F, 0x02, 0x03, 0xD2, 0x7E, 0x8A, 0xA1); + public static PropertyKey PKEY_Contact_OtherAddressCity = new PropertyKey(100, 0x6E682923, 0x7F7B, 0x4F0C, 0xA3, 0x37, 0xCF, 0xCA, 0x29, 0x66, 0x87, 0xBF); + public static PropertyKey PKEY_Contact_OtherAddressCountry = new PropertyKey(100, 0x8F167568, 0x0AAE, 0x4322, 0x8E, 0xD9, 0x60, 0x55, 0xB7, 0xB0, 0xE3, 0x98); + public static PropertyKey PKEY_Contact_OtherAddressPostalCode = new PropertyKey(100, 0x95C656C1, 0x2ABF, 0x4148, 0x9E, 0xD3, 0x9E, 0xC6, 0x02, 0xE3, 0xB7, 0xCD); + public static PropertyKey PKEY_Contact_OtherAddressPostOfficeBox = new PropertyKey(100, 0x8B26EA41, 0x058F, 0x43F6, 0xAE, 0xCC, 0x40, 0x35, 0x68, 0x1C, 0xE9, 0x77); + public static PropertyKey PKEY_Contact_OtherAddressState = new PropertyKey(100, 0x71B377D6, 0xE570, 0x425F, 0xA1, 0x70, 0x80, 0x9F, 0xAE, 0x73, 0xE5, 0x4E); + public static PropertyKey PKEY_Contact_OtherAddressStreet = new PropertyKey(100, 0xFF962609, 0xB7D6, 0x4999, 0x86, 0x2D, 0x95, 0x18, 0x0D, 0x52, 0x9A, 0xEA); + public static PropertyKey PKEY_Contact_OtherEmailAddresses = new PropertyKey(100, 0x11D6336B, 0x38C4, 0x4EC9, 0x84, 0xD6, 0xEB, 0x38, 0xD0, 0xB1, 0x50, 0xAF); + public static PropertyKey PKEY_Contact_PagerTelephone = new PropertyKey(100, 0xD6304E01, 0xF8F5, 0x4F45, 0x8B, 0x15, 0xD0, 0x24, 0xA6, 0x29, 0x67, 0x89); + public static PropertyKey PKEY_Contact_PersonalTitle = new PropertyKey(69, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_PhoneNumbersCanonical = new PropertyKey(100, 0xD042D2A1, 0x927E, 0x40B5, 0xA5, 0x03, 0x6E, 0xDB, 0xD4, 0x2A, 0x51, 0x7E); + public static PropertyKey PKEY_Contact_Prefix = new PropertyKey(75, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_PrimaryAddressCity = new PropertyKey(100, 0xC8EA94F0, 0xA9E3, 0x4969, 0xA9, 0x4B, 0x9C, 0x62, 0xA9, 0x53, 0x24, 0xE0); + public static PropertyKey PKEY_Contact_PrimaryAddressCountry = new PropertyKey(100, 0xE53D799D, 0x0F3F, 0x466E, 0xB2, 0xFF, 0x74, 0x63, 0x4A, 0x3C, 0xB7, 0xA4); + public static PropertyKey PKEY_Contact_PrimaryAddressPostalCode = new PropertyKey(100, 0x18BBD425, 0xECFD, 0x46EF, 0xB6, 0x12, 0x7B, 0x4A, 0x60, 0x34, 0xED, 0xA0); + public static PropertyKey PKEY_Contact_PrimaryAddressPostOfficeBox = new PropertyKey(100, 0xDE5EF3C7, 0x46E1, 0x484E, 0x99, 0x99, 0x62, 0xC5, 0x30, 0x83, 0x94, 0xC1); + public static PropertyKey PKEY_Contact_PrimaryAddressState = new PropertyKey(100, 0xF1176DFE, 0x7138, 0x4640, 0x8B, 0x4C, 0xAE, 0x37, 0x5D, 0xC7, 0x0A, 0x6D); + public static PropertyKey PKEY_Contact_PrimaryAddressStreet = new PropertyKey(100, 0x63C25B20, 0x96BE, 0x488F, 0x87, 0x88, 0xC0, 0x9C, 0x40, 0x7A, 0xD8, 0x12); + public static PropertyKey PKEY_Contact_PrimaryEmailAddress = new PropertyKey(48, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_PrimaryTelephone = new PropertyKey(25, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_Profession = new PropertyKey(100, 0x7268AF55, 0x1CE4, 0x4F6E, 0xA4, 0x1F, 0xB6, 0xE4, 0xEF, 0x10, 0xE4, 0xA9); + public static PropertyKey PKEY_Contact_SpouseName = new PropertyKey(100, 0x9D2408B6, 0x3167, 0x422B, 0x82, 0xB0, 0xF5, 0x83, 0xB7, 0xA7, 0xCF, 0xE3); + public static PropertyKey PKEY_Contact_Suffix = new PropertyKey(73, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9); + public static PropertyKey PKEY_Contact_TelexNumber = new PropertyKey(100, 0xC554493C, 0xC1F7, 0x40C1, 0xA7, 0x6C, 0xEF, 0x8C, 0x06, 0x14, 0x00, 0x3E); + public static PropertyKey PKEY_Contact_TTYTDDTelephone = new PropertyKey(100, 0xAAF16BAC, 0x2B55, 0x45E6, 0x9F, 0x6D, 0x41, 0x5E, 0xB9, 0x49, 0x10, 0xDF); + public static PropertyKey PKEY_Contact_WebPage = new PropertyKey(18, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Contact_Webpage2 = new PropertyKey(124, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_Contact_Webpage3 = new PropertyKey(125, 0x00F63DD8, 0x22BD, 0x4A5D, 0xBA, 0x34, 0x5C, 0xB0, 0xB9, 0xBD, 0xCB, 0x03); + public static PropertyKey PKEY_AcquisitionID = new PropertyKey(100, 0x65A98875, 0x3C80, 0x40AB, 0xAB, 0xBC, 0xEF, 0xDA, 0xF7, 0x7D, 0xBE, 0xE2); + public static PropertyKey PKEY_ApplicationDefinedProperties = new PropertyKey(100, 0xCDBFC167, 0x337E, 0x41D8, 0xAF, 0x7C, 0x8C, 0x09, 0x20, 0x54, 0x29, 0xC7); + public static PropertyKey PKEY_ApplicationName = new PropertyKey(18, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_AppZoneIdentifier = new PropertyKey(102, 0x502CFEAB, 0x47EB, 0x459C, 0xB9, 0x60, 0xE6, 0xD8, 0x72, 0x8F, 0x77, 0x01); + public static PropertyKey PKEY_Author = new PropertyKey(4, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_CachedFileUpdaterContentIdForConflictResolution = new PropertyKey(114, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_CachedFileUpdaterContentIdForStream = new PropertyKey(113, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_Capacity = new PropertyKey(3, 0x9B174B35, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71); + public static PropertyKey PKEY_Category = new PropertyKey(2, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_Comment = new PropertyKey(6, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Company = new PropertyKey(15, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_ComputerName = new PropertyKey(5, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_ContainedItems = new PropertyKey(29, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_ContentId = new PropertyKey(132, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_ContentStatus = new PropertyKey(27, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_ContentType = new PropertyKey(26, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_ContentUri = new PropertyKey(131, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_Copyright = new PropertyKey(11, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_CreatorAppId = new PropertyKey(2, 0xC2EA046E, 0x033C, 0x4E91, 0xBD, 0x5B, 0xD4, 0x94, 0x2F, 0x6B, 0xBE, 0x49); + public static PropertyKey PKEY_CreatorOpenWithUIOptions = new PropertyKey(3, 0xC2EA046E, 0x033C, 0x4E91, 0xBD, 0x5B, 0xD4, 0x94, 0x2F, 0x6B, 0xBE, 0x49); + public static PropertyKey PKEY_DataObjectFormat = new PropertyKey(2, 0x1E81A3F8, 0xA30F, 0x4247, 0xB9, 0xEE, 0x1D, 0x03, 0x68, 0xA9, 0x42, 0x5C); + public static PropertyKey PKEY_DateAccessed = new PropertyKey(16, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_DateAcquired = new PropertyKey(100, 0x2CBAA8F5, 0xD81F, 0x47CA, 0xB1, 0x7A, 0xF8, 0xD8, 0x22, 0x30, 0x01, 0x31); + public static PropertyKey PKEY_DateArchived = new PropertyKey(100, 0x43F8D7B7, 0xA444, 0x4F87, 0x93, 0x83, 0x52, 0x27, 0x1C, 0x9B, 0x91, 0x5C); + public static PropertyKey PKEY_DateCompleted = new PropertyKey(100, 0x72FAB781, 0xACDA, 0x43E5, 0xB1, 0x55, 0xB2, 0x43, 0x4F, 0x85, 0xE6, 0x78); + public static PropertyKey PKEY_DateCreated = new PropertyKey(15, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_DateImported = new PropertyKey(18258, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_DateModified = new PropertyKey(14, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_DefaultSaveLocationDisplay = new PropertyKey(10, 0x5D76B67F, 0x9B3D, 0x44BB, 0xB6, 0xAE, 0x25, 0xDA, 0x4F, 0x63, 0x8A, 0x67); + public static PropertyKey PKEY_DueDate = new PropertyKey(100, 0x3F8472B5, 0xE0AF, 0x4DB2, 0x80, 0x71, 0xC5, 0x3F, 0xE7, 0x6A, 0xE7, 0xCE); + public static PropertyKey PKEY_EndDate = new PropertyKey(100, 0xC75FAA05, 0x96FD, 0x49E7, 0x9C, 0xB4, 0x9F, 0x60, 0x10, 0x82, 0xD5, 0x53); + public static PropertyKey PKEY_ExpandoProperties = new PropertyKey(100, 0x6FA20DE6, 0xD11C, 0x4D9D, 0xA1, 0x54, 0x64, 0x31, 0x76, 0x28, 0xC1, 0x2D); + public static PropertyKey PKEY_FileAllocationSize = new PropertyKey(18, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_FileAttributes = new PropertyKey(13, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_FileCount = new PropertyKey(12, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_FileDescription = new PropertyKey(3, 0x0CEF7D53, 0xFA64, 0x11D1, 0xA2, 0x03, 0x00, 0x00, 0xF8, 0x1F, 0xED, 0xEE); + public static PropertyKey PKEY_FileExtension = new PropertyKey(100, 0xE4F10A3C, 0x49E6, 0x405D, 0x82, 0x88, 0xA2, 0x3B, 0xD4, 0xEE, 0xAA, 0x6C); + public static PropertyKey PKEY_FileFRN = new PropertyKey(21, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_FileName = new PropertyKey(100, 0x41CF5AE0, 0xF75A, 0x4806, 0xBD, 0x87, 0x59, 0xC7, 0xD9, 0x24, 0x8E, 0xB9); + public static PropertyKey PKEY_FileOfflineAvailabilityStatus = new PropertyKey(100, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_FileOwner = new PropertyKey(4, 0x9B174B34, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71); + public static PropertyKey PKEY_FilePlaceholderStatus = new PropertyKey(2, 0xB2F9B9D6, 0xFEC4, 0x4DD5, 0x94, 0xD7, 0x89, 0x57, 0x48, 0x8C, 0x80, 0x7B); + public static PropertyKey PKEY_FileVersion = new PropertyKey(4, 0x0CEF7D53, 0xFA64, 0x11D1, 0xA2, 0x03, 0x00, 0x00, 0xF8, 0x1F, 0xED, 0xEE); + public static PropertyKey PKEY_FindData = new PropertyKey(0, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_FlagColor = new PropertyKey(100, 0x67DF94DE, 0x0CA7, 0x4D6F, 0xB7, 0x92, 0x05, 0x3A, 0x3E, 0x4F, 0x03, 0xCF); + public static PropertyKey PKEY_FlagColorText = new PropertyKey(100, 0x45EAE747, 0x8E2A, 0x40AE, 0x8C, 0xBF, 0xCA, 0x52, 0xAB, 0xA6, 0x15, 0x2A); + public static PropertyKey PKEY_FlagStatus = new PropertyKey(12, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_FlagStatusText = new PropertyKey(100, 0xDC54FD2E, 0x189D, 0x4871, 0xAA, 0x01, 0x08, 0xC2, 0xF5, 0x7A, 0x4A, 0xBC); + public static PropertyKey PKEY_FolderKind = new PropertyKey(101, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_FolderNameDisplay = new PropertyKey(25, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_FreeSpace = new PropertyKey(2, 0x9B174B35, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71); + public static PropertyKey PKEY_FullText = new PropertyKey(6, 0x1E3EE840, 0xBC2B, 0x476C, 0x82, 0x37, 0x2A, 0xCD, 0x1A, 0x83, 0x9B, 0x22); + public static PropertyKey PKEY_HighKeywords = new PropertyKey(24, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Identity = new PropertyKey(100, 0xA26F4AFC, 0x7346, 0x4299, 0xBE, 0x47, 0xEB, 0x1A, 0xE6, 0x13, 0x13, 0x9F); + public static PropertyKey PKEY_Identity_Blob = new PropertyKey(100, 0x8C3B93A4, 0xBAED, 0x1A83, 0x9A, 0x32, 0x10, 0x2E, 0xE3, 0x13, 0xF6, 0xEB); + public static PropertyKey PKEY_Identity_DisplayName = new PropertyKey(100, 0x7D683FC9, 0xD155, 0x45A8, 0xBB, 0x1F, 0x89, 0xD1, 0x9B, 0xCB, 0x79, 0x2F); + public static PropertyKey PKEY_Identity_InternetSid = new PropertyKey(100, 0x6D6D5D49, 0x265D, 0x4688, 0x9F, 0x4E, 0x1F, 0xDD, 0x33, 0xE7, 0xCC, 0x83); + public static PropertyKey PKEY_Identity_IsMeIdentity = new PropertyKey(100, 0xA4108708, 0x09DF, 0x4377, 0x9D, 0xFC, 0x6D, 0x99, 0x98, 0x6D, 0x5A, 0x67); + public static PropertyKey PKEY_Identity_KeyProviderContext = new PropertyKey(17, 0xA26F4AFC, 0x7346, 0x4299, 0xBE, 0x47, 0xEB, 0x1A, 0xE6, 0x13, 0x13, 0x9F); + public static PropertyKey PKEY_Identity_KeyProviderName = new PropertyKey(16, 0xA26F4AFC, 0x7346, 0x4299, 0xBE, 0x47, 0xEB, 0x1A, 0xE6, 0x13, 0x13, 0x9F); + public static PropertyKey PKEY_Identity_LogonStatusString = new PropertyKey(100, 0xF18DEDF3, 0x337F, 0x42C0, 0x9E, 0x03, 0xCE, 0xE0, 0x87, 0x08, 0xA8, 0xC3); + public static PropertyKey PKEY_Identity_PrimaryEmailAddress = new PropertyKey(100, 0xFCC16823, 0xBAED, 0x4F24, 0x9B, 0x32, 0xA0, 0x98, 0x21, 0x17, 0xF7, 0xFA); + public static PropertyKey PKEY_Identity_PrimarySid = new PropertyKey(100, 0x2B1B801E, 0xC0C1, 0x4987, 0x9E, 0xC5, 0x72, 0xFA, 0x89, 0x81, 0x47, 0x87); + public static PropertyKey PKEY_Identity_ProviderData = new PropertyKey(100, 0xA8A74B92, 0x361B, 0x4E9A, 0xB7, 0x22, 0x7C, 0x4A, 0x73, 0x30, 0xA3, 0x12); + public static PropertyKey PKEY_Identity_ProviderID = new PropertyKey(100, 0x74A7DE49, 0xFA11, 0x4D3D, 0xA0, 0x06, 0xDB, 0x7E, 0x08, 0x67, 0x59, 0x16); + public static PropertyKey PKEY_Identity_QualifiedUserName = new PropertyKey(100, 0xDA520E51, 0xF4E9, 0x4739, 0xAC, 0x82, 0x02, 0xE0, 0xA9, 0x5C, 0x90, 0x30); + public static PropertyKey PKEY_Identity_UniqueID = new PropertyKey(100, 0xE55FC3B0, 0x2B60, 0x4220, 0x91, 0x8E, 0xB2, 0x1E, 0x8B, 0xF1, 0x60, 0x16); + public static PropertyKey PKEY_Identity_UserName = new PropertyKey(100, 0xC4322503, 0x78CA, 0x49C6, 0x9A, 0xCC, 0xA6, 0x8E, 0x2A, 0xFD, 0x7B, 0x6B); + public static PropertyKey PKEY_IdentityProvider_Name = new PropertyKey(100, 0xB96EFF7B, 0x35CA, 0x4A35, 0x86, 0x07, 0x29, 0xE3, 0xA5, 0x4C, 0x46, 0xEA); + public static PropertyKey PKEY_IdentityProvider_Picture = new PropertyKey(100, 0x2425166F, 0x5642, 0x4864, 0x99, 0x2F, 0x98, 0xFD, 0x98, 0xF2, 0x94, 0xC3); + public static PropertyKey PKEY_ImageParsingName = new PropertyKey(100, 0xD7750EE0, 0xC6A4, 0x48EC, 0xB5, 0x3E, 0xB8, 0x7B, 0x52, 0xE6, 0xD0, 0x73); + public static PropertyKey PKEY_Importance = new PropertyKey(11, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_ImportanceText = new PropertyKey(100, 0xA3B29791, 0x7713, 0x4E1D, 0xBB, 0x40, 0x17, 0xDB, 0x85, 0xF0, 0x18, 0x31); + public static PropertyKey PKEY_IsAttachment = new PropertyKey(100, 0xF23F425C, 0x71A1, 0x4FA8, 0x92, 0x2F, 0x67, 0x8E, 0xA4, 0xA6, 0x04, 0x08); + public static PropertyKey PKEY_IsDefaultNonOwnerSaveLocation = new PropertyKey(5, 0x5D76B67F, 0x9B3D, 0x44BB, 0xB6, 0xAE, 0x25, 0xDA, 0x4F, 0x63, 0x8A, 0x67); + public static PropertyKey PKEY_IsDefaultSaveLocation = new PropertyKey(3, 0x5D76B67F, 0x9B3D, 0x44BB, 0xB6, 0xAE, 0x25, 0xDA, 0x4F, 0x63, 0x8A, 0x67); + public static PropertyKey PKEY_IsDeleted = new PropertyKey(100, 0x5CDA5FC8, 0x33EE, 0x4FF3, 0x90, 0x94, 0xAE, 0x7B, 0xD8, 0x86, 0x8C, 0x4D); + public static PropertyKey PKEY_IsEncrypted = new PropertyKey(10, 0x90E5E14E, 0x648B, 0x4826, 0xB2, 0xAA, 0xAC, 0xAF, 0x79, 0x0E, 0x35, 0x13); + public static PropertyKey PKEY_IsFlagged = new PropertyKey(100, 0x5DA84765, 0xE3FF, 0x4278, 0x86, 0xB0, 0xA2, 0x79, 0x67, 0xFB, 0xDD, 0x03); + public static PropertyKey PKEY_IsFlaggedComplete = new PropertyKey(100, 0xA6F360D2, 0x55F9, 0x48DE, 0xB9, 0x09, 0x62, 0x0E, 0x09, 0x0A, 0x64, 0x7C); + public static PropertyKey PKEY_IsIncomplete = new PropertyKey(100, 0x346C8BD1, 0x2E6A, 0x4C45, 0x89, 0xA4, 0x61, 0xB7, 0x8E, 0x8E, 0x70, 0x0F); + public static PropertyKey PKEY_IsLocationSupported = new PropertyKey(8, 0x5D76B67F, 0x9B3D, 0x44BB, 0xB6, 0xAE, 0x25, 0xDA, 0x4F, 0x63, 0x8A, 0x67); + public static PropertyKey PKEY_IsPinnedToNameSpaceTree = new PropertyKey(2, 0x5D76B67F, 0x9B3D, 0x44BB, 0xB6, 0xAE, 0x25, 0xDA, 0x4F, 0x63, 0x8A, 0x67); + public static PropertyKey PKEY_IsRead = new PropertyKey(10, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_IsSearchOnlyItem = new PropertyKey(4, 0x5D76B67F, 0x9B3D, 0x44BB, 0xB6, 0xAE, 0x25, 0xDA, 0x4F, 0x63, 0x8A, 0x67); + public static PropertyKey PKEY_IsSendToTarget = new PropertyKey(33, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_IsShared = new PropertyKey(100, 0xEF884C5B, 0x2BFE, 0x41BB, 0xAA, 0xE5, 0x76, 0xEE, 0xDF, 0x4F, 0x99, 0x02); + public static PropertyKey PKEY_ItemAuthors = new PropertyKey(100, 0xD0A04F0A, 0x462A, 0x48A4, 0xBB, 0x2F, 0x37, 0x06, 0xE8, 0x8D, 0xBD, 0x7D); + public static PropertyKey PKEY_ItemClassType = new PropertyKey(100, 0x048658AD, 0x2DB8, 0x41A4, 0xBB, 0xB6, 0xAC, 0x1E, 0xF1, 0x20, 0x7E, 0xB1); + public static PropertyKey PKEY_ItemDate = new PropertyKey(100, 0xF7DB74B4, 0x4287, 0x4103, 0xAF, 0xBA, 0xF1, 0xB1, 0x3D, 0xCD, 0x75, 0xCF); + public static PropertyKey PKEY_ItemFolderNameDisplay = new PropertyKey(2, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_ItemFolderPathDisplay = new PropertyKey(6, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_ItemFolderPathDisplayNarrow = new PropertyKey(100, 0xDABD30ED, 0x0043, 0x4789, 0xA7, 0xF8, 0xD0, 0x13, 0xA4, 0x73, 0x66, 0x22); + public static PropertyKey PKEY_ItemName = new PropertyKey(100, 0x6B8DA074, 0x3B5C, 0x43BC, 0x88, 0x6F, 0x0A, 0x2C, 0xDC, 0xE0, 0x0B, 0x6F); + public static PropertyKey PKEY_ItemNameDisplay = new PropertyKey(10, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_ItemNameDisplayWithoutExtension = new PropertyKey(24, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_ItemNamePrefix = new PropertyKey(100, 0xD7313FF1, 0xA77A, 0x401C, 0x8C, 0x99, 0x3D, 0xBD, 0xD6, 0x8A, 0xDD, 0x36); + public static PropertyKey PKEY_ItemNameSortOverride = new PropertyKey(23, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_ItemParticipants = new PropertyKey(100, 0xD4D0AA16, 0x9948, 0x41A4, 0xAA, 0x85, 0xD9, 0x7F, 0xF9, 0x64, 0x69, 0x93); + public static PropertyKey PKEY_ItemPathDisplay = new PropertyKey(7, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_ItemPathDisplayNarrow = new PropertyKey(8, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_ItemSubType = new PropertyKey(37, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_ItemType = new PropertyKey(11, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_ItemTypeText = new PropertyKey(4, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_ItemUrl = new PropertyKey(9, 0x49691C90, 0x7E17, 0x101A, 0xA9, 0x1C, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9); + public static PropertyKey PKEY_Keywords = new PropertyKey(5, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Kind = new PropertyKey(3, 0x1E3EE840, 0xBC2B, 0x476C, 0x82, 0x37, 0x2A, 0xCD, 0x1A, 0x83, 0x9B, 0x22); + public static PropertyKey PKEY_KindText = new PropertyKey(100, 0xF04BEF95, 0xC585, 0x4197, 0xA2, 0xB7, 0xDF, 0x46, 0xFD, 0xC9, 0xEE, 0x6D); + public static PropertyKey PKEY_Language = new PropertyKey(28, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_LastSyncError = new PropertyKey(107, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_LastSyncWarning = new PropertyKey(128, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_LastWriterPackageFamilyName = new PropertyKey(101, 0x502CFEAB, 0x47EB, 0x459C, 0xB9, 0x60, 0xE6, 0xD8, 0x72, 0x8F, 0x77, 0x01); + public static PropertyKey PKEY_LowKeywords = new PropertyKey(25, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_MediumKeywords = new PropertyKey(26, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_MileageInformation = new PropertyKey(100, 0xFDF84370, 0x031A, 0x4ADD, 0x9E, 0x91, 0x0D, 0x77, 0x5F, 0x1C, 0x66, 0x05); + public static PropertyKey PKEY_MIMEType = new PropertyKey(5, 0x0B63E350, 0x9CCC, 0x11D0, 0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04); + public static PropertyKey PKEY_Null = new PropertyKey(0, 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + public static PropertyKey PKEY_OfflineAvailability = new PropertyKey(100, 0xA94688B6, 0x7D9F, 0x4570, 0xA6, 0x48, 0xE3, 0xDF, 0xC0, 0xAB, 0x2B, 0x3F); + public static PropertyKey PKEY_OfflineStatus = new PropertyKey(100, 0x6D24888F, 0x4718, 0x4BDA, 0xAF, 0xED, 0xEA, 0x0F, 0xB4, 0x38, 0x6C, 0xD8); + public static PropertyKey PKEY_OriginalFileName = new PropertyKey(6, 0x0CEF7D53, 0xFA64, 0x11D1, 0xA2, 0x03, 0x00, 0x00, 0xF8, 0x1F, 0xED, 0xEE); + public static PropertyKey PKEY_OwnerSID = new PropertyKey(6, 0x5D76B67F, 0x9B3D, 0x44BB, 0xB6, 0xAE, 0x25, 0xDA, 0x4F, 0x63, 0x8A, 0x67); + public static PropertyKey PKEY_ParentalRating = new PropertyKey(21, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_ParentalRatingReason = new PropertyKey(100, 0x10984E0A, 0xF9F2, 0x4321, 0xB7, 0xEF, 0xBA, 0xF1, 0x95, 0xAF, 0x43, 0x19); + public static PropertyKey PKEY_ParentalRatingsOrganization = new PropertyKey(100, 0xA7FE0840, 0x1344, 0x46F0, 0x8D, 0x37, 0x52, 0xED, 0x71, 0x2A, 0x4B, 0xF9); + public static PropertyKey PKEY_ParsingBindContext = new PropertyKey(100, 0xDFB9A04D, 0x362F, 0x4CA3, 0xB3, 0x0B, 0x02, 0x54, 0xB1, 0x7B, 0x5B, 0x84); + public static PropertyKey PKEY_ParsingName = new PropertyKey(24, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_ParsingPath = new PropertyKey(30, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_PerceivedType = new PropertyKey(9, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_PercentFull = new PropertyKey(5, 0x9B174B35, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71); + public static PropertyKey PKEY_Priority = new PropertyKey(5, 0x9C1FCF74, 0x2D97, 0x41BA, 0xB4, 0xAE, 0xCB, 0x2E, 0x36, 0x61, 0xA6, 0xE4); + public static PropertyKey PKEY_PriorityText = new PropertyKey(100, 0xD98BE98B, 0xB86B, 0x4095, 0xBF, 0x52, 0x9D, 0x23, 0xB2, 0xE0, 0xA7, 0x52); + public static PropertyKey PKEY_Project = new PropertyKey(100, 0x39A7F922, 0x477C, 0x48DE, 0x8B, 0xC8, 0xB2, 0x84, 0x41, 0xE3, 0x42, 0xE3); + public static PropertyKey PKEY_ProviderItemID = new PropertyKey(100, 0xF21D9941, 0x81F0, 0x471A, 0xAD, 0xEE, 0x4E, 0x74, 0xB4, 0x92, 0x17, 0xED); + public static PropertyKey PKEY_Rating = new PropertyKey(9, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_RatingText = new PropertyKey(100, 0x90197CA7, 0xFD8F, 0x4E8C, 0x9D, 0xA3, 0xB5, 0x7E, 0x1E, 0x60, 0x92, 0x95); + public static PropertyKey PKEY_RemoteConflictingFile = new PropertyKey(115, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_Security_AllowedEnterpriseDataProtectionIdentities = new PropertyKey(32, 0x38D43380, 0xD418, 0x4830, 0x84, 0xD5, 0x46, 0x93, 0x5A, 0x81, 0xC5, 0xC6); + public static PropertyKey PKEY_Security_EncryptionOwners = new PropertyKey(34, 0x5F5AFF6A, 0x37E5, 0x4780, 0x97, 0xEA, 0x80, 0xC7, 0x56, 0x5C, 0xF5, 0x35); + public static PropertyKey PKEY_Security_EncryptionOwnersDisplay = new PropertyKey(25, 0xDE621B8F, 0xE125, 0x43A3, 0xA3, 0x2D, 0x56, 0x65, 0x44, 0x6D, 0x63, 0x2A); + public static PropertyKey PKEY_Sensitivity = new PropertyKey(100, 0xF8D3F6AC, 0x4874, 0x42CB, 0xBE, 0x59, 0xAB, 0x45, 0x4B, 0x30, 0x71, 0x6A); + public static PropertyKey PKEY_SensitivityText = new PropertyKey(100, 0xD0C7F054, 0x3F72, 0x4725, 0x85, 0x27, 0x12, 0x9A, 0x57, 0x7C, 0xB2, 0x69); + public static PropertyKey PKEY_SFGAOFlags = new PropertyKey(25, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_SharedWith = new PropertyKey(200, 0xEF884C5B, 0x2BFE, 0x41BB, 0xAA, 0xE5, 0x76, 0xEE, 0xDF, 0x4F, 0x99, 0x02); + public static PropertyKey PKEY_ShareUserRating = new PropertyKey(12, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_SharingStatus = new PropertyKey(300, 0xEF884C5B, 0x2BFE, 0x41BB, 0xAA, 0xE5, 0x76, 0xEE, 0xDF, 0x4F, 0x99, 0x02); + public static PropertyKey PKEY_Shell_OmitFromView = new PropertyKey(2, 0xDE35258C, 0xC695, 0x4CBC, 0xB9, 0x82, 0x38, 0xB0, 0xAD, 0x24, 0xCE, 0xD0); + public static PropertyKey PKEY_SimpleRating = new PropertyKey(100, 0xA09F084E, 0xAD41, 0x489F, 0x80, 0x76, 0xAA, 0x5B, 0xE3, 0x08, 0x2B, 0xCA); + public static PropertyKey PKEY_Size = new PropertyKey(12, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_SoftwareUsed = new PropertyKey(305, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_SourceItem = new PropertyKey(100, 0x668CDFA5, 0x7A1B, 0x4323, 0xAE, 0x4B, 0xE5, 0x27, 0x39, 0x3A, 0x1D, 0x81); + public static PropertyKey PKEY_SourcePackageFamilyName = new PropertyKey(100, 0xFFAE9DB7, 0x1C8D, 0x43FF, 0x81, 0x8C, 0x84, 0x40, 0x3A, 0xA3, 0x73, 0x2D); + public static PropertyKey PKEY_StartDate = new PropertyKey(100, 0x48FD6EC8, 0x8A12, 0x4CDF, 0xA0, 0x3E, 0x4E, 0xC5, 0xA5, 0x11, 0xED, 0xDE); + public static PropertyKey PKEY_Status = new PropertyKey(9, 0x000214A1, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); + public static PropertyKey PKEY_StorageProviderCallerVersionInformation = new PropertyKey(7, 0xB2F9B9D6, 0xFEC4, 0x4DD5, 0x94, 0xD7, 0x89, 0x57, 0x48, 0x8C, 0x80, 0x7B); + public static PropertyKey PKEY_StorageProviderError = new PropertyKey(109, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_StorageProviderFileChecksum = new PropertyKey(5, 0xB2F9B9D6, 0xFEC4, 0x4DD5, 0x94, 0xD7, 0x89, 0x57, 0x48, 0x8C, 0x80, 0x7B); + public static PropertyKey PKEY_StorageProviderFileFlags = new PropertyKey(8, 0xB2F9B9D6, 0xFEC4, 0x4DD5, 0x94, 0xD7, 0x89, 0x57, 0x48, 0x8C, 0x80, 0x7B); + public static PropertyKey PKEY_StorageProviderFileIdentifier = new PropertyKey(3, 0xB2F9B9D6, 0xFEC4, 0x4DD5, 0x94, 0xD7, 0x89, 0x57, 0x48, 0x8C, 0x80, 0x7B); + public static PropertyKey PKEY_StorageProviderFileRemoteUri = new PropertyKey(112, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_StorageProviderFileVersion = new PropertyKey(4, 0xB2F9B9D6, 0xFEC4, 0x4DD5, 0x94, 0xD7, 0x89, 0x57, 0x48, 0x8C, 0x80, 0x7B); + public static PropertyKey PKEY_StorageProviderFileVersionWaterline = new PropertyKey(6, 0xB2F9B9D6, 0xFEC4, 0x4DD5, 0x94, 0xD7, 0x89, 0x57, 0x48, 0x8C, 0x80, 0x7B); + public static PropertyKey PKEY_StorageProviderId = new PropertyKey(108, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_StorageProviderShareStatuses = new PropertyKey(111, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_StorageProviderSharingStatus = new PropertyKey(117, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_StorageProviderStatus = new PropertyKey(110, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_Subject = new PropertyKey(3, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_SyncTransferStatus = new PropertyKey(103, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_Thumbnail = new PropertyKey(17, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_ThumbnailCacheId = new PropertyKey(100, 0x446D16B1, 0x8DAD, 0x4870, 0xA7, 0x48, 0x40, 0x2E, 0xA4, 0x3D, 0x78, 0x8C); + public static PropertyKey PKEY_ThumbnailStream = new PropertyKey(27, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Title = new PropertyKey(2, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_TitleSortOverride = new PropertyKey(300, 0xF0F7984D, 0x222E, 0x4AD2, 0x82, 0xAB, 0x1D, 0xD8, 0xEA, 0x40, 0xE5, 0x7E); + public static PropertyKey PKEY_TotalFileSize = new PropertyKey(14, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_Trademarks = new PropertyKey(9, 0x0CEF7D53, 0xFA64, 0x11D1, 0xA2, 0x03, 0x00, 0x00, 0xF8, 0x1F, 0xED, 0xEE); + public static PropertyKey PKEY_TransferOrder = new PropertyKey(106, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_TransferPosition = new PropertyKey(104, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_TransferSize = new PropertyKey(105, 0xFCEFF153, 0xE839, 0x4CF3, 0xA9, 0xE7, 0xEA, 0x22, 0x83, 0x20, 0x94, 0xB8); + public static PropertyKey PKEY_VolumeId = new PropertyKey(104, 0x446D16B1, 0x8DAD, 0x4870, 0xA7, 0x48, 0x40, 0x2E, 0xA4, 0x3D, 0x78, 0x8C); + public static PropertyKey PKEY_ZoneIdentifier = new PropertyKey(100, 0x502CFEAB, 0x47EB, 0x459C, 0xB9, 0x60, 0xE6, 0xD8, 0x72, 0x8F, 0x77, 0x01); + public static PropertyKey PKEY_Device_PrinterURL = new PropertyKey(15, 0x0B48F35A, 0xBE6E, 0x4F17, 0xB1, 0x08, 0x3C, 0x40, 0x73, 0xD1, 0x66, 0x9A); + public static PropertyKey PKEY_DeviceInterface_Bluetooth_DeviceAddress = new PropertyKey(1, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A); + public static PropertyKey PKEY_DeviceInterface_Bluetooth_Flags = new PropertyKey(3, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A); + public static PropertyKey PKEY_DeviceInterface_Bluetooth_LastConnectedTime = new PropertyKey(11, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A); + public static PropertyKey PKEY_DeviceInterface_Bluetooth_Manufacturer = new PropertyKey(4, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A); + public static PropertyKey PKEY_DeviceInterface_Bluetooth_ModelNumber = new PropertyKey(5, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A); + public static PropertyKey PKEY_DeviceInterface_Bluetooth_ProductId = new PropertyKey(8, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A); + public static PropertyKey PKEY_DeviceInterface_Bluetooth_ProductVersion = new PropertyKey(9, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A); + public static PropertyKey PKEY_DeviceInterface_Bluetooth_ServiceGuid = new PropertyKey(2, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A); + public static PropertyKey PKEY_DeviceInterface_Bluetooth_VendorId = new PropertyKey(7, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A); + public static PropertyKey PKEY_DeviceInterface_Bluetooth_VendorIdSource = new PropertyKey(6, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A); + public static PropertyKey PKEY_DeviceInterface_Hid_IsReadOnly = new PropertyKey(4, 0xCBF38310, 0x4A17, 0x4310, 0xA1, 0xEB, 0x24, 0x7F, 0x0B, 0x67, 0x59, 0x3B); + public static PropertyKey PKEY_DeviceInterface_Hid_ProductId = new PropertyKey(6, 0xCBF38310, 0x4A17, 0x4310, 0xA1, 0xEB, 0x24, 0x7F, 0x0B, 0x67, 0x59, 0x3B); + public static PropertyKey PKEY_DeviceInterface_Hid_UsageId = new PropertyKey(3, 0xCBF38310, 0x4A17, 0x4310, 0xA1, 0xEB, 0x24, 0x7F, 0x0B, 0x67, 0x59, 0x3B); + public static PropertyKey PKEY_DeviceInterface_Hid_UsagePage = new PropertyKey(2, 0xCBF38310, 0x4A17, 0x4310, 0xA1, 0xEB, 0x24, 0x7F, 0x0B, 0x67, 0x59, 0x3B); + public static PropertyKey PKEY_DeviceInterface_Hid_VendorId = new PropertyKey(5, 0xCBF38310, 0x4A17, 0x4310, 0xA1, 0xEB, 0x24, 0x7F, 0x0B, 0x67, 0x59, 0x3B); + public static PropertyKey PKEY_DeviceInterface_Hid_VersionNumber = new PropertyKey(7, 0xCBF38310, 0x4A17, 0x4310, 0xA1, 0xEB, 0x24, 0x7F, 0x0B, 0x67, 0x59, 0x3B); + public static PropertyKey PKEY_DeviceInterface_PrinterDriverDirectory = new PropertyKey(14, 0x847C66DE, 0xB8D6, 0x4AF9, 0xAB, 0xC3, 0x6F, 0x4F, 0x92, 0x6B, 0xC0, 0x39); + public static PropertyKey PKEY_DeviceInterface_PrinterDriverName = new PropertyKey(11, 0xAFC47170, 0x14F5, 0x498C, 0x8F, 0x30, 0xB0, 0xD1, 0x9B, 0xE4, 0x49, 0xC6); + public static PropertyKey PKEY_DeviceInterface_PrinterEnumerationFlag = new PropertyKey(3, 0xA00742A1, 0xCD8C, 0x4B37, 0x95, 0xAB, 0x70, 0x75, 0x55, 0x87, 0x76, 0x7A); + public static PropertyKey PKEY_DeviceInterface_PrinterName = new PropertyKey(10, 0x0A7B84EF, 0x0C27, 0x463F, 0x84, 0xEF, 0x06, 0xC5, 0x07, 0x00, 0x01, 0xBE); + public static PropertyKey PKEY_DeviceInterface_PrinterPortName = new PropertyKey(12, 0xEEC7B761, 0x6F94, 0x41B1, 0x94, 0x9F, 0xC7, 0x29, 0x72, 0x0D, 0xD1, 0x3C); + public static PropertyKey PKEY_DeviceInterface_Proximity_SupportsNfc = new PropertyKey(2, 0xFB3842CD, 0x9E2A, 0x4F83, 0x8F, 0xCC, 0x4B, 0x07, 0x61, 0x13, 0x9A, 0xE9); + public static PropertyKey PKEY_DeviceInterface_Serial_PortName = new PropertyKey(4, 0x4C6BF15C, 0x4C03, 0x4AAC, 0x91, 0xF5, 0x64, 0xC0, 0xF8, 0x52, 0xBC, 0xF4); + public static PropertyKey PKEY_DeviceInterface_Serial_UsbProductId = new PropertyKey(3, 0x4C6BF15C, 0x4C03, 0x4AAC, 0x91, 0xF5, 0x64, 0xC0, 0xF8, 0x52, 0xBC, 0xF4); + public static PropertyKey PKEY_DeviceInterface_Serial_UsbVendorId = new PropertyKey(2, 0x4C6BF15C, 0x4C03, 0x4AAC, 0x91, 0xF5, 0x64, 0xC0, 0xF8, 0x52, 0xBC, 0xF4); + public static PropertyKey PKEY_DeviceInterface_WinUsb_DeviceInterfaceClasses = new PropertyKey(7, 0x95E127B5, 0x79CC, 0x4E83, 0x9C, 0x9E, 0x84, 0x22, 0x18, 0x7B, 0x3E, 0x0E); + public static PropertyKey PKEY_DeviceInterface_WinUsb_UsbClass = new PropertyKey(4, 0x95E127B5, 0x79CC, 0x4E83, 0x9C, 0x9E, 0x84, 0x22, 0x18, 0x7B, 0x3E, 0x0E); + public static PropertyKey PKEY_DeviceInterface_WinUsb_UsbProductId = new PropertyKey(3, 0x95E127B5, 0x79CC, 0x4E83, 0x9C, 0x9E, 0x84, 0x22, 0x18, 0x7B, 0x3E, 0x0E); + public static PropertyKey PKEY_DeviceInterface_WinUsb_UsbProtocol = new PropertyKey(6, 0x95E127B5, 0x79CC, 0x4E83, 0x9C, 0x9E, 0x84, 0x22, 0x18, 0x7B, 0x3E, 0x0E); + public static PropertyKey PKEY_DeviceInterface_WinUsb_UsbSubClass = new PropertyKey(5, 0x95E127B5, 0x79CC, 0x4E83, 0x9C, 0x9E, 0x84, 0x22, 0x18, 0x7B, 0x3E, 0x0E); + public static PropertyKey PKEY_DeviceInterface_WinUsb_UsbVendorId = new PropertyKey(2, 0x95E127B5, 0x79CC, 0x4E83, 0x9C, 0x9E, 0x84, 0x22, 0x18, 0x7B, 0x3E, 0x0E); + public static PropertyKey PKEY_Devices_Aep_AepId = new PropertyKey(8, 0x3B2CE006, 0x5E61, 0x4FDE, 0xBA, 0xB8, 0x9B, 0x8A, 0xAC, 0x9B, 0x26, 0xDF); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Cod_Major = new PropertyKey(2, 0x5FBD34CD, 0x561A, 0x412E, 0xBA, 0x98, 0x47, 0x8A, 0x6B, 0x0F, 0xEF, 0x1D); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Cod_Minor = new PropertyKey(3, 0x5FBD34CD, 0x561A, 0x412E, 0xBA, 0x98, 0x47, 0x8A, 0x6B, 0x0F, 0xEF, 0x1D); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Cod_Services_Audio = new PropertyKey(10, 0x5FBD34CD, 0x561A, 0x412E, 0xBA, 0x98, 0x47, 0x8A, 0x6B, 0x0F, 0xEF, 0x1D); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Cod_Services_Capturing = new PropertyKey(8, 0x5FBD34CD, 0x561A, 0x412E, 0xBA, 0x98, 0x47, 0x8A, 0x6B, 0x0F, 0xEF, 0x1D); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Cod_Services_Information = new PropertyKey(12, 0x5FBD34CD, 0x561A, 0x412E, 0xBA, 0x98, 0x47, 0x8A, 0x6B, 0x0F, 0xEF, 0x1D); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Cod_Services_LimitedDiscovery = new PropertyKey(4, 0x5FBD34CD, 0x561A, 0x412E, 0xBA, 0x98, 0x47, 0x8A, 0x6B, 0x0F, 0xEF, 0x1D); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Cod_Services_Networking = new PropertyKey(6, 0x5FBD34CD, 0x561A, 0x412E, 0xBA, 0x98, 0x47, 0x8A, 0x6B, 0x0F, 0xEF, 0x1D); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Cod_Services_ObjectXfer = new PropertyKey(9, 0x5FBD34CD, 0x561A, 0x412E, 0xBA, 0x98, 0x47, 0x8A, 0x6B, 0x0F, 0xEF, 0x1D); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Cod_Services_Positioning = new PropertyKey(5, 0x5FBD34CD, 0x561A, 0x412E, 0xBA, 0x98, 0x47, 0x8A, 0x6B, 0x0F, 0xEF, 0x1D); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Cod_Services_Rendering = new PropertyKey(7, 0x5FBD34CD, 0x561A, 0x412E, 0xBA, 0x98, 0x47, 0x8A, 0x6B, 0x0F, 0xEF, 0x1D); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Cod_Services_Telephony = new PropertyKey(11, 0x5FBD34CD, 0x561A, 0x412E, 0xBA, 0x98, 0x47, 0x8A, 0x6B, 0x0F, 0xEF, 0x1D); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_LastSeenTime = new PropertyKey(12, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Le_AddressType = new PropertyKey(4, 0x995EF0B0, 0x7EB3, 0x4A8B, 0xB9, 0xCE, 0x06, 0x8B, 0xB3, 0xF4, 0xAF, 0x69); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Le_Appearance = new PropertyKey(1, 0x995EF0B0, 0x7EB3, 0x4A8B, 0xB9, 0xCE, 0x06, 0x8B, 0xB3, 0xF4, 0xAF, 0x69); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Le_Appearance_Category = new PropertyKey(5, 0x995EF0B0, 0x7EB3, 0x4A8B, 0xB9, 0xCE, 0x06, 0x8B, 0xB3, 0xF4, 0xAF, 0x69); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Le_Appearance_Subcategory = new PropertyKey(6, 0x995EF0B0, 0x7EB3, 0x4A8B, 0xB9, 0xCE, 0x06, 0x8B, 0xB3, 0xF4, 0xAF, 0x69); + public static PropertyKey PKEY_Devices_Aep_Bluetooth_Le_IsConnectable = new PropertyKey(8, 0x995EF0B0, 0x7EB3, 0x4A8B, 0xB9, 0xCE, 0x06, 0x8B, 0xB3, 0xF4, 0xAF, 0x69); + public static PropertyKey PKEY_Devices_Aep_CanPair = new PropertyKey(3, 0xE7C3FB29, 0xCAA7, 0x4F47, 0x8C, 0x8B, 0xBE, 0x59, 0xB3, 0x30, 0xD4, 0xC5); + public static PropertyKey PKEY_Devices_Aep_Category = new PropertyKey(17, 0xA35996AB, 0x11CF, 0x4935, 0x8B, 0x61, 0xA6, 0x76, 0x10, 0x81, 0xEC, 0xDF); + public static PropertyKey PKEY_Devices_Aep_ContainerId = new PropertyKey(2, 0xE7C3FB29, 0xCAA7, 0x4F47, 0x8C, 0x8B, 0xBE, 0x59, 0xB3, 0x30, 0xD4, 0xC5); + public static PropertyKey PKEY_Devices_Aep_DeviceAddress = new PropertyKey(12, 0xA35996AB, 0x11CF, 0x4935, 0x8B, 0x61, 0xA6, 0x76, 0x10, 0x81, 0xEC, 0xDF); + public static PropertyKey PKEY_Devices_Aep_IsConnected = new PropertyKey(7, 0xA35996AB, 0x11CF, 0x4935, 0x8B, 0x61, 0xA6, 0x76, 0x10, 0x81, 0xEC, 0xDF); + public static PropertyKey PKEY_Devices_Aep_IsPaired = new PropertyKey(16, 0xA35996AB, 0x11CF, 0x4935, 0x8B, 0x61, 0xA6, 0x76, 0x10, 0x81, 0xEC, 0xDF); + public static PropertyKey PKEY_Devices_Aep_IsPresent = new PropertyKey(9, 0xA35996AB, 0x11CF, 0x4935, 0x8B, 0x61, 0xA6, 0x76, 0x10, 0x81, 0xEC, 0xDF); + public static PropertyKey PKEY_Devices_Aep_Manufacturer = new PropertyKey(5, 0xA35996AB, 0x11CF, 0x4935, 0x8B, 0x61, 0xA6, 0x76, 0x10, 0x81, 0xEC, 0xDF); + public static PropertyKey PKEY_Devices_Aep_ModelId = new PropertyKey(4, 0xA35996AB, 0x11CF, 0x4935, 0x8B, 0x61, 0xA6, 0x76, 0x10, 0x81, 0xEC, 0xDF); + public static PropertyKey PKEY_Devices_Aep_ModelName = new PropertyKey(3, 0xA35996AB, 0x11CF, 0x4935, 0x8B, 0x61, 0xA6, 0x76, 0x10, 0x81, 0xEC, 0xDF); + public static PropertyKey PKEY_Devices_Aep_PointOfService_ConnectionTypes = new PropertyKey(6, 0xD4BF61B3, 0x442E, 0x4ADA, 0x88, 0x2D, 0xFA, 0x7B, 0x70, 0xC8, 0x32, 0xD9); + public static PropertyKey PKEY_Devices_Aep_ProtocolId = new PropertyKey(5, 0x3B2CE006, 0x5E61, 0x4FDE, 0xBA, 0xB8, 0x9B, 0x8A, 0xAC, 0x9B, 0x26, 0xDF); + public static PropertyKey PKEY_Devices_Aep_SignalStrength = new PropertyKey(6, 0xA35996AB, 0x11CF, 0x4935, 0x8B, 0x61, 0xA6, 0x76, 0x10, 0x81, 0xEC, 0xDF); + public static PropertyKey PKEY_Devices_AepContainer_CanPair = new PropertyKey(3, 0x0BBA1EDE, 0x7566, 0x4F47, 0x90, 0xEC, 0x25, 0xFC, 0x56, 0x7C, 0xED, 0x2A); + public static PropertyKey PKEY_Devices_AepContainer_Categories = new PropertyKey(9, 0x0BBA1EDE, 0x7566, 0x4F47, 0x90, 0xEC, 0x25, 0xFC, 0x56, 0x7C, 0xED, 0x2A); + public static PropertyKey PKEY_Devices_AepContainer_Children = new PropertyKey(2, 0x0BBA1EDE, 0x7566, 0x4F47, 0x90, 0xEC, 0x25, 0xFC, 0x56, 0x7C, 0xED, 0x2A); + public static PropertyKey PKEY_Devices_AepContainer_ContainerId = new PropertyKey(12, 0x0BBA1EDE, 0x7566, 0x4F47, 0x90, 0xEC, 0x25, 0xFC, 0x56, 0x7C, 0xED, 0x2A); + public static PropertyKey PKEY_Devices_AepContainer_DialProtocol_InstalledApplications = new PropertyKey(6, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepContainer_IsPaired = new PropertyKey(4, 0x0BBA1EDE, 0x7566, 0x4F47, 0x90, 0xEC, 0x25, 0xFC, 0x56, 0x7C, 0xED, 0x2A); + public static PropertyKey PKEY_Devices_AepContainer_IsPresent = new PropertyKey(11, 0x0BBA1EDE, 0x7566, 0x4F47, 0x90, 0xEC, 0x25, 0xFC, 0x56, 0x7C, 0xED, 0x2A); + public static PropertyKey PKEY_Devices_AepContainer_Manufacturer = new PropertyKey(6, 0x0BBA1EDE, 0x7566, 0x4F47, 0x90, 0xEC, 0x25, 0xFC, 0x56, 0x7C, 0xED, 0x2A); + public static PropertyKey PKEY_Devices_AepContainer_ModelIds = new PropertyKey(8, 0x0BBA1EDE, 0x7566, 0x4F47, 0x90, 0xEC, 0x25, 0xFC, 0x56, 0x7C, 0xED, 0x2A); + public static PropertyKey PKEY_Devices_AepContainer_ModelName = new PropertyKey(7, 0x0BBA1EDE, 0x7566, 0x4F47, 0x90, 0xEC, 0x25, 0xFC, 0x56, 0x7C, 0xED, 0x2A); + public static PropertyKey PKEY_Devices_AepContainer_ProtocolIds = new PropertyKey(13, 0x0BBA1EDE, 0x7566, 0x4F47, 0x90, 0xEC, 0x25, 0xFC, 0x56, 0x7C, 0xED, 0x2A); + public static PropertyKey PKEY_Devices_AepContainer_SupportedUriSchemes = new PropertyKey(5, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepContainer_SupportsAudio = new PropertyKey(2, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepContainer_SupportsCapturing = new PropertyKey(11, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepContainer_SupportsImages = new PropertyKey(4, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepContainer_SupportsInformation = new PropertyKey(14, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepContainer_SupportsLimitedDiscovery = new PropertyKey(7, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepContainer_SupportsNetworking = new PropertyKey(9, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepContainer_SupportsObjectTransfer = new PropertyKey(12, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepContainer_SupportsPositioning = new PropertyKey(8, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepContainer_SupportsRendering = new PropertyKey(10, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepContainer_SupportsTelephony = new PropertyKey(13, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepContainer_SupportsVideo = new PropertyKey(3, 0x6AF55D45, 0x38DB, 0x4495, 0xAC, 0xB0, 0xD4, 0x72, 0x8A, 0x3B, 0x83, 0x14); + public static PropertyKey PKEY_Devices_AepService_AepId = new PropertyKey(6, 0xC9C141A9, 0x1B4C, 0x4F17, 0xA9, 0xD1, 0xF2, 0x98, 0x53, 0x8C, 0xAD, 0xB8); + public static PropertyKey PKEY_Devices_AepService_Bluetooth_CacheMode = new PropertyKey(5, 0x9744311E, 0x7951, 0x4B2E, 0xB6, 0xF0, 0xEC, 0xB2, 0x93, 0xCA, 0xC1, 0x19); + public static PropertyKey PKEY_Devices_AepService_Bluetooth_ServiceGuid = new PropertyKey(2, 0xA399AAC7, 0xC265, 0x474E, 0xB0, 0x73, 0xFF, 0xCE, 0x57, 0x72, 0x17, 0x16); + public static PropertyKey PKEY_Devices_AepService_Bluetooth_TargetDevice = new PropertyKey(6, 0x9744311E, 0x7951, 0x4B2E, 0xB6, 0xF0, 0xEC, 0xB2, 0x93, 0xCA, 0xC1, 0x19); + public static PropertyKey PKEY_Devices_AepService_ContainerId = new PropertyKey(4, 0x71724756, 0x3E74, 0x4432, 0x9B, 0x59, 0xE7, 0xB2, 0xF6, 0x68, 0xA5, 0x93); + public static PropertyKey PKEY_Devices_AepService_FriendlyName = new PropertyKey(2, 0x71724756, 0x3E74, 0x4432, 0x9B, 0x59, 0xE7, 0xB2, 0xF6, 0x68, 0xA5, 0x93); + public static PropertyKey PKEY_Devices_AepService_IoT_ServiceInterfaces = new PropertyKey(2, 0x79D94E82, 0x4D79, 0x45AA, 0x82, 0x1A, 0x74, 0x85, 0x8B, 0x4E, 0x4C, 0xA6); + public static PropertyKey PKEY_Devices_AepService_ParentAepIsPaired = new PropertyKey(7, 0xC9C141A9, 0x1B4C, 0x4F17, 0xA9, 0xD1, 0xF2, 0x98, 0x53, 0x8C, 0xAD, 0xB8); + public static PropertyKey PKEY_Devices_AepService_ProtocolId = new PropertyKey(5, 0xC9C141A9, 0x1B4C, 0x4F17, 0xA9, 0xD1, 0xF2, 0x98, 0x53, 0x8C, 0xAD, 0xB8); + public static PropertyKey PKEY_Devices_AepService_ServiceClassId = new PropertyKey(3, 0x71724756, 0x3E74, 0x4432, 0x9B, 0x59, 0xE7, 0xB2, 0xF6, 0x68, 0xA5, 0x93); + public static PropertyKey PKEY_Devices_AepService_ServiceId = new PropertyKey(2, 0xC9C141A9, 0x1B4C, 0x4F17, 0xA9, 0xD1, 0xF2, 0x98, 0x53, 0x8C, 0xAD, 0xB8); + public static PropertyKey PKEY_Devices_AppPackageFamilyName = new PropertyKey(100, 0x51236583, 0x0C4A, 0x4FE8, 0xB8, 0x1F, 0x16, 0x6A, 0xEC, 0x13, 0xF5, 0x10); + public static PropertyKey PKEY_Devices_AudioDevice_Microphone_IsFarField = new PropertyKey(6, 0x8943B373, 0x388C, 0x4395, 0xB5, 0x57, 0xBC, 0x6D, 0xBA, 0xFF, 0xAF, 0xDB); + public static PropertyKey PKEY_Devices_AudioDevice_Microphone_SensitivityInDbfs = new PropertyKey(3, 0x8943B373, 0x388C, 0x4395, 0xB5, 0x57, 0xBC, 0x6D, 0xBA, 0xFF, 0xAF, 0xDB); + public static PropertyKey PKEY_Devices_AudioDevice_Microphone_SensitivityInDbfs2 = new PropertyKey(5, 0x8943B373, 0x388C, 0x4395, 0xB5, 0x57, 0xBC, 0x6D, 0xBA, 0xFF, 0xAF, 0xDB); + public static PropertyKey PKEY_Devices_AudioDevice_Microphone_SignalToNoiseRatioInDb = new PropertyKey(4, 0x8943B373, 0x388C, 0x4395, 0xB5, 0x57, 0xBC, 0x6D, 0xBA, 0xFF, 0xAF, 0xDB); + public static PropertyKey PKEY_Devices_AudioDevice_RawProcessingSupported = new PropertyKey(2, 0x8943B373, 0x388C, 0x4395, 0xB5, 0x57, 0xBC, 0x6D, 0xBA, 0xFF, 0xAF, 0xDB); + public static PropertyKey PKEY_Devices_AudioDevice_SpeechProcessingSupported = new PropertyKey(2, 0xFB1DE864, 0xE06D, 0x47F4, 0x82, 0xA6, 0x8A, 0x0A, 0xEF, 0x44, 0x49, 0x3C); + public static PropertyKey PKEY_Devices_BatteryLife = new PropertyKey(10, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_BatteryPlusCharging = new PropertyKey(22, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_BatteryPlusChargingText = new PropertyKey(23, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_Category = new PropertyKey(91, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_CategoryGroup = new PropertyKey(94, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_CategoryIds = new PropertyKey(90, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_CategoryPlural = new PropertyKey(92, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_ChargingState = new PropertyKey(11, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_Children = new PropertyKey(9, 0x4340A6C5, 0x93FA, 0x4706, 0x97, 0x2C, 0x7B, 0x64, 0x80, 0x08, 0xA5, 0xA7); + public static PropertyKey PKEY_Devices_ClassGuid = new PropertyKey(10, 0xA45C254E, 0xDF1C, 0x4EFD, 0x80, 0x20, 0x67, 0xD1, 0x46, 0xA8, 0x50, 0xE0); + public static PropertyKey PKEY_Devices_CompatibleIds = new PropertyKey(4, 0xA45C254E, 0xDF1C, 0x4EFD, 0x80, 0x20, 0x67, 0xD1, 0x46, 0xA8, 0x50, 0xE0); + public static PropertyKey PKEY_Devices_Connected = new PropertyKey(55, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_ContainerId = new PropertyKey(2, 0x8C7ED206, 0x3F8A, 0x4827, 0xB3, 0xAB, 0xAE, 0x9E, 0x1F, 0xAE, 0xFC, 0x6C); + public static PropertyKey PKEY_Devices_DefaultTooltip = new PropertyKey(153, 0x880F70A2, 0x6082, 0x47AC, 0x8A, 0xAB, 0xA7, 0x39, 0xD1, 0xA3, 0x00, 0xC3); + public static PropertyKey PKEY_Devices_DeviceCapabilities = new PropertyKey(17, 0xA45C254E, 0xDF1C, 0x4EFD, 0x80, 0x20, 0x67, 0xD1, 0x46, 0xA8, 0x50, 0xE0); + public static PropertyKey PKEY_Devices_DeviceCharacteristics = new PropertyKey(29, 0xA45C254E, 0xDF1C, 0x4EFD, 0x80, 0x20, 0x67, 0xD1, 0x46, 0xA8, 0x50, 0xE0); + public static PropertyKey PKEY_Devices_DeviceDescription1 = new PropertyKey(81, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_DeviceDescription2 = new PropertyKey(82, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_DeviceHasProblem = new PropertyKey(6, 0x540B947E, 0x8B40, 0x45BC, 0xA8, 0xA2, 0x6A, 0x0B, 0x89, 0x4C, 0xBD, 0xA2); + public static PropertyKey PKEY_Devices_DeviceInstanceId = new PropertyKey(256, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_DeviceManufacturer = new PropertyKey(13, 0xA45C254E, 0xDF1C, 0x4EFD, 0x80, 0x20, 0x67, 0xD1, 0x46, 0xA8, 0x50, 0xE0); + public static PropertyKey PKEY_Devices_DevObjectType = new PropertyKey(2, 0x13673F42, 0xA3D6, 0x49F6, 0xB4, 0xDA, 0xAE, 0x46, 0xE0, 0xC5, 0x23, 0x7C); + public static PropertyKey PKEY_Devices_DialProtocol_InstalledApplications = new PropertyKey(3, 0x6845CC72, 0x1B71, 0x48C3, 0xAF, 0x86, 0xB0, 0x91, 0x71, 0xA1, 0x9B, 0x14); + public static PropertyKey PKEY_Devices_DiscoveryMethod = new PropertyKey(52, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_Dnssd_Domain = new PropertyKey(3, 0xBF79C0AB, 0xBB74, 0x4CEE, 0xB0, 0x70, 0x47, 0x0B, 0x5A, 0xE2, 0x02, 0xEA); + public static PropertyKey PKEY_Devices_Dnssd_FullName = new PropertyKey(5, 0xBF79C0AB, 0xBB74, 0x4CEE, 0xB0, 0x70, 0x47, 0x0B, 0x5A, 0xE2, 0x02, 0xEA); + public static PropertyKey PKEY_Devices_Dnssd_HostName = new PropertyKey(7, 0xBF79C0AB, 0xBB74, 0x4CEE, 0xB0, 0x70, 0x47, 0x0B, 0x5A, 0xE2, 0x02, 0xEA); + public static PropertyKey PKEY_Devices_Dnssd_InstanceName = new PropertyKey(4, 0xBF79C0AB, 0xBB74, 0x4CEE, 0xB0, 0x70, 0x47, 0x0B, 0x5A, 0xE2, 0x02, 0xEA); + public static PropertyKey PKEY_Devices_Dnssd_NetworkAdapterId = new PropertyKey(11, 0xBF79C0AB, 0xBB74, 0x4CEE, 0xB0, 0x70, 0x47, 0x0B, 0x5A, 0xE2, 0x02, 0xEA); + public static PropertyKey PKEY_Devices_Dnssd_PortNumber = new PropertyKey(12, 0xBF79C0AB, 0xBB74, 0x4CEE, 0xB0, 0x70, 0x47, 0x0B, 0x5A, 0xE2, 0x02, 0xEA); + public static PropertyKey PKEY_Devices_Dnssd_Priority = new PropertyKey(9, 0xBF79C0AB, 0xBB74, 0x4CEE, 0xB0, 0x70, 0x47, 0x0B, 0x5A, 0xE2, 0x02, 0xEA); + public static PropertyKey PKEY_Devices_Dnssd_ServiceName = new PropertyKey(2, 0xBF79C0AB, 0xBB74, 0x4CEE, 0xB0, 0x70, 0x47, 0x0B, 0x5A, 0xE2, 0x02, 0xEA); + public static PropertyKey PKEY_Devices_Dnssd_TextAttributes = new PropertyKey(6, 0xBF79C0AB, 0xBB74, 0x4CEE, 0xB0, 0x70, 0x47, 0x0B, 0x5A, 0xE2, 0x02, 0xEA); + public static PropertyKey PKEY_Devices_Dnssd_Ttl = new PropertyKey(10, 0xBF79C0AB, 0xBB74, 0x4CEE, 0xB0, 0x70, 0x47, 0x0B, 0x5A, 0xE2, 0x02, 0xEA); + public static PropertyKey PKEY_Devices_Dnssd_Weight = new PropertyKey(8, 0xBF79C0AB, 0xBB74, 0x4CEE, 0xB0, 0x70, 0x47, 0x0B, 0x5A, 0xE2, 0x02, 0xEA); + public static PropertyKey PKEY_Devices_FriendlyName = new PropertyKey(12288, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD); + public static PropertyKey PKEY_Devices_FunctionPaths = new PropertyKey(3, 0xD08DD4C0, 0x3A9E, 0x462E, 0x82, 0x90, 0x7B, 0x63, 0x6B, 0x25, 0x76, 0xB9); + public static PropertyKey PKEY_Devices_GlyphIcon = new PropertyKey(123, 0x51236583, 0x0C4A, 0x4FE8, 0xB8, 0x1F, 0x16, 0x6A, 0xEC, 0x13, 0xF5, 0x10); + public static PropertyKey PKEY_Devices_HardwareIds = new PropertyKey(3, 0xA45C254E, 0xDF1C, 0x4EFD, 0x80, 0x20, 0x67, 0xD1, 0x46, 0xA8, 0x50, 0xE0); + public static PropertyKey PKEY_Devices_Icon = new PropertyKey(57, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_InLocalMachineContainer = new PropertyKey(4, 0x8C7ED206, 0x3F8A, 0x4827, 0xB3, 0xAB, 0xAE, 0x9E, 0x1F, 0xAE, 0xFC, 0x6C); + public static PropertyKey PKEY_Devices_InterfaceClassGuid = new PropertyKey(4, 0x026E516E, 0xB814, 0x414B, 0x83, 0xCD, 0x85, 0x6D, 0x6F, 0xEF, 0x48, 0x22); + public static PropertyKey PKEY_Devices_InterfaceEnabled = new PropertyKey(3, 0x026E516E, 0xB814, 0x414B, 0x83, 0xCD, 0x85, 0x6D, 0x6F, 0xEF, 0x48, 0x22); + public static PropertyKey PKEY_Devices_InterfacePaths = new PropertyKey(2, 0xD08DD4C0, 0x3A9E, 0x462E, 0x82, 0x90, 0x7B, 0x63, 0x6B, 0x25, 0x76, 0xB9); + public static PropertyKey PKEY_Devices_IpAddress = new PropertyKey(12297, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD); + public static PropertyKey PKEY_Devices_IsDefault = new PropertyKey(86, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_IsNetworkConnected = new PropertyKey(85, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_IsShared = new PropertyKey(84, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_IsSoftwareInstalling = new PropertyKey(9, 0x83DA6326, 0x97A6, 0x4088, 0x94, 0x53, 0xA1, 0x92, 0x3F, 0x57, 0x3B, 0x29); + public static PropertyKey PKEY_Devices_LaunchDeviceStageFromExplorer = new PropertyKey(77, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_LocalMachine = new PropertyKey(70, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_LocationPaths = new PropertyKey(37, 0xA45C254E, 0xDF1C, 0x4EFD, 0x80, 0x20, 0x67, 0xD1, 0x46, 0xA8, 0x50, 0xE0); + public static PropertyKey PKEY_Devices_Manufacturer = new PropertyKey(8192, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD); + public static PropertyKey PKEY_Devices_MetadataPath = new PropertyKey(71, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_MicrophoneArray_Geometry = new PropertyKey(2, 0xA1829EA2, 0x27EB, 0x459E, 0x93, 0x5D, 0xB2, 0xFA, 0xD7, 0xB0, 0x77, 0x62); + public static PropertyKey PKEY_Devices_MissedCalls = new PropertyKey(5, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_ModelId = new PropertyKey(2, 0x80D81EA6, 0x7473, 0x4B0C, 0x82, 0x16, 0xEF, 0xC1, 0x1A, 0x2C, 0x4C, 0x8B); + public static PropertyKey PKEY_Devices_ModelName = new PropertyKey(8194, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD); + public static PropertyKey PKEY_Devices_ModelNumber = new PropertyKey(8195, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD); + public static PropertyKey PKEY_Devices_NetworkedTooltip = new PropertyKey(152, 0x880F70A2, 0x6082, 0x47AC, 0x8A, 0xAB, 0xA7, 0x39, 0xD1, 0xA3, 0x00, 0xC3); + public static PropertyKey PKEY_Devices_NetworkName = new PropertyKey(7, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_NetworkType = new PropertyKey(8, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_NewPictures = new PropertyKey(4, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_Notification = new PropertyKey(3, 0x06704B0C, 0xE830, 0x4C81, 0x91, 0x78, 0x91, 0xE4, 0xE9, 0x5A, 0x80, 0xA0); + public static PropertyKey PKEY_Devices_Notifications_LowBattery = new PropertyKey(2, 0xC4C07F2B, 0x8524, 0x4E66, 0xAE, 0x3A, 0xA6, 0x23, 0x5F, 0x10, 0x3B, 0xEB); + public static PropertyKey PKEY_Devices_Notifications_MissedCall = new PropertyKey(2, 0x6614EF48, 0x4EFE, 0x4424, 0x9E, 0xDA, 0xC7, 0x9F, 0x40, 0x4E, 0xDF, 0x3E); + public static PropertyKey PKEY_Devices_Notifications_NewMessage = new PropertyKey(2, 0x2BE9260A, 0x2012, 0x4742, 0xA5, 0x55, 0xF4, 0x1B, 0x63, 0x8B, 0x7D, 0xCB); + public static PropertyKey PKEY_Devices_Notifications_NewVoicemail = new PropertyKey(2, 0x59569556, 0x0A08, 0x4212, 0x95, 0xB9, 0xFA, 0xE2, 0xAD, 0x64, 0x13, 0xDB); + public static PropertyKey PKEY_Devices_Notifications_StorageFull = new PropertyKey(2, 0xA0E00EE1, 0xF0C7, 0x4D41, 0xB8, 0xE7, 0x26, 0xA7, 0xBD, 0x8D, 0x38, 0xB0); + public static PropertyKey PKEY_Devices_Notifications_StorageFullLinkText = new PropertyKey(3, 0xA0E00EE1, 0xF0C7, 0x4D41, 0xB8, 0xE7, 0x26, 0xA7, 0xBD, 0x8D, 0x38, 0xB0); + public static PropertyKey PKEY_Devices_NotificationStore = new PropertyKey(2, 0x06704B0C, 0xE830, 0x4C81, 0x91, 0x78, 0x91, 0xE4, 0xE9, 0x5A, 0x80, 0xA0); + public static PropertyKey PKEY_Devices_NotWorkingProperly = new PropertyKey(83, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_Paired = new PropertyKey(56, 0x78C34FC8, 0x104A, 0x4ACA, 0x9E, 0xA4, 0x52, 0x4D, 0x52, 0x99, 0x6E, 0x57); + public static PropertyKey PKEY_Devices_Panel_PanelGroup = new PropertyKey(3, 0x8DBC9C86, 0x97A9, 0x4BFF, 0x9B, 0xC6, 0xBF, 0xE9, 0x5D, 0x3E, 0x6D, 0xAD); + public static PropertyKey PKEY_Devices_Panel_PanelId = new PropertyKey(2, 0x8DBC9C86, 0x97A9, 0x4BFF, 0x9B, 0xC6, 0xBF, 0xE9, 0x5D, 0x3E, 0x6D, 0xAD); + public static PropertyKey PKEY_Devices_Parent = new PropertyKey(8, 0x4340A6C5, 0x93FA, 0x4706, 0x97, 0x2C, 0x7B, 0x64, 0x80, 0x08, 0xA5, 0xA7); + public static PropertyKey PKEY_Devices_PhoneLineTransportDevice_Connected = new PropertyKey(2, 0xAECF2FE8, 0x1D00, 0x4FEE, 0x8A, 0x6D, 0xA7, 0x0D, 0x71, 0x9B, 0x77, 0x2B); + public static PropertyKey PKEY_Devices_PhysicalDeviceLocation = new PropertyKey(9, 0x540B947E, 0x8B40, 0x45BC, 0xA8, 0xA2, 0x6A, 0x0B, 0x89, 0x4C, 0xBD, 0xA2); + public static PropertyKey PKEY_Devices_PlaybackPositionPercent = new PropertyKey(5, 0x3633DE59, 0x6825, 0x4381, 0xA4, 0x9B, 0x9F, 0x6B, 0xA1, 0x3A, 0x14, 0x71); + public static PropertyKey PKEY_Devices_PlaybackState = new PropertyKey(2, 0x3633DE59, 0x6825, 0x4381, 0xA4, 0x9B, 0x9F, 0x6B, 0xA1, 0x3A, 0x14, 0x71); + public static PropertyKey PKEY_Devices_PlaybackTitle = new PropertyKey(3, 0x3633DE59, 0x6825, 0x4381, 0xA4, 0x9B, 0x9F, 0x6B, 0xA1, 0x3A, 0x14, 0x71); + public static PropertyKey PKEY_Devices_Present = new PropertyKey(5, 0x540B947E, 0x8B40, 0x45BC, 0xA8, 0xA2, 0x6A, 0x0B, 0x89, 0x4C, 0xBD, 0xA2); + public static PropertyKey PKEY_Devices_PresentationUrl = new PropertyKey(8198, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD); + public static PropertyKey PKEY_Devices_PrimaryCategory = new PropertyKey(10, 0xD08DD4C0, 0x3A9E, 0x462E, 0x82, 0x90, 0x7B, 0x63, 0x6B, 0x25, 0x76, 0xB9); + public static PropertyKey PKEY_Devices_RemainingDuration = new PropertyKey(4, 0x3633DE59, 0x6825, 0x4381, 0xA4, 0x9B, 0x9F, 0x6B, 0xA1, 0x3A, 0x14, 0x71); + public static PropertyKey PKEY_Devices_RestrictedInterface = new PropertyKey(6, 0x026E516E, 0xB814, 0x414B, 0x83, 0xCD, 0x85, 0x6D, 0x6F, 0xEF, 0x48, 0x22); + public static PropertyKey PKEY_Devices_Roaming = new PropertyKey(9, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_SafeRemovalRequired = new PropertyKey(2, 0xAFD97640, 0x86A3, 0x4210, 0xB6, 0x7C, 0x28, 0x9C, 0x41, 0xAA, 0xBE, 0x55); + public static PropertyKey PKEY_Devices_SchematicName = new PropertyKey(9, 0x026E516E, 0xB814, 0x414B, 0x83, 0xCD, 0x85, 0x6D, 0x6F, 0xEF, 0x48, 0x22); + public static PropertyKey PKEY_Devices_ServiceAddress = new PropertyKey(16384, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD); + public static PropertyKey PKEY_Devices_ServiceId = new PropertyKey(16385, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD); + public static PropertyKey PKEY_Devices_SharedTooltip = new PropertyKey(151, 0x880F70A2, 0x6082, 0x47AC, 0x8A, 0xAB, 0xA7, 0x39, 0xD1, 0xA3, 0x00, 0xC3); + public static PropertyKey PKEY_Devices_SignalStrength = new PropertyKey(2, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_SmartCards_ReaderKind = new PropertyKey(2, 0xD6B5B883, 0x18BD, 0x4B4D, 0xB2, 0xEC, 0x9E, 0x38, 0xAF, 0xFE, 0xDA, 0x82); + public static PropertyKey PKEY_Devices_Status = new PropertyKey(259, 0xD08DD4C0, 0x3A9E, 0x462E, 0x82, 0x90, 0x7B, 0x63, 0x6B, 0x25, 0x76, 0xB9); + public static PropertyKey PKEY_Devices_Status1 = new PropertyKey(257, 0xD08DD4C0, 0x3A9E, 0x462E, 0x82, 0x90, 0x7B, 0x63, 0x6B, 0x25, 0x76, 0xB9); + public static PropertyKey PKEY_Devices_Status2 = new PropertyKey(258, 0xD08DD4C0, 0x3A9E, 0x462E, 0x82, 0x90, 0x7B, 0x63, 0x6B, 0x25, 0x76, 0xB9); + public static PropertyKey PKEY_Devices_StorageCapacity = new PropertyKey(12, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_StorageFreeSpace = new PropertyKey(13, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_StorageFreeSpacePercent = new PropertyKey(14, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_TextMessages = new PropertyKey(3, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_Voicemail = new PropertyKey(6, 0x49CD1F76, 0x5626, 0x4B17, 0xA4, 0xE8, 0x18, 0xB4, 0xAA, 0x1A, 0x22, 0x13); + public static PropertyKey PKEY_Devices_WiaDeviceType = new PropertyKey(2, 0x6BDD1FC6, 0x810F, 0x11D0, 0xBE, 0xC7, 0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F); + public static PropertyKey PKEY_Devices_WiFi_InterfaceGuid = new PropertyKey(2, 0xEF1167EB, 0xCBFC, 0x4341, 0xA5, 0x68, 0xA7, 0xC9, 0x1A, 0x68, 0x98, 0x2C); + public static PropertyKey PKEY_Devices_WiFiDirect_DeviceAddress = new PropertyKey(13, 0x1506935D, 0xE3E7, 0x450F, 0x86, 0x37, 0x82, 0x23, 0x3E, 0xBE, 0x5F, 0x6E); + public static PropertyKey PKEY_Devices_WiFiDirect_GroupId = new PropertyKey(4, 0x1506935D, 0xE3E7, 0x450F, 0x86, 0x37, 0x82, 0x23, 0x3E, 0xBE, 0x5F, 0x6E); + public static PropertyKey PKEY_Devices_WiFiDirect_InformationElements = new PropertyKey(12, 0x1506935D, 0xE3E7, 0x450F, 0x86, 0x37, 0x82, 0x23, 0x3E, 0xBE, 0x5F, 0x6E); + public static PropertyKey PKEY_Devices_WiFiDirect_InterfaceAddress = new PropertyKey(2, 0x1506935D, 0xE3E7, 0x450F, 0x86, 0x37, 0x82, 0x23, 0x3E, 0xBE, 0x5F, 0x6E); + public static PropertyKey PKEY_Devices_WiFiDirect_InterfaceGuid = new PropertyKey(3, 0x1506935D, 0xE3E7, 0x450F, 0x86, 0x37, 0x82, 0x23, 0x3E, 0xBE, 0x5F, 0x6E); + public static PropertyKey PKEY_Devices_WiFiDirect_IsConnected = new PropertyKey(5, 0x1506935D, 0xE3E7, 0x450F, 0x86, 0x37, 0x82, 0x23, 0x3E, 0xBE, 0x5F, 0x6E); + public static PropertyKey PKEY_Devices_WiFiDirect_IsLegacyDevice = new PropertyKey(7, 0x1506935D, 0xE3E7, 0x450F, 0x86, 0x37, 0x82, 0x23, 0x3E, 0xBE, 0x5F, 0x6E); + public static PropertyKey PKEY_Devices_WiFiDirect_IsMiracastLcpSupported = new PropertyKey(9, 0x1506935D, 0xE3E7, 0x450F, 0x86, 0x37, 0x82, 0x23, 0x3E, 0xBE, 0x5F, 0x6E); + public static PropertyKey PKEY_Devices_WiFiDirect_IsVisible = new PropertyKey(6, 0x1506935D, 0xE3E7, 0x450F, 0x86, 0x37, 0x82, 0x23, 0x3E, 0xBE, 0x5F, 0x6E); + public static PropertyKey PKEY_Devices_WiFiDirect_MiracastVersion = new PropertyKey(8, 0x1506935D, 0xE3E7, 0x450F, 0x86, 0x37, 0x82, 0x23, 0x3E, 0xBE, 0x5F, 0x6E); + public static PropertyKey PKEY_Devices_WiFiDirect_Services = new PropertyKey(10, 0x1506935D, 0xE3E7, 0x450F, 0x86, 0x37, 0x82, 0x23, 0x3E, 0xBE, 0x5F, 0x6E); + public static PropertyKey PKEY_Devices_WiFiDirect_SupportedChannelList = new PropertyKey(11, 0x1506935D, 0xE3E7, 0x450F, 0x86, 0x37, 0x82, 0x23, 0x3E, 0xBE, 0x5F, 0x6E); + public static PropertyKey PKEY_Devices_WiFiDirectServices_AdvertisementId = new PropertyKey(5, 0x31B37743, 0x7C5E, 0x4005, 0x93, 0xE6, 0xE9, 0x53, 0xF9, 0x2B, 0x82, 0xE9); + public static PropertyKey PKEY_Devices_WiFiDirectServices_RequestServiceInformation = new PropertyKey(7, 0x31B37743, 0x7C5E, 0x4005, 0x93, 0xE6, 0xE9, 0x53, 0xF9, 0x2B, 0x82, 0xE9); + public static PropertyKey PKEY_Devices_WiFiDirectServices_ServiceAddress = new PropertyKey(2, 0x31B37743, 0x7C5E, 0x4005, 0x93, 0xE6, 0xE9, 0x53, 0xF9, 0x2B, 0x82, 0xE9); + public static PropertyKey PKEY_Devices_WiFiDirectServices_ServiceConfigMethods = new PropertyKey(6, 0x31B37743, 0x7C5E, 0x4005, 0x93, 0xE6, 0xE9, 0x53, 0xF9, 0x2B, 0x82, 0xE9); + public static PropertyKey PKEY_Devices_WiFiDirectServices_ServiceInformation = new PropertyKey(4, 0x31B37743, 0x7C5E, 0x4005, 0x93, 0xE6, 0xE9, 0x53, 0xF9, 0x2B, 0x82, 0xE9); + public static PropertyKey PKEY_Devices_WiFiDirectServices_ServiceName = new PropertyKey(3, 0x31B37743, 0x7C5E, 0x4005, 0x93, 0xE6, 0xE9, 0x53, 0xF9, 0x2B, 0x82, 0xE9); + public static PropertyKey PKEY_Devices_WinPhone8CameraFlags = new PropertyKey(2, 0xB7B4D61C, 0x5A64, 0x4187, 0xA5, 0x2E, 0xB1, 0x53, 0x9F, 0x35, 0x90, 0x99); + public static PropertyKey PKEY_Devices_Wwan_InterfaceGuid = new PropertyKey(2, 0xFF1167EB, 0xCBFC, 0x4341, 0xA5, 0x68, 0xA7, 0xC9, 0x1A, 0x68, 0x98, 0x2C); + public static PropertyKey PKEY_Storage_Portable = new PropertyKey(2, 0x4D1EBEE8, 0x0803, 0x4774, 0x98, 0x42, 0xB7, 0x7D, 0xB5, 0x02, 0x65, 0xE9); + public static PropertyKey PKEY_Storage_RemovableMedia = new PropertyKey(3, 0x4D1EBEE8, 0x0803, 0x4774, 0x98, 0x42, 0xB7, 0x7D, 0xB5, 0x02, 0x65, 0xE9); + public static PropertyKey PKEY_Storage_SystemCritical = new PropertyKey(4, 0x4D1EBEE8, 0x0803, 0x4774, 0x98, 0x42, 0xB7, 0x7D, 0xB5, 0x02, 0x65, 0xE9); + public static PropertyKey PKEY_Document_ByteCount = new PropertyKey(4, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_Document_CharacterCount = new PropertyKey(16, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Document_ClientID = new PropertyKey(100, 0x276D7BB0, 0x5B34, 0x4FB0, 0xAA, 0x4B, 0x15, 0x8E, 0xD1, 0x2A, 0x18, 0x09); + public static PropertyKey PKEY_Document_Contributor = new PropertyKey(100, 0xF334115E, 0xDA1B, 0x4509, 0x9B, 0x3D, 0x11, 0x95, 0x04, 0xDC, 0x7A, 0xBB); + public static PropertyKey PKEY_Document_DateCreated = new PropertyKey(12, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Document_DatePrinted = new PropertyKey(11, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Document_DateSaved = new PropertyKey(13, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Document_Division = new PropertyKey(100, 0x1E005EE6, 0xBF27, 0x428B, 0xB0, 0x1C, 0x79, 0x67, 0x6A, 0xCD, 0x28, 0x70); + public static PropertyKey PKEY_Document_DocumentID = new PropertyKey(100, 0xE08805C8, 0xE395, 0x40DF, 0x80, 0xD2, 0x54, 0xF0, 0xD6, 0xC4, 0x31, 0x54); + public static PropertyKey PKEY_Document_HiddenSlideCount = new PropertyKey(9, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_Document_LastAuthor = new PropertyKey(8, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Document_LineCount = new PropertyKey(5, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_Document_Manager = new PropertyKey(14, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_Document_MultimediaClipCount = new PropertyKey(10, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_Document_NoteCount = new PropertyKey(8, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_Document_PageCount = new PropertyKey(14, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Document_ParagraphCount = new PropertyKey(6, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_Document_PresentationFormat = new PropertyKey(3, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_Document_RevisionNumber = new PropertyKey(9, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Document_Security = new PropertyKey(19, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Document_SlideCount = new PropertyKey(7, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_Document_Template = new PropertyKey(7, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Document_TotalEditingTime = new PropertyKey(10, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_Document_Version = new PropertyKey(29, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE); + public static PropertyKey PKEY_Document_WordCount = new PropertyKey(15, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9); + public static PropertyKey PKEY_DRM_DatePlayExpires = new PropertyKey(6, 0xAEAC19E4, 0x89AE, 0x4508, 0xB9, 0xB7, 0xBB, 0x86, 0x7A, 0xBE, 0xE2, 0xED); + public static PropertyKey PKEY_DRM_DatePlayStarts = new PropertyKey(5, 0xAEAC19E4, 0x89AE, 0x4508, 0xB9, 0xB7, 0xBB, 0x86, 0x7A, 0xBE, 0xE2, 0xED); + public static PropertyKey PKEY_DRM_Description = new PropertyKey(3, 0xAEAC19E4, 0x89AE, 0x4508, 0xB9, 0xB7, 0xBB, 0x86, 0x7A, 0xBE, 0xE2, 0xED); + public static PropertyKey PKEY_DRM_IsDisabled = new PropertyKey(7, 0xAEAC19E4, 0x89AE, 0x4508, 0xB9, 0xB7, 0xBB, 0x86, 0x7A, 0xBE, 0xE2, 0xED); + public static PropertyKey PKEY_DRM_IsProtected = new PropertyKey(2, 0xAEAC19E4, 0x89AE, 0x4508, 0xB9, 0xB7, 0xBB, 0x86, 0x7A, 0xBE, 0xE2, 0xED); + public static PropertyKey PKEY_DRM_PlayCount = new PropertyKey(4, 0xAEAC19E4, 0x89AE, 0x4508, 0xB9, 0xB7, 0xBB, 0x86, 0x7A, 0xBE, 0xE2, 0xED); + public static PropertyKey PKEY_GPS_Altitude = new PropertyKey(100, 0x827EDB4F, 0x5B73, 0x44A7, 0x89, 0x1D, 0xFD, 0xFF, 0xAB, 0xEA, 0x35, 0xCA); + public static PropertyKey PKEY_GPS_AltitudeDenominator = new PropertyKey(100, 0x78342DCB, 0xE358, 0x4145, 0xAE, 0x9A, 0x6B, 0xFE, 0x4E, 0x0F, 0x9F, 0x51); + public static PropertyKey PKEY_GPS_AltitudeNumerator = new PropertyKey(100, 0x2DAD1EB7, 0x816D, 0x40D3, 0x9E, 0xC3, 0xC9, 0x77, 0x3B, 0xE2, 0xAA, 0xDE); + public static PropertyKey PKEY_GPS_AltitudeRef = new PropertyKey(100, 0x46AC629D, 0x75EA, 0x4515, 0x86, 0x7F, 0x6D, 0xC4, 0x32, 0x1C, 0x58, 0x44); + public static PropertyKey PKEY_GPS_AreaInformation = new PropertyKey(100, 0x972E333E, 0xAC7E, 0x49F1, 0x8A, 0xDF, 0xA7, 0x0D, 0x07, 0xA9, 0xBC, 0xAB); + public static PropertyKey PKEY_GPS_Date = new PropertyKey(100, 0x3602C812, 0x0F3B, 0x45F0, 0x85, 0xAD, 0x60, 0x34, 0x68, 0xD6, 0x94, 0x23); + public static PropertyKey PKEY_GPS_DestBearing = new PropertyKey(100, 0xC66D4B3C, 0xE888, 0x47CC, 0xB9, 0x9F, 0x9D, 0xCA, 0x3E, 0xE3, 0x4D, 0xEA); + public static PropertyKey PKEY_GPS_DestBearingDenominator = new PropertyKey(100, 0x7ABCF4F8, 0x7C3F, 0x4988, 0xAC, 0x91, 0x8D, 0x2C, 0x2E, 0x97, 0xEC, 0xA5); + public static PropertyKey PKEY_GPS_DestBearingNumerator = new PropertyKey(100, 0xBA3B1DA9, 0x86EE, 0x4B5D, 0xA2, 0xA4, 0xA2, 0x71, 0xA4, 0x29, 0xF0, 0xCF); + public static PropertyKey PKEY_GPS_DestBearingRef = new PropertyKey(100, 0x9AB84393, 0x2A0F, 0x4B75, 0xBB, 0x22, 0x72, 0x79, 0x78, 0x69, 0x77, 0xCB); + public static PropertyKey PKEY_GPS_DestDistance = new PropertyKey(100, 0xA93EAE04, 0x6804, 0x4F24, 0xAC, 0x81, 0x09, 0xB2, 0x66, 0x45, 0x21, 0x18); + public static PropertyKey PKEY_GPS_DestDistanceDenominator = new PropertyKey(100, 0x9BC2C99B, 0xAC71, 0x4127, 0x9D, 0x1C, 0x25, 0x96, 0xD0, 0xD7, 0xDC, 0xB7); + public static PropertyKey PKEY_GPS_DestDistanceNumerator = new PropertyKey(100, 0x2BDA47DA, 0x08C6, 0x4FE1, 0x80, 0xBC, 0xA7, 0x2F, 0xC5, 0x17, 0xC5, 0xD0); + public static PropertyKey PKEY_GPS_DestDistanceRef = new PropertyKey(100, 0xED4DF2D3, 0x8695, 0x450B, 0x85, 0x6F, 0xF5, 0xC1, 0xC5, 0x3A, 0xCB, 0x66); + public static PropertyKey PKEY_GPS_DestLatitude = new PropertyKey(100, 0x9D1D7CC5, 0x5C39, 0x451C, 0x86, 0xB3, 0x92, 0x8E, 0x2D, 0x18, 0xCC, 0x47); + public static PropertyKey PKEY_GPS_DestLatitudeDenominator = new PropertyKey(100, 0x3A372292, 0x7FCA, 0x49A7, 0x99, 0xD5, 0xE4, 0x7B, 0xB2, 0xD4, 0xE7, 0xAB); + public static PropertyKey PKEY_GPS_DestLatitudeNumerator = new PropertyKey(100, 0xECF4B6F6, 0xD5A6, 0x433C, 0xBB, 0x92, 0x40, 0x76, 0x65, 0x0F, 0xC8, 0x90); + public static PropertyKey PKEY_GPS_DestLatitudeRef = new PropertyKey(100, 0xCEA820B9, 0xCE61, 0x4885, 0xA1, 0x28, 0x00, 0x5D, 0x90, 0x87, 0xC1, 0x92); + public static PropertyKey PKEY_GPS_DestLongitude = new PropertyKey(100, 0x47A96261, 0xCB4C, 0x4807, 0x8A, 0xD3, 0x40, 0xB9, 0xD9, 0xDB, 0xC6, 0xBC); + public static PropertyKey PKEY_GPS_DestLongitudeDenominator = new PropertyKey(100, 0x425D69E5, 0x48AD, 0x4900, 0x8D, 0x80, 0x6E, 0xB6, 0xB8, 0xD0, 0xAC, 0x86); + public static PropertyKey PKEY_GPS_DestLongitudeNumerator = new PropertyKey(100, 0xA3250282, 0xFB6D, 0x48D5, 0x9A, 0x89, 0xDB, 0xCA, 0xCE, 0x75, 0xCC, 0xCF); + public static PropertyKey PKEY_GPS_DestLongitudeRef = new PropertyKey(100, 0x182C1EA6, 0x7C1C, 0x4083, 0xAB, 0x4B, 0xAC, 0x6C, 0x9F, 0x4E, 0xD1, 0x28); + public static PropertyKey PKEY_GPS_Differential = new PropertyKey(100, 0xAAF4EE25, 0xBD3B, 0x4DD7, 0xBF, 0xC4, 0x47, 0xF7, 0x7B, 0xB0, 0x0F, 0x6D); + public static PropertyKey PKEY_GPS_DOP = new PropertyKey(100, 0x0CF8FB02, 0x1837, 0x42F1, 0xA6, 0x97, 0xA7, 0x01, 0x7A, 0xA2, 0x89, 0xB9); + public static PropertyKey PKEY_GPS_DOPDenominator = new PropertyKey(100, 0xA0BE94C5, 0x50BA, 0x487B, 0xBD, 0x35, 0x06, 0x54, 0xBE, 0x88, 0x81, 0xED); + public static PropertyKey PKEY_GPS_DOPNumerator = new PropertyKey(100, 0x47166B16, 0x364F, 0x4AA0, 0x9F, 0x31, 0xE2, 0xAB, 0x3D, 0xF4, 0x49, 0xC3); + public static PropertyKey PKEY_GPS_ImgDirection = new PropertyKey(100, 0x16473C91, 0xD017, 0x4ED9, 0xBA, 0x4D, 0xB6, 0xBA, 0xA5, 0x5D, 0xBC, 0xF8); + public static PropertyKey PKEY_GPS_ImgDirectionDenominator = new PropertyKey(100, 0x10B24595, 0x41A2, 0x4E20, 0x93, 0xC2, 0x57, 0x61, 0xC1, 0x39, 0x5F, 0x32); + public static PropertyKey PKEY_GPS_ImgDirectionNumerator = new PropertyKey(100, 0xDC5877C7, 0x225F, 0x45F7, 0xBA, 0xC7, 0xE8, 0x13, 0x34, 0xB6, 0x13, 0x0A); + public static PropertyKey PKEY_GPS_ImgDirectionRef = new PropertyKey(100, 0xA4AAA5B7, 0x1AD0, 0x445F, 0x81, 0x1A, 0x0F, 0x8F, 0x6E, 0x67, 0xF6, 0xB5); + public static PropertyKey PKEY_GPS_Latitude = new PropertyKey(100, 0x8727CFFF, 0x4868, 0x4EC6, 0xAD, 0x5B, 0x81, 0xB9, 0x85, 0x21, 0xD1, 0xAB); + public static PropertyKey PKEY_GPS_LatitudeDecimal = new PropertyKey(100, 0x0F55CDE2, 0x4F49, 0x450D, 0x92, 0xC1, 0xDC, 0xD1, 0x63, 0x01, 0xB1, 0xB7); + public static PropertyKey PKEY_GPS_LatitudeDenominator = new PropertyKey(100, 0x16E634EE, 0x2BFF, 0x497B, 0xBD, 0x8A, 0x43, 0x41, 0xAD, 0x39, 0xEE, 0xB9); + public static PropertyKey PKEY_GPS_LatitudeNumerator = new PropertyKey(100, 0x7DDAAAD1, 0xCCC8, 0x41AE, 0xB7, 0x50, 0xB2, 0xCB, 0x80, 0x31, 0xAE, 0xA2); + public static PropertyKey PKEY_GPS_LatitudeRef = new PropertyKey(100, 0x029C0252, 0x5B86, 0x46C7, 0xAC, 0xA0, 0x27, 0x69, 0xFF, 0xC8, 0xE3, 0xD4); + public static PropertyKey PKEY_GPS_Longitude = new PropertyKey(100, 0xC4C4DBB2, 0xB593, 0x466B, 0xBB, 0xDA, 0xD0, 0x3D, 0x27, 0xD5, 0xE4, 0x3A); + public static PropertyKey PKEY_GPS_LongitudeDecimal = new PropertyKey(100, 0x4679C1B5, 0x844D, 0x4590, 0xBA, 0xF5, 0xF3, 0x22, 0x23, 0x1F, 0x1B, 0x81); + public static PropertyKey PKEY_GPS_LongitudeDenominator = new PropertyKey(100, 0xBE6E176C, 0x4534, 0x4D2C, 0xAC, 0xE5, 0x31, 0xDE, 0xDA, 0xC1, 0x60, 0x6B); + public static PropertyKey PKEY_GPS_LongitudeNumerator = new PropertyKey(100, 0x02B0F689, 0xA914, 0x4E45, 0x82, 0x1D, 0x1D, 0xDA, 0x45, 0x2E, 0xD2, 0xC4); + public static PropertyKey PKEY_GPS_LongitudeRef = new PropertyKey(100, 0x33DCF22B, 0x28D5, 0x464C, 0x80, 0x35, 0x1E, 0xE9, 0xEF, 0xD2, 0x52, 0x78); + public static PropertyKey PKEY_GPS_MapDatum = new PropertyKey(100, 0x2CA2DAE6, 0xEDDC, 0x407D, 0xBE, 0xF1, 0x77, 0x39, 0x42, 0xAB, 0xFA, 0x95); + public static PropertyKey PKEY_GPS_MeasureMode = new PropertyKey(100, 0xA015ED5D, 0xAAEA, 0x4D58, 0x8A, 0x86, 0x3C, 0x58, 0x69, 0x20, 0xEA, 0x0B); + public static PropertyKey PKEY_GPS_ProcessingMethod = new PropertyKey(100, 0x59D49E61, 0x840F, 0x4AA9, 0xA9, 0x39, 0xE2, 0x09, 0x9B, 0x7F, 0x63, 0x99); + public static PropertyKey PKEY_GPS_Satellites = new PropertyKey(100, 0x467EE575, 0x1F25, 0x4557, 0xAD, 0x4E, 0xB8, 0xB5, 0x8B, 0x0D, 0x9C, 0x15); + public static PropertyKey PKEY_GPS_Speed = new PropertyKey(100, 0xDA5D0862, 0x6E76, 0x4E1B, 0xBA, 0xBD, 0x70, 0x02, 0x1B, 0xD2, 0x54, 0x94); + public static PropertyKey PKEY_GPS_SpeedDenominator = new PropertyKey(100, 0x7D122D5A, 0xAE5E, 0x4335, 0x88, 0x41, 0xD7, 0x1E, 0x7C, 0xE7, 0x2F, 0x53); + public static PropertyKey PKEY_GPS_SpeedNumerator = new PropertyKey(100, 0xACC9CE3D, 0xC213, 0x4942, 0x8B, 0x48, 0x6D, 0x08, 0x20, 0xF2, 0x1C, 0x6D); + public static PropertyKey PKEY_GPS_SpeedRef = new PropertyKey(100, 0xECF7F4C9, 0x544F, 0x4D6D, 0x9D, 0x98, 0x8A, 0xD7, 0x9A, 0xDA, 0xF4, 0x53); + public static PropertyKey PKEY_GPS_Status = new PropertyKey(100, 0x125491F4, 0x818F, 0x46B2, 0x91, 0xB5, 0xD5, 0x37, 0x75, 0x36, 0x17, 0xB2); + public static PropertyKey PKEY_GPS_Track = new PropertyKey(100, 0x76C09943, 0x7C33, 0x49E3, 0x9E, 0x7E, 0xCD, 0xBA, 0x87, 0x2C, 0xFA, 0xDA); + public static PropertyKey PKEY_GPS_TrackDenominator = new PropertyKey(100, 0xC8D1920C, 0x01F6, 0x40C0, 0xAC, 0x86, 0x2F, 0x3A, 0x4A, 0xD0, 0x07, 0x70); + public static PropertyKey PKEY_GPS_TrackNumerator = new PropertyKey(100, 0x702926F4, 0x44A6, 0x43E1, 0xAE, 0x71, 0x45, 0x62, 0x71, 0x16, 0x89, 0x3B); + public static PropertyKey PKEY_GPS_TrackRef = new PropertyKey(100, 0x35DBE6FE, 0x44C3, 0x4400, 0xAA, 0xAE, 0xD2, 0xC7, 0x99, 0xC4, 0x07, 0xE8); + public static PropertyKey PKEY_GPS_VersionID = new PropertyKey(100, 0x22704DA4, 0xC6B2, 0x4A99, 0x8E, 0x56, 0xF1, 0x6D, 0xF8, 0xC9, 0x25, 0x99); + public static PropertyKey PKEY_History_VisitCount = new PropertyKey(7, 0x5CBF2787, 0x48CF, 0x4208, 0xB9, 0x0E, 0xEE, 0x5E, 0x5D, 0x42, 0x02, 0x94); + public static PropertyKey PKEY_Image_BitDepth = new PropertyKey(7, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Image_ColorSpace = new PropertyKey(40961, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Image_CompressedBitsPerPixel = new PropertyKey(100, 0x364B6FA9, 0x37AB, 0x482A, 0xBE, 0x2B, 0xAE, 0x02, 0xF6, 0x0D, 0x43, 0x18); + public static PropertyKey PKEY_Image_CompressedBitsPerPixelDenominator = new PropertyKey(100, 0x1F8844E1, 0x24AD, 0x4508, 0x9D, 0xFD, 0x53, 0x26, 0xA4, 0x15, 0xCE, 0x02); + public static PropertyKey PKEY_Image_CompressedBitsPerPixelNumerator = new PropertyKey(100, 0xD21A7148, 0xD32C, 0x4624, 0x89, 0x00, 0x27, 0x72, 0x10, 0xF7, 0x9C, 0x0F); + public static PropertyKey PKEY_Image_Compression = new PropertyKey(259, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Image_CompressionText = new PropertyKey(100, 0x3F08E66F, 0x2F44, 0x4BB9, 0xA6, 0x82, 0xAC, 0x35, 0xD2, 0x56, 0x23, 0x22); + public static PropertyKey PKEY_Image_Dimensions = new PropertyKey(13, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Image_HorizontalResolution = new PropertyKey(5, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Image_HorizontalSize = new PropertyKey(3, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Image_ImageID = new PropertyKey(100, 0x10DABE05, 0x32AA, 0x4C29, 0xBF, 0x1A, 0x63, 0xE2, 0xD2, 0x20, 0x58, 0x7F); + public static PropertyKey PKEY_Image_ResolutionUnit = new PropertyKey(100, 0x19B51FA6, 0x1F92, 0x4A5C, 0xAB, 0x48, 0x7D, 0xF0, 0xAB, 0xD6, 0x74, 0x44); + public static PropertyKey PKEY_Image_VerticalResolution = new PropertyKey(6, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Image_VerticalSize = new PropertyKey(4, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Journal_Contacts = new PropertyKey(100, 0xDEA7C82C, 0x1D89, 0x4A66, 0x94, 0x27, 0xA4, 0xE3, 0xDE, 0xBA, 0xBC, 0xB1); + public static PropertyKey PKEY_Journal_EntryType = new PropertyKey(100, 0x95BEB1FC, 0x326D, 0x4644, 0xB3, 0x96, 0xCD, 0x3E, 0xD9, 0x0E, 0x6D, 0xDF); + public static PropertyKey PKEY_LayoutPattern_ContentViewModeForBrowse = new PropertyKey(500, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_LayoutPattern_ContentViewModeForSearch = new PropertyKey(501, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_History_SelectionCount = new PropertyKey(8, 0x1CE0D6BC, 0x536C, 0x4600, 0xB0, 0xDD, 0x7E, 0x0C, 0x66, 0xB3, 0x50, 0xD5); + public static PropertyKey PKEY_History_TargetUrlHostName = new PropertyKey(9, 0x1CE0D6BC, 0x536C, 0x4600, 0xB0, 0xDD, 0x7E, 0x0C, 0x66, 0xB3, 0x50, 0xD5); + public static PropertyKey PKEY_Link_Arguments = new PropertyKey(100, 0x436F2667, 0x14E2, 0x4FEB, 0xB3, 0x0A, 0x14, 0x6C, 0x53, 0xB5, 0xB6, 0x74); + public static PropertyKey PKEY_Link_Comment = new PropertyKey(5, 0xB9B4B3FC, 0x2B51, 0x4A42, 0xB5, 0xD8, 0x32, 0x41, 0x46, 0xAF, 0xCF, 0x25); + public static PropertyKey PKEY_Link_DateVisited = new PropertyKey(23, 0x5CBF2787, 0x48CF, 0x4208, 0xB9, 0x0E, 0xEE, 0x5E, 0x5D, 0x42, 0x02, 0x94); + public static PropertyKey PKEY_Link_Description = new PropertyKey(21, 0x5CBF2787, 0x48CF, 0x4208, 0xB9, 0x0E, 0xEE, 0x5E, 0x5D, 0x42, 0x02, 0x94); + public static PropertyKey PKEY_Link_FeedItemLocalId = new PropertyKey(2, 0x8A2F99F9, 0x3C37, 0x465D, 0xA8, 0xD7, 0x69, 0x77, 0x7A, 0x24, 0x6D, 0x0C); + public static PropertyKey PKEY_Link_Status = new PropertyKey(3, 0xB9B4B3FC, 0x2B51, 0x4A42, 0xB5, 0xD8, 0x32, 0x41, 0x46, 0xAF, 0xCF, 0x25); + public static PropertyKey PKEY_Link_TargetExtension = new PropertyKey(2, 0x7A7D76F4, 0xB630, 0x4BD7, 0x95, 0xFF, 0x37, 0xCC, 0x51, 0xA9, 0x75, 0xC9); + public static PropertyKey PKEY_Link_TargetParsingPath = new PropertyKey(2, 0xB9B4B3FC, 0x2B51, 0x4A42, 0xB5, 0xD8, 0x32, 0x41, 0x46, 0xAF, 0xCF, 0x25); + public static PropertyKey PKEY_Link_TargetSFGAOFlags = new PropertyKey(8, 0xB9B4B3FC, 0x2B51, 0x4A42, 0xB5, 0xD8, 0x32, 0x41, 0x46, 0xAF, 0xCF, 0x25); + public static PropertyKey PKEY_Link_TargetUrlHostName = new PropertyKey(5, 0x8A2F99F9, 0x3C37, 0x465D, 0xA8, 0xD7, 0x69, 0x77, 0x7A, 0x24, 0x6D, 0x0C); + public static PropertyKey PKEY_Link_TargetUrlPath = new PropertyKey(6, 0x8A2F99F9, 0x3C37, 0x465D, 0xA8, 0xD7, 0x69, 0x77, 0x7A, 0x24, 0x6D, 0x0C); + public static PropertyKey PKEY_Media_AuthorUrl = new PropertyKey(32, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_AverageLevel = new PropertyKey(100, 0x09EDD5B6, 0xB301, 0x43C5, 0x99, 0x90, 0xD0, 0x03, 0x02, 0xEF, 0xFD, 0x46); + public static PropertyKey PKEY_Media_ClassPrimaryID = new PropertyKey(13, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_ClassSecondaryID = new PropertyKey(14, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_CollectionGroupID = new PropertyKey(24, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_CollectionID = new PropertyKey(25, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_ContentDistributor = new PropertyKey(18, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_ContentID = new PropertyKey(26, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_CreatorApplication = new PropertyKey(27, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_CreatorApplicationVersion = new PropertyKey(28, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_DateEncoded = new PropertyKey(100, 0x2E4B640D, 0x5019, 0x46D8, 0x88, 0x81, 0x55, 0x41, 0x4C, 0xC5, 0xCA, 0xA0); + public static PropertyKey PKEY_Media_DateReleased = new PropertyKey(100, 0xDE41CC29, 0x6971, 0x4290, 0xB4, 0x72, 0xF5, 0x9F, 0x2E, 0x2F, 0x31, 0xE2); + public static PropertyKey PKEY_Media_DlnaProfileID = new PropertyKey(100, 0xCFA31B45, 0x525D, 0x4998, 0xBB, 0x44, 0x3F, 0x7D, 0x81, 0x54, 0x2F, 0xA4); + public static PropertyKey PKEY_Media_Duration = new PropertyKey(3, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_DVDID = new PropertyKey(15, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_EncodedBy = new PropertyKey(36, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_EncodingSettings = new PropertyKey(37, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_EpisodeNumber = new PropertyKey(100, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_FrameCount = new PropertyKey(12, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_MCDI = new PropertyKey(16, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_MetadataContentProvider = new PropertyKey(17, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_Producer = new PropertyKey(22, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_PromotionUrl = new PropertyKey(33, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_ProtectionType = new PropertyKey(38, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_ProviderRating = new PropertyKey(39, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_ProviderStyle = new PropertyKey(40, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_Publisher = new PropertyKey(30, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_SeasonNumber = new PropertyKey(101, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_SeriesName = new PropertyKey(42, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_SubscriptionContentId = new PropertyKey(100, 0x9AEBAE7A, 0x9644, 0x487D, 0xA9, 0x2C, 0x65, 0x75, 0x85, 0xED, 0x75, 0x1A); + public static PropertyKey PKEY_Media_SubTitle = new PropertyKey(38, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Media_ThumbnailLargePath = new PropertyKey(47, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_ThumbnailLargeUri = new PropertyKey(48, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_ThumbnailSmallPath = new PropertyKey(49, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_ThumbnailSmallUri = new PropertyKey(50, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_UniqueFileIdentifier = new PropertyKey(35, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_UserNoAutoInfo = new PropertyKey(41, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_UserWebUrl = new PropertyKey(34, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_Writer = new PropertyKey(23, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Media_Year = new PropertyKey(5, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Message_AttachmentContents = new PropertyKey(100, 0x3143BF7C, 0x80A8, 0x4854, 0x88, 0x80, 0xE2, 0xE4, 0x01, 0x89, 0xBD, 0xD0); + public static PropertyKey PKEY_Message_AttachmentNames = new PropertyKey(21, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Message_BccAddress = new PropertyKey(2, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Message_BccName = new PropertyKey(3, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Message_CcAddress = new PropertyKey(4, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Message_CcName = new PropertyKey(5, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Message_ConversationID = new PropertyKey(100, 0xDC8F80BD, 0xAF1E, 0x4289, 0x85, 0xB6, 0x3D, 0xFC, 0x1B, 0x49, 0x39, 0x92); + public static PropertyKey PKEY_Message_ConversationIndex = new PropertyKey(101, 0xDC8F80BD, 0xAF1E, 0x4289, 0x85, 0xB6, 0x3D, 0xFC, 0x1B, 0x49, 0x39, 0x92); + public static PropertyKey PKEY_Message_DateReceived = new PropertyKey(20, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Message_DateSent = new PropertyKey(19, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Message_Flags = new PropertyKey(100, 0xA82D9EE7, 0xCA67, 0x4312, 0x96, 0x5E, 0x22, 0x6B, 0xCE, 0xA8, 0x50, 0x23); + public static PropertyKey PKEY_Message_FromAddress = new PropertyKey(13, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Message_FromName = new PropertyKey(14, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Message_HasAttachments = new PropertyKey(8, 0x9C1FCF74, 0x2D97, 0x41BA, 0xB4, 0xAE, 0xCB, 0x2E, 0x36, 0x61, 0xA6, 0xE4); + public static PropertyKey PKEY_Message_IsFwdOrReply = new PropertyKey(100, 0x9A9BC088, 0x4F6D, 0x469E, 0x99, 0x19, 0xE7, 0x05, 0x41, 0x20, 0x40, 0xF9); + public static PropertyKey PKEY_Message_MessageClass = new PropertyKey(103, 0xCD9ED458, 0x08CE, 0x418F, 0xA7, 0x0E, 0xF9, 0x12, 0xC7, 0xBB, 0x9C, 0x5C); + public static PropertyKey PKEY_Message_Participants = new PropertyKey(2, 0x1A9BA605, 0x8E7C, 0x4D11, 0xAD, 0x7D, 0xA5, 0x0A, 0xDA, 0x18, 0xBA, 0x1B); + public static PropertyKey PKEY_Message_ProofInProgress = new PropertyKey(100, 0x9098F33C, 0x9A7D, 0x48A8, 0x8D, 0xE5, 0x2E, 0x12, 0x27, 0xA6, 0x4E, 0x91); + public static PropertyKey PKEY_Message_SenderAddress = new PropertyKey(100, 0x0BE1C8E7, 0x1981, 0x4676, 0xAE, 0x14, 0xFD, 0xD7, 0x8F, 0x05, 0xA6, 0xE7); + public static PropertyKey PKEY_Message_SenderName = new PropertyKey(100, 0x0DA41CFA, 0xD224, 0x4A18, 0xAE, 0x2F, 0x59, 0x61, 0x58, 0xDB, 0x4B, 0x3A); + public static PropertyKey PKEY_Message_Store = new PropertyKey(15, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Message_ToAddress = new PropertyKey(16, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Message_ToDoFlags = new PropertyKey(100, 0x1F856A9F, 0x6900, 0x4ABA, 0x95, 0x05, 0x2D, 0x5F, 0x1B, 0x4D, 0x66, 0xCB); + public static PropertyKey PKEY_Message_ToDoTitle = new PropertyKey(100, 0xBCCC8A3C, 0x8CEF, 0x42E5, 0x9B, 0x1C, 0xC6, 0x90, 0x79, 0x39, 0x8B, 0xC7); + public static PropertyKey PKEY_Message_ToName = new PropertyKey(17, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD); + public static PropertyKey PKEY_Music_AlbumArtist = new PropertyKey(13, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Music_AlbumArtistSortOverride = new PropertyKey(103, 0xF1FDB4AF, 0xF78C, 0x466C, 0xBB, 0x05, 0x56, 0xE9, 0x2D, 0xB0, 0xB8, 0xEC); + public static PropertyKey PKEY_Music_AlbumID = new PropertyKey(100, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Music_AlbumTitle = new PropertyKey(4, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Music_AlbumTitleSortOverride = new PropertyKey(101, 0x13EB7FFC, 0xEC89, 0x4346, 0xB1, 0x9D, 0xCC, 0xC6, 0xF1, 0x78, 0x42, 0x23); + public static PropertyKey PKEY_Music_Artist = new PropertyKey(2, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Music_ArtistSortOverride = new PropertyKey(102, 0xDEEB2DB5, 0x0696, 0x4CE0, 0x94, 0xFE, 0xA0, 0x1F, 0x77, 0xA4, 0x5F, 0xB5); + public static PropertyKey PKEY_Music_BeatsPerMinute = new PropertyKey(35, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Music_Composer = new PropertyKey(19, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Music_ComposerSortOverride = new PropertyKey(105, 0x00BC20A3, 0xBD48, 0x4085, 0x87, 0x2C, 0xA8, 0x8D, 0x77, 0xF5, 0x09, 0x7E); + public static PropertyKey PKEY_Music_Conductor = new PropertyKey(36, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Music_ContentGroupDescription = new PropertyKey(33, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Music_DiscNumber = new PropertyKey(104, 0x6AFE7437, 0x9BCD, 0x49C7, 0x80, 0xFE, 0x4A, 0x5C, 0x65, 0xFA, 0x58, 0x74); + public static PropertyKey PKEY_Music_DisplayArtist = new PropertyKey(100, 0xFD122953, 0xFA93, 0x4EF7, 0x92, 0xC3, 0x04, 0xC9, 0x46, 0xB2, 0xF7, 0xC8); + public static PropertyKey PKEY_Music_Genre = new PropertyKey(11, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Music_InitialKey = new PropertyKey(34, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Music_IsCompilation = new PropertyKey(100, 0xC449D5CB, 0x9EA4, 0x4809, 0x82, 0xE8, 0xAF, 0x9D, 0x59, 0xDE, 0xD6, 0xD1); + public static PropertyKey PKEY_Music_Lyrics = new PropertyKey(12, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Music_Mood = new PropertyKey(39, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Music_PartOfSet = new PropertyKey(37, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Music_Period = new PropertyKey(31, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Music_SynchronizedLyrics = new PropertyKey(100, 0x6B223B6A, 0x162E, 0x4AA9, 0xB3, 0x9F, 0x05, 0xD6, 0x78, 0xFC, 0x6D, 0x77); + public static PropertyKey PKEY_Music_TrackNumber = new PropertyKey(7, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6); + public static PropertyKey PKEY_Note_Color = new PropertyKey(100, 0x4776CAFA, 0xBCE4, 0x4CB1, 0xA2, 0x3E, 0x26, 0x5E, 0x76, 0xD8, 0xEB, 0x11); + public static PropertyKey PKEY_Note_ColorText = new PropertyKey(100, 0x46B4E8DE, 0xCDB2, 0x440D, 0x88, 0x5C, 0x16, 0x58, 0xEB, 0x65, 0xB9, 0x14); + public static PropertyKey PKEY_Photo_Aperture = new PropertyKey(37378, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_ApertureDenominator = new PropertyKey(100, 0xE1A9A38B, 0x6685, 0x46BD, 0x87, 0x5E, 0x57, 0x0D, 0xC7, 0xAD, 0x73, 0x20); + public static PropertyKey PKEY_Photo_ApertureNumerator = new PropertyKey(100, 0x0337ECEC, 0x39FB, 0x4581, 0xA0, 0xBD, 0x4C, 0x4C, 0xC5, 0x1E, 0x99, 0x14); + public static PropertyKey PKEY_Photo_Brightness = new PropertyKey(100, 0x1A701BF6, 0x478C, 0x4361, 0x83, 0xAB, 0x37, 0x01, 0xBB, 0x05, 0x3C, 0x58); + public static PropertyKey PKEY_Photo_BrightnessDenominator = new PropertyKey(100, 0x6EBE6946, 0x2321, 0x440A, 0x90, 0xF0, 0xC0, 0x43, 0xEF, 0xD3, 0x24, 0x76); + public static PropertyKey PKEY_Photo_BrightnessNumerator = new PropertyKey(100, 0x9E7D118F, 0xB314, 0x45A0, 0x8C, 0xFB, 0xD6, 0x54, 0xB9, 0x17, 0xC9, 0xE9); + public static PropertyKey PKEY_Photo_CameraManufacturer = new PropertyKey(271, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_CameraModel = new PropertyKey(272, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_CameraSerialNumber = new PropertyKey(273, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_Contrast = new PropertyKey(100, 0x2A785BA9, 0x8D23, 0x4DED, 0x82, 0xE6, 0x60, 0xA3, 0x50, 0xC8, 0x6A, 0x10); + public static PropertyKey PKEY_Photo_ContrastText = new PropertyKey(100, 0x59DDE9F2, 0x5253, 0x40EA, 0x9A, 0x8B, 0x47, 0x9E, 0x96, 0xC6, 0x24, 0x9A); + public static PropertyKey PKEY_Photo_DateTaken = new PropertyKey(36867, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_DigitalZoom = new PropertyKey(100, 0xF85BF840, 0xA925, 0x4BC2, 0xB0, 0xC4, 0x8E, 0x36, 0xB5, 0x98, 0x67, 0x9E); + public static PropertyKey PKEY_Photo_DigitalZoomDenominator = new PropertyKey(100, 0x745BAF0E, 0xE5C1, 0x4CFB, 0x8A, 0x1B, 0xD0, 0x31, 0xA0, 0xA5, 0x23, 0x93); + public static PropertyKey PKEY_Photo_DigitalZoomNumerator = new PropertyKey(100, 0x16CBB924, 0x6500, 0x473B, 0xA5, 0xBE, 0xF1, 0x59, 0x9B, 0xCB, 0xE4, 0x13); + public static PropertyKey PKEY_Photo_Event = new PropertyKey(18248, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_EXIFVersion = new PropertyKey(100, 0xD35F743A, 0xEB2E, 0x47F2, 0xA2, 0x86, 0x84, 0x41, 0x32, 0xCB, 0x14, 0x27); + public static PropertyKey PKEY_Photo_ExposureBias = new PropertyKey(37380, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_ExposureBiasDenominator = new PropertyKey(100, 0xAB205E50, 0x04B7, 0x461C, 0xA1, 0x8C, 0x2F, 0x23, 0x38, 0x36, 0xE6, 0x27); + public static PropertyKey PKEY_Photo_ExposureBiasNumerator = new PropertyKey(100, 0x738BF284, 0x1D87, 0x420B, 0x92, 0xCF, 0x58, 0x34, 0xBF, 0x6E, 0xF9, 0xED); + public static PropertyKey PKEY_Photo_ExposureIndex = new PropertyKey(100, 0x967B5AF8, 0x995A, 0x46ED, 0x9E, 0x11, 0x35, 0xB3, 0xC5, 0xB9, 0x78, 0x2D); + public static PropertyKey PKEY_Photo_ExposureIndexDenominator = new PropertyKey(100, 0x93112F89, 0xC28B, 0x492F, 0x8A, 0x9D, 0x4B, 0xE2, 0x06, 0x2C, 0xEE, 0x8A); + public static PropertyKey PKEY_Photo_ExposureIndexNumerator = new PropertyKey(100, 0xCDEDCF30, 0x8919, 0x44DF, 0x8F, 0x4C, 0x4E, 0xB2, 0xFF, 0xDB, 0x8D, 0x89); + public static PropertyKey PKEY_Photo_ExposureProgram = new PropertyKey(34850, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_ExposureProgramText = new PropertyKey(100, 0xFEC690B7, 0x5F30, 0x4646, 0xAE, 0x47, 0x4C, 0xAA, 0xFB, 0xA8, 0x84, 0xA3); + public static PropertyKey PKEY_Photo_ExposureTime = new PropertyKey(33434, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_ExposureTimeDenominator = new PropertyKey(100, 0x55E98597, 0xAD16, 0x42E0, 0xB6, 0x24, 0x21, 0x59, 0x9A, 0x19, 0x98, 0x38); + public static PropertyKey PKEY_Photo_ExposureTimeNumerator = new PropertyKey(100, 0x257E44E2, 0x9031, 0x4323, 0xAC, 0x38, 0x85, 0xC5, 0x52, 0x87, 0x1B, 0x2E); + public static PropertyKey PKEY_Photo_Flash = new PropertyKey(37385, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_FlashEnergy = new PropertyKey(41483, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_FlashEnergyDenominator = new PropertyKey(100, 0xD7B61C70, 0x6323, 0x49CD, 0xA5, 0xFC, 0xC8, 0x42, 0x77, 0x16, 0x2C, 0x97); + public static PropertyKey PKEY_Photo_FlashEnergyNumerator = new PropertyKey(100, 0xFCAD3D3D, 0x0858, 0x400F, 0xAA, 0xA3, 0x2F, 0x66, 0xCC, 0xE2, 0xA6, 0xBC); + public static PropertyKey PKEY_Photo_FlashManufacturer = new PropertyKey(100, 0xAABAF6C9, 0xE0C5, 0x4719, 0x85, 0x85, 0x57, 0xB1, 0x03, 0xE5, 0x84, 0xFE); + public static PropertyKey PKEY_Photo_FlashModel = new PropertyKey(100, 0xFE83BB35, 0x4D1A, 0x42E2, 0x91, 0x6B, 0x06, 0xF3, 0xE1, 0xAF, 0x71, 0x9E); + public static PropertyKey PKEY_Photo_FlashText = new PropertyKey(100, 0x6B8B68F6, 0x200B, 0x47EA, 0x8D, 0x25, 0xD8, 0x05, 0x0F, 0x57, 0x33, 0x9F); + public static PropertyKey PKEY_Photo_FNumber = new PropertyKey(33437, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_FNumberDenominator = new PropertyKey(100, 0xE92A2496, 0x223B, 0x4463, 0xA4, 0xE3, 0x30, 0xEA, 0xBB, 0xA7, 0x9D, 0x80); + public static PropertyKey PKEY_Photo_FNumberNumerator = new PropertyKey(100, 0x1B97738A, 0xFDFC, 0x462F, 0x9D, 0x93, 0x19, 0x57, 0xE0, 0x8B, 0xE9, 0x0C); + public static PropertyKey PKEY_Photo_FocalLength = new PropertyKey(37386, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_FocalLengthDenominator = new PropertyKey(100, 0x305BC615, 0xDCA1, 0x44A5, 0x9F, 0xD4, 0x10, 0xC0, 0xBA, 0x79, 0x41, 0x2E); + public static PropertyKey PKEY_Photo_FocalLengthInFilm = new PropertyKey(100, 0xA0E74609, 0xB84D, 0x4F49, 0xB8, 0x60, 0x46, 0x2B, 0xD9, 0x97, 0x1F, 0x98); + public static PropertyKey PKEY_Photo_FocalLengthNumerator = new PropertyKey(100, 0x776B6B3B, 0x1E3D, 0x4B0C, 0x9A, 0x0E, 0x8F, 0xBA, 0xF2, 0xA8, 0x49, 0x2A); + public static PropertyKey PKEY_Photo_FocalPlaneXResolution = new PropertyKey(100, 0xCFC08D97, 0xC6F7, 0x4484, 0x89, 0xDD, 0xEB, 0xEF, 0x43, 0x56, 0xFE, 0x76); + public static PropertyKey PKEY_Photo_FocalPlaneXResolutionDenominator = new PropertyKey(100, 0x0933F3F5, 0x4786, 0x4F46, 0xA8, 0xE8, 0xD6, 0x4D, 0xD3, 0x7F, 0xA5, 0x21); + public static PropertyKey PKEY_Photo_FocalPlaneXResolutionNumerator = new PropertyKey(100, 0xDCCB10AF, 0xB4E2, 0x4B88, 0x95, 0xF9, 0x03, 0x1B, 0x4D, 0x5A, 0xB4, 0x90); + public static PropertyKey PKEY_Photo_FocalPlaneYResolution = new PropertyKey(100, 0x4FFFE4D0, 0x914F, 0x4AC4, 0x8D, 0x6F, 0xC9, 0xC6, 0x1D, 0xE1, 0x69, 0xB1); + public static PropertyKey PKEY_Photo_FocalPlaneYResolutionDenominator = new PropertyKey(100, 0x1D6179A6, 0xA876, 0x4031, 0xB0, 0x13, 0x33, 0x47, 0xB2, 0xB6, 0x4D, 0xC8); + public static PropertyKey PKEY_Photo_FocalPlaneYResolutionNumerator = new PropertyKey(100, 0xA2E541C5, 0x4440, 0x4BA8, 0x86, 0x7E, 0x75, 0xCF, 0xC0, 0x68, 0x28, 0xCD); + public static PropertyKey PKEY_Photo_GainControl = new PropertyKey(100, 0xFA304789, 0x00C7, 0x4D80, 0x90, 0x4A, 0x1E, 0x4D, 0xCC, 0x72, 0x65, 0xAA); + public static PropertyKey PKEY_Photo_GainControlDenominator = new PropertyKey(100, 0x42864DFD, 0x9DA4, 0x4F77, 0xBD, 0xED, 0x4A, 0xAD, 0x7B, 0x25, 0x67, 0x35); + public static PropertyKey PKEY_Photo_GainControlNumerator = new PropertyKey(100, 0x8E8ECF7C, 0xB7B8, 0x4EB8, 0xA6, 0x3F, 0x0E, 0xE7, 0x15, 0xC9, 0x6F, 0x9E); + public static PropertyKey PKEY_Photo_GainControlText = new PropertyKey(100, 0xC06238B2, 0x0BF9, 0x4279, 0xA7, 0x23, 0x25, 0x85, 0x67, 0x15, 0xCB, 0x9D); + public static PropertyKey PKEY_Photo_ISOSpeed = new PropertyKey(34855, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_LensManufacturer = new PropertyKey(100, 0xE6DDCAF7, 0x29C5, 0x4F0A, 0x9A, 0x68, 0xD1, 0x94, 0x12, 0xEC, 0x70, 0x90); + public static PropertyKey PKEY_Photo_LensModel = new PropertyKey(100, 0xE1277516, 0x2B5F, 0x4869, 0x89, 0xB1, 0x2E, 0x58, 0x5B, 0xD3, 0x8B, 0x7A); + public static PropertyKey PKEY_Photo_LightSource = new PropertyKey(37384, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_MakerNote = new PropertyKey(100, 0xFA303353, 0xB659, 0x4052, 0x85, 0xE9, 0xBC, 0xAC, 0x79, 0x54, 0x9B, 0x84); + public static PropertyKey PKEY_Photo_MakerNoteOffset = new PropertyKey(100, 0x813F4124, 0x34E6, 0x4D17, 0xAB, 0x3E, 0x6B, 0x1F, 0x3C, 0x22, 0x47, 0xA1); + public static PropertyKey PKEY_Photo_MaxAperture = new PropertyKey(100, 0x08F6D7C2, 0xE3F2, 0x44FC, 0xAF, 0x1E, 0x5A, 0xA5, 0xC8, 0x1A, 0x2D, 0x3E); + public static PropertyKey PKEY_Photo_MaxApertureDenominator = new PropertyKey(100, 0xC77724D4, 0x601F, 0x46C5, 0x9B, 0x89, 0xC5, 0x3F, 0x93, 0xBC, 0xEB, 0x77); + public static PropertyKey PKEY_Photo_MaxApertureNumerator = new PropertyKey(100, 0xC107E191, 0xA459, 0x44C5, 0x9A, 0xE6, 0xB9, 0x52, 0xAD, 0x4B, 0x90, 0x6D); + public static PropertyKey PKEY_Photo_MeteringMode = new PropertyKey(37383, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_MeteringModeText = new PropertyKey(100, 0xF628FD8C, 0x7BA8, 0x465A, 0xA6, 0x5B, 0xC5, 0xAA, 0x79, 0x26, 0x3A, 0x9E); + public static PropertyKey PKEY_Photo_Orientation = new PropertyKey(274, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_OrientationText = new PropertyKey(100, 0xA9EA193C, 0xC511, 0x498A, 0xA0, 0x6B, 0x58, 0xE2, 0x77, 0x6D, 0xCC, 0x28); + public static PropertyKey PKEY_Photo_PeopleNames = new PropertyKey(100, 0xE8309B6E, 0x084C, 0x49B4, 0xB1, 0xFC, 0x90, 0xA8, 0x03, 0x31, 0xB6, 0x38); + public static PropertyKey PKEY_Photo_PhotometricInterpretation = new PropertyKey(100, 0x341796F1, 0x1DF9, 0x4B1C, 0xA5, 0x64, 0x91, 0xBD, 0xEF, 0xA4, 0x38, 0x77); + public static PropertyKey PKEY_Photo_PhotometricInterpretationText = new PropertyKey(100, 0x821437D6, 0x9EAB, 0x4765, 0xA5, 0x89, 0x3B, 0x1C, 0xBB, 0xD2, 0x2A, 0x61); + public static PropertyKey PKEY_Photo_ProgramMode = new PropertyKey(100, 0x6D217F6D, 0x3F6A, 0x4825, 0xB4, 0x70, 0x5F, 0x03, 0xCA, 0x2F, 0xBE, 0x9B); + public static PropertyKey PKEY_Photo_ProgramModeText = new PropertyKey(100, 0x7FE3AA27, 0x2648, 0x42F3, 0x89, 0xB0, 0x45, 0x4E, 0x5C, 0xB1, 0x50, 0xC3); + public static PropertyKey PKEY_Photo_RelatedSoundFile = new PropertyKey(100, 0x318A6B45, 0x087F, 0x4DC2, 0xB8, 0xCC, 0x05, 0x35, 0x95, 0x51, 0xFC, 0x9E); + public static PropertyKey PKEY_Photo_Saturation = new PropertyKey(100, 0x49237325, 0xA95A, 0x4F67, 0xB2, 0x11, 0x81, 0x6B, 0x2D, 0x45, 0xD2, 0xE0); + public static PropertyKey PKEY_Photo_SaturationText = new PropertyKey(100, 0x61478C08, 0xB600, 0x4A84, 0xBB, 0xE4, 0xE9, 0x9C, 0x45, 0xF0, 0xA0, 0x72); + public static PropertyKey PKEY_Photo_Sharpness = new PropertyKey(100, 0xFC6976DB, 0x8349, 0x4970, 0xAE, 0x97, 0xB3, 0xC5, 0x31, 0x6A, 0x08, 0xF0); + public static PropertyKey PKEY_Photo_SharpnessText = new PropertyKey(100, 0x51EC3F47, 0xDD50, 0x421D, 0x87, 0x69, 0x33, 0x4F, 0x50, 0x42, 0x4B, 0x1E); + public static PropertyKey PKEY_Photo_ShutterSpeed = new PropertyKey(37377, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_ShutterSpeedDenominator = new PropertyKey(100, 0xE13D8975, 0x81C7, 0x4948, 0xAE, 0x3F, 0x37, 0xCA, 0xE1, 0x1E, 0x8F, 0xF7); + public static PropertyKey PKEY_Photo_ShutterSpeedNumerator = new PropertyKey(100, 0x16EA4042, 0xD6F4, 0x4BCA, 0x83, 0x49, 0x7C, 0x78, 0xD3, 0x0F, 0xB3, 0x33); + public static PropertyKey PKEY_Photo_SubjectDistance = new PropertyKey(37382, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99); + public static PropertyKey PKEY_Photo_SubjectDistanceDenominator = new PropertyKey(100, 0x0C840A88, 0xB043, 0x466D, 0x97, 0x66, 0xD4, 0xB2, 0x6D, 0xA3, 0xFA, 0x77); + public static PropertyKey PKEY_Photo_SubjectDistanceNumerator = new PropertyKey(100, 0x8AF4961C, 0xF526, 0x43E5, 0xAA, 0x81, 0xDB, 0x76, 0x82, 0x19, 0x17, 0x8D); + public static PropertyKey PKEY_Photo_TagViewAggregate = new PropertyKey(100, 0xB812F15D, 0xC2D8, 0x4BBF, 0xBA, 0xCD, 0x79, 0x74, 0x43, 0x46, 0x11, 0x3F); + public static PropertyKey PKEY_Photo_TranscodedForSync = new PropertyKey(100, 0x9A8EBB75, 0x6458, 0x4E82, 0xBA, 0xCB, 0x35, 0xC0, 0x09, 0x5B, 0x03, 0xBB); + public static PropertyKey PKEY_Photo_WhiteBalance = new PropertyKey(100, 0xEE3D3D8A, 0x5381, 0x4CFA, 0xB1, 0x3B, 0xAA, 0xF6, 0x6B, 0x5F, 0x4E, 0xC9); + public static PropertyKey PKEY_Photo_WhiteBalanceText = new PropertyKey(100, 0x6336B95E, 0xC7A7, 0x426D, 0x86, 0xFD, 0x7A, 0xE3, 0xD3, 0x9C, 0x84, 0xB4); + public static PropertyKey PKEY_PropGroup_Advanced = new PropertyKey(100, 0x900A403B, 0x097B, 0x4B95, 0x8A, 0xE2, 0x07, 0x1F, 0xDA, 0xEE, 0xB1, 0x18); + public static PropertyKey PKEY_PropGroup_Audio = new PropertyKey(100, 0x2804D469, 0x788F, 0x48AA, 0x85, 0x70, 0x71, 0xB9, 0xC1, 0x87, 0xE1, 0x38); + public static PropertyKey PKEY_PropGroup_Calendar = new PropertyKey(100, 0x9973D2B5, 0xBFD8, 0x438A, 0xBA, 0x94, 0x53, 0x49, 0xB2, 0x93, 0x18, 0x1A); + public static PropertyKey PKEY_PropGroup_Camera = new PropertyKey(100, 0xDE00DE32, 0x547E, 0x4981, 0xAD, 0x4B, 0x54, 0x2F, 0x2E, 0x90, 0x07, 0xD8); + public static PropertyKey PKEY_PropGroup_Contact = new PropertyKey(100, 0xDF975FD3, 0x250A, 0x4004, 0x85, 0x8F, 0x34, 0xE2, 0x9A, 0x3E, 0x37, 0xAA); + public static PropertyKey PKEY_PropGroup_Content = new PropertyKey(100, 0xD0DAB0BA, 0x368A, 0x4050, 0xA8, 0x82, 0x6C, 0x01, 0x0F, 0xD1, 0x9A, 0x4F); + public static PropertyKey PKEY_PropGroup_Description = new PropertyKey(100, 0x8969B275, 0x9475, 0x4E00, 0xA8, 0x87, 0xFF, 0x93, 0xB8, 0xB4, 0x1E, 0x44); + public static PropertyKey PKEY_PropGroup_FileSystem = new PropertyKey(100, 0xE3A7D2C1, 0x80FC, 0x4B40, 0x8F, 0x34, 0x30, 0xEA, 0x11, 0x1B, 0xDC, 0x2E); + public static PropertyKey PKEY_PropGroup_General = new PropertyKey(100, 0xCC301630, 0xB192, 0x4C22, 0xB3, 0x72, 0x9F, 0x4C, 0x6D, 0x33, 0x8E, 0x07); + public static PropertyKey PKEY_PropGroup_GPS = new PropertyKey(100, 0xF3713ADA, 0x90E3, 0x4E11, 0xAA, 0xE5, 0xFD, 0xC1, 0x76, 0x85, 0xB9, 0xBE); + public static PropertyKey PKEY_PropGroup_Image = new PropertyKey(100, 0xE3690A87, 0x0FA8, 0x4A2A, 0x9A, 0x9F, 0xFC, 0xE8, 0x82, 0x70, 0x55, 0xAC); + public static PropertyKey PKEY_PropGroup_Media = new PropertyKey(100, 0x61872CF7, 0x6B5E, 0x4B4B, 0xAC, 0x2D, 0x59, 0xDA, 0x84, 0x45, 0x92, 0x48); + public static PropertyKey PKEY_PropGroup_MediaAdvanced = new PropertyKey(100, 0x8859A284, 0xDE7E, 0x4642, 0x99, 0xBA, 0xD4, 0x31, 0xD0, 0x44, 0xB1, 0xEC); + public static PropertyKey PKEY_PropGroup_Message = new PropertyKey(100, 0x7FD7259D, 0x16B4, 0x4135, 0x9F, 0x97, 0x7C, 0x96, 0xEC, 0xD2, 0xFA, 0x9E); + public static PropertyKey PKEY_PropGroup_Music = new PropertyKey(100, 0x68DD6094, 0x7216, 0x40F1, 0xA0, 0x29, 0x43, 0xFE, 0x71, 0x27, 0x04, 0x3F); + public static PropertyKey PKEY_PropGroup_Origin = new PropertyKey(100, 0x2598D2FB, 0x5569, 0x4367, 0x95, 0xDF, 0x5C, 0xD3, 0xA1, 0x77, 0xE1, 0xA5); + public static PropertyKey PKEY_PropGroup_PhotoAdvanced = new PropertyKey(100, 0x0CB2BF5A, 0x9EE7, 0x4A86, 0x82, 0x22, 0xF0, 0x1E, 0x07, 0xFD, 0xAD, 0xAF); + public static PropertyKey PKEY_PropGroup_RecordedTV = new PropertyKey(100, 0xE7B33238, 0x6584, 0x4170, 0xA5, 0xC0, 0xAC, 0x25, 0xEF, 0xD9, 0xDA, 0x56); + public static PropertyKey PKEY_PropGroup_Video = new PropertyKey(100, 0xBEBE0920, 0x7671, 0x4C54, 0xA3, 0xEB, 0x49, 0xFD, 0xDF, 0xC1, 0x91, 0xEE); + public static PropertyKey PKEY_InfoTipText = new PropertyKey(17, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_PropList_ConflictPrompt = new PropertyKey(11, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_PropList_ContentViewModeForBrowse = new PropertyKey(13, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_PropList_ContentViewModeForSearch = new PropertyKey(14, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_PropList_ExtendedTileInfo = new PropertyKey(9, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_PropList_FileOperationPrompt = new PropertyKey(10, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_PropList_FullDetails = new PropertyKey(2, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_PropList_InfoTip = new PropertyKey(4, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_PropList_NonPersonal = new PropertyKey(100, 0x49D1091F, 0x082E, 0x493F, 0xB2, 0x3F, 0xD2, 0x30, 0x8A, 0xA9, 0x66, 0x8C); + public static PropertyKey PKEY_PropList_PreviewDetails = new PropertyKey(8, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_PropList_PreviewTitle = new PropertyKey(6, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_PropList_QuickTip = new PropertyKey(5, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_PropList_TileInfo = new PropertyKey(3, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B); + public static PropertyKey PKEY_PropList_XPDetailsPanel = new PropertyKey(0, 0xF2275480, 0xF782, 0x4291, 0xBD, 0x94, 0xF1, 0x36, 0x93, 0x51, 0x3A, 0xEC); + public static PropertyKey PKEY_RecordedTV_ChannelNumber = new PropertyKey(7, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57); + public static PropertyKey PKEY_RecordedTV_Credits = new PropertyKey(4, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57); + public static PropertyKey PKEY_RecordedTV_DateContentExpires = new PropertyKey(15, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57); + public static PropertyKey PKEY_RecordedTV_EpisodeName = new PropertyKey(2, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57); + public static PropertyKey PKEY_RecordedTV_IsATSCContent = new PropertyKey(16, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57); + public static PropertyKey PKEY_RecordedTV_IsClosedCaptioningAvailable = new PropertyKey(12, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57); + public static PropertyKey PKEY_RecordedTV_IsDTVContent = new PropertyKey(17, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57); + public static PropertyKey PKEY_RecordedTV_IsHDContent = new PropertyKey(18, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57); + public static PropertyKey PKEY_RecordedTV_IsRepeatBroadcast = new PropertyKey(13, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57); + public static PropertyKey PKEY_RecordedTV_IsSAP = new PropertyKey(14, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57); + public static PropertyKey PKEY_RecordedTV_NetworkAffiliation = new PropertyKey(100, 0x2C53C813, 0xFB63, 0x4E22, 0xA1, 0xAB, 0x0B, 0x33, 0x1C, 0xA1, 0xE2, 0x73); + public static PropertyKey PKEY_RecordedTV_OriginalBroadcastDate = new PropertyKey(100, 0x4684FE97, 0x8765, 0x4842, 0x9C, 0x13, 0xF0, 0x06, 0x44, 0x7B, 0x17, 0x8C); + public static PropertyKey PKEY_RecordedTV_ProgramDescription = new PropertyKey(3, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57); + public static PropertyKey PKEY_RecordedTV_RecordingTime = new PropertyKey(100, 0xA5477F61, 0x7A82, 0x4ECA, 0x9D, 0xDE, 0x98, 0xB6, 0x9B, 0x24, 0x79, 0xB3); + public static PropertyKey PKEY_RecordedTV_StationCallSign = new PropertyKey(5, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57); + public static PropertyKey PKEY_RecordedTV_StationName = new PropertyKey(100, 0x1B5439E7, 0xEBA1, 0x4AF8, 0xBD, 0xD7, 0x7A, 0xF1, 0xD4, 0x54, 0x94, 0x93); + public static PropertyKey PKEY_Search_AutoSummary = new PropertyKey(2, 0x560C36C0, 0x503A, 0x11CF, 0xBA, 0xA1, 0x00, 0x00, 0x4C, 0x75, 0x2A, 0x9A); + public static PropertyKey PKEY_Search_ContainerHash = new PropertyKey(100, 0xBCEEE283, 0x35DF, 0x4D53, 0x82, 0x6A, 0xF3, 0x6A, 0x3E, 0xEF, 0xC6, 0xBE); + public static PropertyKey PKEY_Search_Contents = new PropertyKey(19, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC); + public static PropertyKey PKEY_Search_EntryID = new PropertyKey(5, 0x49691C90, 0x7E17, 0x101A, 0xA9, 0x1C, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9); + public static PropertyKey PKEY_Search_ExtendedProperties = new PropertyKey(100, 0x7B03B546, 0xFA4F, 0x4A52, 0xA2, 0xFE, 0x03, 0xD5, 0x31, 0x1E, 0x58, 0x65); + public static PropertyKey PKEY_Search_GatherTime = new PropertyKey(8, 0x0B63E350, 0x9CCC, 0x11D0, 0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04); + public static PropertyKey PKEY_Search_HitCount = new PropertyKey(4, 0x49691C90, 0x7E17, 0x101A, 0xA9, 0x1C, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9); + public static PropertyKey PKEY_Search_IsClosedDirectory = new PropertyKey(23, 0x0B63E343, 0x9CCC, 0x11D0, 0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04); + public static PropertyKey PKEY_Search_IsFullyContained = new PropertyKey(24, 0x0B63E343, 0x9CCC, 0x11D0, 0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04); + public static PropertyKey PKEY_Search_QueryFocusedSummary = new PropertyKey(3, 0x560C36C0, 0x503A, 0x11CF, 0xBA, 0xA1, 0x00, 0x00, 0x4C, 0x75, 0x2A, 0x9A); + public static PropertyKey PKEY_Search_QueryFocusedSummaryWithFallback = new PropertyKey(4, 0x560C36C0, 0x503A, 0x11CF, 0xBA, 0xA1, 0x00, 0x00, 0x4C, 0x75, 0x2A, 0x9A); + public static PropertyKey PKEY_Search_QueryPropertyHits = new PropertyKey(21, 0x49691C90, 0x7E17, 0x101A, 0xA9, 0x1C, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9); + public static PropertyKey PKEY_Search_Rank = new PropertyKey(3, 0x49691C90, 0x7E17, 0x101A, 0xA9, 0x1C, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9); + public static PropertyKey PKEY_Search_Store = new PropertyKey(100, 0xA06992B3, 0x8CAF, 0x4ED7, 0xA5, 0x47, 0xB2, 0x59, 0xE3, 0x2A, 0xC9, 0xFC); + public static PropertyKey PKEY_Search_UrlToIndex = new PropertyKey(2, 0x0B63E343, 0x9CCC, 0x11D0, 0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04); + public static PropertyKey PKEY_Search_UrlToIndexWithModificationTime = new PropertyKey(12, 0x0B63E343, 0x9CCC, 0x11D0, 0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04); + public static PropertyKey PKEY_Supplemental_Album = new PropertyKey(6, 0x0C73B141, 0x39D6, 0x4653, 0xA6, 0x83, 0xCA, 0xB2, 0x91, 0xEA, 0xF9, 0x5B); + public static PropertyKey PKEY_Supplemental_AlbumID = new PropertyKey(2, 0x0C73B141, 0x39D6, 0x4653, 0xA6, 0x83, 0xCA, 0xB2, 0x91, 0xEA, 0xF9, 0x5B); + public static PropertyKey PKEY_Supplemental_Location = new PropertyKey(5, 0x0C73B141, 0x39D6, 0x4653, 0xA6, 0x83, 0xCA, 0xB2, 0x91, 0xEA, 0xF9, 0x5B); + public static PropertyKey PKEY_Supplemental_Person = new PropertyKey(7, 0x0C73B141, 0x39D6, 0x4653, 0xA6, 0x83, 0xCA, 0xB2, 0x91, 0xEA, 0xF9, 0x5B); + public static PropertyKey PKEY_Supplemental_ResourceId = new PropertyKey(3, 0x0C73B141, 0x39D6, 0x4653, 0xA6, 0x83, 0xCA, 0xB2, 0x91, 0xEA, 0xF9, 0x5B); + public static PropertyKey PKEY_Supplemental_Tag = new PropertyKey(4, 0x0C73B141, 0x39D6, 0x4653, 0xA6, 0x83, 0xCA, 0xB2, 0x91, 0xEA, 0xF9, 0x5B); + public static PropertyKey PKEY_DescriptionID = new PropertyKey(2, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_InternalName = new PropertyKey(5, 0x0CEF7D53, 0xFA64, 0x11D1, 0xA2, 0x03, 0x00, 0x00, 0xF8, 0x1F, 0xED, 0xEE); + public static PropertyKey PKEY_LibraryLocationsCount = new PropertyKey(2, 0x908696C7, 0x8F87, 0x44F2, 0x80, 0xED, 0xA8, 0xC1, 0xC6, 0x89, 0x45, 0x75); + public static PropertyKey PKEY_Link_TargetSFGAOFlagsStrings = new PropertyKey(3, 0xD6942081, 0xD53B, 0x443D, 0xAD, 0x47, 0x5E, 0x05, 0x9D, 0x9C, 0xD2, 0x7A); + public static PropertyKey PKEY_Link_TargetUrl = new PropertyKey(2, 0x5CBF2787, 0x48CF, 0x4208, 0xB9, 0x0E, 0xEE, 0x5E, 0x5D, 0x42, 0x02, 0x94); + public static PropertyKey PKEY_NamespaceCLSID = new PropertyKey(6, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0); + public static PropertyKey PKEY_Shell_SFGAOFlagsStrings = new PropertyKey(2, 0xD6942081, 0xD53B, 0x443D, 0xAD, 0x47, 0x5E, 0x05, 0x9D, 0x9C, 0xD2, 0x7A); + public static PropertyKey PKEY_StatusBarSelectedItemCount = new PropertyKey(3, 0x26DC287C, 0x6E3D, 0x4BD3, 0xB2, 0xB0, 0x6A, 0x26, 0xBA, 0x2E, 0x34, 0x6D); + public static PropertyKey PKEY_StatusBarViewItemCount = new PropertyKey(2, 0x26DC287C, 0x6E3D, 0x4BD3, 0xB2, 0xB0, 0x6A, 0x26, 0xBA, 0x2E, 0x34, 0x6D); + public static PropertyKey PKEY_AppUserModel_ExcludeFromShowInNewInstall = new PropertyKey(8, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3); + public static PropertyKey PKEY_AppUserModel_ID = new PropertyKey(5, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3); + public static PropertyKey PKEY_AppUserModel_IsDestListSeparator = new PropertyKey(6, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3); + public static PropertyKey PKEY_AppUserModel_IsDualMode = new PropertyKey(11, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3); + public static PropertyKey PKEY_AppUserModel_PreventPinning = new PropertyKey(9, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3); + public static PropertyKey PKEY_AppUserModel_RelaunchCommand = new PropertyKey(2, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3); + public static PropertyKey PKEY_AppUserModel_RelaunchDisplayNameResource = new PropertyKey(4, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3); + public static PropertyKey PKEY_AppUserModel_RelaunchIconResource = new PropertyKey(3, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3); + public static PropertyKey PKEY_AppUserModel_StartPinOption = new PropertyKey(12, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3); + public static PropertyKey PKEY_AppUserModel_ToastActivatorCLSID = new PropertyKey(26, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3); + public static PropertyKey PKEY_AppUserModel_VisualElementsManifestHintPath = new PropertyKey(31, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3); + public static PropertyKey PKEY_EdgeGesture_DisableTouchWhenFullscreen = new PropertyKey(2, 0x32CE38B2, 0x2C9A, 0x41B1, 0x9B, 0xC5, 0xB3, 0x78, 0x43, 0x94, 0xAA, 0x44); + public static PropertyKey PKEY_Software_DateLastUsed = new PropertyKey(16, 0x841E4F90, 0xFF59, 0x4D16, 0x89, 0x47, 0xE8, 0x1B, 0xBF, 0xFA, 0xB3, 0x6D); + public static PropertyKey PKEY_Software_ProductName = new PropertyKey(7, 0x0CEF7D53, 0xFA64, 0x11D1, 0xA2, 0x03, 0x00, 0x00, 0xF8, 0x1F, 0xED, 0xEE); + public static PropertyKey PKEY_Sync_Comments = new PropertyKey(13, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32); + public static PropertyKey PKEY_Sync_ConflictDescription = new PropertyKey(4, 0xCE50C159, 0x2FB8, 0x41FD, 0xBE, 0x68, 0xD3, 0xE0, 0x42, 0xE2, 0x74, 0xBC); + public static PropertyKey PKEY_Sync_ConflictFirstLocation = new PropertyKey(6, 0xCE50C159, 0x2FB8, 0x41FD, 0xBE, 0x68, 0xD3, 0xE0, 0x42, 0xE2, 0x74, 0xBC); + public static PropertyKey PKEY_Sync_ConflictSecondLocation = new PropertyKey(7, 0xCE50C159, 0x2FB8, 0x41FD, 0xBE, 0x68, 0xD3, 0xE0, 0x42, 0xE2, 0x74, 0xBC); + public static PropertyKey PKEY_Sync_HandlerCollectionID = new PropertyKey(2, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32); + public static PropertyKey PKEY_Sync_HandlerID = new PropertyKey(3, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32); + public static PropertyKey PKEY_Sync_HandlerName = new PropertyKey(2, 0xCE50C159, 0x2FB8, 0x41FD, 0xBE, 0x68, 0xD3, 0xE0, 0x42, 0xE2, 0x74, 0xBC); + public static PropertyKey PKEY_Sync_HandlerType = new PropertyKey(8, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32); + public static PropertyKey PKEY_Sync_HandlerTypeLabel = new PropertyKey(9, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32); + public static PropertyKey PKEY_Sync_ItemID = new PropertyKey(6, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32); + public static PropertyKey PKEY_Sync_ItemName = new PropertyKey(3, 0xCE50C159, 0x2FB8, 0x41FD, 0xBE, 0x68, 0xD3, 0xE0, 0x42, 0xE2, 0x74, 0xBC); + public static PropertyKey PKEY_Sync_ProgressPercentage = new PropertyKey(23, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32); + public static PropertyKey PKEY_Sync_State = new PropertyKey(24, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32); + public static PropertyKey PKEY_Sync_Status = new PropertyKey(10, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32); + public static PropertyKey PKEY_Task_BillingInformation = new PropertyKey(100, 0xD37D52C6, 0x261C, 0x4303, 0x82, 0xB3, 0x08, 0xB9, 0x26, 0xAC, 0x6F, 0x12); + public static PropertyKey PKEY_Task_CompletionStatus = new PropertyKey(100, 0x084D8A0A, 0xE6D5, 0x40DE, 0xBF, 0x1F, 0xC8, 0x82, 0x0E, 0x7C, 0x87, 0x7C); + public static PropertyKey PKEY_Task_Owner = new PropertyKey(100, 0x08C7CC5F, 0x60F2, 0x4494, 0xAD, 0x75, 0x55, 0xE3, 0xE0, 0xB5, 0xAD, 0xD0); + public static PropertyKey PKEY_Video_Compression = new PropertyKey(10, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_Director = new PropertyKey(20, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_EncodingBitrate = new PropertyKey(8, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_FourCC = new PropertyKey(44, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_FrameHeight = new PropertyKey(4, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_FrameRate = new PropertyKey(6, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_FrameWidth = new PropertyKey(3, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_HorizontalAspectRatio = new PropertyKey(42, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_IsSpherical = new PropertyKey(100, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_IsStereo = new PropertyKey(98, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_Orientation = new PropertyKey(99, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_SampleSize = new PropertyKey(9, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_StreamName = new PropertyKey(2, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_StreamNumber = new PropertyKey(11, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_TotalBitrate = new PropertyKey(43, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_TranscodedForSync = new PropertyKey(46, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Video_VerticalAspectRatio = new PropertyKey(45, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03); + public static PropertyKey PKEY_Volume_FileSystem = new PropertyKey(4, 0x9B174B35, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71); + public static PropertyKey PKEY_Volume_IsMappedDrive = new PropertyKey(2, 0x149C0B69, 0x2C2D, 0x48FC, 0x80, 0x8F, 0xD3, 0x18, 0xD7, 0x8C, 0x46, 0x36); + public static PropertyKey PKEY_Volume_IsRoot = new PropertyKey(10, 0x9B174B35, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71); + + #endregion + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/PropertyValue.cs b/src/Lithnet.CredentialProvider/Interop/PropertyValue.cs new file mode 100644 index 0000000..11c9af8 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/PropertyValue.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct PropertyValue + { + public ushort vt; + + public byte wReserved1; + + public byte wReserved2; + + public uint wReserved3; + + public InnerPropertyValue Value; + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/ULargeInteger.cs b/src/Lithnet.CredentialProvider/Interop/ULargeInteger.cs new file mode 100644 index 0000000..41eda0b --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/ULargeInteger.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct ULargeInteger + { + public ulong QuadPart; + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/UnmanagedArray.cs b/src/Lithnet.CredentialProvider/Interop/UnmanagedArray.cs new file mode 100644 index 0000000..946fc95 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/UnmanagedArray.cs @@ -0,0 +1,14 @@ +using System; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal struct UnmanagedArray + { + public uint cElems; + + [ComConversionLoss] + public IntPtr pElems; + } +} diff --git a/src/Lithnet.CredentialProvider/Interop/UnmanagedBlob.cs b/src/Lithnet.CredentialProvider/Interop/UnmanagedBlob.cs new file mode 100644 index 0000000..5bca237 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Interop/UnmanagedBlob.cs @@ -0,0 +1,14 @@ +using System; +using System.Runtime.InteropServices; + +namespace Lithnet.CredentialProvider.Interop +{ + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal struct UnmanagedBlob + { + public uint cbSize; + + [ComConversionLoss] + public IntPtr pData; + } +} diff --git a/src/Lithnet.CredentialProvider/Lithnet.CredentialProvider.csproj b/src/Lithnet.CredentialProvider/Lithnet.CredentialProvider.csproj new file mode 100644 index 0000000..0f93076 --- /dev/null +++ b/src/Lithnet.CredentialProvider/Lithnet.CredentialProvider.csproj @@ -0,0 +1,32 @@ + + + netstandard2.0 + false + Library + true + AnyCPU + true + + + + Lithnet Windows Credential Provider + Lithnet + Copyright 2023 Lithnet Pty Ltd + Lithnet Windows Credential Provider + 1.0.0 + beta.3 + Lithnet + true + true + true + Lithnet.CredentialProvider + MIT + https://github.com/lithnet/windows-credential-provider + https://github.com/lithnet/windows-credential-provider + + + + + + + diff --git a/src/Lithnet.CredentialProvider/NativeSerializationResponse.cs b/src/Lithnet.CredentialProvider/NativeSerializationResponse.cs new file mode 100644 index 0000000..918a99c --- /dev/null +++ b/src/Lithnet.CredentialProvider/NativeSerializationResponse.cs @@ -0,0 +1,33 @@ +namespace Lithnet.CredentialProvider +{ + /// + /// An object that represents a response to LogonUI/CredUI that includes serialized credentials, or the result of the attempt to obtain them. + /// + public class NativeSerializationResponse + { + /// + /// Gets or sets the final HRESULT of the serialization operation + /// + public int HResult { get; set; } + + /// + /// Gets or sets the status result of the serialization operation + /// + public SerializationResponse SerializationResponse { get; set; } + + /// + /// Gets or sets the serialzied credential blob + /// + public CredentialSerialization SerializedCredentials { get; set; } + + /// + /// Gets or sets the optional status text to display to the user + /// + public string OptionalStatusText { get; set; } + + /// + /// Gets or sets the optional status icon to display to the user + /// + public StatusIcon OptionalStatusIcon { get; set; } + } +}