C# - Assign ConsoleKey then reassign using ConsoleKeyInfo - c#

What I'm trying to accomplish is have a ConsoleKey assigned to a variable then using ConsoleKeyInfo to modify the variable.
I'm getting errors saying Cannot convert source type 'System.ConsoleKey' to target type 'System.ConsoleKeyInfo'.
The reasoning behind this is I wish to have the user be able to reprogram the keys used inside the application.
I have this so far;
public static ConsoleKeyInfo keyboardkeynorth;
keyboardkeynorth = Console.ReadKey();
This works, but it doesn't allow me to start the program with keyboardkeynorth already set to ConsoleKey.W.
Elsewhere in the program I would call keyboardkeynorth to be used as a ConsoleKey
This may be simple but it seems to be eluding me.

Realizing this is a short 3+ years after you asked...
public static ConsoleKeyInfo keyboardkeynorth =
new ConsoleKeyInfo('W', ConsoleKey.W, false, false, false);
And don't you want "north" to be 'N' initially? ;^)
It's a strange, verbose constructor, but does what you appear to be asking.

Here is a complete, and simple, program to show you how you might do this. I say simple because it doesn't take into consideration CTRL, ALT, or SHIFT -- and based on how I gather the custom key info you wouldn't even be able to set those because I'm using ReadKey. But you'll get the idea.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
namespace ConsoleApplication23
{
class Program
{
private static ConsoleKeyInfo keyAction1, keyAction2, keyAction3;
static void Main(string[] args)
{
InitializeKeyActions();
Console.Write("Do you want a new key action for #1? ");
var result = Console.ReadKey();
if (result.Key != ConsoleKey.Enter) { UpdateKeyInfo("keyAction1", result); }
}
private static void UpdateKeyInfo(string keyName, ConsoleKeyInfo result)
{
var propertyInfo = typeof(Program).GetField(keyName, BindingFlags.NonPublic | BindingFlags.Static);
if (propertyInfo == null) { return; }
var key = result.KeyChar;
propertyInfo.SetValue(null, new ConsoleKeyInfo(key, (ConsoleKey)key, false, false, false));
StringBuilder keyActions = new StringBuilder();
foreach (var line in File.ReadAllLines("keyactions.ini"))
{
var kvp = line.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
if (kvp[0] != keyName)
{
keyActions.AppendLine(line);
continue;
}
keyActions.AppendLine(string.Format("{0}: {1}", kvp[0], result.KeyChar));
}
File.WriteAllText("keyactions.ini", keyActions.ToString());
}
private static void InitializeKeyActions()
{
if (!File.Exists("keyactions.ini"))
{
StringBuilder keyActions = new StringBuilder();
keyActions.AppendLine("keyAction1: A");
keyActions.AppendLine("keyAction2: B");
keyActions.AppendLine("keyAction3: C");
File.WriteAllText("keyactions.ini", keyActions.ToString());
}
foreach (var line in File.ReadAllLines("keyactions.ini"))
{
var kvp = line.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
var propertyInfo = typeof(Program).GetField(kvp[0], BindingFlags.NonPublic | BindingFlags.Static);
if (propertyInfo == null) { continue; }
var key = kvp[1].Trim()[0];
propertyInfo.SetValue(null, new ConsoleKeyInfo(key, (ConsoleKey)key, false, false, false));
}
}
}
}

Related

How to insert lambda coordinate output into KeyValuePair?

I'm trying to create a MD5 malware scanner using C#. Using normal dictionary comparison has a fatal flaw, there exists duplicate files with the same hash across directories so, the same key (md5) would represent a lot of file directories to relate with. I tried switching to KeyValuePair<> but due to my inexperience, I still can't figure out how to insert lambda coordinate output into KeyValuePair<> (represented by Idon'tknowwhatshouldbehere in the code below).
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Diagnostics;
using System.Text;
using System.Web;
using static System.Net.WebRequestMethods;
namespace RiskRemover
{
class Program
{
private static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
var currDir = Directory.GetCurrentDirectory();
Console.WriteLine("Stage 1: Update");
HttpWebRequest updRq = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/drive/v3/files/15WR2yTVJzgwg2pn64IhxFUbfy2BmmsdL?alt=media&key=APIKey");
updRq.Referer = "referrer";
HttpWebResponse updRqF = (HttpWebResponse)updRq.GetResponse();
using (Stream output = System.IO.File.OpenWrite("virushashesL.txt"))
using (Stream input = updRqF.GetResponseStream())
{
input.CopyTo(output);
}
bool dbExist = System.IO.File.Exists($"{currDir}\\virushashesL.txt");
if (!dbExist)
{
Console.WriteLine("Database Doesn't exist, Terminating...");
return;
}
var lineCount = System.IO.File.ReadLines($"{currDir}\\virushashesL.txt").Count();
Console.WriteLine(" ");
Console.WriteLine($"Database Hash Count: {lineCount}");
Console.WriteLine(" ");
Console.Write("Press any key to continue...");
Console.Clear();
Console.Write("Scan Path:");
string pathScan = #Console.ReadLine();
Console.Clear();
Console.WriteLine("Stage 2: MD5 Hashing");
var data = GetHasList(#pathScan, false).Select(x => $"\"{x.fileName}\" {x.hash}");
System.IO.File.WriteAllLines("output.txt", data);
Console.Clear();
Console.WriteLine("Stage 3: Comparing MD5 hashes to DB");
KeyValuePair<string, string> dic = new KeyValuePair<string, string>();
dic = System.IO.File.ReadAllLines("output.txt")
.Select(l => l.Split(new[] { '<' }))
.Idon'tknowwhatshouldbehere(s => s[1].Trim().Substring(0, 10), s => s[0].Trim());
List<string> lines = System.IO.File.ReadAllLines("virushashesL.txt").ToList();
foreach (var line in lines)
{
bool malicious = dic.ContainsKey(line);
if (malicious)
{
string malPath = dic[line];
System.IO.File.Delete(malPath);
}
}
Console.Clear();
sw.Stop();
Console.Write($"Done in {sw.Elapsed}...");
Console.ReadKey();
return;
}
public static IEnumerable<(string fileName, string hash)> GetHasList(string path, bool isRelative)
{
foreach (var file in Directory.GetFiles(path, "*.*", SearchOption.AllDirectories))
{
string hash;
using (var md5 = MD5.Create())
using (var stream = System.IO.File.OpenRead(file))
hash = BitConverter.ToString(md5.ComputeHash(stream)).ToLower();
hash = hash.Replace("-", "");
if (isRelative)
yield return (file.Remove(0, path.TrimEnd('/').Length + 1), hash);
else
yield return ($"{file}<", hash);
}
}
}
}
Example output.txt
"D:\EvaxHybrid\Downloads\CS8\insdir\CSMediaLibParser.dll<" a384ff0a72a89028fc5edc894309ce81
"D:\EvaxHybrid\Downloads\CS8\insdir\CSMediaLibTools.dll<" 62cd2374d3a2bbeb888a078dc20e6b18
...
Example virushashesL.txt
2d3f18345c
2d427ec2c7
...
I think you want to delete all paths with malware
ILookup<string, string> lookup = System.IO.File.ReadAllLines("output.txt")
.Select(l => l.Split(new[] { '<' }))
.Select(s => (key: s[1].Trim().Substring(0, 10), value: s[0].Trim())) // create a value tuple (string key, string value)
.ToLookup(s => s.key, s => s.value); // make a lookup from the tuples
List<string> lines = System.IO.File.ReadAllLines("virushashesL.txt").ToList();
foreach (var line in lines)
{
var malPaths = lookup[line];
// if the key is not found an empty sequence is returned
// so no further checks are neccessary
foreach (var malPath in malPaths)
{
// delete all malicious paths
System.IO.File.Delete(malPath);
}
}
D://output.txt
D:\EvaxHybrid\Downloads\CS8\insdir\CSMediaLibParser.dll< a384ff0a72a89028fc5edc894309ce81
D:\EvaxHybrid\Downloads\CS8\insdir\CSMediaLibTools.dll< 62cd2374d3a2bbeb888a078dc20e6b18
D://virushashesL.txt
a384ff0a72a89028fc5edc894309ce81
62cd2374d3a2bbeb888a078dc20e6b18
private void fileintodis()
{
List<KeyValuePair<string, string>> dic = new List<KeyValuePair<string, string>>();
dic = System.IO.File.ReadAllLines("D://output.txt").ToList()
.Select(l => new KeyValuePair<string, string>(l.Split('<')[1].Trim(), l.Split('<')[0].Trim())).ToList();
List<string> lines = System.IO.File.ReadAllLines("D://virushashesL.txt").ToList();
foreach (var line in lines)
{
bool malicious = dic.Where(s => s.Key.Trim() == line).Count() > 0 ? true : false;
if (malicious)
{
string malPath = dic.Where(s => s.Key == line).Select(e => e.Value).FirstOrDefault().ToString();
System.IO.File.Delete(malPath);
}
}
}

How do I remove the keys from Local machine\SOFTWARE?

I tried to delete a test key through a C# script. The following code is my script, I also added admin value in manifest file for this project UAC. But it still doesn't work. Even restarted Visual Studio 2017 with Admin mode.
The error message said Cannot write to the registry key.
Not sure what's wrong in the script.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
using System.Security;
using System.Security.AccessControl;
using System.Security.Principal;
namespace temp_code_tester
{
class Program
{
static void Main(string[] args)
{
//Get current login account info from another Class
//string userName = WindowsIdentity.GetCurrent().Name;
//var SecCheck = new SecutriyProcesser();
//SecCheck.AddRule(userName);
var RunCheck = new AccessRegistry();
RunCheck.ACL("Test");
}
}
class AccessRegistry
{
public void ACL(string name)
{
Console.WriteLine("Getting the registry keys.....");
Console.WriteLine("---------------------------------------------\n");
//Open the SOFTWARE keys and input those keys into array
RegistryKey SoftKey = Registry.LocalMachine.OpenSubKey(#"SOFTWARE");
string[] lists = SoftKey.GetSubKeyNames();
foreach (string KeyName in lists)
{
Console.WriteLine(KeyName);
}
foreach (string value in lists)
{
if (value.Contains(name)) // if we find the key, then lists all subkeys
{
//Registry.LocalMachine.DeleteSubKeyTree(value);
Console.WriteLine("\nMatch one: {0}", value);
var RightKey = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\" + value);
string[] SubList = RightKey.GetSubKeyNames();
foreach (string SubValue in SubList)
{
Console.WriteLine("Folder: {0} is under this key", SubValue);
}
if (SubList.Length > 1)
{
try
{
SoftKey.DeleteSubKeyTree(value);
Console.WriteLine("\nThe folder {0} has been removed", value);
}
catch (Exception er)
{
Console.WriteLine("Error: {0}", er.Message);
}
}
else
{
try
{
SoftKey.DeleteSubKey(value);
}
catch (Exception)
{
throw;
}
}
}
}
SoftKey.Close();
}
}
class SecutriyProcesser
{
// A method about add enough roles for current window account
public void AddRule(string userName)
{
RegistrySecurity rs = new RegistrySecurity();
rs.AddAccessRule(new RegistryAccessRule(userName,
RegistryRights.FullControl,
InheritanceFlags.ObjectInherit,
PropagationFlags.InheritOnly,
AccessControlType.Allow));
}
// Try to list the security level
public void ShowSecurity(RegistrySecurity security)
{
Console.WriteLine("\r\nCurrent access rules:\r\n");
foreach (RegistryAccessRule ar in security.GetAccessRules(true, true, typeof(NTAccount)))
{
Console.WriteLine(" User: {0}", ar.IdentityReference);
Console.WriteLine(" Type: {0}", ar.AccessControlType);
Console.WriteLine(" Rights: {0}", ar.RegistryRights);
Console.WriteLine(" Inheritance: {0}", ar.InheritanceFlags);
Console.WriteLine(" Propagation: {0}", ar.PropagationFlags);
Console.WriteLine(" Inherited? {0}", ar.IsInherited);
Console.WriteLine();
}
}
}
}
You forgot the 'writable' parameter of the 'OpenSubkey' method.
Try this :
RegistryKey SoftKey = Registry.LocalMachine.OpenSubKey(#"SOFTWARE", true);
It should work like this.
EDIT : This method will probably fail if you don't run Visual Studio as Administrator while debugging.

Find all references in Visual Studio solution using Roslyn

TLDR;
How do I find all the const string parameters of the references to the index property Microsoft.Extensions.Localization.IStringLocalizer.Item[String] in my Visual Studio solution? All source code is written in C#. The solution must also support MVC razor views.
Additional info
I believe that Roslyn is the answer to the question. I, however, haven't yet found my way through the API to achieve this. I'm also uncertain about whether to use syntax tree, compilation or semantic model. The following is an attempt based on other Q&A here on stackoverflow. Any help to make it work is highly appreciated :-) If you are curious you can read about the reason for this need here.
namespace AspNetCoreLocalizationKeysExtractor
{
using System;
using System.Linq;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.MSBuild;
class Program
{
static void Main(string[] args)
{
string solutionPath = #"..\source\MySolution.sln";
var msWorkspace = MSBuildWorkspace.Create();
var solution = msWorkspace.OpenSolutionAsync(solutionPath).Result;
foreach (var project in solution.Projects.Where(p => p.AssemblyName.StartsWith("MyCompanyNamespace.")))
{
var compilation = project.GetCompilationAsync().Result;
var interfaceType = compilation.GetTypeByMetadataName("Microsoft.Extensions.Localization.IStringLocalizer");
// TODO: Find the indexer based on the name ("Item"/"this"?) and/or on the parameter and return type
var indexer = interfaceType.GetMembers().First();
var indexReferences = SymbolFinder.FindReferencesAsync(indexer, solution).Result.ToList();
foreach (var symbol in indexReferences)
{
// TODO: How to get output comprised by "a location" like e.g. a namespace qualified name and the parameter of the index call. E.g:
//
// MyCompanyNamespace.MyLib.SomeClass: "Please try again"
// MyCompanyNamespace.MyWebApp.Views.Shared._Layout: "Welcome to our cool website"
Console.WriteLine(symbol.Definition.ToDisplayString());
}
}
}
}
}
Update: Workaround
Despite the great help from #Oxoron I've chosen to resort to a simple workaround. Currently Roslyn doesn't find any references using SymbolFinder.FindReferencesAsync. It appears to be according to "silent" msbuild failures. These errors are available like this:
msWorkspace.WorkspaceFailed += (sender, eventArgs) =>
{
Console.Error.WriteLine($"{eventArgs.Diagnostic.Kind}: {eventArgs.Diagnostic.Message}");
Console.Error.WriteLine();
};
and
var compilation = project.GetCompilationAsync().Result;
foreach (var diagnostic in compilation.GetDiagnostics())
Console.Error.WriteLine(diagnostic);
My workaround is roughly like this:
public void ParseSource()
{
var sourceFiles = from f in Directory.GetFiles(SourceDir, "*.cs*", SearchOption.AllDirectories)
where f.EndsWith(".cs") || f.EndsWith(".cshtml")
where !f.Contains(#"\obj\") && !f.Contains(#"\packages\")
select f;
// _["Hello, World!"]
// _[#"Hello, World!"]
// _localizer["Hello, World!"]
var regex = new Regex(#"_(localizer)?\[""(.*?)""\]");
foreach (var sourceFile in sourceFiles)
{
foreach (var line in File.ReadLines(sourceFile))
{
var matches = regex.Matches(line);
foreach (Match match in matches)
{
var resourceKey = GetResourceKeyFromFileName(sourceFile);
var key = match.Groups[2].Value;
Console.WriteLine($"{resourceKey}: {key}");
}
}
}
}
Of course the solution isn't bullet proof and relies on naming conventions and doesn't handle multiline verbatim strings. But it'll probably do the job for us :-)
Take a look on this and this questions, they will help with indexers.
Determine namespaces - it's a bit more difficult.
You can determine it using code like
int spanStart = symbol.Locations[0].Location.SourceSpan.Start;
Document doc = symbol.Locations[0].Location.Document;
var indexerInvokation = doc.GetSyntaxRootAsync().Result.DescendantNodes()
.FirstOrDefault(node => node.GetLocation().SourceSpan.Start == spanStart );
After that just find indexerInvokation parents nodes until MethodDeclarationSyntax, ClassDeclarationSyntax, etc.
Upd1.
Test project code:
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
int test0 = new A().GetInt();
int test1 = new IndexedUno()[2];
int test2 = new IndexedDo()[2];
}
}
public interface IIndexed
{
int this[int i] { get; }
}
public class IndexedUno : IIndexed
{
public int this[int i] => i;
}
public class IndexedDo : IIndexed
{
public int this[int i] => i;
}
public class A
{
public int GetInt() { return new IndexedUno()[1]; }
}
public class B
{
public int GetInt() { return new IndexedDo()[4]; }
}
}
Search code:
using System;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.MSBuild;
namespace AnalyzeIndexers
{
class Program
{
static void Main(string[] args)
{
string solutionPath = #"PathToSolution.sln";
var msWorkspace = MSBuildWorkspace.Create();
var solution = msWorkspace.OpenSolutionAsync(solutionPath).Result;
foreach (var project in solution.Projects.Where(p => p.AssemblyName.StartsWith("TestApp")))
{
var compilation = project.GetCompilationAsync().Result;
var interfaceType = compilation.GetTypeByMetadataName("TestApp.IIndexed");
var indexer = interfaceType
.GetMembers()
.OfType<IPropertySymbol>()
.First(member => member.IsIndexer);
var indexReferences = SymbolFinder.FindReferencesAsync(indexer, solution).Result.ToList();
foreach (var indexReference in indexReferences)
{
foreach (ReferenceLocation indexReferenceLocation in indexReference.Locations)
{
int spanStart = indexReferenceLocation.Location.SourceSpan.Start;
var doc = indexReferenceLocation.Document;
var indexerInvokation = doc.GetSyntaxRootAsync().Result
.DescendantNodes()
.FirstOrDefault(node => node.GetLocation().SourceSpan.Start == spanStart);
var className = indexerInvokation.Ancestors()
.OfType<ClassDeclarationSyntax>()
.FirstOrDefault()
?.Identifier.Text ?? String.Empty;
var #namespace = indexerInvokation.Ancestors()
.OfType<NamespaceDeclarationSyntax>()
.FirstOrDefault()
?.Name.ToString() ?? String.Empty;
Console.WriteLine($"{#namespace}.{className} : {indexerInvokation.GetText()}");
}
}
}
Console.WriteLine();
Console.ReadKey();
}
}
}
Take a look at the var indexer = ... code - it extracts indexer from a type. Maybe you'll need to work with getter\setter.
Other point of interest: indexerInvokation computation. We get SyntaxRoot too often, maybe you'll need some kind of cache.
Next: class and namespace search. I didn't find a method, but recommend not to find it: there can be properties, other indexers, anonymous methods used your indexers. If you don't really care about this - just find ancestors of type MethodDeclarationSyntax.

Compiling with CodeDom

I started experimenting a bit with CodeDom and made simple Application which collects sourcecode from the user input and tries to compile it with C#-Syntax.
For those who want to try the whole proccess, type end... to finish up the sourcecode entry.
Here's the example:
using System;
using System.Collections;
using System.Reflection;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
namespace CodeDomTest
{
class Program
{
static void Main(string[] args)
{
getTestCode();
}
public static Assembly getTestCode()
{
CompilerParameters CompilerOptions = new CompilerParameters(
assemblyNames: new String[] { "mscorlib.dll", "System.dll", "System.Core.dll" },
outputName: "test.dll",
includeDebugInformation: false)
{ TreatWarningsAsErrors = true, WarningLevel = 0, GenerateExecutable = false, GenerateInMemory = true };
List<String> newList = new List<String>();
String a = null;
while(a != "end...")
{
a = Console.ReadLine();
if (!a.Equals( "end..."))
newList.Add(a);
}
String[] source = { "class Test {static void test() {System.Console.WriteLine(\"test\");}}" };
source = newList.ToArray();
CSharpCodeProvider zb = new CSharpCodeProvider(new Dictionary<String, String> { { "CompilerVersion", "v4.0" } });
CompilerResults Results = zb.CompileAssemblyFromSource(CompilerOptions, source);
Console.WriteLine(Results.Errors.HasErrors);
CompilerErrorCollection errs = Results.Errors;
foreach(CompilerError z in errs)
{
Console.WriteLine(z.ErrorText);
}
if (!(errs.Count > 0))
{
AssemblyName assemblyRef = Results.CompiledAssembly.GetName();
AppDomain.CurrentDomain.Load(assemblyRef);
//foreach (String a in )
Console.WriteLine(Results.CompiledAssembly.FullName.ToString());
Type tempType = Results.CompiledAssembly.GetType("Test");
MethodInfo tempMethodInfo = tempType.GetMethod("test", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
if (tempMethodInfo != null)
tempMethodInfo.Invoke(null,null);
}
Console.ReadLine();
return null;
}
}
}
Now as you can see, basically it compiles the following code:
class Test {static void test() {System.Console.WriteLine(\"test\");}}
Which works fine if you enter it like that (without the ") as userinput into the program. But as soon as you insert a line break by pressing enter after one finished line, the compiling breaks with several errors. It seems like it would evaluate each line as own program by giving following statements:
} expected
Expected class, delegate, enum, interface, or struct
A namespace cannot directly contain members such as fields or methods
A namespace cannot directly contain members such as fields or methods
Type or namespace definition, or end-of-file expected
Type or namespace definition, or end-of-file expected
For following input:
class Test
{
static void test()
{
System.Console.WriteLine
("test");
}
}
Do I have to break user (custom) entries down to one line then?
Each line in sources should contain complete source code not a single line of code. Since you're gathering the code line by line into your source array, you'll have to collapse it into a single string then add that string to an array to pass to CompileAssemblyFromSource
Try this:
while (a != "end...")
{
a = Console.ReadLine();
if (!a.Equals("end..."))
newList.Add(a);
}
string code = string.Join("\r\n", newList);
string[] source = new string[] { code };

C# program that dumps the entire HKLM registry tree to the console?

I'm trying to write a simple console app that dumps the contents of HKLM to the console. The output should look something like:
HKEY_LOCAL_MACHINE
HKEY_LOCAL_MACHINE\BCD00000000
HKEY_LOCAL_MACHINE\BCD00000000\Description
KeyName: BCD00000000
System: 1
TreatAsSystem: 1
GuidCache: System.Byte[]
HKEY_LOCAL_MACHINE\BCD00000000\Objects
HKEY_LOCAL_MACHINE\BCD00000000\Objects\{0ce4991b-e6b3-4b16-b23c-5e0d9250e5d9}
HKEY_LOCAL_MACHINE\BCD00000000\Objects\{0ce4991b-e6b3-4b16-b23c-5e0d9250e5d9}\Description
Type: 537919488
HKEY_LOCAL_MACHINE\BCD00000000\Objects\{0ce4991b-e6b3-4b16-b23c-5e0d9250e5d9}\Elements
HKEY_LOCAL_MACHINE\BCD00000000\Objects\{0ce4991b-e6b3-4b16-b23c-5e0d9250e5d9}\Elements\16000020
Element: System.Byte[]
I haven't had much luck researching how to do this. Any help would be greatly appreciated.
You know there's already an app that dumps registry contents, right?
REG EXPORT HKLM hklm.reg
Fun part is, it exports the keys in a text format, but that text file can be imported using either REG or the registry editor.
cHao way is the safiest approach to your question. In the meanwhile, I was bored on this sunday night and wrote something. Just change the Console.WriteLine or add a few other Console.WriteLine to suit your need, whatever need there is.
class Program
{
static void Main(string[] args)
{
Registry.CurrentUser.GetSubKeyNames()
.Select(x => Registry.CurrentUser.OpenSubKey(x))
.Traverse(key =>
{
if (key != null)
{
// You will most likely hit some security exception
return key.GetSubKeyNames().Select(subKey => key.OpenSubKey(subKey));
}
return null;
})
.ForEach(key =>
{
key.GetValueNames()
.ForEach(valueName => Console.WriteLine("{0}\\{1}:{2} ({3})", key, valueName, key.GetValue(valueName), key.GetValueKind(valueName)));
});
Console.ReadLine();
}
}
public static class Extensions
{
public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
{
foreach (T item in source)
{
yield return item;
IEnumerable<T> seqRecurse = fnRecurse(item);
if (seqRecurse != null)
{
foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
{
yield return itemRecurse;
}
}
}
}
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
{
action(item);
}
}
}
thanks for the answer Pierre-Alain Vigeant, i like ur solution. for the most part it worked with a couple of minor alterations for the text formatting, but i still couldnt deal with the security exception that was being thrown. turns out linq is not so great for this because it does alot of behind the scenes stuff. the following solution is a basic idea of how to do it
class Program
{
static void Main(string[] args)
{
RegistryKey key = Registry.LocalMachine;
Traverse(key, 0);
key.Close();
Console.Read();
}
private static void Traverse(RegistryKey key, int indent)
{
Console.WriteLine(key.Name);
string[] names = key.GetSubKeyNames();
foreach (var subkeyname in names)
{
try
{
string[] valnames = key.GetValueNames();
foreach (string valname in valnames)
{
Console.WriteLine(returnIndentions(indent)+valname + ":" + key.GetValue(valname));
}
Traverse(key.OpenSubKey(subkeyname),indent++);
}
catch {
//do nothing
}
}
}
private static string returnIndentions(int indent)
{
string indentions = "";
for (int i = 0; i < indent; i++) {
indentions += " ";
}
return indentions;
}
}
using System;
using System.Text;
using Microsoft.Win32;
class Program
{
static void Main(string[] args)
{
using RegistryKey key = Registry.LocalMachine;
string keyName = args[0]; // eg #"SOFTWARE\Microsoft\Speech\Voices"
var sb = new StringBuilder();
var subKey = key.OpenSubKey(keyName);
Traverse(subKey);
void Traverse(RegistryKey key, int indent = 0)
{
sb.AppendLine(new string(' ', Math.Max(0, indent - 2)) + key.Name);
indent++;
string[] valnames = key.GetValueNames();
foreach (string valname in valnames)
{
sb.AppendLine(new string(' ', indent) + valname + " : " + key.GetValue(valname));
}
string[] names = key.GetSubKeyNames();
foreach (var subkeyname in names)
{
Traverse(key.OpenSubKey(subkeyname), indent + 2);
}
}
Console.WriteLine(sb.ToString());
}
}

Categories

Resources