Leaked source code of windows server 2003
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.

1273 lines
46 KiB

  1. //*************************************************************
  2. //
  3. // General.cpp - General property sheet page
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1996-2000
  7. // All rights reserved
  8. //
  9. //*************************************************************
  10. // NT base apis
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <ntdddisk.h>
  15. #include <sysdm.h>
  16. #include <regstr.h>
  17. #include <help.h>
  18. #include <shellapi.h>
  19. #include <shlapip.h>
  20. #include <shlobjp.h>
  21. #include <regapix.h>
  22. #include <wininet.h>
  23. #include <wbemcli.h> // Contains the WMI APIs: IWbemLocator, etc.
  24. #include <ccstock.h> // Contains IID_PPV_ARG()
  25. #include <debug.h> // For TraceMsg()
  26. #include <stdio.h>
  27. #include <math.h>
  28. #include <winbrand.h>
  29. #define CP_ENGLISH 1252 // This is the English code page.
  30. #ifdef DEBUG
  31. #undef TraceMsg
  32. #define TraceMsg(nTFFlags, str, n1) DbgPrintf(TEXT(str) TEXT("\n"), n1)
  33. #else // DEBUG
  34. #endif // DEBUG
  35. #define SYSCPL_ASYNC_COMPUTER_INFO (WM_APP + 1)
  36. #define SZ_REGKEY_MYCOMP_OEMLINKS TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\OEMLinks")
  37. #define SZ_REGKEY_MYCOMP_OEMENGLISH TEXT("1252")
  38. #define SZ_ATCOMPATIBLE TEXT("AT/AT COMPATIBLE")
  39. #define SZ_WMI_WIN32PROCESSOR_ATTRIB_NAME L"Name" // Example, "Intel Pentium III Xeon processor"
  40. #define SZ_WMI_WIN32PROCESSOR_ATTRIB_SPEED L"CurrentClockSpeed" // Example, "550".
  41. #define SZ_WMI_WIN32PROCESSOR_ATTRIB_MAXSPEED L"MaxClockSpeed" // Example, "550".
  42. #define SZ_WMI_WQL_QUERY_STRING L"select Name,CurrentClockSpeed,MaxClockSpeed from Win32_Processor"
  43. #define MHZ_TO_GHZ_THRESHHOLD 1000
  44. // if cpu speed comes back slower than WMI_WIN32PROCESSOR_SPEEDSTEP_CUTOFF,
  45. // assume we're in power-save mode, display max speed instead.
  46. #define WMI_WIN32PROCESSOR_SPEEDSTEP_CUTOFF 50
  47. #define FEATURE_IGNORE_ATCOMPAT
  48. #define FEATURE_LINKS
  49. #define MAX_URL_STRING (INTERNET_MAX_SCHEME_LENGTH \
  50. + sizeof("://") \
  51. + INTERNET_MAX_PATH_LENGTH)
  52. #define MAX_PROCESSOR_DESCRIPTION MAX_URL_STRING
  53. // Globals for this page
  54. static const WCHAR c_szEmpty[] = TEXT("");
  55. static const WCHAR c_szCRLF[] = TEXT("\r\n");
  56. static const WCHAR c_szAboutKey[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion");
  57. static const WCHAR c_szAboutRegisteredOwner[] = REGSTR_VAL_REGOWNER;
  58. static const WCHAR c_szAboutRegisteredOrganization[] = REGSTR_VAL_REGORGANIZATION;
  59. static const WCHAR c_szAboutProductId[] = REGSTR_VAL_PRODUCTID;
  60. static const WCHAR c_szAboutAnotherSerialNumber[] = TEXT("Plus! VersionNumber");
  61. static const WCHAR c_szAboutAnotherProductId[] = TEXT("Plus! ProductId");
  62. // oeminfo stuff
  63. static const WCHAR c_szSystemDir[] = TEXT("System\\");
  64. static const WCHAR c_szOemFile[] = TEXT("OemInfo.Ini");
  65. static const WCHAR c_szOemImageFile[] = TEXT("OemLogo.Bmp");
  66. static const WCHAR c_szOemGenSection[] = TEXT("General");
  67. static const WCHAR c_szOemSupportSection[] = TEXT("Support Information");
  68. static const WCHAR c_szOemName[] = TEXT("Manufacturer");
  69. static const WCHAR c_szOemModel[] = TEXT("Model");
  70. static const WCHAR c_szOemSupportLinePrefix[] = TEXT("line");
  71. static const WCHAR c_szDefSupportLineText[] = TEXT("@");
  72. static const WCHAR SZ_REGKEY_HARDWARE_CPU[] = TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
  73. static const WCHAR c_szMemoryManagement[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
  74. static const WCHAR c_szPhysicalAddressExtension[] = TEXT("PhysicalAddressExtension");
  75. static const WCHAR c_szIndentifier[] = TEXT("Identifier");
  76. static const WCHAR SZ_REGVALUE_PROCESSORNAMESTRING[] = TEXT("ProcessorNameString");
  77. #define SZ_REGKEY_HARDWARE TEXT("HARDWARE\\DESCRIPTION\\System")
  78. #define SZ_REGKEY_USE_WMI TEXT("UseWMI")
  79. // Help ID's
  80. int g_nStartOfOEMLinks = 0;
  81. DWORD aGeneralHelpIds[] = {
  82. IDC_GEN_WINDOWS_IMAGE, NO_HELP,
  83. IDC_TEXT_1, (IDH_GENERAL + 0),
  84. IDC_GEN_VERSION_0, (IDH_GENERAL + 1),
  85. IDC_GEN_VERSION_1, (IDH_GENERAL + 1),
  86. IDC_GEN_VERSION_2, (IDH_GENERAL + 1),
  87. IDC_GEN_VERSION_3, (IDH_GENERAL + 1),
  88. IDC_TEXT_3, (IDH_GENERAL + 3),
  89. IDC_GEN_REGISTERED_0, (IDH_GENERAL + 3),
  90. IDC_GEN_REGISTERED_1, (IDH_GENERAL + 3),
  91. IDC_GEN_REGISTERED_2, (IDH_GENERAL + 3),
  92. IDC_GEN_REGISTERED_3, (IDH_GENERAL + 3),
  93. IDC_GEN_OEM_IMAGE, NO_HELP,
  94. IDC_TEXT_4, (IDH_GENERAL + 6),
  95. IDC_GEN_MACHINE_0, (IDH_GENERAL + 7),
  96. IDC_GEN_MACHINE_1, (IDH_GENERAL + 8),
  97. IDC_GEN_MACHINE_2, (IDH_GENERAL + 9),
  98. IDC_GEN_MACHINE_3, (IDH_GENERAL + 10),
  99. IDC_GEN_MACHINE_4, (IDH_GENERAL + 11),
  100. IDC_GEN_MACHINE_5, NO_HELP,
  101. IDC_GEN_MACHINE_6, NO_HELP,
  102. IDC_GEN_MACHINE_7, NO_HELP,
  103. IDC_GEN_MACHINE_8, NO_HELP,
  104. IDC_GEN_OEM_SUPPORT, (IDH_GENERAL + 12),
  105. IDC_GEN_REGISTERED_2, (IDH_GENERAL + 14),
  106. IDC_GEN_REGISTERED_3, (IDH_GENERAL + 15),
  107. IDC_GEN_MACHINE, (IDH_GENERAL + 7),
  108. IDC_GEN_OEM_NUDGE, NO_HELP,
  109. 0, 0
  110. };
  111. //
  112. // Macros
  113. //
  114. #define BytesToK(pDW) (*(pDW) = (*(pDW) + 512) / 1024) // round up
  115. //
  116. // Function proto-types
  117. //
  118. INT_PTR APIENTRY PhoneSupportProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  119. DWORD WINAPI InitGeneralDlgThread(LPVOID lpParam);
  120. typedef struct {
  121. WCHAR szProcessorDesc[MAX_PROCESSOR_DESCRIPTION];
  122. WCHAR szProcessorClockSpeed[MAX_PROCESSOR_DESCRIPTION];
  123. } PROCESSOR_INFO;
  124. typedef struct {
  125. LONGLONG llMem;
  126. PROCESSOR_INFO pi;
  127. BOOL fShowProcName;
  128. BOOL fShowProcSpeed;
  129. } INITDLGSTRUCT;
  130. #define GETOEMFILE_OEMDATA 0
  131. #define GETOEMFILE_OEMIMAGE 1
  132. HRESULT _GetOemFile(LPWSTR szOemFile, UINT cchOemFile, DWORD dwFlags)
  133. {
  134. HRESULT hr;
  135. LPCWSTR szFileName = (GETOEMFILE_OEMDATA == dwFlags) ? c_szOemFile : c_szOemImageFile;
  136. szOemFile[0] = 0;
  137. // first look in system directory
  138. if (!GetSystemDirectory(szOemFile, cchOemFile))
  139. {
  140. hr = E_FAIL;
  141. }
  142. else
  143. {
  144. if (!PathAppend(szOemFile, szFileName))
  145. {
  146. hr = E_FAIL;
  147. }
  148. else
  149. {
  150. if (PathFileExists(szOemFile))
  151. {
  152. hr = S_OK;
  153. }
  154. else // if it's not there, then look in %windir%\system (on 9X oems would put files here)
  155. {
  156. if (!GetWindowsDirectory(szOemFile, ARRAYSIZE(szOemFile)))
  157. {
  158. hr = E_FAIL;
  159. }
  160. else
  161. {
  162. if (PathAppend(szOemFile, c_szSystemDir) &&
  163. PathAppend(szOemFile, szFileName) &&
  164. PathFileExists(szOemFile))
  165. {
  166. hr = S_OK;
  167. }
  168. else
  169. {
  170. hr = E_FAIL;
  171. }
  172. }
  173. }
  174. }
  175. }
  176. return hr;
  177. }
  178. HRESULT _SetMachineInfoLine(HWND hDlg, int idControl, LPCWSTR pszText, BOOL fSetTabStop)
  179. {
  180. HRESULT hr = S_OK;
  181. #ifdef FEATURE_LINKS
  182. HWND hwndItem = GetDlgItem(hDlg, idControl);
  183. SetDlgItemText(hDlg, idControl, pszText);
  184. if (fSetTabStop)
  185. {
  186. // We also want to add the WS_TABSTOP attribute for accessibility.
  187. SetWindowLong(hwndItem, GWL_STYLE, (WS_TABSTOP | GetWindowLong(hwndItem, GWL_STYLE)));
  188. }
  189. else
  190. {
  191. // We want to remove the tab stop behavior and we do that by removing
  192. // the LWIS_ENABLED attribute
  193. LWITEM item = {0};
  194. item.mask = (LWIF_ITEMINDEX | LWIF_STATE);
  195. item.stateMask = LWIS_ENABLED;
  196. item.state = 0; // 0 if we want it disabled.
  197. item.iLink = 0;
  198. hr = (SendMessage(hwndItem, LWM_SETITEM, 0, (LPARAM)&item) ? S_OK : E_FAIL);
  199. }
  200. #else // FEATURE_LINKS
  201. SetDlgItemText(hDlg, idControl, pszText);
  202. #endif // FEATURE_LINKS
  203. return hr;
  204. }
  205. //*************************************************************
  206. // Purpose: Sets or clears an image in a static control.
  207. //
  208. // Parameters: control - handle of static control
  209. // resource - resource / filename of bitmap
  210. // fl - SCB_ flags:
  211. // SCB_FROMFILE 'resource' specifies a filename instead of a resource
  212. // SCB_REPLACEONLY only put the new image up if there was an old one
  213. //
  214. // Return: (BOOL) TRUE if successful
  215. // FALSE if an error occurs
  216. //
  217. // Comments:
  218. //
  219. // History: Date Author Comment
  220. // 5/24/95 ericflo Ported
  221. //*************************************************************
  222. #define SCB_FROMFILE (0x1)
  223. #define SCB_REPLACEONLY (0x2)
  224. BOOL SetClearBitmap(HWND control, LPCWSTR resource, UINT fl)
  225. {
  226. HBITMAP hbm = (HBITMAP)SendMessage(control, STM_GETIMAGE, IMAGE_BITMAP, 0);
  227. if(hbm)
  228. {
  229. DeleteObject(hbm);
  230. }
  231. else if(fl & SCB_REPLACEONLY)
  232. {
  233. return FALSE;
  234. }
  235. if(resource)
  236. {
  237. SendMessage(control, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)
  238. LoadImage(hInstance, resource, IMAGE_BITMAP, 0, 0,
  239. LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS |
  240. ((fl & SCB_FROMFILE)? LR_LOADFROMFILE : 0)));
  241. }
  242. return
  243. ((HBITMAP)SendMessage(control, STM_GETIMAGE, IMAGE_BITMAP, 0) != NULL);
  244. }
  245. BOOL IsLowColor (HWND hDlg)
  246. {
  247. BOOL fLowColor = FALSE;
  248. HDC hdc = GetDC(hDlg);
  249. if (hdc)
  250. {
  251. INT iColors = GetDeviceCaps(hdc, NUMCOLORS);
  252. fLowColor = ((iColors != -1) && (iColors <= 256));
  253. ReleaseDC(hDlg, hdc);
  254. }
  255. return fLowColor;
  256. }
  257. HRESULT _GetLinkInfo(HKEY hkey, LPCWSTR pszLanguageKey, int nIndex, LPWSTR pszLink, SIZE_T cchNameSize)
  258. {
  259. HRESULT hr;
  260. DWORD cbSize = (DWORD)(cchNameSize * sizeof(pszLink[0]));
  261. WCHAR szIndex[10];
  262. hr = StringCchPrintf(szIndex, ARRAYSIZE(szIndex), TEXT("%03d"), nIndex);
  263. if (SUCCEEDED(hr))
  264. {
  265. DWORD dwError = SHRegGetValue(hkey,
  266. pszLanguageKey,
  267. szIndex,
  268. SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND,
  269. NULL,
  270. (void *) pszLink,
  271. &cbSize);
  272. hr = HRESULT_FROM_WIN32(dwError);
  273. }
  274. return hr;
  275. }
  276. // GSierra is worried that if we allow admins to put an arbirary
  277. // number of OEM links that they will abuse the privalage.
  278. // So we use this arbitrary limit. PMs may want to change it in
  279. // the future.
  280. #define ARTIFICIAL_MAX_SLOTS 3
  281. HRESULT AddOEMHyperLinks(HWND hDlg, int * pControlID)
  282. {
  283. HKEY hkey;
  284. DWORD dwError;
  285. HRESULT hr;
  286. g_nStartOfOEMLinks = *pControlID;
  287. dwError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_REGKEY_MYCOMP_OEMLINKS, 0, KEY_READ, &hkey);
  288. hr = HRESULT_FROM_WIN32(dwError);
  289. if (SUCCEEDED(hr))
  290. {
  291. int nIndex;
  292. // While we have room and haven't hit the limit.
  293. for (nIndex = 0; ((nIndex <= ARTIFICIAL_MAX_SLOTS) &&
  294. (*pControlID <= LAST_GEN_MACHINES_SLOT)); nIndex++)
  295. {
  296. WCHAR szLink[2 * MAX_URL_STRING];
  297. WCHAR szLanguageKey[10];
  298. hr = StringCchPrintf(szLanguageKey, ARRAYSIZE(szLanguageKey), TEXT("%u"), GetACP());
  299. if (SUCCEEDED(hr))
  300. {
  301. hr = _GetLinkInfo(hkey, szLanguageKey, nIndex, szLink, ARRAYSIZE(szLink));
  302. if (FAILED(hr) && (CP_ENGLISH != GetACP()))
  303. {
  304. // We failed to find it in the natural language, so try English.
  305. hr = _GetLinkInfo(hkey, SZ_REGKEY_MYCOMP_OEMENGLISH, nIndex, szLink, ARRAYSIZE(szLink));
  306. }
  307. }
  308. if (SUCCEEDED(hr))
  309. {
  310. // TODO: Find out how to turn on the link control and set the URL.
  311. _SetMachineInfoLine(hDlg, *pControlID, szLink, TRUE);
  312. }
  313. (*pControlID)++;
  314. }
  315. RegCloseKey(hkey);
  316. }
  317. return hr;
  318. }
  319. HRESULT HrSysAllocStringW(IN const OLECHAR * pwzSource, OUT BSTR * pbstrDest)
  320. {
  321. HRESULT hr = S_OK;
  322. if (pbstrDest)
  323. {
  324. *pbstrDest = SysAllocString(pwzSource);
  325. if (pwzSource)
  326. {
  327. if (*pbstrDest)
  328. hr = S_OK;
  329. else
  330. hr = E_OUTOFMEMORY;
  331. }
  332. }
  333. return hr;
  334. }
  335. HRESULT SetWMISecurityBlanket(IN IUnknown * punk, IUnknown * punkToPass)
  336. {
  337. IClientSecurity * pClientSecurity;
  338. HRESULT hr = punk->QueryInterface(IID_PPV_ARG(IClientSecurity, &pClientSecurity));
  339. TraceMsg(TF_ALWAYS, "IEnumWbemClassObject::QueryInterface(IClientSecurity) called and hr=%#08lx", hr);
  340. if (SUCCEEDED(hr))
  341. {
  342. // Nuke after we get this working. RPC_C_AUTHN_NONE , RPC_C_AUTHZ_NAME
  343. hr = pClientSecurity->SetBlanket(punk, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
  344. RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
  345. TraceMsg(TF_ALWAYS, "IClientSecurity::SetBlanket() called and hr=%#08lx", hr);
  346. pClientSecurity->Release();
  347. }
  348. return hr;
  349. }
  350. // DESCRIPTION:
  351. // WMI's Win32_Processor object will return a lot of rich information.
  352. // We use this because we want rich information even if the processor doesn't
  353. // provide it (like intel pre-Willette). Millennium uses cpuid.asm as a
  354. // hack and we want to prevent from copying that because there is a political
  355. // pressure from the NT team to intel to have the processors provide this
  356. // information. That way the OS doesn't need to rev to include new processor
  357. // names when they are released. WMI does something to generate good results
  358. // (\admin\wmi\WBEM\Providers\Win32Provider\Providers\processor.cpp) which
  359. // includes asm. I don't know if it's the exact same logic as Millennium and
  360. // I don't care. The important fact is that they are the only ones to maintain
  361. // any hard coded list. Therefore we are willing to use their poorly written
  362. // API so we can re-use code and get out of the maintaince problems.
  363. HRESULT GetWMI_Win32_Processor(OUT IEnumWbemClassObject ** ppEnumProcessors)
  364. {
  365. HRESULT hr = E_NOTIMPL;
  366. *ppEnumProcessors = NULL;
  367. // Our second try is to use the WMI automation object. It has a Win32_Processor object
  368. // that can give us a good Description, even when SZ_REGVALUE_PROCESSORNAMESTRING
  369. // isn't set.
  370. IWbemLocator * pLocator;
  371. hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IWbemLocator, &pLocator));
  372. if (SUCCEEDED(hr))
  373. {
  374. hr = E_OUTOFMEMORY;
  375. BSTR bstrLocalMachine = SysAllocString(L"root\\cimv2");
  376. if (bstrLocalMachine)
  377. {
  378. IWbemServices * pIWbemServices;
  379. hr = pLocator->ConnectServer(bstrLocalMachine, NULL, NULL, 0L, 0L, NULL, NULL, &pIWbemServices);
  380. TraceMsg(TF_ALWAYS, "IWbemLocator::ConnectServer() called and hr=%#08lx", hr);
  381. if (SUCCEEDED(hr))
  382. {
  383. hr = E_OUTOFMEMORY;
  384. BSTR bstrQueryLang = SysAllocString(L"WQL");
  385. BSTR bstrQuery = SysAllocString(SZ_WMI_WQL_QUERY_STRING);
  386. if (bstrQueryLang && bstrQuery)
  387. {
  388. IEnumWbemClassObject * pEnum = NULL;
  389. hr = pIWbemServices->ExecQuery(bstrQueryLang, bstrQuery, (WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY), NULL , &pEnum);
  390. TraceMsg(TF_ALWAYS, "IWbemServices::CreateInstanceEnum() called and hr=%#08lx", hr);
  391. if (SUCCEEDED(hr))
  392. {
  393. hr = SetWMISecurityBlanket(pEnum, pIWbemServices);
  394. TraceMsg(TF_ALWAYS, "SetWMISecurityBlanket() called and hr=%#08lx", hr);
  395. if (SUCCEEDED(hr))
  396. {
  397. hr = pEnum->QueryInterface(IID_PPV_ARG(IEnumWbemClassObject, ppEnumProcessors));
  398. }
  399. pEnum->Release();
  400. }
  401. }
  402. SysFreeString(bstrQuery); // SysFreeString is happy to take NULL
  403. SysFreeString(bstrQueryLang);
  404. pIWbemServices->Release();
  405. }
  406. SysFreeString(bstrLocalMachine);
  407. }
  408. pLocator->Release();
  409. }
  410. return hr;
  411. }
  412. HRESULT GetProcessorDescFromWMI(PROCESSOR_INFO *ppi)
  413. {
  414. IEnumWbemClassObject * pEnumProcessors;
  415. HRESULT hr = GetWMI_Win32_Processor(&pEnumProcessors);
  416. if (SUCCEEDED(hr))
  417. {
  418. IWbemClassObject * pProcessor;
  419. ULONG ulRet;
  420. // Currently we only care about the first processor.
  421. hr = pEnumProcessors->Next(WBEM_INFINITE, 1, &pProcessor, &ulRet);
  422. TraceMsg(TF_ALWAYS, "IEnumWbemClassObject::Next() called and hr=%#08lx", hr);
  423. if (SUCCEEDED(hr))
  424. {
  425. VARIANT varProcessorName = {0};
  426. hr = pProcessor->Get(SZ_WMI_WIN32PROCESSOR_ATTRIB_NAME, 0, &varProcessorName, NULL, NULL);
  427. if (SUCCEEDED(hr))
  428. {
  429. VARIANT varProcessorSpeed = {0};
  430. hr = pProcessor->Get(SZ_WMI_WIN32PROCESSOR_ATTRIB_SPEED, 0, &varProcessorSpeed, NULL, NULL);
  431. if (SUCCEEDED(hr) &&
  432. VT_I4 == varProcessorSpeed.vt &&
  433. varProcessorSpeed.lVal < WMI_WIN32PROCESSOR_SPEEDSTEP_CUTOFF) // we're in speed step power-saving mode
  434. {
  435. hr = pProcessor->Get(SZ_WMI_WIN32PROCESSOR_ATTRIB_MAXSPEED, 0, &varProcessorSpeed, NULL, NULL);
  436. }
  437. if (SUCCEEDED(hr))
  438. {
  439. if ((VT_BSTR == varProcessorName.vt) && (VT_I4 == varProcessorSpeed.vt))
  440. {
  441. if (FAILED(StringCchCopy(ppi->szProcessorDesc, ARRAYSIZE(ppi->szProcessorDesc), varProcessorName.bstrVal)))
  442. {
  443. ppi->szProcessorDesc[0] = 0;
  444. }
  445. WCHAR szTemplate[MAX_PATH];
  446. UINT idStringTemplate = IDS_PROCESSOR_SPEED;
  447. szTemplate[0] = 0;
  448. if (MHZ_TO_GHZ_THRESHHOLD <= varProcessorSpeed.lVal)
  449. {
  450. WCHAR szSpeed[20];
  451. double dGHz = (varProcessorSpeed.lVal / (double)1000.0);
  452. // Someone released a "1.13 GHz" chip, so let's display that correctly...
  453. if (FAILED(StringCchPrintf(szSpeed, ARRAYSIZE(szSpeed), TEXT("%1.2f"), dGHz)))
  454. {
  455. ppi->szProcessorClockSpeed[0] = 0;
  456. }
  457. else
  458. {
  459. LoadString(hInstance, IDS_PROCESSOR_SPEEDGHZ, szTemplate, ARRAYSIZE(szTemplate));
  460. if (FAILED(StringCchPrintf(ppi->szProcessorClockSpeed, ARRAYSIZE(ppi->szProcessorClockSpeed), szTemplate, szSpeed)))
  461. {
  462. ppi->szProcessorClockSpeed[0] = 0;
  463. }
  464. }
  465. }
  466. else
  467. {
  468. LoadString(hInstance, IDS_PROCESSOR_SPEED, szTemplate, ARRAYSIZE(szTemplate));
  469. if (FAILED(StringCchPrintf(ppi->szProcessorClockSpeed, ARRAYSIZE(ppi->szProcessorClockSpeed), szTemplate, varProcessorSpeed.lVal)))
  470. {
  471. ppi->szProcessorClockSpeed[0] = 0;
  472. }
  473. }
  474. }
  475. else
  476. {
  477. hr = E_FAIL;
  478. }
  479. }
  480. VariantClear(&varProcessorSpeed);
  481. }
  482. VariantClear(&varProcessorName);
  483. pProcessor->Release();
  484. }
  485. pEnumProcessors->Release();
  486. }
  487. return hr;
  488. }
  489. HRESULT GetProcessorInfoFromRegistry(HKEY hkey, PROCESSOR_INFO *ppi)
  490. {
  491. HRESULT hr = E_FAIL;
  492. WCHAR szTemp[MAX_PROCESSOR_DESCRIPTION];
  493. *szTemp = NULL;
  494. DWORD cbData = sizeof(szTemp);
  495. //To avoid copying blank string.
  496. if ((SHRegGetValue(hkey, NULL, SZ_REGVALUE_PROCESSORNAMESTRING, SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND, NULL, (LPBYTE)szTemp, &cbData) == ERROR_SUCCESS) &&
  497. (*szTemp != NULL) && (cbData > 1))
  498. {
  499. //ISSUE - How do I get the processor clock speed.
  500. hr = StringCchCopy (ppi->szProcessorDesc, ARRAYSIZE(ppi->szProcessorDesc), szTemp);
  501. }
  502. return hr;
  503. }
  504. // This is the number of chars that will fit on one line in our dialog
  505. // with the current layout.
  506. #define SIZE_CHARSINLINE 30
  507. BOOL _GetProcessorDescription(PROCESSOR_INFO* ppi, BOOL* pbShowClockSpeed)
  508. {
  509. BOOL bShowProcessorInfo = FALSE;
  510. *pbShowClockSpeed = TRUE;
  511. HKEY hkey;
  512. // In general, WMI is a lowse API. However, they provide the processor description on
  513. // downlevel so we need them. They implement this in a hacky way so we want them to
  514. // maintain the hack and all the problems associated with it. We need to turn this feature
  515. // off until they fix their bugs. Currently, they call JET which recently regressed and
  516. // causes their API to take 10-20 seconds. -BryanSt
  517. if (SHRegGetBoolUSValue(SZ_REGKEY_HARDWARE, SZ_REGKEY_USE_WMI, FALSE, TRUE))
  518. {
  519. if (SUCCEEDED(GetProcessorDescFromWMI(ppi)))
  520. {
  521. bShowProcessorInfo = TRUE;
  522. }
  523. }
  524. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_REGKEY_HARDWARE_CPU, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
  525. {
  526. // Try for ProcessorNameString if present.
  527. // This registry entry will contain the most correct description of the processor
  528. // because it came directly from the CPU. AMD and Cyrix support this but
  529. // intel won't until Willette.
  530. if (FAILED(GetProcessorInfoFromRegistry(hkey, ppi)))
  531. {
  532. if (!bShowProcessorInfo)
  533. {
  534. // Our last try is to use the generic Identifier. This is normally formatted like,
  535. // "x86 Family 6 Model 7 Stepping 3" but it's better than nothing.
  536. DWORD cbData = sizeof(ppi->szProcessorDesc);
  537. if (SHRegGetValue(hkey, NULL, c_szIndentifier, SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND, NULL, (LPBYTE)ppi->szProcessorDesc, &cbData) == ERROR_SUCCESS)
  538. {
  539. bShowProcessorInfo = TRUE;
  540. *pbShowClockSpeed = FALSE;
  541. }
  542. }
  543. }
  544. RegCloseKey(hkey);
  545. }
  546. return bShowProcessorInfo;
  547. }
  548. void _SetProcessorDescription(HWND hDlg, PROCESSOR_INFO* ppi, BOOL bShowClockSpeed, BOOL bShowProcessorInfo, int * pnControlID)
  549. {
  550. if (bShowProcessorInfo)
  551. {
  552. WCHAR szProcessorLine1[MAX_PATH];
  553. WCHAR szProcessorLine2[MAX_PATH];
  554. // We need to get the CPU name from the CPU itself so we don't
  555. // need to rev our OS's INF files every time they ship a new processor. So we guaranteed
  556. // them that we would display whatever string they provide in whatever way they provide it
  557. // up to 49 chars. The layout on the dlg doesn't allow 49 chars on one line so we need to wrap
  558. // in that case. Whistler #159510.
  559. // Don't change this without talking to me (BryanSt) or JVert.
  560. //
  561. // Note: there is often talk of stripping leading spaces. Intel even asks software to do this.
  562. // (http://developer.intel.com/design/processor/future/manuals/CPUID_Supplement.htm)
  563. // However, we SHOULD NOT do this. This call was defined and standardized by AMD long ago.
  564. // The rule we make is they must be compatible with AMD�s existing implementation.
  565. // (http://www.amd.com/products/cpg/athlon/techdocs/pdf/20734.pdf)
  566. // Contact JVert for questions on stripping leading spaces.
  567. StringCchCopy(szProcessorLine1, ARRAYSIZE(szProcessorLine1), ppi->szProcessorDesc); // display string, truncation ok
  568. szProcessorLine2[0] = 0;
  569. if (SIZE_CHARSINLINE < lstrlen(szProcessorLine1))
  570. {
  571. // Now word wrap
  572. WCHAR* pszWrapPoint = StrRChr(szProcessorLine1, szProcessorLine1 + SIZE_CHARSINLINE, TEXT(' '));
  573. if (pszWrapPoint)
  574. {
  575. StringCchCopy(szProcessorLine2, ARRAYSIZE(szProcessorLine2), pszWrapPoint + 1); // display string, truncation ok
  576. *pszWrapPoint = 0;
  577. }
  578. else // if no space found, just wrap at SIZE_CHARSINLINE
  579. {
  580. StringCchCopy(szProcessorLine2, ARRAYSIZE(szProcessorLine2), &szProcessorLine1[SIZE_CHARSINLINE]); // display string, truncation ok
  581. szProcessorLine1[SIZE_CHARSINLINE] = 0;
  582. }
  583. }
  584. _SetMachineInfoLine(hDlg, (*pnControlID)++, szProcessorLine1, FALSE);
  585. if (szProcessorLine2[0])
  586. {
  587. _SetMachineInfoLine(hDlg, (*pnControlID)++, szProcessorLine2, FALSE);
  588. }
  589. if (bShowClockSpeed)
  590. {
  591. _SetMachineInfoLine(hDlg, (*pnControlID)++, ppi->szProcessorClockSpeed, FALSE);
  592. }
  593. }
  594. }
  595. typedef struct _OSNAMEIDPAIR {
  596. UINT iOSType;
  597. UINT iOSName;
  598. BOOL fWinBrandDll;
  599. } OSNAMEIDPAIR;
  600. //*************************************************************
  601. // Purpose: Initalize the general page
  602. //
  603. // Parameters: hDlg - Handle to the dialog box
  604. //
  605. // Return: void
  606. //
  607. // Comments:
  608. //
  609. // History: Date Author Comment
  610. // 11/20/95 ericflo Ported
  611. //*************************************************************
  612. VOID InitGeneralDlg(HWND hDlg)
  613. {
  614. OSVERSIONINFO ver;
  615. WCHAR szScratch1[64];
  616. WCHAR szScratch2[64];
  617. DWORD cbData;
  618. HKEY hkey;
  619. int ctlid;
  620. UINT id;
  621. HMODULE hResourceDll = hInstance;
  622. // Set the default bitmap
  623. SetClearBitmap(GetDlgItem(hDlg, IDC_GEN_WINDOWS_IMAGE),
  624. IsLowColor(hDlg) ? MAKEINTRESOURCE(IDB_WINDOWS_256) : MAKEINTRESOURCE(IDB_WINDOWS), 0);
  625. /////////////////////////
  626. // Version info
  627. ctlid = IDC_GEN_VERSION_0;
  628. // Query for the build number information
  629. ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  630. if (!GetVersionEx(&ver)) {
  631. return;
  632. }
  633. // Major Branding ("Microsoft Windows XP", ".NET Server 2003", etc.)
  634. if (IsOS(OS_ANYSERVER))
  635. {
  636. id = IDS_WINVER_WINDOWSDOTNET;
  637. }
  638. else
  639. {
  640. id = IDS_WINVER_WINDOWSXP;
  641. }
  642. LoadString(hInstance, id, szScratch1, ARRAYSIZE(szScratch1));
  643. SetDlgItemText(hDlg, ctlid++, szScratch1);
  644. // Minor Branding ("Personal", "Professional", "64-Bit Edition", etc)
  645. szScratch1[0] = TEXT('\0');
  646. id = 0;
  647. // note: OS_EMBEDDED must be before any options that may co-occur with OS_EMBEDDED
  648. #ifndef _WIN64
  649. OSNAMEIDPAIR rgID[] = {{OS_EMBEDDED, IDS_WINVER_EMBEDDED, FALSE},
  650. {OS_MEDIACENTER, IDS_WINVER_MEDIACENTER_SYSDM_CPL, TRUE},
  651. {OS_TABLETPC, IDS_WINVER_TABLETPC_SYSDM_CPL, TRUE},
  652. {OS_PERSONAL, IDS_WINVER_PERSONAL, FALSE},
  653. {OS_PROFESSIONAL, IDS_WINVER_PROFESSIONAL, FALSE},
  654. //{OS_APPLIANCE, IDS_WINVER_APPLIANCE_SYSDM_CPL, TRUE},
  655. {OS_SERVER, IDS_WINVER_SERVER, FALSE},
  656. {OS_ADVSERVER, IDS_WINVER_ADVANCEDSERVER, FALSE},
  657. {OS_DATACENTER, IDS_WINVER_DATACENTER, FALSE},
  658. {OS_BLADE, IDS_WINVER_BLADE, FALSE},
  659. {OS_SMALLBUSINESSSERVER, IDS_WINVER_SBS, FALSE}};
  660. #else
  661. OSNAMEIDPAIR rgID[] = {{OS_PROFESSIONAL, IDS_WINVER_PROFESSIONAL_WIN64, FALSE},
  662. {OS_SERVER, IDS_WINVER_SERVER, FALSE},
  663. {OS_ADVSERVER, IDS_WINVER_ADVANCEDSERVER, FALSE},
  664. {OS_DATACENTER, IDS_WINVER_DATACENTER, FALSE}};
  665. #endif
  666. for (int i = 0; i < ARRAYSIZE(rgID); i++)
  667. {
  668. if (IsOS(rgID[i].iOSType))
  669. {
  670. id = (rgID[i].iOSName);
  671. // If this resource lives in the special Windows branding DLL,
  672. // attempt to load the DLL now. If this fails, just leave this
  673. // string empty.
  674. if (rgID[i].fWinBrandDll)
  675. {
  676. hResourceDll = LoadLibraryEx(TEXT("winbrand.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE);
  677. if (hResourceDll == NULL)
  678. {
  679. // This will result in an empty string, which is
  680. // acceptable for this very unlikely scenario.
  681. id = 0;
  682. hResourceDll = hInstance;
  683. }
  684. }
  685. break;
  686. }
  687. };
  688. LoadString(hResourceDll, id, szScratch1, ARRAYSIZE(szScratch1));
  689. if (hResourceDll != hInstance)
  690. {
  691. FreeLibrary(hResourceDll);
  692. }
  693. SetDlgItemText(hDlg, ctlid++, szScratch1);
  694. // Version Year and/or Debug-ness
  695. if (GetSystemMetrics(SM_DEBUG))
  696. {
  697. LoadString(hInstance, IDS_DEBUG, szScratch2, ARRAYSIZE(szScratch2));
  698. if (!IsOS(OS_ANYSERVER))
  699. {
  700. // non-srv / debug = "Version 2003 (Debug)"
  701. LoadString(hInstance, IDS_WINVER_YEAR, szScratch1, ARRAYSIZE(szScratch1));
  702. StringCchCat(szScratch1, ARRAYSIZE(szScratch1), L" ");
  703. StringCchCat(szScratch1, ARRAYSIZE(szScratch1), szScratch2);
  704. // ISSUE-aidanl-2002-09-12 - this should be rewritten eventually using %1 and %2
  705. // (we can get away with it here b/c few people see debug builds)
  706. }
  707. else
  708. {
  709. // server / debug = "(Debug)"
  710. StringCchCopy(szScratch1, ARRAYSIZE(szScratch1), szScratch2);
  711. }
  712. }
  713. else
  714. {
  715. if (!IsOS(OS_ANYSERVER))
  716. {
  717. // non-srv / free = "Version 2003"
  718. LoadString(hInstance, IDS_WINVER_YEAR, szScratch1, ARRAYSIZE(szScratch1));
  719. }
  720. else
  721. {
  722. // server / free = line not present
  723. szScratch1[0] = 0;
  724. }
  725. }
  726. if (szScratch1[0])
  727. {
  728. SetDlgItemText(hDlg, ctlid++, szScratch1);
  729. }
  730. // Service Pack (if any)
  731. SetDlgItemText(hDlg, ctlid++, ver.szCSDVersion);
  732. /////////////////////////
  733. // User Info / Product ID
  734. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szAboutKey, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
  735. {
  736. // Do registered user info
  737. ctlid = IDC_GEN_REGISTERED_0; // start here and use more as needed
  738. cbData = sizeof(szScratch2);
  739. if((SHRegGetValue(hkey, NULL, c_szAboutRegisteredOwner,
  740. SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND, NULL, (LPBYTE)szScratch2, &cbData) == ERROR_SUCCESS) &&
  741. (cbData > 1))
  742. {
  743. SetDlgItemText(hDlg, ctlid++, szScratch2);
  744. }
  745. cbData = sizeof(szScratch2);
  746. if((SHRegGetValue(hkey, NULL, c_szAboutRegisteredOrganization,
  747. SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND, NULL, (LPBYTE)szScratch2, &cbData) == ERROR_SUCCESS) &&
  748. (cbData > 1))
  749. {
  750. SetDlgItemText(hDlg, ctlid++, szScratch2);
  751. }
  752. cbData = sizeof(szScratch2);
  753. if((SHRegGetValue(hkey, NULL, c_szAboutProductId,
  754. SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND, NULL, (LPBYTE)szScratch2, &cbData) == ERROR_SUCCESS) &&
  755. (cbData > 1))
  756. {
  757. SetDlgItemText(hDlg, ctlid++, szScratch2);
  758. }
  759. cbData = sizeof(szScratch2);
  760. if((SHRegGetValue(hkey, NULL, c_szAboutAnotherProductId,
  761. SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND, NULL, (LPBYTE)szScratch2, &cbData) == ERROR_SUCCESS) &&
  762. (cbData > 1))
  763. {
  764. SetDlgItemText(hDlg, ctlid++, szScratch2);
  765. }
  766. RegCloseKey(hkey);
  767. }
  768. SHCreateThread(InitGeneralDlgThread, hDlg, CTF_COINIT | CTF_FREELIBANDEXIT, NULL);
  769. }
  770. DWORD WINAPI InitGeneralDlgThread(LPVOID lpParam)
  771. {
  772. SYSTEM_BASIC_INFORMATION BasicInfo;
  773. NTSTATUS Status;
  774. if (!lpParam)
  775. return -1;
  776. INITDLGSTRUCT* pids = (INITDLGSTRUCT*)LocalAlloc(LPTR, sizeof(INITDLGSTRUCT));
  777. if (pids)
  778. {
  779. // Memory
  780. Status = NtQuerySystemInformation(
  781. SystemBasicInformation,
  782. &BasicInfo,
  783. sizeof(BasicInfo),
  784. NULL
  785. );
  786. if (NT_SUCCESS(Status))
  787. {
  788. LONGLONG nTotalBytes = BasicInfo.NumberOfPhysicalPages;
  789. nTotalBytes *= BasicInfo.PageSize;
  790. // WORKAROUND - NtQuerySystemInformation doesn't really return the total available physical
  791. // memory, it instead just reports the total memory seen by the Operating System. Since
  792. // some amount of memory is reserved by BIOS, the total available memory is reported
  793. // incorrectly. To work around this limitation, we convert the total bytes to
  794. // the nearest 4MB value
  795. #define ONEMB 1048576 //1MB = 1048576 bytes.
  796. double nTotalMB = (double)(nTotalBytes / ONEMB);
  797. pids->llMem = (LONGLONG)((ceil(ceil(nTotalMB) / 4.0) * 4.0) * ONEMB);
  798. }
  799. pids->fShowProcName = _GetProcessorDescription(&pids->pi, &pids->fShowProcSpeed);
  800. PostMessage((HWND)lpParam, SYSCPL_ASYNC_COMPUTER_INFO, (WPARAM)pids, 0);
  801. }
  802. return 0;
  803. }
  804. VOID CompleteGeneralDlgInitialization(HWND hDlg, INITDLGSTRUCT* pids)
  805. {
  806. WCHAR oemfile[MAX_PATH];
  807. int ctlid;
  808. NTSTATUS Status;
  809. HKEY hkey;
  810. WCHAR szScratch1[64];
  811. WCHAR szScratch2[64];
  812. WCHAR szScratch3[64];
  813. DWORD cbData;
  814. // Do machine info
  815. ctlid = IDC_GEN_MACHINE_0; // start here and use controls as needed
  816. // if OEM name is present, show logo and check for phone support info
  817. if (SUCCEEDED(_GetOemFile(oemfile, ARRAYSIZE(oemfile), GETOEMFILE_OEMDATA)))
  818. {
  819. if (GetPrivateProfileString(c_szOemGenSection, c_szOemName, c_szEmpty,
  820. szScratch1, ARRAYSIZE(szScratch1), oemfile)) // we don't care about truncation
  821. {
  822. _SetMachineInfoLine(hDlg, ctlid++, szScratch1, FALSE);
  823. if(GetPrivateProfileString(c_szOemGenSection, c_szOemModel,
  824. c_szEmpty, szScratch1, ARRAYSIZE(szScratch1), oemfile)) // we don't care about truncation
  825. {
  826. _SetMachineInfoLine(hDlg, ctlid++, szScratch1, FALSE);
  827. }
  828. if (SUCCEEDED(StringCchCopy(szScratch2, ARRAYSIZE(szScratch2), c_szOemSupportLinePrefix)) &&
  829. SUCCEEDED(StringCchCat(szScratch2, ARRAYSIZE(szScratch2), TEXT("1"))))
  830. {
  831. if(GetPrivateProfileString(c_szOemSupportSection,
  832. szScratch2, c_szEmpty, szScratch1, ARRAYSIZE(szScratch1), oemfile)) // sure
  833. {
  834. HWND wnd = GetDlgItem(hDlg, IDC_GEN_OEM_SUPPORT);
  835. EnableWindow(wnd, TRUE);
  836. ShowWindow(wnd, SW_SHOW);
  837. }
  838. if (SUCCEEDED(_GetOemFile(oemfile, ARRAYSIZE(oemfile), GETOEMFILE_OEMIMAGE)) &&
  839. SetClearBitmap(GetDlgItem(hDlg, IDC_GEN_OEM_IMAGE), oemfile, SCB_FROMFILE))
  840. {
  841. ShowWindow(GetDlgItem(hDlg, IDC_GEN_OEM_NUDGE), SW_SHOWNA);
  842. ShowWindow(GetDlgItem(hDlg, IDC_GEN_MACHINE), SW_HIDE);
  843. }
  844. }
  845. }
  846. }
  847. // Get Processor Description
  848. _SetProcessorDescription(hDlg, &pids->pi, pids->fShowProcSpeed, pids->fShowProcName, &ctlid);
  849. // System identifier
  850. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_REGKEY_HARDWARE, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
  851. {
  852. cbData = sizeof(szScratch2);
  853. if (SHRegGetValue(hkey, NULL, c_szIndentifier, SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND, 0, (LPBYTE)szScratch2, &cbData) == ERROR_SUCCESS)
  854. {
  855. // Some OEMs put "AT/AT Compatible" as the System Identifier. Since this
  856. // is completely obsolete, we may want to have a feature that simply ignores
  857. // it.
  858. #ifdef FEATURE_IGNORE_ATCOMPAT
  859. if (StrCmpI(szScratch2, SZ_ATCOMPATIBLE))
  860. #endif // FEATURE_IGNORE_ATCOMPAT
  861. {
  862. _SetMachineInfoLine(hDlg, ctlid++, szScratch2, FALSE);
  863. }
  864. }
  865. RegCloseKey(hkey);
  866. }
  867. StrFormatByteSize(pids->llMem, szScratch1, ARRAYSIZE(szScratch1));
  868. LoadString(hInstance, IDS_XDOTX_MB, szScratch3, ARRAYSIZE(szScratch3));
  869. if (SUCCEEDED(StringCchPrintf(szScratch2, ARRAYSIZE(szScratch2), szScratch3, szScratch1)))
  870. {
  871. _SetMachineInfoLine(hDlg, ctlid++, szScratch2, FALSE);
  872. }
  873. // Physical address extension
  874. Status = RegOpenKey(
  875. HKEY_LOCAL_MACHINE,
  876. c_szMemoryManagement,
  877. &hkey
  878. );
  879. if (ERROR_SUCCESS == Status)
  880. {
  881. DWORD paeEnabled;
  882. Status = SHRegGetValue(hkey,
  883. NULL,
  884. c_szPhysicalAddressExtension,
  885. SRRF_RT_REG_DWORD,
  886. NULL,
  887. (LPBYTE)&paeEnabled,
  888. &cbData);
  889. if (ERROR_SUCCESS == Status &&
  890. sizeof(paeEnabled) == cbData &&
  891. 0 != paeEnabled) {
  892. LoadString(hInstance, IDS_PAE, szScratch1, ARRAYSIZE(szScratch1));
  893. _SetMachineInfoLine(hDlg, ctlid++, szScratch1, FALSE);
  894. }
  895. RegCloseKey(hkey);
  896. }
  897. AddOEMHyperLinks(hDlg, &ctlid);
  898. }
  899. HRESULT _DisplayHelp(LPHELPINFO lpHelpInfo)
  900. {
  901. // We will call WinHelp() unless it's an OEM link
  902. // because in that case, we don't know what to show.
  903. if ((g_nStartOfOEMLinks <= lpHelpInfo->iCtrlId) && // Is it outside of the IDC_GEN_MACHINE_* range used by OEM Links?
  904. (LAST_GEN_MACHINES_SLOT >= lpHelpInfo->iCtrlId) && // Is it outside of the IDC_GEN_MACHINE_* range used by OEM Links?
  905. (IDC_GEN_OEM_SUPPORT != lpHelpInfo->iCtrlId)) // Is it outside of the IDC_GEN_MACHINE_* range used by OEM Links?
  906. {
  907. int nIndex;
  908. // This item is an OEM link, so let's mark it as "No Help".
  909. for (nIndex = 0; nIndex < ARRAYSIZE(aGeneralHelpIds); nIndex++)
  910. {
  911. if ((DWORD)lpHelpInfo->iCtrlId == aGeneralHelpIds[nIndex])
  912. {
  913. aGeneralHelpIds[nIndex + 1] = NO_HELP;
  914. break;
  915. }
  916. nIndex++; // We need to skip every other entry because it's a list.
  917. }
  918. }
  919. WinHelp((HWND)lpHelpInfo->hItemHandle, HELP_FILE, HELP_WM_HELP, (DWORD_PTR) (LPSTR) aGeneralHelpIds);
  920. return S_OK;
  921. }
  922. //*************************************************************
  923. // Purpose: Dialog box procedure for general tab
  924. //
  925. // Parameters: hDlg - handle to the dialog box
  926. // uMsg - window message
  927. // wParam - wParam
  928. // lParam - lParam
  929. //
  930. // Return: TRUE if message was processed
  931. // FALSE if not
  932. //
  933. // Comments:
  934. //
  935. // History: Date Author Comment
  936. // 11/17/95 ericflo Created
  937. //*************************************************************
  938. INT_PTR APIENTRY GeneralDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  939. {
  940. switch (uMsg)
  941. {
  942. case WM_INITDIALOG:
  943. InitGeneralDlg(hDlg);
  944. break;
  945. case WM_NOTIFY:
  946. switch (((NMHDR FAR*)lParam)->code)
  947. {
  948. case PSN_APPLY:
  949. SetWindowLongPtr (hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
  950. return TRUE;
  951. default:
  952. return FALSE;
  953. }
  954. break;
  955. case WM_COMMAND:
  956. if (wParam == IDC_GEN_OEM_SUPPORT) {
  957. DialogBox(hInstance, MAKEINTRESOURCE(IDD_PHONESUP),
  958. GetParent(hDlg), PhoneSupportProc);
  959. }
  960. break;
  961. case WM_SYSCOLORCHANGE:
  962. {
  963. WCHAR oemfile[MAX_PATH];
  964. if (SUCCEEDED(_GetOemFile(oemfile, ARRAYSIZE(oemfile), GETOEMFILE_OEMIMAGE)))
  965. {
  966. SetClearBitmap(GetDlgItem(hDlg, IDC_GEN_OEM_IMAGE), oemfile, SCB_FROMFILE | SCB_REPLACEONLY);
  967. SetClearBitmap(GetDlgItem(hDlg, IDC_GEN_WINDOWS_IMAGE),
  968. IsLowColor(hDlg) ? MAKEINTRESOURCE(IDB_WINDOWS_256) : MAKEINTRESOURCE(IDB_WINDOWS), 0);
  969. }
  970. }
  971. break;
  972. case SYSCPL_ASYNC_COMPUTER_INFO:
  973. {
  974. if (wParam)
  975. {
  976. CompleteGeneralDlgInitialization(hDlg, (INITDLGSTRUCT*)wParam);
  977. LocalFree((HLOCAL)wParam);
  978. }
  979. }
  980. break;
  981. case WM_DESTROY:
  982. SetClearBitmap(GetDlgItem(hDlg, IDC_GEN_OEM_IMAGE), NULL, 0);
  983. SetClearBitmap(GetDlgItem(hDlg, IDC_GEN_WINDOWS_IMAGE), NULL, 0);
  984. break;
  985. case WM_HELP: // F1
  986. _DisplayHelp((LPHELPINFO) lParam);
  987. break;
  988. case WM_CONTEXTMENU: // right mouse click
  989. WinHelp((HWND) wParam, HELP_FILE, HELP_CONTEXTMENU,
  990. (DWORD_PTR) (LPSTR) aGeneralHelpIds);
  991. break;
  992. default:
  993. return FALSE;
  994. }
  995. return TRUE;
  996. }
  997. //*************************************************************
  998. //
  999. // PhoneSupportProc()
  1000. //
  1001. // Purpose: Dialog box procedure for OEM phone support dialog
  1002. //
  1003. // Parameters: hDlg - handle to the dialog box
  1004. // uMsg - window message
  1005. // wParam - wParam
  1006. // lParam - lParam
  1007. //
  1008. // Return: TRUE if message was processed
  1009. // FALSE if not
  1010. //
  1011. // Comments:
  1012. //
  1013. // History: Date Author Comment
  1014. // 11/17/95 ericflo Created
  1015. //
  1016. //*************************************************************
  1017. INT_PTR APIENTRY PhoneSupportProc(HWND hDlg, UINT uMsg,
  1018. WPARAM wParam, LPARAM lParam)
  1019. {
  1020. switch(uMsg) {
  1021. case WM_INITDIALOG:
  1022. {
  1023. HWND hwndEdit = GetDlgItem(hDlg, IDC_SUPPORT_TEXT);
  1024. WCHAR oemfile[MAX_PATH];
  1025. WCHAR szText[ 256 ];
  1026. WCHAR szLine[ 12 ];
  1027. LPWSTR pszEnd = szLine + lstrlen(c_szOemSupportLinePrefix);
  1028. if (SUCCEEDED(_GetOemFile(oemfile, ARRAYSIZE(oemfile), GETOEMFILE_OEMDATA)))
  1029. {
  1030. GetPrivateProfileString(c_szOemGenSection, c_szOemName, c_szEmpty,
  1031. szText, ARRAYSIZE(szText), oemfile);
  1032. SetWindowText(hDlg, szText);
  1033. if (SUCCEEDED(StringCchCopy(szLine, ARRAYSIZE(szLine), c_szOemSupportLinePrefix)))
  1034. {
  1035. SendMessage (hwndEdit, WM_SETREDRAW, FALSE, 0);
  1036. HRESULT hr = S_OK;
  1037. for(UINT i = 1; SUCCEEDED(hr); i++) // 1-based by design
  1038. {
  1039. hr = StringCchPrintf(pszEnd, ARRAYSIZE(szLine) - lstrlen(c_szOemSupportLinePrefix), TEXT("%u"), i);
  1040. if (SUCCEEDED(hr))
  1041. {
  1042. GetPrivateProfileString(c_szOemSupportSection,
  1043. szLine, c_szDefSupportLineText, szText, ARRAYSIZE(szText) - 2,
  1044. oemfile); // truncation fine
  1045. if(!lstrcmpi(szText, c_szDefSupportLineText)) // because we passed in szText as default, this
  1046. { // means GetPrivateProfileString failed
  1047. hr = E_FAIL;
  1048. }
  1049. else
  1050. {
  1051. hr = StringCchCat(szText, ARRAYSIZE(szText), c_szCRLF);
  1052. if (SUCCEEDED(hr))
  1053. {
  1054. SendMessage(hwndEdit, EM_SETSEL, (WPARAM)-1, (LPARAM)-1);
  1055. SendMessage(hwndEdit, EM_REPLACESEL, 0, (LPARAM)szText);
  1056. }
  1057. }
  1058. }
  1059. }
  1060. }
  1061. SendMessage (hwndEdit, WM_SETREDRAW, TRUE, 0);
  1062. }
  1063. break;
  1064. }
  1065. case WM_COMMAND:
  1066. switch (LOWORD(wParam)) {
  1067. case IDOK:
  1068. case IDCANCEL:
  1069. EndDialog(hDlg, 0);
  1070. break;
  1071. default:
  1072. return FALSE;
  1073. }
  1074. break;
  1075. default:
  1076. return FALSE;
  1077. }
  1078. return TRUE;
  1079. }