summaryrefslogtreecommitdiffstats
path: root/toolkit/components/utils/WindowsVersionInfo.sys.mjs
blob: 70fa3ef9c609a7e8c6ff667ac7a69bdcd0b6ec55 (plain)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
import { ctypes } from "resource://gre/modules/ctypes.sys.mjs";

const BYTE = ctypes.uint8_t;
const WORD = ctypes.uint16_t;
const DWORD = ctypes.uint32_t;
const WCHAR = ctypes.char16_t;
const BOOL = ctypes.int;

export var WindowsVersionInfo = {
  UNKNOWN_VERSION_INFO: {
    servicePackMajor: null,
    servicePackMinor: null,
    buildNumber: null,
  },

  /**
   * Gets the service pack and build number on Windows platforms.
   *
   * @param opts {Object} keyword arguments
   * @param opts.throwOnError {boolean} Optional, defaults to true. If set to
   *    false will return an object with keys set to null instead of throwing an
   *    error. If set to true, errors will be thrown instead.
   * @throws If `throwOnError` is true and version information cannot be
   *    determined.
   * @return {object} An object containing keys `servicePackMajor`,
   *    `servicePackMinor`, and `buildNumber`. If `throwOnError` is false, these
   *    values may be null.
   */
  get({ throwOnError = true } = {}) {
    function throwOrUnknown(err) {
      if (throwOnError) {
        throw err;
      }
      console.error(err);
      return WindowsVersionInfo.UNKNOWN_VERSION_INFO;
    }

    if (AppConstants.platform !== "win") {
      return throwOrUnknown(
        WindowsVersionInfo.NotWindowsError(
          `Cannot get Windows version info on platform ${AppConstants.platform}`
        )
      );
    }

    // This structure is described at:
    // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx
    const SZCSDVERSIONLENGTH = 128;
    const OSVERSIONINFOEXW = new ctypes.StructType("OSVERSIONINFOEXW", [
      { dwOSVersionInfoSize: DWORD },
      { dwMajorVersion: DWORD },
      { dwMinorVersion: DWORD },
      { dwBuildNumber: DWORD },
      { dwPlatformId: DWORD },
      { szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH) },
      { wServicePackMajor: WORD },
      { wServicePackMinor: WORD },
      { wSuiteMask: WORD },
      { wProductType: BYTE },
      { wReserved: BYTE },
    ]);

    let kernel32;
    try {
      kernel32 = ctypes.open("kernel32");
    } catch (err) {
      return throwOrUnknown(
        new WindowsVersionInfo.CannotOpenKernelError(
          `Unable to open kernel32! ${err}`
        )
      );
    }

    try {
      let GetVersionEx = kernel32.declare(
        "GetVersionExW",
        ctypes.winapi_abi,
        BOOL,
        OSVERSIONINFOEXW.ptr
      );
      let winVer = OSVERSIONINFOEXW();
      winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size;

      if (GetVersionEx(winVer.address()) === 0) {
        throw new WindowsVersionInfo.GetVersionExError(
          "Failure in GetVersionEx (returned 0)"
        );
      }

      return {
        servicePackMajor: winVer.wServicePackMajor,
        servicePackMinor: winVer.wServicePackMinor,
        buildNumber: winVer.dwBuildNumber,
      };
    } catch (err) {
      return throwOrUnknown(err);
    } finally {
      if (kernel32) {
        kernel32.close();
      }
    }
  },

  CannotOpenKernelError: class extends Error {},
  GetVersionExError: class extends Error {},
  NotWindowsError: class extends Error {},
};