How to Read and Write 32 bit WoW REG_MULTI_SZ Registry Key on Windows 7 64-Bit OS using C#?

I'm a novice C# programmer trying to rework some old VS2008 Source Code (original dev is long gone) that works great on Windows XP, but is now broken since I've upgraded to Win7 64-bit. I'm using VS2012 Express to attempt to migrate the "PathFix.exe" utility. I've upgraded the original Source Code to VS2012 Express, but am having difficulty making sense of what syntax needs to be tweaked for full 64-bit OS compatibility.

I've already tried to run the "PathFix.exe" utility in XP-SP3 Compatibility Mode at the .exe level - doesn't work.

I've found some helpful resources here on EE for successfully reading/writing DWORD registry subkeys in the WOW6432Node without any trouble.

However, I'm still stumped after more hours than I care to admit on how to handle the REG_MULTI_SZ registry subkey I need to prepend a new path string to.

Original XP Code Snippet:
  const string pathGraphics = @"\SOFTWARE\CTool\Applications\graphic\";

        RegistryKey regGraphics = Registry.LocalMachine.CreateSubKey(pathGraphics);
        string[] currentPaths = (string[])regGraphics.GetValue("BackgroundPaths");
        if (currentPaths.Length == 2)
            string[] paths = new string[3];
            paths[0] = bgPath;
            paths[1] = currentPaths[0];
            paths[2] = currentPaths[1];
            regGraphics.SetValue("BackgroundPaths", paths);
            regGraphics.SetValue("LinkPicturePath", bgPath);
            regGraphics.SetValue("ImportPath", bgPath);

Open in new window

New Code:
  string pathArray = string.Empty;

        RegistryKey pathsGraphic = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry32);
        pathsGraphic = pathsGraphic.OpenSubKey(@"\SOFTWARE\CTool\Applications\graphic\");
            if (pathsGraphic != null)
            pathArray = pathsGraphic.GetValue("BackgroundPaths").ToString();

Open in new window

The BackgroundPaths key has two existing strings in it that I need to read and then prepend with a new path for a total of 3 path statements. Problem is I can' t get my head around how to get an array working with .ToString(); in order to get the bgPath string inserted. An Expert's help would definitely be appreciated.

Brian EsserZone Technology ExpertAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Jacques Bourgeois (James Burger)PresidentCommented:
The best way to go for many applications that used to work great on 32-bit and have problems on 64-bit is simply to set the target CPU to x86. They then compile in 32-bit, and Windows 64-bit automatically handle them in WOW so that they work as they used to do.
Brian EsserZone Technology ExpertAuthor Commented:
Thanks for your suggestion James:

Not sure what I'm doing wrong, but it isn't liking me changing to Debug (Config) & x86 (Platform).

Error      10      The OutputPath property is not set for project 'pathFix.csproj'.  Please check to make sure that you have specified a valid combination of Configuration and Platform for this project.  Configuration='Debug'  Platform='x86'.  This error may also appear if some other project is trying to follow a project-to-project reference to this project, this project has been unloaded or is not included in the solution, and the referencing project does not build using the same or an equivalent Configuration or Platform.      pathFix
Jacques Bourgeois (James Burger)PresidentCommented:
Do you also have the problem in Release, or only in Debug?

Try with AnyCPU instead of x86, and see if it solves the last error as well as the original one.

If not, when you upgraded, did you upgrade a .csproj file (project) or a .sln file (solution). A solution is a group of projects working together, such as an application and a dll. If the original code was designed around a solution, and you upgraded only the .csproj, then you have a missing project code in your environment.

The following sentence in your error message let me think that this can be your problem: This error may also appear if some other project is trying to follow a project-to-project reference to this project, this project has been unloaded or is not included in the solution.

If you are already working in a solution, then a few programmers found out that they received this error message in the following situation: the output path (Build tab of the project's Properties window) for the 2 projects did not match for a given configuration. If one of the projects is set to compile in bin\Debug but the other one in bin only, then they get that message about the OutputPath.

I hope this helps.
Exploring SQL Server 2016: Fundamentals

Learn the fundamentals of Microsoft SQL Server, a relational database management system that stores and retrieves data when requested by other software applications.

Brian EsserZone Technology ExpertAuthor Commented:
The Error follows both Builds with Release and Debug Configs with x86 Platform.

AnyCPU Builds without any Errors, but the debug/final build .exe fails to write/fix the new path.

I upgraded the VS2K8 .sln File by double clicking on it which initiated VS2K12 launch/upgrade process.

The main problem with the legacy code as upgraded into VS2K12 is the following line of code:
string[] currentPaths = (string[])regGraphics.GetValue("BackgroundPaths");

Open in new window

"currentPaths" is NULL because the subkey "BackgroundPaths" is not returning a result with this syntax. regGraphics.GetVaule appears to be returning the right Registry path (via const string define), but the REG_MULTI_SZ subkey value for "BackgroundPaths" is not being passed to "currentPaths" properly i.e. Null.

While experimenting with other syntax from this site and others I've discovered a successful means to access the "BackgroundPaths" value, but I don't understand yet how to get the multiple values into "currentPaths" Array to write back and prepend the primary path I need in this REG_MULTI_SZ subkey.

Thank you for your support
Jacques Bourgeois (James Burger)PresidentCommented:
Because of the way your question was formulated, I concentrated on the 32-bit to 64-bit change.

But looking back at your code with another eye, I see that your are trying to work in LocalMachine. Security is tighter in Windows 7 than it was on XP, and if I am not mislead, you need to be administrator to work with that part of the registry.

Have you tried running the application as an administrator? When running from Visual Studio, you have to start Visual Studio itself as administrator so that the account is passed to the application when you start it with F5 or through the Debug menu.

If BackgroundPaths is a custom registry entry, you might want to move it to the CurrentUser instead of LocalMachine.
Brian EsserZone Technology ExpertAuthor Commented:
Formulating a good question is my biggest challenge, so I apologize for any ambiguity on my part.

Due to the new (perplexing) paradigm of separate 32/64 Bit Registry views using registry redirector and registry reflection I thought that was where I needed to start my ASCII head scratching here on EE. Evidently, this new paradigm can be transparent to legacy 32 Bit applications without much difficulty as long as permissions/UAC isn't in play. However, in my particular case, all users are in the Administrators group on the Win7 computers so I presume this isn't why we can't read the "BackgroundPaths" REG_MULTI_SZ subkey value as needed.

I did try launching VS2k12 as Administrator as well, but there is no difference in the result of my debug session using F11 to step though the code execution.

BackgroundPaths is a custom registry entry resulting from the installation of the application I'm using fixPath.exe to manage, but I don't have control over where it is located.

Thanks for all the great suggestions
Jacques Bourgeois (James Burger)PresidentCommented:
Dumb question, but it has to be asked. Have you checked the registry with Regedit to make sure that the key exist and that it contains the values you are looking for?
Brian EsserZone Technology ExpertAuthor Commented:
Haha, that's not a dumb question, but one has to wonder sooner than later if it is "plugged in" and "turned on". Yes, we are good with the BackgroundPaths check in both regedit and regedt32 views.
Jacques Bourgeois (James Burger)PresidentCommented:
I overlooked one thing in there. Could be the culprit.

The way I understand it (these things seem to never be clearly explained anywhere), compile with AnyCPU and by default the application will start in 32-bits on a 32-bit system, 64-bit on a 64-bit system.

Compile with x86, and the application with start in 32-bits and register with WOW, but everything underneath has to be 32-bits or AnyCPU.

When  you tried switching to x86, did you do it for all the projects in your solution?

Boy! Why don't they have useful error messages that tell us straight away why something does not work?
Brian EsserZone Technology ExpertAuthor Commented:
The syntax below, when used with another REG_SZ type subkey (@"SOFTWARE\Microsoft\Windows NT\CurrentVersion") in LocalMachine, returns the "RegisteredOrganization" subkey value string ("HP") without issue.

The difficulty appears to be related to the "BackgroundPaths" subkey being a REG_MULTI_SZ type.
            string[] pathArray = new string[2];
            RegistryKey pathsGraphic = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry32);
            pathsGraphic = pathsGraphic.OpenSubKey(@"\SOFTWARE\CTool\Applications\graphic\");
            if (pathsGraphic != null)
                pathArray[2] = pathsGraphic.GetValue("BackgroundPaths").ToString();

Open in new window

What this code snippet returns for BackgroundPaths via pathArray[2] in the VS Locals Pane during debug is {string[2]} instead of the two paths as expected.
Brian EsserZone Technology ExpertAuthor Commented:
I just have the one Project in this Solution. However, I'm not exactly confident/clear on how to manipulate Configuration Manager to create the x86 Platform option.Copy Settings from Any CPU for x86 in Configuration Manager? Do I Copy Settings from Any CPU or just leave it blank?

As mentioned in my previous post, why can I read other LocalMachine subkeys with the new updated syntax as currently compiled for AnyCPU Platform?
Jacques Bourgeois (James Burger)PresidentCommented:
Personnally, and even more when there is only one project in the solution, I do not set the Platform through the Configuration Manager, I do it through the Build tab of the project's Properties window. Since all the other build settings are there, I do not see the need to do it through the Configuration Manager, unless I work with a solution that has many projects in it. In such a case, the Configuration Manager can be useful because then you have a better picture of the whole solution.

As for the copying of settings from one platform to another, I do not understand it and, I confess, it scares the hell out of me. So I leave that alone. This is not available by the way if you work from the project's Properties window.

Back to your problem with the registry, do you really need to use the registry. I find that the registry is overused and overcharged. There are a few instances where this is the best thing to use, but most of the time, the configuration file of the application is a better place to store data.

Since it is prepared by the environment as you develop your application, you do not end up with the problems that you encounter. It never causes security problems. It is a lot easier to use. And it uses .NET types instead of the C types used in the registry, so you never have to deal with conversion problems.

Unless you absolutely have to use the registry for one reason or another, I would suggest that you give a look to the possibility of using configuration files instead of the registry for your string array storage.
Brian EsserZone Technology ExpertAuthor Commented:
I've found the Build tab per your recommendation and I've updated the settings for 32bit and x86 per the attached screen capture. I ran a Debug Build and ran the .exe out of the Debug BIN with the same failed result.

As for using the Registry, I'm stuck with it since the Legacy Application that PathFix.exe fixes will not be updated to accommodate a Config File in lieu of the Registry. Although, I do concur with your reasoned recommendation completely.

Now if I could just code up the appropriate string array storage syntax I'd be moving past this hurdle and getting some sleep.

Thanks again
Brian EsserZone Technology ExpertAuthor Commented:
Still trying to... Read and Write 32 bit WoW REG_MULTI_SZ Registry Key on Windows 7 64-Bit OS using C#...
Robberbaron (robr)Commented:
you seem to be reading the REG_MULTI_SZ differently than i have seen before

//pathArray[2] = pathsGraphic.GetValue("BackgroundPaths").ToString();
// have to cast the GteValue object to a string array

string[] pathArray = (string[]) pathsGraphic.GetValue("BackgroundPaths");

foreach (string multival in pathArray )
   debug.Print( multival );
//or debug.Print(patharray[2]);  //if you just want the third one. as zero based
Brian EsserZone Technology ExpertAuthor Commented:
Thanks robr, this is just the nudge I needed to get me 50% of what I needed.
I've successfully read the two existing paths from "BackgroundPaths" into string "pathArray" and then parsed them out into a new "paths[3]" array to prepend "bgPath".

Now I'm stuck again trying to SetValue in the WOW Registry target "BackgroundPaths" for all three paths with an Unauthorized Access Exception referenced in attached png file.Unauthorized Access Exception occuredPlease Note that I did run my VS2012 Express Dev Environment by r-click Run As Administrator and still received the same Unauthorized Access Exception.
Brian EsserZone Technology ExpertAuthor Commented:
Worked past the Unauthorized Access Exception by adding "true" to the "pathsGraphic" .OpenBaseKey statement to make the subkey writable. Problem now is the way I'm handling it results in a REG_SZ write and not the necessary REG_MULTI_SZ kind. Tried to use RegistryValueKind.MultiString on the Write, but that has thrown a RegistryValueKind Exception.RegistryValueKind ExceptionI've found a C++ code walk through on MSDN Link for Registry Value Types which isn't making sense to me. Specifically, C# syntax to terminate strings with null characters and how many null characters per string (2ea?). The quest continues for the proper way to ...Write 32 bit WoW REG_MULTI_SZ Registry Key on Windows 7 64-Bit OS using C#?
Robberbaron (robr)Commented:
with reference to
You cannot store a single string value as a RegistryValueKind.MultiString.

the 'value' is an object so you use the array as the value. so the MSDN example is...
    rk.SetValue("MultipleStringValue", new string[] {"One", "Two", "Three"}, RegistryValueKind.MultiString);


Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Brian EsserZone Technology ExpertAuthor Commented:
Sure do appreciate EE and their Experts 100% SOLVED
Learned a ton in the process.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.