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.

598 lines
17 KiB

  1. /****************************************************************************\
  2. PRODKEY.C / OPK Wizard (SETUPMGR.EXE)
  3. Microsoft Confidential
  4. Copyright (c) Microsoft Corporation 2001-2002
  5. All rights reserved
  6. Source file for the OPK Wizard that contains the external and internal
  7. functions used by the "Product Key" wizard page.
  8. 09/2000 - Stephen Lodwick (STELO)
  9. Ported OPK Wizard to Whistler
  10. \****************************************************************************/
  11. //
  12. // Include File(s):
  13. //
  14. #include "pch.h"
  15. #include "wizard.h"
  16. #include "resource.h"
  17. //
  18. // Internal Defined Value(s):
  19. //
  20. #define INI_SEC_USERDATA _T("UserData")
  21. #define INI_KEY_PRODUCTKEY _T("ProductKey")
  22. #define INI_KEY_PRODUCTKEY_OLD _T("ProductID")
  23. #define MAX_PID_FIELD 5
  24. #define STR_DASH _T("-")
  25. #define STR_VALID_KEYCHARS _T("23456789BCDFGHJKMPQRTVWXY")
  26. //
  27. // Internal Function Prototype(s):
  28. //
  29. static BOOL OnInit(HWND, HWND, LPARAM);
  30. static void OnCommand(HWND, INT, HWND, UINT);
  31. static BOOL ValidData(HWND);
  32. static void SaveData(HWND);
  33. LONG CALLBACK PidEditSubWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  34. static void PidChar(HWND hwnd, INT id, HWND hwndCtl, WPARAM wParam, LPARAM lParam);
  35. static int PidPrev(int id);
  36. static int PidNext(int id);
  37. static BOOL PidPaste(HWND hwnd, INT id, HWND hwndCtl);
  38. //
  39. // External Function(s):
  40. //
  41. LRESULT CALLBACK ProductKeyDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  42. {
  43. switch (uMsg)
  44. {
  45. HANDLE_MSG(hwnd, WM_INITDIALOG, OnInit);
  46. HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);
  47. case WM_NOTIFY:
  48. switch ( ((NMHDR FAR *) lParam)->code )
  49. {
  50. case PSN_KILLACTIVE:
  51. case PSN_RESET:
  52. case PSN_WIZBACK:
  53. case PSN_WIZFINISH:
  54. break;
  55. case PSN_WIZNEXT:
  56. if ( ValidData(hwnd) )
  57. {
  58. SaveData(hwnd);
  59. // If we are currently in the wizard, press the finish button
  60. //
  61. if ( GET_FLAG(OPK_ACTIVEWIZ) )
  62. WIZ_PRESS(hwnd, PSBTN_FINISH);
  63. }
  64. else
  65. WIZ_FAIL(hwnd);
  66. break;
  67. case PSN_QUERYCANCEL:
  68. WIZ_CANCEL(hwnd);
  69. break;
  70. case PSN_HELP:
  71. WIZ_HELP();
  72. break;
  73. case PSN_SETACTIVE:
  74. g_App.dwCurrentHelp = IDH_OEMINFO;
  75. WIZ_BUTTONS(hwnd, GET_FLAG(OPK_OEM) ? (PSWIZB_BACK | PSWIZB_NEXT) : PSWIZB_NEXT);
  76. // Press next if the user is in auto mode
  77. //
  78. WIZ_NEXTONAUTO(hwnd, PSBTN_NEXT);
  79. // We should continue on to maint. wizard if in maintenance mode
  80. //
  81. //if ( GET_FLAG(OPK_MAINTMODE) )
  82. // WIZ_PRESS(hwnd, PSBTN_NEXT);
  83. break;
  84. }
  85. break;
  86. default:
  87. return FALSE;
  88. }
  89. return TRUE;
  90. }
  91. //
  92. // Internal Function(s):
  93. //
  94. static BOOL OnInit(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  95. {
  96. TCHAR szBuf[MAX_URL];
  97. LPTSTR lpCurrent,
  98. lpIndex;
  99. DWORD dwIndex = IDC_PRODUCT_KEY1;
  100. // Set the text limits, disable IME, and replace window proc for each edit box.
  101. //
  102. for ( dwIndex = IDC_PRODUCT_KEY1; dwIndex <= IDC_PRODUCT_KEY5; dwIndex++)
  103. {
  104. // Limit the edit box text
  105. //
  106. SendDlgItemMessage(hwnd, dwIndex, EM_LIMITTEXT, MAX_PID_FIELD, 0);
  107. // Turn off the IME
  108. //
  109. ImmAssociateContext(GetDlgItem(hwnd, dwIndex), NULL);
  110. // Replace the wndproc for the pid edit boxes.
  111. //
  112. PidEditSubWndProc(GetDlgItem(hwnd, dwIndex), WM_SUBWNDPROC, 0, 0L);
  113. }
  114. // Populate the Product Key fields
  115. //
  116. szBuf[0] = NULLCHR;
  117. GetPrivateProfileString(INI_SEC_USERDATA, INI_KEY_PRODUCTKEY, NULLSTR, szBuf, MAX_INFOLEN, GET_FLAG(OPK_BATCHMODE) ? g_App.szOpkWizIniFile : g_App.szUnattendTxtFile);
  118. // Check for the old ProductID as well
  119. //
  120. if ( szBuf[0] == NULLCHR )
  121. {
  122. GetPrivateProfileString(INI_SEC_USERDATA, INI_KEY_PRODUCTKEY_OLD, NULLSTR, szBuf, MAX_INFOLEN, GET_FLAG(OPK_BATCHMODE) ? g_App.szOpkWizIniFile : g_App.szUnattendTxtFile);
  123. }
  124. lpCurrent = szBuf;
  125. lpIndex = lpCurrent;
  126. // Reset the index for the next loop
  127. //
  128. dwIndex = IDC_PRODUCT_KEY1;
  129. // If we have not reached the end of the string and we haven't exceded the number of fields, then continue
  130. //
  131. while ( *lpCurrent && dwIndex < (IDC_PRODUCT_KEY1 + 5) )
  132. {
  133. // If we've reached a dash, then we have the next field in the product key
  134. //
  135. if ( *lpCurrent == _T('-') )
  136. {
  137. // Set the current char to null so lpIndex is a string
  138. //
  139. *lpCurrent = NULLCHR;
  140. // Set the proper Product Key field
  141. //
  142. SetWindowText(GetDlgItem(hwnd, dwIndex++), lpIndex);
  143. // Move lpIndex past the NULLCHR
  144. //
  145. lpIndex = lpCurrent + 1;
  146. }
  147. // Move to the next character
  148. //
  149. lpCurrent++;
  150. // We have to special case the last field because lpCurrent==NULLCHR and we would fall
  151. // through without populating the last field
  152. //
  153. if ( (*lpCurrent == NULLCHR) && *lpIndex)
  154. SetWindowText(GetDlgItem(hwnd, dwIndex++), lpIndex);
  155. }
  156. // Always return false to WM_INITDIALOG.
  157. //
  158. return FALSE;
  159. }
  160. static void OnCommand(HWND hwnd, INT id, HWND hwndCtl, UINT codeNotify)
  161. {
  162. if ( ( codeNotify == EN_CHANGE ) &&
  163. ( MAX_PID_FIELD == GetWindowTextLength(hwndCtl) ) )
  164. {
  165. if ( IDC_PRODUCT_KEY5 == id )
  166. {
  167. id = ID_MAINT_NEXT;
  168. hwnd = GetParent(hwnd);
  169. }
  170. else
  171. id = PidNext(id);
  172. if ( id )
  173. {
  174. hwndCtl = GetDlgItem(hwnd, id);
  175. SetFocus(hwndCtl);
  176. SendMessage(hwndCtl, EM_SETSEL, 0, (LPARAM) MAX_PID_FIELD);
  177. }
  178. }
  179. }
  180. static BOOL ValidData(HWND hwnd)
  181. {
  182. TCHAR szBuffer[MAX_PATH];
  183. BOOL bProductKey = FALSE;
  184. LPTSTR lpCurrent;
  185. DWORD dwIndex = IDC_PRODUCT_KEY1;
  186. UINT cb;
  187. //
  188. // Validate the product key
  189. //
  190. // Check to see if there was a key entered
  191. //
  192. while ( dwIndex < (IDC_PRODUCT_KEY1 + 5) && !bProductKey)
  193. {
  194. if ( (cb = GetDlgItemText(hwnd, dwIndex, szBuffer, STRSIZE(szBuffer)) != 0) )
  195. bProductKey = TRUE;
  196. dwIndex++;
  197. }
  198. // Make sure that each field has the proper number of characters
  199. //
  200. while ( dwIndex < (IDC_PRODUCT_KEY1 + 5) && bProductKey)
  201. {
  202. // Check to make sure that each field is five characters in length
  203. //
  204. if ( (cb = GetDlgItemText(hwnd, dwIndex, szBuffer, STRSIZE(szBuffer)) != 5) )
  205. {
  206. MsgBox(GetParent(hwnd), IDS_ERROR_PRODKEY_LEN, IDS_APPNAME, MB_ERRORBOX);
  207. SetFocus( GetDlgItem(hwnd, dwIndex) );
  208. return FALSE;
  209. }
  210. // Go to the next field
  211. //
  212. dwIndex++;
  213. }
  214. // Check to make sure that there are no invalid characters
  215. //
  216. dwIndex = IDC_PRODUCT_KEY1;
  217. while ( dwIndex < (IDC_PRODUCT_KEY1 + 5) && bProductKey)
  218. {
  219. // Check for invalid characters in the strings
  220. //
  221. GetDlgItemText(hwnd, dwIndex, szBuffer, STRSIZE(szBuffer));
  222. for ( lpCurrent = szBuffer; *lpCurrent; lpCurrent++)
  223. {
  224. if ( !(_tcschr(STR_VALID_KEYCHARS, *lpCurrent)) )
  225. {
  226. MsgBox(GetParent(hwnd), IDS_ERROR_PRODKEY_INV, IDS_APPNAME, MB_ERRORBOX);
  227. SetFocus( GetDlgItem(hwnd, dwIndex) );
  228. return FALSE;
  229. }
  230. }
  231. // Go to the next field
  232. //
  233. dwIndex++;
  234. }
  235. //
  236. // Return our search result.
  237. //
  238. return TRUE;
  239. }
  240. static void SaveData(HWND hwnd)
  241. {
  242. TCHAR szKeyBuf[32],
  243. szProductKey[MAX_PATH];
  244. HRESULT hrCat;
  245. // Save the product ID information
  246. //
  247. GetDlgItemText(hwnd, IDC_PRODUCT_KEY1, szKeyBuf, STRSIZE(szKeyBuf));
  248. lstrcpyn(szProductKey, szKeyBuf,AS(szProductKey));
  249. hrCat=StringCchCat(szProductKey, AS(szProductKey), STR_DASH);
  250. GetDlgItemText(hwnd, IDC_PRODUCT_KEY2, szKeyBuf, STRSIZE(szKeyBuf));
  251. hrCat=StringCchCat(szProductKey, AS(szProductKey), szKeyBuf);
  252. hrCat=StringCchCat(szProductKey, AS(szProductKey), STR_DASH);
  253. GetDlgItemText(hwnd, IDC_PRODUCT_KEY3, szKeyBuf, STRSIZE(szKeyBuf));
  254. hrCat=StringCchCat(szProductKey, AS(szProductKey), szKeyBuf);
  255. hrCat=StringCchCat(szProductKey, AS(szProductKey), STR_DASH);
  256. GetDlgItemText(hwnd, IDC_PRODUCT_KEY4, szKeyBuf, STRSIZE(szKeyBuf));
  257. hrCat=StringCchCat(szProductKey, AS(szProductKey), szKeyBuf);
  258. hrCat=StringCchCat(szProductKey, AS(szProductKey), STR_DASH);
  259. GetDlgItemText(hwnd, IDC_PRODUCT_KEY5, szKeyBuf, STRSIZE(szKeyBuf));
  260. hrCat=StringCchCat(szProductKey, AS(szProductKey), szKeyBuf);
  261. if ( lstrlen(szProductKey) <= 4 )
  262. szProductKey[0] = NULLCHR;
  263. // Write out the product key, if the user is not an OEM write NULL to the section just in case they populated the field in the inf
  264. //
  265. WritePrivateProfileString(INI_SEC_USERDATA, INI_KEY_PRODUCTKEY, ( szProductKey[0] ? szProductKey : NULL ), g_App.szUnattendTxtFile);
  266. WritePrivateProfileString(INI_SEC_USERDATA, INI_KEY_PRODUCTKEY, ( szProductKey[0] ? szProductKey : NULL ), g_App.szOpkWizIniFile);
  267. // if Product key specified, delete old ProductId
  268. if (szProductKey[0]) {
  269. WritePrivateProfileString(INI_SEC_USERDATA, INI_KEY_PRODUCTKEY_OLD, NULL, g_App.szUnattendTxtFile);
  270. WritePrivateProfileString(INI_SEC_USERDATA, INI_KEY_PRODUCTKEY_OLD, NULL, g_App.szOpkWizIniFile);
  271. }
  272. }
  273. LONG CALLBACK PidEditSubWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  274. {
  275. static FARPROC lpfnOldProc = NULL;
  276. switch ( msg )
  277. {
  278. case WM_SUBWNDPROC:
  279. lpfnOldProc = (FARPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
  280. SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) PidEditSubWndProc);
  281. return 1;
  282. case WM_KEYDOWN:
  283. // We want to let the VK_LEFT and VK_RIGHT WM_KEYDOWN messages to call the pid char
  284. // function because they don't generate a WM_CHAR message.
  285. //
  286. switch ( (TCHAR) wParam )
  287. {
  288. case VK_LEFT:
  289. case VK_RIGHT:
  290. PidChar(GetParent(hwnd), GetDlgCtrlID(hwnd), hwnd, (TCHAR) wParam, (DWORD) lParam);
  291. break;
  292. }
  293. break;
  294. case WM_CHAR:
  295. // Only need to do this for VK_BACK right now.
  296. //
  297. switch ( (TCHAR) wParam )
  298. {
  299. case VK_BACK:
  300. PidChar(GetParent(hwnd), GetDlgCtrlID(hwnd), hwnd, (TCHAR) wParam, (DWORD) lParam);
  301. break;
  302. }
  303. break;
  304. case WM_PASTE:
  305. if ( PidPaste(GetParent(hwnd), GetDlgCtrlID(hwnd), hwnd) )
  306. return 0;
  307. break;
  308. }
  309. if ( lpfnOldProc )
  310. return (LONG) CallWindowProc((WNDPROC) lpfnOldProc, hwnd, msg, wParam, lParam);
  311. else
  312. return 0;
  313. }
  314. static void PidChar(HWND hwnd, INT id, HWND hwndCtl, WPARAM wParam, LPARAM lParam)
  315. {
  316. DWORD dwPos = 0,
  317. dwLast;
  318. switch ( (TCHAR) wParam )
  319. {
  320. case VK_BACK:
  321. // Only if we are at the beginning of the box do
  322. // we want to switch to the previous one and delete
  323. // a character from the end of that one.
  324. //
  325. SendMessage(hwndCtl, EM_GETSEL, (WPARAM) &dwPos, 0L);
  326. if ( ( 0 == dwPos ) &&
  327. ( id = PidPrev(id) ) )
  328. {
  329. // First set the focus to the previous pid edit control.
  330. //
  331. hwndCtl = GetDlgItem(hwnd, id);
  332. SetFocus(hwndCtl);
  333. // Need to reset the caret to the end of the text box, or we will
  334. // do weird things.
  335. //
  336. SendMessage(hwndCtl, EM_SETSEL, MAX_PID_FIELD, (LPARAM) MAX_PID_FIELD);
  337. // Now pass the backspace key to the previous edit box.
  338. //
  339. PostMessage(hwndCtl, WM_CHAR, wParam, lParam);
  340. }
  341. break;
  342. case VK_LEFT:
  343. // Only if we are at the beginning of the box do
  344. // we want to switch to the previous one.
  345. //
  346. SendMessage(hwndCtl, EM_GETSEL, (WPARAM) &dwPos, 0L);
  347. if ( ( 0 == dwPos ) &&
  348. ( id = PidPrev(id) ) )
  349. {
  350. // First set the focus to the previous pid edit control.
  351. //
  352. hwndCtl = GetDlgItem(hwnd, id);
  353. SetFocus(hwndCtl);
  354. // Now make sure the caret is at the end of this edit box
  355. // if at MAX_PID_FIELD, or 2nd to last if it isn't and the
  356. // shift key isn't down.
  357. //
  358. if ( ( MAX_PID_FIELD <= (dwLast = (DWORD) GetWindowTextLength(hwndCtl)) ) &&
  359. ( 0 == (0XFF00 & GetKeyState(VK_SHIFT)) ) )
  360. {
  361. dwLast--;
  362. }
  363. SendMessage(hwndCtl, EM_SETSEL, dwLast, (LPARAM) dwLast);
  364. }
  365. break;
  366. case VK_RIGHT:
  367. // Need to first know where the caret is in the edit box.
  368. //
  369. SendMessage(hwndCtl, EM_GETSEL, 0, (LPARAM) &dwPos);
  370. // Now we need to know how much text is in the buffer now. If the numer
  371. // of characters is already at the max, we subtract one so that you can
  372. // we arror to the next box instead of the end of the string. Unless the
  373. // shift key is down, then we want them to be able to select the whole string.
  374. //
  375. dwLast = (DWORD) GetWindowTextLength(hwndCtl);
  376. if ( ( MAX_PID_FIELD == GetWindowTextLength(hwndCtl) ) &&
  377. ( 0 == (0XFF00 & GetKeyState(VK_SHIFT)) ) )
  378. {
  379. dwLast--;
  380. }
  381. // Now only if this is the last character do we switch to the next pid
  382. // edit box.
  383. //
  384. if ( ( dwLast <= dwPos ) &&
  385. ( id = PidNext(id) ) )
  386. {
  387. // First set the focus to the next pid edit control.
  388. //
  389. hwndCtl = GetDlgItem(hwnd, id);
  390. SetFocus(hwndCtl);
  391. // Now make sure the caret is at the beginning of this
  392. // edit box.
  393. //
  394. SendMessage(hwndCtl, EM_SETSEL, 0, 0L);
  395. }
  396. break;
  397. }
  398. }
  399. static int PidPrev(int id)
  400. {
  401. switch ( id )
  402. {
  403. case IDC_PRODUCT_KEY2:
  404. id = IDC_PRODUCT_KEY1;
  405. break;
  406. case IDC_PRODUCT_KEY3:
  407. id = IDC_PRODUCT_KEY2;
  408. break;
  409. case IDC_PRODUCT_KEY4:
  410. id = IDC_PRODUCT_KEY3;
  411. break;
  412. case IDC_PRODUCT_KEY5:
  413. id = IDC_PRODUCT_KEY4;
  414. break;
  415. default:
  416. id = 0;
  417. }
  418. return id;
  419. }
  420. static int PidNext(int id)
  421. {
  422. switch ( id )
  423. {
  424. case IDC_PRODUCT_KEY1:
  425. id = IDC_PRODUCT_KEY2;
  426. break;
  427. case IDC_PRODUCT_KEY2:
  428. id = IDC_PRODUCT_KEY3;
  429. break;
  430. case IDC_PRODUCT_KEY3:
  431. id = IDC_PRODUCT_KEY4;
  432. break;
  433. case IDC_PRODUCT_KEY4:
  434. id = IDC_PRODUCT_KEY5;
  435. break;
  436. default:
  437. id = 0;
  438. }
  439. return id;
  440. }
  441. static BOOL PidPaste(HWND hwnd, INT id, HWND hwndCtl)
  442. {
  443. BOOL bRet = FALSE;
  444. #ifdef _UNICODE
  445. UINT uFormat = CF_UNICODETEXT;
  446. #else // _UNICODE
  447. UINT uFormat = CF_TEXT;
  448. #endif // _UNICODE
  449. if ( IsClipboardFormatAvailable(uFormat) &&
  450. OpenClipboard(NULL) )
  451. {
  452. HGLOBAL hClip;
  453. LPTSTR lpText;
  454. DWORD dwFirst,
  455. dwLast,
  456. dwLength;
  457. SendMessage(hwndCtl, EM_GETSEL, (WPARAM) &dwFirst, (LPARAM) &dwLast);
  458. dwLength = (DWORD) GetWindowTextLength(hwndCtl);
  459. if ( ( dwLength <= (dwLast - dwFirst) ) &&
  460. ( hClip = GetClipboardData(uFormat) ) &&
  461. ( lpText = (LPTSTR) GlobalLock(hClip) ) )
  462. {
  463. LPTSTR lpSearch = lpText;
  464. TCHAR szPaste[MAX_PID_FIELD + 1];
  465. bRet = TRUE;
  466. do
  467. {
  468. hwndCtl = GetDlgItem(hwnd, id);
  469. SetFocus(hwndCtl);
  470. lstrcpyn(szPaste, lpSearch, AS(szPaste));
  471. SetWindowText(hwndCtl, szPaste);
  472. lpSearch = lpSearch + lstrlen(szPaste);
  473. if ( ( _T('-') == *lpSearch ) ||
  474. ( _T(' ') == *lpSearch ) )
  475. {
  476. lpSearch++;
  477. }
  478. }
  479. while ( *lpSearch && ( id = PidNext(id) ) );
  480. GlobalUnlock(hClip);
  481. }
  482. CloseClipboard();
  483. }
  484. return bRet;
  485. }