web-dev-qa-db-ja.com

Windowsのシリアル番号の取得(以前は:レジストリからのMachineGuidの取得)

レジストリからMachineGuidをフェッチして、ライセンスシステムのOSとのある程度のバインディングを作成しようとしています。私が使用できるドキュメントから

string key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography";
string r = (string)Registry.GetValue(key, "MachineGuid", (object)"default");

それを取得します。また、ドキュメントには、名前が見つからない場合は"default"が表示され、キーが存在しない場合はnullが表示されると記載されています。アクセスできない場合は、セキュリティ例外が発生するはずです。

上記のコードは私に"default"を与えます。これは、名前が見つからないことを意味します。ただし、RegEditを使用してレジストリを調べると、そこにあります。管理者権限のないアプリケーションからMachineGuid値を取得するにはどうすればよいですか?

更新reg.exeを使用する場合値の取得に問題はありません。

更新:タイトルを更新したので、Windowsのインストールを決定する独自の方法を探している人もここにアクセスします。

11

他の人がすでに指摘しているように、レジストリから直接その値を取得することは想定されていません(これが、異なるバージョンのWindows間で確実に機能しない理由です)。

少し検索すると、 Win32_OperatingSystemWMIクラス になりました。このクラスを使用すると、実際にWindowsのシリアル番号を取得できます。それを正しくするために検索と実験が必要でしたが、これがC#での使用方法です。

プロジェクトにSystem.Management.dll参照があることを確認してください。

using System.Management;

...

ManagementObject os = new ManagementObject("Win32_OperatingSystem=@");
string serial = (string)os["SerialNumber"];

[]演算子を使用すると、クラス内の任意のプロパティを取得できます。

17

これがおそらく、異なるバージョンのWindows間で確実に機能しない理由です。

いいえ、それは理由ではありません。この問題は、EXEプロジェクトのプラットフォームターゲットの選択が原因で発生します。プロジェクト+プロパティ、ビルドタブ、プラットフォームターゲットコンボボックス。 AnyCPUではなくx86に設定しています。 VS2012では、[32ビットを優先する]チェックボックスが重要です。この設定により、プログラムは64ビットバージョンのWindowsで32ビットモードで実行されます。これには多くの副作用がありますが、ここで重要なのは、レジストリキーへのアクセスがリダイレクトされることです。プログラムは実際にHKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\MachineGuidの値を読み取っています。どちらも存在しません。

X86の選択は、VS2010以降のデフォルトであり、以前はAnyCPUがデフォルトでした。 Microsoftはx86を好み、VisualStudioは32ビットモードのプロセスでより適切に機能します。特にデバッグの場合、VSはそれ自体が32ビットプロセスであるため、プログラムを64ビットモードで実行する場合はリモートデバッガーが必要です。これには、サポートされていない混合モードのデバッグなど、いくつかの制限があります。また、編集+続行機能は32ビットコードでのみ機能します。ただし、AnyCPUに設定がある場合、プログラム自体は「より適切に」機能します。これには、ファイルシステムに噛まれないことや、Windowsに組み込まれているレジストリリダイレクトappcompat機能が含まれます。

本当にx86モードで立ち往生している場合、通常は更新できない32ビットのネイティブコードに依存しているため、次の回避策は.NET 4+ RegistryKey.OpenBaseKey()メソッドを使用することです。これにより、RegistryView.Registry64を渡すことができ、リダイレクトされていないキーを確実に読み取ることができます。

もちろん、WMIを使用することは回避策です。 Win32_OperatingSystem.SerialNumberを使用するときは、同じ情報を読んでいることを覚えておいてくださいnot。そのキーがさまざまなマシンで確実にランダムであるかどうかは私にはわかりませんが、この値は、製品のライセンス料の支払いにあまり関心がない種類のユーザーにとってはかなり魅力的なターゲットであるとだけ言っておきます。

最後になりましたが、Windowsにまったく依存しない独自の一意のIDを生成するのは非常に簡単であると考えてください。顧客が自分のマシンでWindowsを更新するときに、顧客を怒らせないというかなりの利点があります。 Guid.NewGuid()を1回使用して、値をファイルに保存するだけです。ドライブが悪くなるとそれは失われますが、それは通常あなたの製品も奪います。

20
Hans Passant

私の謙虚な意見では、どの答えも質問を満たしていません。レジストリからMachineGuidを読み取る方法を尋ねるのは非常に簡単です...だからここに私の答えがあります:「Microsoft.Win32」への参照を追加する必要があります。このコードはデモンストレーション目的で作成されたものであり、それに応じて調整する必要があります。 編集:誰かがx64コードは役に立たないと間違って述べました。 64ビットOSでは、正しいキーが見つかります。したがって、この答えは、質問を満たす唯一の答えです。

private void buttonGetMachineGuid_Click(object sender, RoutedEventArgs e)
{
  try
  {
    string x64Result = string.Empty;
    string x86Result = string.Empty;
    RegistryKey keyBaseX64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
    RegistryKey keyBaseX86 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
    RegistryKey keyX64 = keyBaseX64.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography", RegistryKeyPermissionCheck.ReadSubTree);
    RegistryKey keyX86 = keyBaseX86.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography", RegistryKeyPermissionCheck.ReadSubTree);
    object resultObjX64 = keyX64.GetValue("MachineGuid", (object)"default");
    object resultObjX86 = keyX86.GetValue("MachineGuid", (object)"default");
    keyX64.Close();
    keyX86.Close();
    keyBaseX64.Close();
    keyBaseX86.Close();
    keyX64.Dispose();
    keyX86.Dispose();
    keyBaseX64.Dispose();
    keyBaseX86.Dispose();
    keyX64 = null;
    keyX86 = null;
    keyBaseX64 = null;
    keyBaseX86 = null;
    if(resultObjX64 != null && resultObjX64.ToString() != "default")
    {
      MessageBox.Show(resultObjX64.ToString());
    }
    if(resultObjX86 != null && resultObjX86.ToString() != "default")
    {
      MessageBox.Show(resultObjX86.ToString());
    }
  }
  catch(Exception)
  {
  }
}

これが誰かを助けることを願っています。

9
Jonathan Alfaro