0

I have the following code, which returns "Success", but searching the registry with two different tools with the search string "{3BDAAC43-E734-11D5-93AF-00105A990292}" yields no results.

 RegistryKey RK = Registry.ClassesRoot.CreateSubKey("CLSID\\{3BDAAC43-E734-11D5-93AF-00105A990292}");
 if ( RK != null ) 
     {
         MessageBox.Show("Success", "Success");
     }
 else 
     {
        MessageBox.Show("Failure", "Failure");

}

[Edit] I hate problems that I solve without knowing how, but I'm past this issue.

I'm now able to create a subkey, but I can't set any value pairs. I've found several examples how it should be done, but can't see how my code is different than them.

This is my new code. The subkey appears, but never has anything in it.

     Registry.ClassesRoot.DeleteSubKey(clsid.EntryGuid, false);

                RK.CreateSubKey(clsid.EntryGuid);
                RK.OpenSubKey(clsid.EntryGuid, true);
                RK.SetValue("(Default", clsid.RootObjectName);
                RK.CreateSubKey("InprocServer32", true);
                RK.SetValue("(Default", clsid.InprocServer32);
                RK.SetValue("(Default", clsid.ThreadingModel);
                RK.CreateSubKey("ProgID", true);
                RK.SetValue("(Default", clsid.ProgID);
                RK.CreateSubKey("TypeLib", true);
                RK.SetValue("(Default", clsid.TypeLib);
                RK.CreateSubKey("Version", true);
                RK.SetValue("(Default", clsid.Version);
                RK.Close(); 


 if ( RK != null ) 
     {
         MessageBox.Show("Success", "Success");
     }
 else 
     {
        MessageBox.Show("Failure", "Failure");

     }

In the above code, clsid is an object of class, clsRegistryCLSID, which is a part of my project:

    public clsRegistryCLSID(int ID, string hive, string rootObjectName, string ThreadingModel, string InprocServer32, string ProgID, string TypeLib, string Version, string EntryGuid)
    {

    public int ID { get; set; } 
    public string hive { get; set; }    
    public string RootObjectName { get; set; }
    public string ThreadingModel { get; set; }
    public string InprocServer32 { get; set; }  
    public string ProgID { get; set; }
    public string TypeLib { get; set; }
    public string Version { get; set; }
    public string EntryGuid { get; set; }   
  • 1
    99.99999% of times this sort of question is asked, it's because of 32-bit vs 64-bit registry. – Damien_The_Unbeliever Jan 18 '23 at 14:28
  • Thx, Damien. I'm searching the entirety of the HKCR hive. Is there a way to specify which registry to write to? My program is compiled "any CPU", if that means anything. –  Jan 18 '23 at 14:36
  • The following may be helpful: https://stackoverflow.com/a/71500768/10024425 – Tu deschizi eu inchid Jan 18 '23 at 15:08
  • user09938 Thx. I tried the code at the bottom of the article and it claimed success, but, since the GUID is for file explorer, I can't tell if any change was made or not. I then modified the code to try one of my own subkeys that I am certain don't exist and, again, it seemed to work, but the subkey is nowhere to be found. I searched both 32 and 64 bit registries. Most mysterious. –  Jan 18 '23 at 21:04
  • Not everything has both 32-bit and 64-bit entries. If you wish to modify the registry, it's important that you don't open it as read-only. Also, you may need administrator privileges to modify certain parts of the registry which one can do by adding an `Application Manifest File` to your project as described in this [post](https://stackoverflow.com/a/71344930/10024425). – Tu deschizi eu inchid Jan 18 '23 at 21:10
  • I run the program in the VS2022 IDE as administrator and don't get access violations, so I'm pretty sure it's not a permissions issue. I use RegScanner to search for the new keys. It has a dropdown to select 32 and 64 bit, as well as default. I've tried all three and the key does not appear. I subsequently opened a whole new app with a form and put just a CreateSubKey statement in it inside a try/catch block, inside the formload. No exceptions and no key, searching 32,64, and default. –  Jan 18 '23 at 21:35
  • I'm not familiar with _RegScanner_. You may consider using the Windows built-in _regedit.exe_ - if the subkey doesn't show up, try refreshing. Also, you may consider appending the updated code to your OP as an "Update". – Tu deschizi eu inchid Jan 18 '23 at 21:43
  • Your post is a bit hard to follow - it's too minimal. It's not clear about what subkeys and value names you're trying to create. You should be disposing anything that has a _Dispose_ method. The best way to do this is to use a [using statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement). Alternatively, one could use a `try-catch-finally` or a `try-finally` block. I recommend that you use [Registry.OpenBaseKey](https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.registrykey.openbasekey?view=net-7.0) as shown in the referenced posts. – Tu deschizi eu inchid Jan 19 '23 at 05:30
  • [RegistryKey.OpenSubKey](https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.registrykey.opensubkey?view=net-7.0) returns _The subkey requested, or null if the operation failed_. – Tu deschizi eu inchid Jan 19 '23 at 05:32
  • You may consider using `regedit` to manually create the desired subkeys, values, and data. Then either post images of what it looks like, and/or right-click the subkey and select _Export_ to save it to a text file and append the contents of the text file to your post. – Tu deschizi eu inchid Jan 19 '23 at 05:40
  • The most recent post reflects what the subkey should look like. I'm writing a setup program to install an ActiveX dll (plugin), readme file, and toolbar for a 3d modeling program (Rhinoceros) . –  Jan 19 '23 at 18:36
  • My needs are so simple, I can't believe it's so difficult to achieve. I want to create the subkey (accomplished) and write from 3-6 name/value pairs. If I could do one name/value pair, that should do it. I'm writing some HKLM subkeys, so I will require the user to run as admmin, so there should be no problem with those keys. The final part is that I have to write the program's registry to finish the install. If it wasn't for this last part, I would simply use Installshield or Inno. I wonder if someone can see what's wrong with the latest code I posted. –  Jan 19 '23 at 18:37

1 Answers1

0

The following shows how to add subkeys to HKEY_CLASSES_ROOT\CLSID, as well as, values and data. I searched the (Win10) registry, found subkeys with similar names, and followed the structure of existing subkeys.

The structure of the subkey that is created in the code below is:

enter image description here


Create a new Windows Forms App (.NET Framework) project (name: RegistryCreateSubkeyAndValues)

Add an Application Manifest to your project

Note: This is used to prompt the user to execute the program as Administrator.

  • In VS menu, click Project
  • Select Add New Item...
  • Select Application Manifest File (Windows Only) (name: app.manifest)
  • Click Add

In app.manifest, replace

<requestedExecutionLevel level="asInvoker" uiAccess="false" />

with

<requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />

As can be seen in the image above, the subkeys are nested. To be in harmony with this concept, I'll create a variety of nested classes to hold the necessary information.

I'll name the top-level class RegClsid which will be created last to avoid errors showing in Visual Studio. To keep the class names organized, I've chosen to prepend each class name with its parent's name.

Create a class (name: RegClsidInprocServer32.cs) - name is RegClsid + InprocServer32 => RegClsidInprocServer32

public class RegClsidInprocServer32
{
    public string Default { get; set; }
    public string ThreadingModel { get; set; }
}

Create a class (name: RegClsidProgId.cs) - name is RegClsid + ProgId => RegClsidProgId

public class RegClsidProgId
{
    public string Default { get; set; }
}

Create a class (name: RegClsIdTypeLib.cs) - name is RegClsid + TypeLib => RegClsidTypeLib

public class RegClsIdTypeLib
{
    public string Default { get; set; }
}

Create a class (name: RegClsIdVersion.cs) - name is RegClsid + Version => RegClsidVersion

public class RegClsIdVersion
{
    public string Default { get; set; }
}

Create a class (name: RegClsid.cs)

public class RegClsid
{
    public string EntryGuid { get; set; }
    public RegClsidInprocServer32 InprocServer32 { get; set; } = new RegClsidInprocServer32();
    public RegClsidProgId ProgId { get; set; } = new RegClsidProgId();
    public RegClsIdTypeLib TypeLib { get; set; } = new RegClsIdTypeLib();
    public RegClsIdVersion Version { get; set; } = new RegClsIdVersion();
}

Add the following using directives:

  • using Microsoft.Win32;

The following shows how to add/update a registry subkey in HKEY_CLASSES_ROOT\CLSID. using statements are used to ensure that each RegistryKey is properly disposed.

Here's an illustration of the code below. Notice the nesting of the using statements and how the return value is used in each of the nested using statements.

enter image description here

AddUpdateRegClsid:

private bool AddUpdateRegClsid(RegClsid clsid, RegistryView regView = RegistryView.Registry64)
{
    //open HKCR hive using the specified view
    using (RegistryKey localKey = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, regView))
    {
        if (localKey != null)
        {
            //open subkey with write permissions
            using (RegistryKey clsidKey = localKey.OpenSubKey(@"CLSID", true))
            {
                if (clsidKey != null)
                {
                    //create or open subkey with write permissions
                    using (RegistryKey guidKey = clsidKey.CreateSubKey(clsid.EntryGuid, true))
                    {
                        if (guidKey != null)
                        {
                            //create or open subkey 'InprocServer32' with write permissions
                            //HKCR\Clsid\<entryGuid>\InprocServer32
                            using (RegistryKey inprocServer32Key = guidKey.CreateSubKey("InprocServer32", true))
                            {
                                if (inprocServer32Key != null)
                                {
                                    //default
                                    inprocServer32Key.SetValue("", clsid.InprocServer32.Default, RegistryValueKind.String);
                                    
                                    //ThreadingModel
                                    inprocServer32Key.SetValue("ThreadingModel", clsid.InprocServer32.ThreadingModel, RegistryValueKind.String);
                                }
                            }

                            //create or open subkey 'ProgID' with write permissions
                            //HKCR\Clsid\<entryGuid>\ProgID
                            using (RegistryKey progidKey = guidKey.CreateSubKey("ProgID", true))
                            {
                                if (progidKey != null)
                                {
                                    //default
                                    progidKey.SetValue("", clsid.ProgId.Default, RegistryValueKind.String);
                                }
                            }

                            //create or open subkey 'TypeLib' with write permissions
                            //HKCR\Clsid\<entryGuid>\TypeLib
                            using (RegistryKey typeLibKey = guidKey.CreateSubKey("TypeLib", true))
                            {
                                if (typeLibKey != null)
                                {
                                    //default
                                    typeLibKey.SetValue("", clsid.TypeLib.Default, RegistryValueKind.String);
                                }
                            }

                            //create or open subkey 'Version' with write permissions
                            //HKCR\Clsid\<entryGuid>\Version
                            using (RegistryKey versionKey = guidKey.CreateSubKey("Version", true))
                            {
                                if (versionKey != null)
                                {
                                    //default
                                    versionKey.SetValue("", clsid.Version.Default, RegistryValueKind.String);
                                }
                            }

                            return true;
                        }
                    }
                }
            }
        }
    }

    return false;
}

Usage 1:

//ToDo: replace values below with desired values
//create new instance and set values
RegClsid clsid = new RegClsid()
{
    EntryGuid = "{3BDAAC43-E734-11D5-93AF-00105A990292}",
    InprocServer32 = new RegClsidInprocServer32() 
    { 
        Default = "My InprocServer32 default",
        ThreadingModel = "Both"
    },
    ProgId = new RegClsidProgId()
    {
        Default = "My ProgID default"
    },
    TypeLib = new RegClsIdTypeLib()
    {
        Default = "My TypeLib default"
    },
    Version = new RegClsIdVersion()
    {
        Default = "My Version default"
    }
};

//add CLSID entry to registry
bool result = AddUpdateRegClsid(clsid);

if (result)
    MessageBox.Show($@"'HKEY_Classes_Root\CLSID\{clsid.EntryGuid}' successfully added/updated.");
else
    MessageBox.Show($@"Error: Failed to add/update 'HKEY_Classes_Root\CLSID\{clsid.EntryGuid}'.");

Usage 2:

//ToDo: replace values below with desired values

//InprocServer32 - create new instance and set value(s)
RegClsidInprocServer32 inprocServer32 = new RegClsidInprocServer32()
{
    Default = "My InprocServer32 default",
    ThreadingModel = "Both"
};

//ProgID - create new instance and set values
RegClsidProgId progId = new RegClsidProgId()
{
    Default = "My ProgID default"
};

//TypeLib - create new instance and set value(s)
RegClsIdTypeLib typeLib = new RegClsIdTypeLib()
{
    Default = "My TypeLib default"
};

//Version - create new instance and set value(s)
RegClsIdVersion version = new RegClsIdVersion()
{
    Default = "My Version default"
};

//Clsid - create new instance and set values
RegClsid clsid = new RegClsid()
{
    EntryGuid = "{3BDAAC43-E734-11D5-93AF-00105A990292}",
    InprocServer32 = inprocServer32,
    ProgId = progId,
    TypeLib = typeLib,
    Version = version
};


//add CLSID entry to registry
bool result = AddUpdateRegClsid(clsid);

if (result)
    MessageBox.Show($@"'HKEY_Classes_Root\CLSID\{clsid.EntryGuid}' successfully added/updated.");
else
    MessageBox.Show($@"Error: Failed to add/update 'HKEY_Classes_Root\CLSID\{clsid.EntryGuid}'.");

Usage 3:

//ToDo: replace values below with desired values

//InprocServer32 - create new instance and set value(s)
RegClsidInprocServer32 inprocServer32 = new RegClsidInprocServer32();
inprocServer32.Default = "My InprocServer32 default";
inprocServer32.ThreadingModel = "Both";

//ProgID - create new instance and set value(s)
RegClsidProgId progId = new RegClsidProgId();
progId.Default = "My ProgID default";

//TypeLib - create new instance and set value(s)
RegClsIdTypeLib typeLib = new RegClsIdTypeLib(); 
typeLib.Default = "My TypeLib default";

//Version - create new instance and set value(s)
RegClsIdVersion version = new RegClsIdVersion();
version.Default = "My Version default";

//Clsid - create new instance and set values
RegClsid clsid = new RegClsid();
clsid.EntryGuid = "{3BDAAC43-E734-11D5-93AF-00105A990292}";
clsid.InprocServer32 = inprocServer32;
clsid.ProgId= progId;
clsid.TypeLib = typeLib;
clsid.Version = version;

//add CLSID entry to registry
bool result = AddUpdateRegClsid(clsid);

if (result)
    MessageBox.Show($@"'HKEY_Classes_Root\CLSID\{clsid.EntryGuid}' successfully added/updated.");
else
    MessageBox.Show($@"Error: Failed to add/update 'HKEY_Classes_Root\CLSID\{clsid.EntryGuid}'.");

Here's the result of executing the code above:

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here


The following shows how to delete the registry subkey and child subkeys from HKEY_CLASSES_ROOT\CLSID.

DeleteRegClsid:

private bool DeleteRegClsid(string entryClsid, RegistryView regView = RegistryView.Registry64)
{
    //open HKCR hive using the specified view
    using (RegistryKey localKey = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, regView))
    {
        if (localKey != null)
        {
            //open subkey with write permissions
            using (RegistryKey clsidKey = localKey.OpenSubKey(@"CLSID", true))
            {
                if (clsidKey != null)
                {
                    //delete subkey and all child subkeys
                    clsidKey.DeleteSubKeyTree(entryClsid);

                    return true;
                }
            }
        }
    }

    return false;
}

Usage:

string entryGuid = "{3BDAAC43-E734-11D5-93AF-00105A990292}";
bool result = DeleteRegClsid(entryGuid);

if (result)
    MessageBox.Show($@"'HKEY_Classes_Root\CLSID\{entryGuid}' successfully deleted.");
else
    MessageBox.Show($@"Error: Failed to delete 'HKEY_Classes_Root\CLSID\{entryGuid}'.");

Resources:

Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24
  • 1
    Your solution is magnificent and is just what I was looking for. What you've provided was not available in any reference I perused. Thx. –  Jan 20 '23 at 23:53