Skip to content

Commit

Permalink
First push
Browse files Browse the repository at this point in the history
  • Loading branch information
thebookisclosed committed Sep 19, 2019
1 parent 7a88130 commit c0462a1
Show file tree
Hide file tree
Showing 18 changed files with 1,049 additions and 0 deletions.
14 changes: 14 additions & 0 deletions README.md
@@ -0,0 +1,14 @@
# ViVe
ViVe is a C# library you can use to make your own programs that interact with Windows 10's A/B feature mechanism

In case you'd like to talk to NTDLL exports directly, you can use its *NativeMethods*.

Otherwise, *RtlFeatureManager* offers the same featureset with the benefit of all unmanaged structures being delivered as standard C# classes instead.

# ViVeTool
ViVeTool is both an example of how to use ViVe, as well as a straightforward tool for power users which want to use the new APIs instantly.

# Compatibility
In order to use ViVe, you must be running Windows 10 build 18963 or newer.

![ViVeTool Helpfile](https://i.imgur.com/HrLiSxe.png)
31 changes: 31 additions & 0 deletions ViVe.sln
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29306.81
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ViVe", "ViVe\ViVe.csproj", "{80DCDA4D-8022-4740-8CCF-459DD3FE6F72}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ViVeTool", "ViVeTool\ViVeTool.csproj", "{4DAAB723-3613-4133-AE54-646133538E44}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{80DCDA4D-8022-4740-8CCF-459DD3FE6F72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{80DCDA4D-8022-4740-8CCF-459DD3FE6F72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{80DCDA4D-8022-4740-8CCF-459DD3FE6F72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{80DCDA4D-8022-4740-8CCF-459DD3FE6F72}.Release|Any CPU.Build.0 = Release|Any CPU
{4DAAB723-3613-4133-AE54-646133538E44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4DAAB723-3613-4133-AE54-646133538E44}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4DAAB723-3613-4133-AE54-646133538E44}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4DAAB723-3613-4133-AE54-646133538E44}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E5173A5A-E3A8-4C36-9798-11628C4E4684}
EndGlobalSection
EndGlobal
76 changes: 76 additions & 0 deletions ViVe/FeatureConfiguration.cs
@@ -0,0 +1,76 @@
using System;

namespace Albacore.ViVe
{
public class FeatureConfiguration
{
private int _group;
private FeatureEnabledState _enabledState;
private int _enabledStateOptions;
private int _variant;
private int _variantPayloadKind;
private FeatureConfigurationAction _action;

public uint FeatureId { get; set; }
public int Group
{
get { return _group; }
set {
if (value > 15)
throw new ArgumentException("Group must not be more than 15");
_group = value;
}
}
public FeatureEnabledState EnabledState
{
get { return _enabledState; }
set
{
if ((int)value > 3)
throw new ArgumentException("EnabledState must not be more than 3");
_enabledState = value;
}
}
public int EnabledStateOptions
{
get { return _enabledStateOptions; }
set
{
if (value > 1)
throw new ArgumentException("EnabledStateOptions must not be more than 1");
_enabledStateOptions = value;
}
}
public int Variant
{
get { return _variant; }
set
{
if (value > 63)
throw new ArgumentException("Variant must not be more than 63");
_variant = value;
}
}
public int VariantPayloadKind
{
get { return _variantPayloadKind; }
set
{
if (value > 3)
throw new ArgumentException("VariantPayloadKind must not be more than 3");
_variantPayloadKind = value;
}
}
public int VariantPayload { get; set; }
public FeatureConfigurationAction Action
{
get { return _action; }
set
{
if ((int)value > 4)
throw new ArgumentException("Invalid feature configuration action");
_action = value;
}
}
}
}
11 changes: 11 additions & 0 deletions ViVe/FeatureConfigurationAction.cs
@@ -0,0 +1,11 @@
namespace Albacore.ViVe
{
public enum FeatureConfigurationAction
{
None = 0,
UpdateEnabledState = 1,
UpdateVariant = 2,
UpdateAll = 3,
Delete = 4
}
}
9 changes: 9 additions & 0 deletions ViVe/FeatureConfigurationSection.cs
@@ -0,0 +1,9 @@
namespace Albacore.ViVe
{
public enum FeatureConfigurationSection
{
Boot = 0,
Runtime = 1,
UsageTriggers = 2
}
}
9 changes: 9 additions & 0 deletions ViVe/FeatureEnabledState.cs
@@ -0,0 +1,9 @@
namespace Albacore.ViVe
{
public enum FeatureEnabledState
{
Default = 0,
Disabled = 1,
Enabled = 2
}
}
9 changes: 9 additions & 0 deletions ViVe/FeatureUsageReport.cs
@@ -0,0 +1,9 @@
namespace Albacore.ViVe
{
public class FeatureUsageReport
{
public uint FeatureId { get; set; }
public ushort ReportingKind { get; set; }
public ushort ReportingOptions { get; set; }
}
}
10 changes: 10 additions & 0 deletions ViVe/FeatureUsageSubscription.cs
@@ -0,0 +1,10 @@
namespace Albacore.ViVe
{
public class FeatureUsageSubscription
{
public uint FeatureId { get; set; }
public ushort ReportingKind { get; set; }
public ushort ReportingOptions { get; set; }
public ulong ReportingTarget { get; set; }
}
}
73 changes: 73 additions & 0 deletions ViVe/NativeMethods.cs
@@ -0,0 +1,73 @@
using System;
using System.Runtime.InteropServices;

namespace Albacore.ViVe
{
public delegate void FeatureConfigurationChangeCallback(IntPtr Context);

public static class NativeMethods
{
[DllImport("ntdll.dll")]
public static extern int RtlQueryAllFeatureConfigurations(
FeatureConfigurationSection sectionType,
ref uint changeStamp,
IntPtr buffer,
ref int featureCount
);

[DllImport("ntdll.dll")]
public static extern int RtlQueryFeatureConfiguration(
uint featureId,
FeatureConfigurationSection sectionType,
ref uint changeStamp,
IntPtr buffer
);

[DllImport("ntdll.dll")]
public static extern uint RtlQueryFeatureConfigurationChangeStamp();

[DllImport("ntdll.dll")]
public static extern int RtlQueryFeatureUsageNotificationSubscriptions(
IntPtr buffer,
ref int subscriptionCount
);

[DllImport("ntdll.dll")]
public static extern int RtlSetFeatureConfigurations(
ref uint changeStamp,
FeatureConfigurationSection sectionType,
byte[] buffer,
int featureCount
);

[DllImport("ntdll.dll")]
public static extern int RtlRegisterFeatureConfigurationChangeNotification(
FeatureConfigurationChangeCallback callback,
IntPtr context,
IntPtr unknown,
out IntPtr subscription
);

[DllImport("ntdll.dll")]
public static extern int RtlUnregisterFeatureConfigurationChangeNotification(
IntPtr subscription
);

[DllImport("ntdll.dll")]
public static extern int RtlSubscribeForFeatureUsageNotification(
byte[] buffer,
int subscriptionCount
);

[DllImport("ntdll.dll")]
public static extern int RtlUnsubscribeFromFeatureUsageNotifications(
byte[] buffer,
int subscriptionCount
);

[DllImport("ntdll.dll")]
public static extern int RtlNotifyFeatureUsage(
byte[] buffer
);
}
}
36 changes: 36 additions & 0 deletions ViVe/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Albacore.ViVe")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Albacore.ViVe")]
[assembly: AssemblyCopyright("Copyright © @thebookisclosed 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("80dcda4d-8022-4740-8ccf-459dd3fe6f72")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2019.9.18.1002")]
[assembly: AssemblyFileVersion("2019.9.18.1002")]
61 changes: 61 additions & 0 deletions ViVe/RtlDataHelpers.cs
@@ -0,0 +1,61 @@
using System.Collections.Generic;
using System.IO;

namespace Albacore.ViVe
{
public static class RtlDataHelpers
{
public static byte[] SerializeFeatureConfigurations(List<FeatureConfiguration> configurations)
{
byte[] retArray = new byte[configurations.Count * 32];
using (MemoryStream ms = new MemoryStream(retArray, true))
{
using (BinaryWriter bw = new BinaryWriter(ms))
foreach (var thing in configurations)
{
bw.Write(thing.FeatureId);
bw.Write(thing.Group);
bw.Write((int)thing.EnabledState);
bw.Write(thing.EnabledStateOptions);
bw.Write(thing.Variant);
bw.Write(thing.VariantPayloadKind);
bw.Write(thing.VariantPayload);
bw.Write((int)thing.Action);
}
}
return retArray;
}

public static byte[] SerializeFeatureUsageSubscriptions(List<FeatureUsageSubscription> subscriptions)
{
byte[] retArray = new byte[subscriptions.Count * 16];
using (MemoryStream ms = new MemoryStream(retArray, true))
{
using (BinaryWriter bw = new BinaryWriter(ms))
foreach (var thing in subscriptions)
{
bw.Write(thing.FeatureId);
bw.Write(thing.ReportingKind);
bw.Write(thing.ReportingOptions);
bw.Write(thing.ReportingTarget);
}
}
return retArray;
}

public static byte[] SerializeFeatureUsageReport(FeatureUsageReport report)
{
byte[] retArray = new byte[8];
using (MemoryStream ms = new MemoryStream(retArray, true))
{
using (BinaryWriter bw = new BinaryWriter(ms))
{
bw.Write(report.FeatureId);
bw.Write(report.ReportingKind);
bw.Write(report.ReportingOptions);
}
}
return retArray;
}
}
}

0 comments on commit c0462a1

Please sign in to comment.