Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

476 lines
16 KiB

  1. #include <shlwapi.h>
  2. #if (_WIN32_WINNT >= 0x0500)
  3. #include <lm.h> // for NetGetJoinInformation
  4. #endif
  5. // stolen from winuser
  6. #ifndef SM_REMOTESESSION
  7. #define SM_REMOTESESSION 0x1000
  8. #endif
  9. BOOL IsWinlogonRegValueSet(HKEY hKey, LPSTR pszKeyName, LPSTR pszPolicyKeyName, LPSTR pszValueName)
  10. {
  11. BOOL bRet = FALSE;
  12. DWORD dwType;
  13. DWORD dwSize;
  14. HKEY hkey;
  15. // first check the per-machine location.
  16. if (RegOpenKeyExA(hKey, pszKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
  17. {
  18. dwSize = sizeof(bRet);
  19. if (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)&bRet, &dwSize) == ERROR_SUCCESS)
  20. {
  21. if (dwType != REG_DWORD)
  22. {
  23. bRet = FALSE;
  24. }
  25. }
  26. RegCloseKey(hkey);
  27. }
  28. // then let the policy value override
  29. if (RegOpenKeyExA(hKey, pszPolicyKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
  30. {
  31. dwSize = sizeof(bRet);
  32. if (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)&bRet, &dwSize) == ERROR_SUCCESS)
  33. {
  34. if (dwType != REG_DWORD)
  35. {
  36. bRet = FALSE;
  37. }
  38. }
  39. RegCloseKey(hkey);
  40. }
  41. return bRet;
  42. }
  43. BOOL IsWinlogonRegValuePresent(HKEY hKey, LPSTR pszKeyName, LPSTR pszValueName)
  44. {
  45. BOOL bRet = FALSE;
  46. DWORD dwType;
  47. DWORD dwSize;
  48. HKEY hkey;
  49. // first check the per-machine location.
  50. if (RegOpenKeyExA(hKey, pszKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
  51. {
  52. char szValueData[MAX_PATH];
  53. dwSize = sizeof(szValueData);
  54. bRet = (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)szValueData, &dwSize) == ERROR_SUCCESS);
  55. RegCloseKey(hkey);
  56. }
  57. return bRet;
  58. }
  59. /*
  60. BOOL IsTermsrvRunning()
  61. {
  62. BOOL fResult = TRUE; // assume the service is running
  63. SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  64. if (hSCManager)
  65. {
  66. SC_HANDLE hSCService = OpenService(hSCManager, TEXT("TermService"), SERVICE_QUERY_CONFIG);
  67. if (hSCService)
  68. {
  69. SERVICE_STATUS ServiceStatus;
  70. if (QueryServiceStatus(hSCService, &ServiceStatus))
  71. {
  72. if ((ServiceStatus.dwCurrentState == SERVICE_START_PENDING) ||
  73. (ServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
  74. (ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING))
  75. {
  76. fResult = FALSE;
  77. }
  78. }
  79. }
  80. CloseServiceHandle(hSCManager);
  81. }
  82. return fResult;
  83. }
  84. */
  85. #if (_WIN32_WINNT >= 0x0500)
  86. // Have to use a LoadLibrary/GetProcAddress thunk since we are part of stock4.lib/stock.lib,
  87. // and we can't require users of stocklib to delayload netapi32.dll
  88. typedef NET_API_STATUS (* NETGETJOININFORMATION) (LPCWSTR, LPWSTR*, PNETSETUP_JOIN_STATUS);
  89. NET_API_STATUS NT5_NetGetJoinInformation(LPCWSTR pszServer, LPWSTR* ppszNameBuffer, PNETSETUP_JOIN_STATUS BufferType)
  90. {
  91. static NETGETJOININFORMATION s_pfn = (NETGETJOININFORMATION)-1;
  92. if (s_pfn == (NETGETJOININFORMATION)-1)
  93. {
  94. if (IsOS(OS_WIN2000ORGREATER))
  95. {
  96. s_pfn = (NETGETJOININFORMATION)GetProcAddress(LoadLibrary(TEXT("netapi32")), "NetGetJoinInformation");
  97. }
  98. else
  99. {
  100. s_pfn = NULL;
  101. }
  102. }
  103. if (s_pfn)
  104. {
  105. return s_pfn(pszServer, ppszNameBuffer, BufferType);
  106. }
  107. else
  108. {
  109. return ERROR_PROC_NOT_FOUND;
  110. }
  111. }
  112. typedef NET_API_STATUS (* NETAPIBUFFERFREE) (void*);
  113. NET_API_STATUS NT5_NetApiBufferFree(LPVOID pv)
  114. {
  115. static NETAPIBUFFERFREE s_pfn = (NETAPIBUFFERFREE)-1;
  116. if (s_pfn == (NETAPIBUFFERFREE)-1)
  117. {
  118. if (IsOS(OS_WIN2000ORGREATER))
  119. {
  120. s_pfn = (NETAPIBUFFERFREE)GetProcAddress(GetModuleHandle(TEXT("netapi32")), "NetApiBufferFree");
  121. }
  122. else
  123. {
  124. s_pfn = NULL;
  125. }
  126. }
  127. if (s_pfn)
  128. {
  129. return s_pfn(pv);
  130. }
  131. else
  132. {
  133. return ERROR_PROC_NOT_FOUND;
  134. }
  135. }
  136. #endif // (_WIN32_WINNT >= 0x0500)
  137. // checks to see if this machine is a member of a domain or not
  138. // NOTE: this will always return FALSE on downlevel platforms (older than win2k)
  139. BOOL IsMachineDomainMember()
  140. {
  141. // don't call NetGetJoinInformation if we are part of stock4.lib
  142. #if (_WIN32_WINNT >= 0x0500)
  143. static BOOL s_bIsDomainMember = FALSE;
  144. static BOOL s_bDomainCached = FALSE;
  145. if (IsOS(OS_WIN2000ORGREATER) && !s_bDomainCached)
  146. {
  147. LPWSTR pwszDomain;
  148. NETSETUP_JOIN_STATUS njs;
  149. NET_API_STATUS nas;
  150. nas = NT5_NetGetJoinInformation(NULL, &pwszDomain, &njs);
  151. if (nas == NERR_Success)
  152. {
  153. if (pwszDomain)
  154. {
  155. NT5_NetApiBufferFree(pwszDomain);
  156. }
  157. if (njs == NetSetupDomainName)
  158. {
  159. // we are joined to a domain!
  160. s_bIsDomainMember = TRUE;
  161. }
  162. }
  163. s_bDomainCached = TRUE;
  164. }
  165. return s_bIsDomainMember;
  166. #else
  167. return FALSE;
  168. #endif
  169. }
  170. typedef LONG (WINAPI *PFNTQUERYINFORMATIONPROCESS) (HANDLE ProcessHandle, int ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
  171. // this function checks to see if we are a 32-bit process running on a 64-bit platform
  172. BOOL RunningOnWow64()
  173. {
  174. static BOOL bRunningOnWow64 = (BOOL)-1;
  175. if (bRunningOnWow64 == (BOOL)-1)
  176. {
  177. PFNTQUERYINFORMATIONPROCESS pfn = (PFNTQUERYINFORMATIONPROCESS)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtQueryInformationProcess");
  178. if (pfn)
  179. {
  180. LONG lStatus;
  181. ULONG_PTR Wow64Info;
  182. #define ProcessWow64Information 26 // stolen from ntpsapi.h
  183. lStatus = pfn(GetCurrentProcess(), ProcessWow64Information, &Wow64Info, sizeof(Wow64Info), NULL);
  184. if ((lStatus >= 0) && Wow64Info)
  185. {
  186. bRunningOnWow64 = TRUE;
  187. }
  188. else
  189. {
  190. bRunningOnWow64 = FALSE;
  191. }
  192. }
  193. else
  194. {
  195. bRunningOnWow64 = FALSE;
  196. }
  197. }
  198. return bRunningOnWow64;
  199. }
  200. /*----------------------------------------------------------
  201. Purpose: Returns TRUE/FALSE if the platform is the given OS_ value.
  202. */
  203. STDAPI_(BOOL) IsOS(DWORD dwOS)
  204. {
  205. BOOL bRet;
  206. static OSVERSIONINFOEXA s_osvi = {0};
  207. static BOOL s_bVersionCached = FALSE;
  208. if (!s_bVersionCached)
  209. {
  210. s_bVersionCached = TRUE;
  211. s_osvi.dwOSVersionInfoSize = sizeof(s_osvi);
  212. if (!GetVersionExA((OSVERSIONINFOA*)&s_osvi))
  213. {
  214. // If it failed, it must be a down level platform
  215. s_osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  216. GetVersionExA((OSVERSIONINFOA*)&s_osvi);
  217. }
  218. }
  219. switch (dwOS)
  220. {
  221. case OS_TERMINALCLIENT:
  222. // WARNING: this will only return TRUE for REMOTE TS sessions (eg you are comming in via tsclient).
  223. // If you want to see if TS is enabled or if the user is on the TS console, the use one of the other flags.
  224. bRet = GetSystemMetrics(SM_REMOTESESSION);
  225. break;
  226. case OS_WIN2000TERMINAL:
  227. // WARNING: this flag is VERY ambiguous... you probably want to use one of
  228. // OS_TERMINALSERVER, OS_TERMINALREMOTEADMIN, or OS_PERSONALTERMINALSERVER instead.
  229. RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use one of OS_TERMINALSERVER, OS_TERMINALREMOTEADMIN, or OS_PERSONALTERMINALSERVER instead !");
  230. bRet = ((VER_SUITE_TERMINAL & s_osvi.wSuiteMask) &&
  231. s_osvi.dwMajorVersion >= 5);
  232. break;
  233. case OS_TERMINALSERVER:
  234. // NOTE: be careful about using OS_TERMINALSERVER. It will only return true for nt server boxes
  235. // configured in what used to be called "Applications Server" mode in the win2k days. It is now simply called
  236. // "Terminal Server" (hence the name of this flag).
  237. bRet = ((VER_SUITE_TERMINAL & s_osvi.wSuiteMask) &&
  238. !(VER_SUITE_SINGLEUSERTS & s_osvi.wSuiteMask));
  239. #ifdef DEBUG
  240. if (bRet)
  241. {
  242. // all "Terminal Server" machines have to be server (cannot be per/pro)
  243. ASSERT(VER_NT_SERVER == s_osvi.wProductType || VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType);
  244. }
  245. #endif
  246. break;
  247. case OS_TERMINALREMOTEADMIN:
  248. // this checks to see if TS has been installed in the "Remote Administration" mode. This is
  249. // the default for server installs on win2k and whistler
  250. bRet = ((VER_SUITE_TERMINAL & s_osvi.wSuiteMask) &&
  251. (VER_SUITE_SINGLEUSERTS & s_osvi.wSuiteMask));
  252. break;
  253. case OS_PERSONALTERMINALSERVER:
  254. bRet = ((VER_SUITE_SINGLEUSERTS & s_osvi.wSuiteMask) &&
  255. !(VER_SUITE_TERMINAL & s_osvi.wSuiteMask));
  256. break;
  257. case OS_FASTUSERSWITCHING:
  258. bRet = (((VER_SUITE_TERMINAL | VER_SUITE_SINGLEUSERTS) & s_osvi.wSuiteMask) &&
  259. IsWinlogonRegValueSet(HKEY_LOCAL_MACHINE,
  260. "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
  261. "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\policies\\system",
  262. "AllowMultipleTSSessions"));
  263. break;
  264. case OS_FRIENDLYLOGONUI:
  265. bRet = (!IsMachineDomainMember() &&
  266. !IsWinlogonRegValuePresent(HKEY_LOCAL_MACHINE,
  267. "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
  268. "GinaDLL") &&
  269. IsWinlogonRegValueSet(HKEY_LOCAL_MACHINE,
  270. "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
  271. "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\policies\\system",
  272. "LogonType"));
  273. break;
  274. case OS_DOMAINMEMBER:
  275. bRet = IsMachineDomainMember();
  276. ASSERT(VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId); // has to be a NT machine to be on a domain!
  277. break;
  278. case 4: // used to be OS_NT5, is the same as OS_WIN2000ORGREATER so use that instead
  279. case OS_WIN2000ORGREATER:
  280. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
  281. s_osvi.dwMajorVersion >= 5);
  282. break;
  283. // NOTE: The flags in this section are bogus and SHOULD NOT BE USED
  284. // (but the ie4 shell32 uses them, so don't RIP on downlevel platforms)
  285. case OS_WIN2000PRO:
  286. RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use OS_PROFESSIONAL instead of OS_WIN2000PRO !");
  287. bRet = (VER_NT_WORKSTATION == s_osvi.wProductType &&
  288. s_osvi.dwMajorVersion == 5);
  289. break;
  290. case OS_WIN2000ADVSERVER:
  291. RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use OS_ADVSERVER instead of OS_WIN2000ADVSERVER !");
  292. bRet = ((VER_NT_SERVER == s_osvi.wProductType ||
  293. VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  294. s_osvi.dwMajorVersion == 5 &&
  295. (VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
  296. !(VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
  297. break;
  298. case OS_WIN2000DATACENTER:
  299. RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use OS_DATACENTER instead of OS_WIN2000DATACENTER !");
  300. bRet = ((VER_NT_SERVER == s_osvi.wProductType ||
  301. VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  302. s_osvi.dwMajorVersion == 5 &&
  303. (VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
  304. break;
  305. case OS_WIN2000SERVER:
  306. RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use OS_SERVER instead of OS_WIN2000SERVER !");
  307. bRet = ((VER_NT_SERVER == s_osvi.wProductType ||
  308. VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  309. !(VER_SUITE_DATACENTER & s_osvi.wSuiteMask) &&
  310. !(VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
  311. s_osvi.dwMajorVersion == 5);
  312. break;
  313. // END bogus Flags
  314. case OS_EMBEDDED:
  315. bRet = (VER_SUITE_EMBEDDEDNT & s_osvi.wSuiteMask);
  316. break;
  317. case OS_WINDOWS:
  318. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId);
  319. break;
  320. case OS_NT:
  321. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId);
  322. break;
  323. case OS_WIN95:
  324. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  325. s_osvi.dwMajorVersion >= 4);
  326. break;
  327. case OS_WIN95GOLD:
  328. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  329. s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion == 0 &&
  330. LOWORD(s_osvi.dwBuildNumber) == 950);
  331. break;
  332. case OS_WIN98ORGREATER:
  333. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  334. (s_osvi.dwMajorVersion > 4 ||
  335. s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion >= 10));
  336. break;
  337. case OS_WIN98_GOLD:
  338. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  339. s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion == 10 &&
  340. LOWORD(s_osvi.dwBuildNumber) == 1998);
  341. break;
  342. case OS_MILLENNIUMORGREATER:
  343. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  344. ((s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion >= 90) ||
  345. s_osvi.dwMajorVersion > 4));
  346. break;
  347. case OS_NT4:
  348. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
  349. s_osvi.dwMajorVersion >= 4);
  350. break;
  351. case OS_WHISTLERORGREATER:
  352. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
  353. ((s_osvi.dwMajorVersion > 5) ||
  354. (s_osvi.dwMajorVersion == 5 && (s_osvi.dwMinorVersion > 0 ||
  355. (s_osvi.dwMinorVersion == 0 && LOWORD(s_osvi.dwBuildNumber) > 2195)))));
  356. break;
  357. case OS_PERSONAL:
  358. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
  359. (VER_SUITE_PERSONAL & s_osvi.wSuiteMask));
  360. break;
  361. case OS_PROFESSIONAL:
  362. bRet = ((VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId) &&
  363. (VER_NT_WORKSTATION == s_osvi.wProductType));
  364. break;
  365. case OS_DATACENTER:
  366. bRet = ((VER_NT_SERVER == s_osvi.wProductType || VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  367. (VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
  368. break;
  369. case OS_ADVSERVER:
  370. bRet = ((VER_NT_SERVER == s_osvi.wProductType || VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  371. (VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
  372. !(VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
  373. break;
  374. case OS_SERVER:
  375. // NOTE: be careful! this specifically means Server -- will return false for Avanced Server and Datacenter machines
  376. bRet = ((VER_NT_SERVER == s_osvi.wProductType || VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  377. !(VER_SUITE_DATACENTER & s_osvi.wSuiteMask) &&
  378. !(VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask));
  379. break;
  380. case OS_ANYSERVER:
  381. // this is for people who want to know if this is ANY type of NT server machine (eg dtc, ads, or srv)
  382. bRet = ((VER_NT_SERVER == s_osvi.wProductType) || (VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType));
  383. break;
  384. case OS_WOW6432:
  385. bRet = RunningOnWow64();
  386. break;
  387. #if (_WIN32_WINNT >= 0x0501)
  388. case OS_TABLETPC:
  389. bRet = GetSystemMetrics(SM_TABLETPC);
  390. break;
  391. case OS_MEDIACENTER:
  392. // eHome Freestyle Project
  393. bRet = GetSystemMetrics(SM_MEDIACENTER);
  394. break;
  395. #endif
  396. default:
  397. bRet = FALSE;
  398. break;
  399. }
  400. return bRet;
  401. }