Accessing Registry Keys from .dll in C# - c#

The environment I'm using might sound a bit messed up, so I will try to explain it at best.
I'm doing some experimental things with Electron. Right now, I have a simple .dll written in C# with using .NET Standard 2.0 as the base. On Electron's side, I'm using electron-edge-js, which, I think, works fine because I'm able to communicate with both of them.
So basic process goes like this,
I'm building my C# code to get my .dll's (I'm also adding reference dlls as well). Putting them into the same folder with Electron project. Starting the project to see how they did.
The problem lies at .dll's code. I'm using the following simple code,
public string RegisterUser(string username, string userkey) {
try {
RegistryKey key;
if (Microsoft.Win32.Registry.CurrentUser == null) return "Current user is null";
key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(#"SOFTWARE\Test\TestFunctions");
if (key == null) return "Key is null";
key.SetValue("uid", username);
key.SetValue("upsw", userkey);
key.Close();
return "Done";
} catch (Exception e) {
return e.ToString();
}
}
However, whenever I call this method, it always returns "Current user is null" no matter what. I tried building my .exe and running it as administrator as well. I checked the privileges in Regedit as well. They all seem fine. I'm having a kinda hard time for such an easy code. A little help would be amazing, thanks!

Related

Saving Modules correctly using Access-Interop

Even though my last questions weren't accepted well, I will give it another try.
I'm working on a program that is capable of controlling a lot of office-application behaviour by using the COM/Interop-Interface Microsoft provided for Word/Access/Excel. Still some functions differ from each other in the way that they are kept specific for the program that gets addressed.
My ambition is to Insert Macro-Code to an existing Access-Database and run the code while the Database is open and delete the code before the Database closes down. Partially this works as wished by using following C# code:
VBProject found = null;
Access.Application currApplication = this._currentInstance.Application;
if (target.Equals("") || scriptText.Equals(""))
return false;
foreach (VBProject vb in currApplication.VBE.VBProjects)
{
if (currApplication.CurrentDb().Name.Equals(vb.FileName))
{
found = vb;
break;
}
}
if (found != null)
{
foreach (VBComponent foundComponent in found.VBComponents)
{
if (foundComponent.Name.Equals(target))
{
return true;
}
}
VBComponent module = found.VBComponents.Add(vbext_ComponentType.vbext_ct_StdModule);
module.Name = target;
module.CodeModule.AddFromString(scriptText);
return true;
}
else
{
return false;
}
Now in particular, Access makes a diversion between VBA-Code-Modules which are visible in the Code-Editor and Modules which are loaded into the Database itself. For inserting the Module into the Database, it needs to be saved another time. When using the GUI, there's a window that popsup and asks for the Name to be used when saving it into the DB. It already takes the correct one etc. and it's fine after doing it by hand.
Besides the manual solution I found no way to do this step programatically.
Initial thoughts were:
currApplication.DoCmd.OpenModule(target, Type.Missing);
currApplication.DoCmd.Save(Access.AcObjectType.acMacro, target);
or
found.VBE.ActiveVBProject.SaveAs("");
The only two methods I could imagine would be doing the step I wanted. VBE in it's new .NET compatible form is documented very bad. Methods that would have applied to the native version are not guilty anymore. So I'm stuck with it now.
In case someone asks, why would you save the module at all, because once it's inserted in VBE it can be run like any other module listed in Access also, that's true, but for some unknown reasons this seems to be more fault-prone then to save it twice. Got runtime errors (like 2501) while launching the macro, which is not the case when it's saved properly.
Keeping it forever in the Access-Databases would be the last option but since those are many MDBs and thus they are changing frequently, I thought it would be nice to have it dynamic.
Hope somebody understands what I wrote here, (not so easy for me), and is enabled to help somehow :)
Thanks for all the reading. Looking forward for some good results, from the best community, hehe.

System.DirectoryServices.AccountManagement.PrincipalContext broken after Windows 10 update

I've been using this little function without any issue for the past few years to validate user credentials. The createPrincipalContext method returns a PrincipalContext with ContextType.Machine and the machine name.
public static bool ValidateCredentials(string username, string password, string domain = null) {
try {
using (var principalContext = createPrincipalContext(username, domain)) {
username = GetLoginInfo(username).Username;
// validate the credentials
if (principalContext.ValidateCredentials(username, password)) {
//once valid check if account is enabled
using (UserPrincipal user = UserPrincipal.FindByIdentity(principalContext, username)) {
return user.Enabled.GetValueOrDefault(false);
}
}
}
} catch (PrincipalOperationException e) {
traceError(e);
} catch (Exception e) {
traceError(e);
}
return false;
}
My development machine automatically updated to the latest version of Windows 10 this recently, and since then, principalContext.ValidateCredentials has been throwing the following exception.
System.IO.FileNotFoundException: The system cannot find the file specified.
Other than the machine update nothing else was changed. I've spend the last few days searching the net for what may have caused the issue.
Does anyone have any experience in identifying what may have been the cause and if possible, a solution?
One final Google before I started rolling back my machine to the previous build and I found this
https://connect.microsoft.com/IE/feedback/details/1904887/windows-10-insider-preview-build-10565
the problem is caused by missing registry entries in HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion, specifically: RegisteredOwner and RegisteredOrganization
EDIT:
Run the Registry Editor by pressing Windows R and typing regedit.exe. Browse to the location above
Just right click on the CurrentVersion in the Registry Editor and select New > String Value. After you add each entry ( RegisteredOwner and RegisteredOrganization ) edit their values. You can use your username and company name respectively.
Uncheck the Prefer 32-bit checkbox in your project's properties window under the Build tab, it is checked by default - see screenshot. This fixed it for me! Checking the checkbox again will cause the exceptions you describe to re-appear. I'm guessing this will force it to run in 64-bit mode if possible, and therefore use the 64-bit registry path rather than the WOW6432Node registry path and hence it will find the correct keys it needs.
Uncheck 'Prefer 32-bit' screenshot
Try change your build platform target to "AnyCPU", i found that if my platform target is x86, I have this issue!
Why, yet have no idea, seems like win 10 bug!!!

Application changes not taking effect

I have made a change to a method used in a Functiod in a mapping file but it seems the new code is not taking effect, ever.
I have deployed properly, started the application, restarted related host instance (actually all host instances I could find) and still, the old code seems to execute.
Here's the, simple, method:
public string RemoveNonNumericChars(string stIn, int maxLength)
{
string strOut;
try
{
strOut = Regex.Replace(stIn, "[^0-9]", "");
System.Diagnostics.EventLog.WriteEntry("BizTalk Server 2009", strOut);
return strOut.Substring(0, maxLength);
}
catch
{
return string.Empty;
}
}
I added the writing to EventLog line to see that this code is indeed being executed, but I don't get anything in "Application" event logs.
I do NOT get an empty string being returned, so it really does seem like the old code that's being executed prior to me fixing the method.
What am I missing exactly ?
Thank you.
For some reason, the script is not able to correctly retrieve the Build Config selected in Visual Studio, it's taken from Debug when I'm actually trying to build it for a Test environment. I should have known, thanks anyways.

C# - Load existing system environment variables when the current process don't have them loaded

On Windows, I have a C# assembly that is COM visible. It references other assemblies to control an application in the machine. It works fine.
However, under Apache Web Server and using CGI, it doesn't work. After doing some debuging, I found out that the problem is that, while running under Apache's CGI, the environment variables SYSTEMROOT and SYSTEMDRIVE, which aparently are needed by the referenced assemblies, are not loaded.
I can configure Apache to pass those environemtn variables too, but before doing so, I'd really like to know if there's some command I can put on my C# COM visible assembly to make it load environment variables as if it was, let's say, the SYSTEM user or something like that, so it doesn't have to relay on the environment passed by the starting application.
How do you force loading an existent system environment variable in C#, when IT IS NOT SET in the current process (or it was process-deleted by the launching process)?
Thanks in advance for any suggestions!
EDIT 1 - ADDED INFO: Just to make it more clear (as I see in the current answers it's not so clear): Apache intendedly deletes a lot of environment variables for CGI processes. It's not that Apache cannot see them, it can, but it won't pass them to CGI processes.
This should do the trick:
Environment.GetEnvironmentVariable("variable", EnvironmentVariableTarget.Machine);
I did a small test and it is working:
//has the value
string a = Environment.GetEnvironmentVariable("TMP");
Environment.SetEnvironmentVariable("TMP", null);
//does not have has the value
a = Environment.GetEnvironmentVariable("TMP");
//has the value
a = Environment.GetEnvironmentVariable("TMP", EnvironmentVariableTarget.Machine);
SOLUTION: Marco's answer was great and technically answered my question - except that I found out that the environment variables SYSTEMROOT and SYSTEMDRIVE are not really set in the registry where all environment variables are set, so, the chosen answer works for all variables except those two, which I specified in the OP.
SYSTEMROOT is defined on the registry in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRoot, and apparently (after more research), SYSTEMDRIVE is generated as a substring of SYSTEMDRIVE.
So, to get SYSTEMDRIVE and SYSTEMROOT from registry and load them into the environment:
using Microsoft.Win32;
namespace MySpace
{
public class Setup
{
public Setup()
{
SetUpEnvironment();
}
private void SetUpEnvironment()
{
string test_a = Environment.GetEnvironmentVariable("SYSTEMDRIVE", EnvironmentVariableTarget.Process);
string test_b = Environment.GetEnvironmentVariable("SYSTEMROOT", EnvironmentVariableTarget.Process);
if (test_a == null || test_a.Length == 0 || test_b == null || test_b.Length == 0)
{
string RegistryPath = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
string SYSTEMROOT = (string) Registry.GetValue(RegistryPath, "SystemRoot", null);
if (SYSTEMROOT == null)
{
throw new System.ApplicationException("Cannot access registry key " + RegistryPath);
}
string SYSTEMDRIVE = SYSTEMROOT.Substring(0, SYSTEMROOT.IndexOf(':') + 1);
Environment.SetEnvironmentVariable("SYSTEMROOT", SYSTEMROOT, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("SYSTEMDRIVE", SYSTEMDRIVE, EnvironmentVariableTarget.Process);
}
}
}
}
Then you can just call Setup setup = new Setup(); from other classes. And that's it. :-)
Environment.GetEnvironmentVariable
see reference here.
e.g.
Environment.CurrentDirectory = Environment.GetEnvironmentVariable("windir");
DirectoryInfo info = new DirectoryInfo(".");
lock(info)
{
Console.WriteLine("Directory Info: "+info.FullName);
}
Are the variables set as system wide?
If they are not, that is what you need to do, otherwise create user variables for the user the COM is running under.
Thank you. I cannot state with any certainty that this has once and for all driven a stake through the heart of the vampire, but amazingly enough, the error has disappeared (for now). The odd thing is that access to the statement
Environment.GetEnvironmentVariable("variable", EnvironmentVariableTarget.Machine);
is a real oddity in the debugger. It does not show up in Intellisense and does not even appear to fire, which leads me to suspect, which you all knew already, that this is some sort of magic runtime object Environment that has no instantiation in the debugger but also can be benignly jumped over. Oh well.
Oh and I should mention that after you see that error, you will note oddities in your Windows OS, which is worrisome. In particular, you will see, if you try to use the Control Panel /System/Advanced Properties (whatever) that it cannot load the dialog for the environment variables any more, indicating that %windir% has been seriously hosed (compromised) across all applications. Bad bad bad....

Registry access exception problem

I'm currently building a registry explorer, mostly because I want to support some much better searching operations. Like 'find all' and regular expressions. One problem I'm facing is that some keys throw a security exception when opening. I HAVE TRIED running the app with administrator priviledges, my user account is an administrator also. I embedded a manifest with "requireAdministrator" requested priviledges. I have also tried setting the ClickOnce security settings to Full trust, which is incompatible with requireAdministrator, or so Visual Studio tells me.... Nothing seems to help with avoiding this exception.
I would just like to iterate over all of the keys. I do not wish to add/delete keys. If a user wishes to delete a key and does not have permission to do so, it would display an error message. I just want to be able to have unrestricted READ access. Is this possible?
FTR: I'm on Win7 x64 and using Vs2010u and project is written in C# on .net 4.0. If regedit is capable of reading all keys even if it doesn't let you edit some of them. It would seem appropriate that we too can make an app to do the same thing. Though I'm finding it very difficult, and there doesn't seem to be any real help on the www. Only link-link circles, yay.
[EDIT]
Here's the code that reads the keys:
private void IterateSubKeys(RegistryKeyModel key) {
var subKeys = key.Key.GetSubKeyNames();
var values = key.Key.GetValueNames();
foreach (var valuename in values) {
try {
var valueKind = key.Key.GetValueKind(valuename);
var value = key.Key.GetValue(valuename);
key.Values.Add(new RegistryValueModel(valuename, value, valueKind));
}
catch { }
}
foreach (var keyname in subKeys) {
try {
var subkey = key.Key.OpenSubKey(
keyname,
RegistryKeyPermissionCheck.ReadSubTree,
RegistryRights.ReadKey);
key.SubKeys.Add(new RegistryKeyModel(subkey));
}
catch { Console.WriteLine("Error reading key: {0}", keyname); }
}
}
This is by design. There are lots of security related keys that can only accessible to the System account. You can't use that account. Regedit can't read these keys either, they are just not visible. Avoiding the expensive exception is going to require pinvoke.

Categories

Resources