티스토리 뷰

목차

    반응형

    다뤄볼 부분은 Registry.GetValue입니다. 결과가 항상 null이거나 null이면 반환되는 값에 대한 문제인데요.

    스택오버플로에 제가 겪었던 유사한 질문과 해답이 있어 인용합니다. 값 가져오기 하면 null만 떨어지던 문제입니다.


    C# Registry.GetValue - 계속 null만 반환

    아래 HKEY_LOCAL_MACHINE\SOFTWARE\RSA 레지스트리에 WebExControlManagerPath 키가 있으며, 값은 C:\입니다.

    저는 아래 소스 코드로 C:\를 얻으려 했습니다.


    1
    2
    3
    4
    var r = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\RSA""WebExControlManagerPth",null);
     
    if(r!=null)
        ProcessAsUser.Launch(ToString());
    cs


    하지만 C# 변수 r 값은 항상 null입니다.

    값 가져오기 결과는 항상 null인 것이죠.


    솔루션

    원인은 32비트와 64비트의 차이 때문에 발생합니다.

    64비트 윈도우 OS 운영 체제를 사용할 경우 HKEY_LOCAL_MACHINE\SOFTWARE\RSA 이 경로는 아래처럼 리디렉션됩니다.


    HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\RSA


    그래서 64비트 OS에서 코딩할 땐, RSA앞에 Wow6432Node를 추가해야 합니다. 그렇지 않으면 무조건 null 값만 받게 됩니다.

    그럼 32bit, 64bit 모두 호환되도록 소스 코드를 어떻게 변경할까요?


    간략히 3가지 방법이 있는데, 모두 사용 가능하니 상황에 맞춰 적절히 사용해 보세요.

    해결 1 : AnyCPU 설정 예제

    1
    2
    3
    4
    5
    6
    7
    RegistryKey myKey = Registry.LocalMachine.OpenSubKey( @"Software\RSA"false);
    String value = (String)myKey.GetValue("WebExControlManagerPth");
     
    if (!String.IsNullOrEmpty(value))
    {
        ProcessAsUser.Launch(ToString());
    }
    cs


    빌드 방식을 AnyCPU로 변경하면 닷넷프레임워크가 Software\RSA 경로를 리디렉션하여 값을 반환합니다.


    해결 2 : .NET 4.0 이상 지원

    1
    2
    3
    4
    5
    6
    7
    RegistryKey localKey;
    if(Environment.Is64BitOperatingSystem)
        localKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
    else
        localKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
     
    string value = localKey.OpenSubKey("RSA").GetValue("WebExControlManagerPth").ToString();
    cs


    64비트 OS라는 것을 C# RegistryKey에 명시적으로 기입합니다.

    이렇게 하면 레지스트리 경로가 의도한 대로 설정됩니다.

    해결 3 : 간단한 예제 함수

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    /// <summary>
    /// Gets the specified setting name.
    /// </summary>
    /// <param name="settingName">Name of the setting.</param>
    /// <returns>Returns Setting if the read was successful otherwise, "undefined".</returns>
    public static string get(string settingName)
    {
        RegistryKey key;
     
        if (Environment.Is64BitOperatingSystem)
            key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Wow6432Node\MyCompany\MyProductName"false);
        else
            key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\MyCompany\MyProductName"false);
     
        try
        {
            String value = (String)key.GetValue(settingName);
     
            return value;
        }
        catch
        {
            // Null is not returned as in this case, it is a valid value.
     
            return "undefined";
        }
        finally
        {
            key.Close();
        }
    }
    cs


    두 번째 예제와 거의 똑같은 소스입니다.


    C# Registry LocalMachine.OpenSubKey 까지 명시적으로 코딩하고, 경로 또한 명시적으로 입력합니다. 이러면 가독성이 조금 높아질 순 있겠네요.



    위 예제 3가지 방법의 하나를 선택해 응용하면 되겠습니다.


    한 5년 전만 해도 64비트 쓸 일이 거의 없다면서, 32bit 고집하는 업체나 개발자 많았던 것으로 기억합니다. 근데 요즘은 고객사에서 64bit로 해달라 요구하는 곳이 많아졌네요.


    저도 이런 이슈가 꾸준히 생기는 상황인데, 나름 ... 해결하는 과정은 재밌군요. ㅎ


    관련 글

    Microsoft Visual C++ 재배포 가능 패키지 설치 확인

    Visual Studio 텍스트 전체 찾기 버그 해결, 레지스트리 편집 방법

    C# Dictionary Value 값 가져오기 (TryGetValue, out 예제)

    C# Dictionary 9가지 사용법, 딕셔너리 예제

    반응형