1

I am using this code to make a list of all the installed programs:

object line;
string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (Microsoft.Win32.RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key))
{
    foreach (string subkey_name in key.GetSubKeyNames())
    {
        using (RegistryKey subkey = key.OpenSubKey(subkey_name))
        {
            line = subkey.GetValue("DisplayName");
            if (line != null)
            {
                listBox1.Items.Add(line);
            }
        }
    }
}

On a 64-bit windows, this redirects to Wow6432Node \Microsoft\Windows\CurrentVersion\Uninstall. But some program entries are still located in the original path and the list is incomplete. How can I avoid redirection and read the values from both paths on a 64-bit Windows installation (and only the first one on a 32-bit windows)?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kidades
  • 600
  • 2
  • 9
  • 26
  • Simply allow your program to run as a 64-bit process. Removing the jitter forcing in Project + Properties, Build tab. – Hans Passant Aug 14 '14 at 13:00

3 Answers3

3

Change your code to the following:

        object line;
        string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
        using (var baseKey = Microsoft.Win32.RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
        {
            using (var key = baseKey.OpenSubKey(registry_key))
            {
                foreach (string subkey_name in key.GetSubKeyNames())
                {
                    using (var subKey = key.OpenSubKey(subkey_name))
                    {
                        line = subKey.GetValue("DisplayName");
                        if (line != null)
                        {
                            listBox1.Items.Add(line);
                        }
                    }
                }
            }
        }

And you can either specify

RegistryView.Registry64

or

RegistryView.Registry32

explicitly, rather than letting it default to whatever it likes.

GoldieLocks
  • 845
  • 7
  • 22
2

I see two options here:

1) Upgrade to .NET 4 or later and follow Avoid Registry Wow6432Node Redirection.

2) Stay on .NET 2 and call the Win32 API directly as described in Disabling registry redirection for a registry key on an x64 platform.

Community
  • 1
  • 1
alik
  • 2,244
  • 3
  • 31
  • 44
0

Managed to get this working after a LOT of trial and error - this is the only place I can see to get the "size" component of the add remove programs.

Runs pretty quickly comparsed to the WMI Win32_Programs counterpart

Might need to be clean up a few if these includes ;-)

#include "shobjidl_core.h"
#include <shlobj.h>
#include <atlbase.h>
#include <atlalloc.h>
#include <propsys.h>
#include <stdio.h>
#include <objbase.h>
#include <ole2.h>
#include <shlwapi.h>
#include <propkey.h>
#include "shlguid.h" 

void IterateAddRemovePrograms()
{
    CComPtr<IShellItem> spPrograms;

    SHCreateItemFromParsingName(
        L"::{26EE0668-A00A-44D7-9371-BEB064C98683}\\8\\"
        L"::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}", nullptr,
        IID_PPV_ARGS(&spPrograms));

    CComPtr<IEnumShellItems> spEnum;
    spPrograms->BindToHandler(nullptr, BHID_EnumItems, IID_PPV_ARGS(&spEnum));

    for (CComPtr<IShellItem> spProgram; spEnum->Next(1, &spProgram, nullptr) == S_OK; spProgram.Release())
    {
        DiskUsageItem d;
        LPWSTR name;
        spProgram->GetDisplayName(SIGDN_NORMALDISPLAY, &name);
        LPWSTR size;
        CComQIPtr<IShellItem2>(spProgram)->GetString(PKEY_Size, &size);
        cout << name << " " << size << endl;
    }
}
Malcolm Swaine
  • 1,929
  • 24
  • 14