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.

1531 lines
42 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. pid.c
  5. Abstract:
  6. Product id routines.
  7. Author:
  8. Ted Miller (tedm) 6-Feb-1995
  9. Revision History:
  10. 13-Sep-1995 (t-stepl) - Check for unattended install
  11. --*/
  12. #include "setupp.h"
  13. #include <spidgen.h>
  14. #include <pencrypt.h>
  15. #pragma hdrstop
  16. CDTYPE CdType;
  17. //
  18. // Constants used for logging that are specific to this source file.
  19. //
  20. PCWSTR szPidKeyName = L"SYSTEM\\Setup\\Pid";
  21. PCWSTR szPidListKeyName = L"SYSTEM\\Setup\\PidList";
  22. PCWSTR szPidValueName = L"Pid";
  23. PCWSTR szPidSelectId = L"270";
  24. #if 0
  25. // msdn no longer exists.
  26. PCWSTR szPidMsdnId = L"335";
  27. #endif
  28. PCWSTR szPidOemId = L"OEM";
  29. PCWSTR szFinalPidKeyName = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
  30. PCWSTR szFinalPidValueName = L"ProductId";
  31. PCWSTR szSkuProfessionalFPP = L"B23-00079";
  32. PCWSTR szSkuProfessionalCCP = L"B23-00082";
  33. PCWSTR szSkuProfessionalSelect = L"B23-00305";
  34. PCWSTR szSkuProfessionalEval = L"B23-00084";
  35. PCWSTR szSkuServerFPP = L"C11-00016";
  36. PCWSTR szSkuServerCCP = L"C11-00027";
  37. PCWSTR szSkuServerSelect = L"C11-00222";
  38. PCWSTR szSkuServerEval = L"C11-00026";
  39. PCWSTR szSkuServerNFR = L"C11-00025";
  40. PCWSTR szSkuAdvServerFPP = L"C10-00010";
  41. PCWSTR szSkuAdvServerCCP = L"C10-00015";
  42. PCWSTR szSkuAdvServerSelect = L"C10-00098";
  43. PCWSTR szSkuAdvServerEval = L"C10-00014";
  44. PCWSTR szSkuAdvServerNFR = L"C10-00013";
  45. PCWSTR szSkuDTCFPP = L"C49-00001";
  46. PCWSTR szSkuDTCSelect = L"C49-00023";
  47. PCWSTR szSkuUnknown = L"A22-00001";
  48. PCWSTR szSkuOEM = L"OEM-93523";
  49. //
  50. // Flag indicating whether to display the product id dialog.
  51. //
  52. BOOL DisplayPidDialog = TRUE;
  53. //
  54. // Product ID.
  55. //
  56. WCHAR ProductId[MAX_PRODUCT_ID+1];
  57. PWSTR* Pid20Array = NULL;
  58. //
  59. // pid 30 product id
  60. //
  61. WCHAR Pid30Text[5][MAX_PID30_EDIT+1];
  62. WCHAR ProductId20FromProductId30[MAX_PRODUCT_ID+1];
  63. WCHAR Pid30Rpc[MAX_PID30_RPC+1];
  64. WCHAR Pid30Site[MAX_PID30_SITE+1];
  65. BYTE DigitalProductId[DIGITALPIDMAXLEN];
  66. //
  67. // global variable used for subclassing.
  68. //
  69. WNDPROC OldPidEditProc[5];
  70. //
  71. // Pid related flags
  72. //
  73. // BOOL DisplayPidCdDialog;
  74. // BOOL DisplayPidOemDialog;
  75. //
  76. // forward declarations
  77. //
  78. CDTYPE
  79. MiniSetupGetCdType(
  80. LPCWSTR Value
  81. )
  82. /*++
  83. Routine Description:
  84. Get the right CD type during Mini-Setup. PidGen changes the channel ID
  85. for the value at HKLM\Software\Microsoft\Windows NT\CurrentVersion!ProductId,
  86. we have to preserve and rely on the value at HKLM\SYSTEM\Setup\Pid!Pid
  87. Return Value:
  88. the CdType.
  89. --*/
  90. {
  91. CDTYPE RetVal;
  92. WCHAR TmpPid30Site[MAX_PID30_SITE+1];
  93. HKEY Key = NULL;
  94. DWORD cbData;
  95. WCHAR Data[ MAX_PATH + 1];
  96. DWORD Type;
  97. cbData = sizeof(Data);
  98. if ( ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  99. szPidKeyName,
  100. 0,
  101. KEY_READ,
  102. &Key ) == ERROR_SUCCESS ) &&
  103. ( RegQueryValueEx( Key,
  104. szPidValueName,
  105. 0,
  106. &Type,
  107. ( LPBYTE )Data,
  108. &cbData ) == ERROR_SUCCESS ) )
  109. {
  110. wcsncpy(TmpPid30Site, Data + MAX_PID30_RPC, MAX_PID30_SITE+1);
  111. }
  112. else
  113. {
  114. if (Value != NULL)
  115. {
  116. wcsncpy(TmpPid30Site, Value, MAX_PID30_SITE+1);
  117. }
  118. else
  119. {
  120. TmpPid30Site[0] = L'\0';
  121. }
  122. }
  123. TmpPid30Site[MAX_PID30_SITE] = (WCHAR)'\0';
  124. if (_wcsicmp( TmpPid30Site, szPidSelectId ) == 0) {
  125. RetVal = CDSelect;
  126. } else if( _wcsicmp( TmpPid30Site, szPidOemId ) == 0 ) {
  127. RetVal = CDOem;
  128. } else {
  129. RetVal = CDRetail;
  130. }
  131. if (Key != NULL)
  132. {
  133. RegCloseKey(Key);
  134. }
  135. return RetVal;
  136. }
  137. PCWSTR GetStockKeepingUnit(
  138. PWCHAR pMPC,
  139. UINT ProductType,
  140. CDTYPE CdType
  141. )
  142. /*++
  143. Routine Description:
  144. This returns the Stock Keeping Unit based off the MPC.
  145. Arguments:
  146. pMPC - pointer to 5 digit MPC code, null terminated.
  147. ProductType - Product type flag, tells us if this is a workataion or server sku.
  148. CdType - one of CDTYPE enum
  149. Return Value:
  150. Returns pointer to sku.
  151. If no match found returns szSkuUnknown.
  152. --*/
  153. {
  154. // check for eval
  155. if (!_wcsicmp(Pid30Rpc,EVAL_MPC) || !_wcsicmp(Pid30Rpc,DOTNET_EVAL_MPC)){
  156. // this is eval media ...
  157. if (ProductType == PRODUCT_WORKSTATION){
  158. return (szSkuProfessionalEval);
  159. } // else
  160. // else it is server or advanced server. I don't think that at this point
  161. // we can easily tell the difference. Since it's been said that having the
  162. // correct sku is not critically important, I shall give them both the sku
  163. // code of server
  164. return (szSkuServerEval);
  165. }
  166. // check for NFR
  167. if (!_wcsicmp(Pid30Rpc,SRV_NFR_MPC)){
  168. return (szSkuServerNFR);
  169. }
  170. if (!_wcsicmp(Pid30Rpc,ASRV_NFR_MPC)){
  171. return (szSkuAdvServerNFR);
  172. }
  173. if (CdType == CDRetail) {
  174. if (!_wcsicmp(Pid30Rpc,L"51873")){
  175. return (szSkuProfessionalFPP);
  176. }
  177. if (!_wcsicmp(Pid30Rpc,L"51874")){
  178. return (szSkuProfessionalCCP);
  179. }
  180. if (!_wcsicmp(Pid30Rpc,L"51876")){
  181. return (szSkuServerFPP);
  182. }
  183. if (!_wcsicmp(Pid30Rpc,L"51877")){
  184. return (szSkuServerCCP);
  185. }
  186. if (!_wcsicmp(Pid30Rpc,L"51879")){
  187. return (szSkuAdvServerFPP);
  188. }
  189. if (!_wcsicmp(Pid30Rpc,L"51880")){
  190. return (szSkuAdvServerCCP);
  191. }
  192. if (!_wcsicmp(Pid30Rpc,L"51891")){
  193. return (szSkuDTCFPP);
  194. }
  195. } else if (CdType == CDSelect) {
  196. if (!_wcsicmp(Pid30Rpc,L"51873")){
  197. return (szSkuProfessionalSelect);
  198. }
  199. if (!_wcsicmp(Pid30Rpc,L"51876")){
  200. return (szSkuServerSelect);
  201. }
  202. if (!_wcsicmp(Pid30Rpc,L"51879")){
  203. return (szSkuAdvServerSelect);
  204. }
  205. if (!_wcsicmp(Pid30Rpc,L"51891")){
  206. return (szSkuDTCSelect);
  207. }
  208. }
  209. return (szSkuUnknown);
  210. }
  211. BOOL
  212. ValidateAndSetPid30(
  213. VOID
  214. )
  215. /*++
  216. Routine Description:
  217. Using the Pid30Text global variables, check if we have a valid id.
  218. This generates the pid30 digital product id and pid20 string id, which
  219. we set into DigitalProductId and ProductId20FromProductId30 globals
  220. Arguments:
  221. None.
  222. Return Value:
  223. TRUE if pid was valid. Set's the globals correctly on success, zero's them out on failure
  224. --*/
  225. {
  226. WCHAR tmpPid30String[5+ 5*MAX_PID30_EDIT];
  227. BOOL rc;
  228. PCWSTR pszSkuCode;
  229. // Since we require a PID in the Select media too, we need to fill the string
  230. wsprintf( tmpPid30String, L"%s-%s-%s-%s-%s",
  231. Pid30Text[0],Pid30Text[1],Pid30Text[2],Pid30Text[3],Pid30Text[4]);
  232. pszSkuCode = GetStockKeepingUnit( Pid30Rpc, ProductType, CdType);
  233. *(LPDWORD)DigitalProductId = sizeof(DigitalProductId);
  234. rc = SetupPIDGenW(
  235. tmpPid30String, // [IN] 25-character Secure CD-Key (gets U-Cased)
  236. Pid30Rpc, // [IN] 5-character Release Product Code
  237. pszSkuCode, // [IN] Stock Keeping Unit (formatted like 123-12345)
  238. (CdType == CDOem), // [IN] is this an OEM install?
  239. ProductId20FromProductId30, // [OUT] PID 2.0, pass in ptr to 24 character array
  240. DigitalProductId, // [OUT] pointer to binary PID3 buffer. First DWORD is the length
  241. NULL); // [OUT] optional ptr to Compliance Checking flag (can be NULL)
  242. #ifdef PRERELEASE
  243. SetupDebugPrint2(L"Pidgen returns for PID:%s and MPC:%s\n", tmpPid30String, Pid30Rpc);
  244. #endif
  245. if (!rc) {
  246. #ifdef PRERELEASE
  247. SetupDebugPrint1(L"Pidgen returns %d for PID.n", rc);
  248. #endif
  249. ZeroMemory(Pid30Text[0],5*(MAX_PID30_EDIT+1));
  250. }
  251. else
  252. {
  253. if (*ProductId20FromProductId30 == L'\0')
  254. {
  255. SetupDebugPrint(L"ProductId20FromProductId30 is empty after call into pidgen and pidgen returns OK\n");
  256. }
  257. if (*DigitalProductId == 0)
  258. {
  259. SetupDebugPrint(L"DigitalProductId is empty after call into pidgen and pidgen returns OK\n");
  260. }
  261. }
  262. return rc;
  263. }
  264. LRESULT
  265. CALLBACK
  266. PidEditSubProc(
  267. IN HWND hwnd,
  268. IN UINT msg,
  269. IN WPARAM wParam,
  270. IN LPARAM lParam
  271. )
  272. /*++
  273. Routine Description:
  274. Edit control subclass routine, sets the focus to the correct edit box when the user enters text.
  275. This routine assumes that the pid controls ids are in sequential order.
  276. Arguments:
  277. Standard window proc arguments.
  278. Returns:
  279. Message-dependent value.
  280. --*/
  281. {
  282. DWORD len, id;
  283. //
  284. // eat spaces
  285. //
  286. if ((msg == WM_CHAR) && (wParam == VK_SPACE)) {
  287. return(0);
  288. }
  289. if ((msg == WM_CHAR)) {
  290. //
  291. // First override: if we have the max characters in the current edit
  292. // box, let's post the character to the next box and set focus to that
  293. // control.
  294. //
  295. if ( ( (len = (DWORD)SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0)) == MAX_PID30_EDIT) &&
  296. ((wParam != VK_DELETE) && (wParam != VK_BACK)) ) {
  297. //
  298. // set the focus to the next edit control and post the character
  299. // to that edit control
  300. //
  301. if ((id = GetDlgCtrlID(hwnd)) < IDT_EDIT_PID5 ) {
  302. DWORD start, end;
  303. SendMessage(hwnd, EM_GETSEL, (WPARAM)&start,(LPARAM)&end);
  304. if (start == end) {
  305. HWND hNext = GetDlgItem(GetParent(hwnd),id+1);
  306. SetFocus(hNext);
  307. SendMessage(hNext, EM_SETSEL, (WPARAM)-1,(LPARAM)-1);
  308. PostMessage( GetDlgItem(GetParent(hwnd),id+1), WM_CHAR, wParam, lParam );
  309. return(0);
  310. }
  311. }
  312. //
  313. // Second override: if the user hit's a delete key and they are at the
  314. // the start of an edit box, then post the delete to the previous edit
  315. // box.
  316. //
  317. } else if ( (len == 0) &&
  318. ((id = GetDlgCtrlID(hwnd)) > IDT_EDIT_PID1) &&
  319. ((wParam == VK_DELETE) || (wParam == VK_BACK) )) {
  320. //
  321. // set the focus to the previous edit control and post the command
  322. // to that edit control
  323. //
  324. HWND hPrev = GetDlgItem(GetParent(hwnd),id-1);
  325. SetFocus(hPrev);
  326. SendMessage(hPrev, EM_SETSEL, (WPARAM)MAX_PID30_EDIT-1,(LPARAM)MAX_PID30_EDIT);
  327. PostMessage( hPrev, WM_CHAR, wParam, lParam );
  328. return(0);
  329. //
  330. // Third override: if posting this message will give us the maximum
  331. // characters in our in the current edit box, let's post the character
  332. // to the next box and set focus to that control.
  333. //
  334. } else if ( (len == MAX_PID30_EDIT-1) &&
  335. ((wParam != VK_DELETE) && (wParam != VK_BACK)) &&
  336. ((id = GetDlgCtrlID(hwnd)) < IDT_EDIT_PID5) ) {
  337. DWORD start, end;
  338. SendMessage(hwnd, EM_GETSEL, (WPARAM)&start,(LPARAM)&end);
  339. if (start == end) {
  340. HWND hNext = GetDlgItem(GetParent(hwnd),id+1);
  341. //
  342. // post the message to the edit box
  343. //
  344. CallWindowProc(OldPidEditProc[GetDlgCtrlID(hwnd)-IDT_EDIT_PID1],hwnd,msg,wParam,lParam);
  345. //
  346. // now set the focus to the next edit control
  347. //
  348. SetFocus(hNext);
  349. SendMessage(hNext, EM_SETSEL, (WPARAM)-1,(LPARAM)-1);
  350. return(0);
  351. }
  352. }
  353. }
  354. return(CallWindowProc(OldPidEditProc[GetDlgCtrlID(hwnd)-IDT_EDIT_PID1],hwnd,msg,wParam,lParam));
  355. }
  356. INT_PTR
  357. CALLBACK
  358. Pid30CDDlgProc(
  359. IN HWND hdlg,
  360. IN UINT msg,
  361. IN WPARAM wParam,
  362. IN LPARAM lParam
  363. )
  364. /*++
  365. Routine Description:
  366. Dialog procedure for the CD Retail Pid dialog.
  367. Arguments:
  368. hWnd - a handle to the dialog proceedure.
  369. msg - the message passed from Windows.
  370. wParam - extra message dependent data.
  371. lParam - extra message dependent data.
  372. Return Value:
  373. TRUE if the value was edited. FALSE if cancelled or if no
  374. changes were made.
  375. --*/
  376. {
  377. NMHDR *NotifyParams;
  378. DWORD i,dwRet;
  379. switch(msg) {
  380. case WM_INITDIALOG: {
  381. if( UiTest ) {
  382. //
  383. // If testing the wizard, make sure that the PidOEM page is
  384. // displayed
  385. //
  386. CdType = CDRetail;
  387. DisplayPidDialog = TRUE;
  388. }
  389. // Disable the IME on the PID edit controls
  390. for (i = 0; i < 5;i++)
  391. {
  392. ImmAssociateContext(GetDlgItem(hdlg, IDT_EDIT_PID1+i), (HIMC)NULL);
  393. }
  394. //
  395. // subclass the edit controls and limit the number of characters
  396. //
  397. for (i = 0; i < 5;i++) {
  398. SendDlgItemMessage(hdlg,IDT_EDIT_PID1+i,EM_LIMITTEXT,MAX_PID30_EDIT,0);
  399. OldPidEditProc[i] = (WNDPROC)GetWindowLongPtr(GetDlgItem(hdlg, IDT_EDIT_PID1+i),GWLP_WNDPROC);
  400. SetWindowLongPtr(GetDlgItem(hdlg, IDT_EDIT_PID1+i),GWLP_WNDPROC,(LONG_PTR)PidEditSubProc);
  401. }
  402. break;
  403. }
  404. case WM_IAMVISIBLE:
  405. MessageBoxFromMessage(hdlg,MSG_PID_IS_INVALID,NULL,
  406. IDS_ERROR,MB_OK|MB_ICONSTOP);
  407. break;
  408. case WM_SIMULATENEXT:
  409. // Simulate the next button somehow
  410. PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
  411. break;
  412. case WM_NOTIFY:
  413. NotifyParams = (NMHDR *)lParam;
  414. switch(NotifyParams->code) {
  415. case PSN_SETACTIVE:
  416. TESTHOOK(506);
  417. BEGIN_SECTION(L"Your (Retail) Product Key Page");
  418. if(DisplayPidDialog && CdType == CDRetail) {
  419. // Page becomes active, make page visible.
  420. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  421. SetWizardButtons(hdlg,WizPageProductIdCd);
  422. SendDlgItemMessage(hdlg,IDT_EDIT_PID1,EM_SETSEL,0,-1);
  423. SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
  424. } else {
  425. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
  426. END_SECTION(L"Your (Retail) Product Key Page");
  427. break;
  428. }
  429. if(Unattended) {
  430. if (UnattendSetActiveDlg(hdlg,IDD_PID_CD))
  431. {
  432. // Page becomes active, make page visible.
  433. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  434. }
  435. }
  436. break;
  437. case PSN_WIZNEXT:
  438. case PSN_WIZFINISH:
  439. for (i = 0; i<5; i++) {
  440. GetDlgItemText(hdlg,IDT_EDIT_PID1+i,Pid30Text[i],MAX_PID30_EDIT+1);
  441. }
  442. if (!ValidateAndSetPid30()) {
  443. // failure
  444. // Tell user that the Pid is not valid, and
  445. // don't allow next page to be activated.
  446. //
  447. if (Unattended) {
  448. UnattendErrorDlg( hdlg, IDD_PID_CD );
  449. }
  450. MessageBoxFromMessage(hdlg,MSG_PID_IS_INVALID,NULL,
  451. IDS_ERROR,MB_OK|MB_ICONSTOP);
  452. SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
  453. if(!UiTest) {
  454. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
  455. }
  456. } else {
  457. // success
  458. //
  459. // Since the Pid is already built, don't let this dialog
  460. // be displayed in the future.
  461. //
  462. // DisplayPidDialog = FALSE;
  463. //
  464. // Allow next page to be activated.
  465. //
  466. dwRet = SetCurrentProductIdInRegistry();
  467. if (dwRet != NOERROR) {
  468. SetuplogError(
  469. LogSevError,
  470. SETUPLOG_USE_MESSAGEID,
  471. MSG_LOG_PID_CANT_WRITE_PID,
  472. dwRet,NULL,NULL);
  473. }
  474. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,0);
  475. }
  476. break;
  477. case PSN_KILLACTIVE:
  478. WizardKillHelp(hdlg);
  479. SetWindowLongPtr(hdlg,DWLP_MSGRESULT, FALSE);
  480. END_SECTION(L"Your (Retail) Product Key Page");
  481. break;
  482. case PSN_HELP:
  483. WizardBringUpHelp(hdlg,WizPageProductIdCd);
  484. break;
  485. default:
  486. break;
  487. }
  488. break;
  489. default:
  490. return(FALSE);
  491. }
  492. return(TRUE);
  493. }
  494. INT_PTR
  495. CALLBACK
  496. Pid30OemDlgProc(
  497. IN HWND hdlg,
  498. IN UINT msg,
  499. IN WPARAM wParam,
  500. IN LPARAM lParam
  501. )
  502. /*++
  503. Routine Description:
  504. Dialog procedure for the OEM Pid dialog.
  505. Arguments:
  506. hWnd - a handle to the dialog proceedure.
  507. msg - the message passed from Windows.
  508. wParam - extra message dependent data.
  509. lParam - extra message dependent data.
  510. Return Value:
  511. TRUE if the value was edited. FALSE if cancelled or if no
  512. changes were made.
  513. --*/
  514. {
  515. NMHDR *NotifyParams;
  516. DWORD i,dwRet;
  517. switch(msg) {
  518. case WM_INITDIALOG: {
  519. if( UiTest ) {
  520. //
  521. // If testing the wizard, make sure that the PidOEM page is
  522. // displayed
  523. //
  524. CdType = CDOem;
  525. DisplayPidDialog = TRUE;
  526. }
  527. // Disable the IME on the PID edit controls
  528. for (i = 0; i < 5;i++)
  529. {
  530. ImmAssociateContext(GetDlgItem(hdlg, IDT_EDIT_PID1+i), (HIMC)NULL);
  531. }
  532. //
  533. // subclass the edit controls and limit the number of characters
  534. //
  535. for (i = 0; i < 5;i++) {
  536. SendDlgItemMessage(hdlg,IDT_EDIT_PID1+i,EM_LIMITTEXT,MAX_PID30_EDIT,0);
  537. OldPidEditProc[i] = (WNDPROC)GetWindowLongPtr(GetDlgItem(hdlg, IDT_EDIT_PID1+i),GWLP_WNDPROC);
  538. SetWindowLongPtr(GetDlgItem(hdlg, IDT_EDIT_PID1+i),GWLP_WNDPROC,(LONG_PTR)PidEditSubProc);
  539. }
  540. break;
  541. }
  542. case WM_SIMULATENEXT:
  543. // Simulate the next button somehow
  544. PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
  545. break;
  546. case WM_IAMVISIBLE:
  547. MessageBoxFromMessage(hdlg,MSG_PID_OEM_IS_INVALID,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
  548. break;
  549. case WM_NOTIFY:
  550. NotifyParams = (NMHDR *)lParam;
  551. switch(NotifyParams->code) {
  552. case PSN_SETACTIVE:
  553. TESTHOOK(507);
  554. BEGIN_SECTION(L"Your (OEM) Product Key Page");
  555. if(DisplayPidDialog && CdType == CDOem) {
  556. // Page becomes active, make page visible.
  557. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  558. SetWizardButtons(hdlg,WizPageProductIdCd);
  559. SendDlgItemMessage(hdlg,IDT_EDIT_PID1,EM_SETSEL,0,-1);
  560. SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
  561. } else {
  562. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
  563. END_SECTION(L"Your (OEM) Product Key Page");
  564. break;
  565. }
  566. if(Unattended) {
  567. if (UnattendSetActiveDlg( hdlg, IDD_PID_OEM ))
  568. {
  569. // Page becomes active, make page visible.
  570. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  571. }
  572. }
  573. break;
  574. case PSN_WIZNEXT:
  575. case PSN_WIZFINISH:
  576. for (i = 0; i<5; i++) {
  577. GetDlgItemText(hdlg,IDT_EDIT_PID1+i,Pid30Text[i],MAX_PID30_EDIT+1);
  578. }
  579. if (!ValidateAndSetPid30()) {
  580. // failure
  581. //
  582. // Tell user that the Pid is not valid, and
  583. // don't allow next page to be activated.
  584. //
  585. if (Unattended) {
  586. UnattendErrorDlg( hdlg, IDD_PID_OEM );
  587. } // if
  588. MessageBoxFromMessage(hdlg,MSG_PID_OEM_IS_INVALID,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
  589. SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
  590. if(!UiTest) {
  591. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
  592. }
  593. } else {
  594. // success
  595. //
  596. // The Pid is valid.
  597. //
  598. //
  599. //
  600. // Since the Pid is already built, don't let this dialog
  601. // be displayed in the future.
  602. //
  603. // DisplayPidDialog = FALSE;
  604. // Allow next page to be activated.
  605. //
  606. dwRet = SetCurrentProductIdInRegistry();
  607. if (dwRet != NOERROR) {
  608. SetuplogError(
  609. LogSevError,
  610. SETUPLOG_USE_MESSAGEID,
  611. MSG_LOG_PID_CANT_WRITE_PID,
  612. dwRet,NULL,NULL);
  613. }
  614. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,0);
  615. }
  616. break;
  617. case PSN_KILLACTIVE:
  618. WizardKillHelp(hdlg);
  619. SetWindowLongPtr(hdlg,DWLP_MSGRESULT, FALSE );
  620. END_SECTION(L"Your (OEM) Product Key Page");
  621. break;
  622. case PSN_HELP:
  623. WizardBringUpHelp(hdlg,WizPageProductIdCd);
  624. break;
  625. default:
  626. break;
  627. }
  628. break;
  629. default:
  630. return(FALSE);
  631. }
  632. return(TRUE);
  633. }
  634. INT_PTR
  635. CALLBACK
  636. Pid30SelectDlgProc(
  637. IN HWND hdlg,
  638. IN UINT msg,
  639. IN WPARAM wParam,
  640. IN LPARAM lParam
  641. )
  642. /*++
  643. Routine Description:
  644. Dialog procedure for the OEM Pid dialog.
  645. Arguments:
  646. hWnd - a handle to the dialog proceedure.
  647. msg - the message passed from Windows.
  648. wParam - extra message dependent data.
  649. lParam - extra message dependent data.
  650. Return Value:
  651. TRUE if the value was edited. FALSE if cancelled or if no
  652. changes were made.
  653. --*/
  654. {
  655. NMHDR *NotifyParams;
  656. DWORD i,dwRet;
  657. switch(msg) {
  658. case WM_INITDIALOG: {
  659. if( UiTest ) {
  660. //
  661. // If testing the wizard, make sure that the PidOEM page is
  662. // displayed
  663. //
  664. CdType = CDSelect;
  665. DisplayPidDialog = TRUE;
  666. }
  667. // Disable the IME on the PID edit controls
  668. for (i = 0; i < 5;i++)
  669. {
  670. ImmAssociateContext(GetDlgItem(hdlg, IDT_EDIT_PID1+i), (HIMC)NULL);
  671. }
  672. //
  673. // subclass the edit controls and limit the number of characters
  674. //
  675. for (i = 0; i < 5;i++) {
  676. SendDlgItemMessage(hdlg,IDT_EDIT_PID1+i,EM_LIMITTEXT,MAX_PID30_EDIT,0);
  677. OldPidEditProc[i] = (WNDPROC)GetWindowLongPtr(GetDlgItem(hdlg, IDT_EDIT_PID1+i),GWLP_WNDPROC);
  678. SetWindowLongPtr(GetDlgItem(hdlg, IDT_EDIT_PID1+i),GWLP_WNDPROC,(LONG_PTR)PidEditSubProc);
  679. }
  680. break;
  681. }
  682. case WM_SIMULATENEXT:
  683. // Simulate the next button somehow
  684. PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
  685. break;
  686. case WM_IAMVISIBLE:
  687. MessageBoxFromMessage(hdlg,MSG_PID_OEM_IS_INVALID,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
  688. break;
  689. case WM_NOTIFY:
  690. NotifyParams = (NMHDR *)lParam;
  691. switch(NotifyParams->code) {
  692. case PSN_SETACTIVE:
  693. TESTHOOK(508);
  694. BEGIN_SECTION(L"Your (Select) Product Key Page");
  695. if(DisplayPidDialog && CdType == CDSelect) {
  696. // Page becomes active, make page visible.
  697. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  698. SetWizardButtons(hdlg,WizPageProductIdCd);
  699. SendDlgItemMessage(hdlg,IDT_EDIT_PID1,EM_SETSEL,0,-1);
  700. SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
  701. } else {
  702. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
  703. END_SECTION(L"Your (Select) Product Key Page");
  704. break;
  705. }
  706. if(Unattended) {
  707. if (UnattendSetActiveDlg( hdlg, IDD_PID_SELECT ))
  708. {
  709. // Page becomes active, make page visible.
  710. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  711. }
  712. }
  713. break;
  714. case PSN_WIZNEXT:
  715. case PSN_WIZFINISH:
  716. for (i = 0; i<5; i++) {
  717. GetDlgItemText(hdlg,IDT_EDIT_PID1+i,Pid30Text[i],MAX_PID30_EDIT+1);
  718. }
  719. if (!ValidateAndSetPid30()) {
  720. // failure
  721. //
  722. // Tell user that the Pid is not valid, and
  723. // don't allow next page to be activated.
  724. //
  725. if (Unattended) {
  726. UnattendErrorDlg( hdlg, IDD_PID_SELECT );
  727. } // if
  728. MessageBoxFromMessage(hdlg,MSG_PID_OEM_IS_INVALID,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
  729. SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
  730. if(!UiTest) {
  731. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
  732. }
  733. } else {
  734. // success
  735. //
  736. // The Pid is valid.
  737. //
  738. //
  739. //
  740. // Since the Pid is already built, don't let this dialog
  741. // be displayed in the future.
  742. //
  743. // DisplayPidDialog = FALSE;
  744. // Allow next page to be activated.
  745. //
  746. dwRet = SetCurrentProductIdInRegistry();
  747. if (dwRet != NOERROR) {
  748. SetuplogError(
  749. LogSevError,
  750. SETUPLOG_USE_MESSAGEID,
  751. MSG_LOG_PID_CANT_WRITE_PID,
  752. dwRet,NULL,NULL);
  753. }
  754. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,0);
  755. }
  756. break;
  757. case PSN_KILLACTIVE:
  758. WizardKillHelp(hdlg);
  759. SetWindowLongPtr(hdlg,DWLP_MSGRESULT, FALSE );
  760. END_SECTION(L"Your (Select) Product Key Page");
  761. break;
  762. case PSN_HELP:
  763. WizardBringUpHelp(hdlg,WizPageProductIdCd);
  764. break;
  765. default:
  766. break;
  767. }
  768. break;
  769. default:
  770. return(FALSE);
  771. }
  772. return(TRUE);
  773. }
  774. BOOL
  775. SetPid30Variables(
  776. PWSTR Buffer
  777. )
  778. {
  779. LPWSTR ptr;
  780. UINT i;
  781. //
  782. // all install cases are the same for pid3.0
  783. // Check that the string specified on the unattended script file
  784. // represents a valid 25 digit product id:
  785. //
  786. // 1 2 3 4 5 - 1 2 3 4 5 - 1 2 3 4 5 - 1 2 3 4 5 - 1 2 3 4 5
  787. // 0 1 2 3 4 5 6 7 8 9 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2
  788. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
  789. //
  790. // As a first validation test, we verify that the length is correct,
  791. // then we check if the "-" characters are in the correct place
  792. //
  793. //
  794. if( ( wcslen( Buffer ) != (4+ MAX_PID30_EDIT*5)) ||
  795. ( Buffer[5] != (WCHAR)L'-' ) ||
  796. ( Buffer[11] != (WCHAR)L'-' ) ||
  797. ( Buffer[17] != (WCHAR)L'-' ) ||
  798. ( Buffer[23] != (WCHAR)L'-' )
  799. ) {
  800. //
  801. // The Pid in the unattended script file is invalid.
  802. //
  803. return(FALSE);
  804. }
  805. for (i = 0;i<5;i++) {
  806. //
  807. // quintet i
  808. //
  809. ptr = &Buffer[i*(MAX_PID30_EDIT+1)];
  810. wcsncpy(Pid30Text[i], ptr, MAX_PID30_EDIT+1 );
  811. Pid30Text[i][MAX_PID30_EDIT] = (WCHAR)L'\0';
  812. }
  813. return TRUE;
  814. }
  815. BOOL
  816. SetPid30FromAnswerFile(
  817. )
  818. /*++
  819. Routine Description:
  820. set the pid3.0 globals based on unattend file parameter, if it exists.
  821. Arguments:
  822. None.
  823. Return Value:
  824. --*/
  825. {
  826. WCHAR Buffer[MAX_BUF];
  827. DWORD dwRet;
  828. if (!GetPrivateProfileString(pwUserData,
  829. pwProductKey,
  830. L"",
  831. Buffer,
  832. sizeof(Buffer)/sizeof(WCHAR),
  833. AnswerFile)) {
  834. return(FALSE);
  835. }
  836. if (!Buffer || !*Buffer) {
  837. return(FALSE);
  838. }
  839. // Buffer contains the Product ID
  840. // Is the PID encrypted?
  841. if (lstrlen(Buffer) > (4 + MAX_PID30_EDIT*5))
  842. {
  843. LPWSTR szDecryptedPID = NULL;
  844. if (ValidateEncryptedPID(Buffer, &szDecryptedPID) == S_OK)
  845. {
  846. lstrcpyn(Buffer, szDecryptedPID, sizeof(Buffer)/sizeof(WCHAR));
  847. }
  848. if (szDecryptedPID)
  849. {
  850. GlobalFree(szDecryptedPID);
  851. }
  852. }
  853. if ( !SetPid30Variables( Buffer ) ) {
  854. return FALSE;
  855. }
  856. SetupDebugPrint(L"Found Product key in Answer file.\n");
  857. //
  858. // check with pid30 to make sure it's valid
  859. //
  860. if (!ValidateAndSetPid30()) {
  861. return(FALSE);
  862. }
  863. dwRet = SetCurrentProductIdInRegistry();
  864. if (dwRet != NOERROR) {
  865. SetuplogError(
  866. LogSevError,
  867. SETUPLOG_USE_MESSAGEID,
  868. MSG_LOG_PID_CANT_WRITE_PID,
  869. dwRet,NULL,NULL);
  870. }
  871. return(TRUE);
  872. }
  873. BOOL
  874. InitializePid20Array(
  875. )
  876. /*++
  877. Routine Description:
  878. Build the array that contains all Pid20 found in the machine
  879. during textmode setup. Even though we are using pid30 now, we still have
  880. a pid20 string id (pid30 is binary and can't be displayed to the user)
  881. Arguments:
  882. None.
  883. Return Value:
  884. --*/
  885. {
  886. LONG Error;
  887. HKEY Key;
  888. DWORD cbData;
  889. WCHAR Data[ MAX_PATH + 1];
  890. DWORD Type;
  891. ULONG i;
  892. ULONG PidIndex;
  893. ULONG Values;
  894. WCHAR ValueName[ MAX_PATH + 1 ];
  895. Pid20Array = NULL;
  896. //
  897. // Get the Pid from HKEY_LOCAL_MACHINE\SYSTEM\Setup\Pid
  898. //
  899. Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  900. szPidListKeyName,
  901. 0,
  902. KEY_READ,
  903. &Key );
  904. if( Error != ERROR_SUCCESS ) {
  905. return( FALSE );
  906. }
  907. Error = RegQueryInfoKey( Key,
  908. NULL,
  909. NULL,
  910. NULL,
  911. NULL,
  912. NULL,
  913. NULL,
  914. &Values,
  915. NULL,
  916. NULL,
  917. NULL,
  918. NULL );
  919. if( Error != ERROR_SUCCESS ) {
  920. return( FALSE );
  921. }
  922. Pid20Array = (PWSTR *)MyMalloc( (Values + 1)* sizeof( PWSTR ) );
  923. for( i = 0, PidIndex = 0; i < Values; i++ ) {
  924. Pid20Array[PidIndex] = NULL;
  925. Pid20Array[PidIndex + 1] = NULL;
  926. swprintf( ValueName, L"Pid_%u", i );
  927. cbData = sizeof(Data);
  928. Error = RegQueryValueEx( Key,
  929. ValueName,
  930. 0,
  931. &Type,
  932. ( LPBYTE )Data,
  933. &cbData );
  934. if( (Error != ERROR_SUCCESS) ||
  935. ( Type != REG_SZ ) ||
  936. ( wcslen( Data ) != MAX_PRODUCT_ID ) ) {
  937. continue;
  938. }
  939. Pid20Array[PidIndex] = pSetupDuplicateString( Data );
  940. PidIndex++;
  941. }
  942. RegCloseKey( Key );
  943. return( TRUE );
  944. }
  945. BOOL
  946. InitializePidVariables(
  947. )
  948. /*++
  949. Routine Description:
  950. Read from the registry some values created by textmode setup,
  951. and initialize some global Pid flags based on the values found
  952. Arguments:
  953. None.
  954. Return Value:
  955. Returns TRUE if the initialization succedded.
  956. Returns FALSE if the Pid could not be read from the registry
  957. --*/
  958. {
  959. LONG Error;
  960. HKEY Key;
  961. DWORD cbData;
  962. WCHAR Data[ MAX_PATH + 1];
  963. DWORD Type;
  964. ULONG StringLength;
  965. PWSTR p;
  966. DWORD Seed;
  967. DWORD RandomNumber;
  968. ULONG ChkDigit;
  969. ULONG i;
  970. PCWSTR q;
  971. BOOLEAN KeyPresent;
  972. WCHAR KeyBuffer[MAX_BUF];
  973. //
  974. // find out if product key was entered by the user or not
  975. // NB : set the answer file (if needed)
  976. //
  977. if (!AnswerFile[0])
  978. SpSetupLoadParameter(pwProductKey, KeyBuffer, sizeof(KeyBuffer)/sizeof(WCHAR));
  979. KeyBuffer[0] = 0;
  980. KeyPresent = ((GetPrivateProfileString(pwUserData, pwProductKey,
  981. pwNull, KeyBuffer, sizeof(KeyBuffer)/sizeof(WCHAR),
  982. AnswerFile) != 0) &&
  983. (KeyBuffer[0] != 0));
  984. // First create an array with the Pids found during textmode setup
  985. //
  986. if( !(MiniSetup || OobeSetup) ) {
  987. InitializePid20Array();
  988. }
  989. //
  990. // Get the Pid from HKEY_LOCAL_MACHINE\SYSTEM\Setup\Pid
  991. //
  992. Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  993. ((MiniSetup || OobeSetup) ? szFinalPidKeyName : szPidKeyName),
  994. 0,
  995. KEY_READ,
  996. &Key );
  997. if( Error != ERROR_SUCCESS ) {
  998. SetuplogError( LogSevFatalError,
  999. SETUPLOG_USE_MESSAGEID,
  1000. MSG_LOG_PID_CANT_READ_PID, NULL,
  1001. SETUPLOG_USE_MESSAGEID,
  1002. MSG_LOG_X_PARAM_RETURNED_WINERR,
  1003. szRegOpenKeyEx,
  1004. Error,
  1005. szPidKeyName,
  1006. NULL,NULL);
  1007. return( FALSE );
  1008. }
  1009. cbData = sizeof(Data);
  1010. Error = RegQueryValueEx( Key,
  1011. ((MiniSetup || OobeSetup) ? szFinalPidValueName : szPidValueName),
  1012. 0,
  1013. &Type,
  1014. ( LPBYTE )Data,
  1015. &cbData );
  1016. RegCloseKey( Key );
  1017. if( (Error != ERROR_SUCCESS) ) {
  1018. SetuplogError( LogSevFatalError,
  1019. SETUPLOG_USE_MESSAGEID,
  1020. MSG_LOG_PID_CANT_READ_PID, NULL,
  1021. SETUPLOG_USE_MESSAGEID,
  1022. MSG_LOG_X_PARAM_RETURNED_WINERR,
  1023. szRegQueryValueEx,
  1024. Error,
  1025. szPidValueName,
  1026. NULL,NULL);
  1027. return( FALSE );
  1028. }
  1029. //
  1030. // Take care of the mini-setup case first because it's quick.
  1031. // The Pid seeds left behind by textmode are long gone, so
  1032. // we're going to pull out a few rabbits. We'll go read the
  1033. // real Pid (the one gui-mode generated the first time he
  1034. // ran through) and use that to determine which kind of
  1035. // PID to prompt for later on.
  1036. //
  1037. if( MiniSetup || OobeSetup ) {
  1038. //
  1039. // tuck away the rpc code for later on
  1040. //
  1041. wcsncpy( Pid30Rpc, Data, MAX_PID30_RPC +1 );
  1042. Pid30Rpc[MAX_PID30_RPC] = (WCHAR)'\0';
  1043. p = Data + (MAX_PID30_RPC + 1);
  1044. wcsncpy(Pid30Site,p,MAX_PID30_SITE+1);
  1045. Pid30Site[MAX_PID30_SITE] = (WCHAR)'\0';
  1046. //
  1047. // Look to see what kind of media we're installing from.
  1048. //
  1049. CdType = MiniSetupGetCdType(Pid30Site);
  1050. if (CdType == CDSelect)
  1051. {
  1052. goto SelectPid;
  1053. }
  1054. else
  1055. {
  1056. DisplayPidDialog = TRUE;
  1057. }
  1058. return( TRUE );
  1059. }
  1060. //
  1061. // Do some validation of the value read
  1062. //
  1063. if( ( Type != REG_SZ ) ||
  1064. ( ( ( StringLength = wcslen( Data ) ) != 0 ) &&
  1065. ( StringLength != MAX_PID30_RPC ) &&
  1066. ( StringLength != MAX_PID30_RPC + MAX_PID30_SITE )
  1067. )
  1068. ) {
  1069. SetuplogError( LogSevFatalError,
  1070. SETUPLOG_USE_MESSAGEID,
  1071. MSG_LOG_PID_CANT_READ_PID, NULL,
  1072. SETUPLOG_USE_MESSAGEID,
  1073. MSG_LOG_PID_INVALID_PID,
  1074. szRegQueryValueEx,
  1075. Type,
  1076. StringLength,
  1077. NULL,NULL);
  1078. return( FALSE );
  1079. }
  1080. //
  1081. // tuck away the rpc code for later on
  1082. //
  1083. wcsncpy( Pid30Rpc, Data, MAX_PID30_RPC +1 );
  1084. Pid30Rpc[MAX_PID30_RPC] = (WCHAR)'\0';
  1085. //
  1086. // Find out the kind of product we have (by looking at the site code):
  1087. // CD Retail, OEM or Select
  1088. //
  1089. if( StringLength > MAX_PID30_RPC ) {
  1090. //
  1091. // If the Pid contains the Site, then find out what it is
  1092. //
  1093. p = Data + MAX_PID30_RPC;
  1094. wcsncpy(Pid30Site,p,MAX_PID30_SITE+1);
  1095. if(_wcsicmp( Pid30Site, szPidSelectId ) == 0) {
  1096. //
  1097. // This is a Select CD
  1098. //
  1099. SelectPid:
  1100. CdType = CDSelect;
  1101. if (!EulaComplete && !KeyPresent) {
  1102. DisplayPidDialog = TRUE;
  1103. } else {
  1104. //
  1105. // The Pid was specified during winnt32.
  1106. // Set the pid globals and build the product id string
  1107. //
  1108. if (!SetPid30FromAnswerFile()) {
  1109. DisplayPidDialog = TRUE;
  1110. goto finish;
  1111. }
  1112. DisplayPidDialog = FALSE;
  1113. }
  1114. /*
  1115. // Old code. previous version of Windows did not require a PID for Select media.
  1116. for (i = 0; i< 5; i++) {
  1117. Pid30Text[i][0] = (WCHAR)L'\0';
  1118. }
  1119. DisplayPidDialog = FALSE;
  1120. if (!ValidateAndSetPid30()) {
  1121. SetuplogError( LogSevFatalError,
  1122. SETUPLOG_USE_MESSAGEID,
  1123. MSG_LOG_PID_CANT_READ_PID, NULL,
  1124. SETUPLOG_USE_MESSAGEID,
  1125. MSG_LOG_PID_INVALID_PID,
  1126. szRegQueryValueEx,
  1127. Type,
  1128. StringLength,
  1129. NULL,NULL);
  1130. return( FALSE );
  1131. }
  1132. if (MiniSetup || OobeSetup) {
  1133. return(TRUE);
  1134. }
  1135. */
  1136. #if 0
  1137. // msdn media no longer exists (and if it does it should be viewed as retail,
  1138. // so later in this case statement we will fall thru to retail
  1139. } else if (_wcsicmp( Pid30Site, szPidMsdnId ) == 0) {
  1140. //
  1141. // This is an MSDN CD
  1142. //
  1143. MsdnPid:
  1144. for (i = 0; i< 5; i++) {
  1145. LPWSTR ptr;
  1146. ptr = (LPTSTR) &szPid30Msdn[i*(MAX_PID30_EDIT+1)];
  1147. wcsncpy(Pid30Text[i], ptr, MAX_PID30_EDIT+1 );
  1148. Pid30Text[i][MAX_PID30_EDIT] = (WCHAR)L'\0';
  1149. }
  1150. CdType = CDSelect;
  1151. DisplayPidDialog = FALSE;
  1152. if (!ValidateAndSetPid30()) {
  1153. SetuplogError( LogSevFatalError,
  1154. SETUPLOG_USE_MESSAGEID,
  1155. MSG_LOG_PID_CANT_READ_PID, NULL,
  1156. SETUPLOG_USE_MESSAGEID,
  1157. MSG_LOG_PID_INVALID_PID,
  1158. szRegQueryValueEx,
  1159. Type,
  1160. StringLength,
  1161. NULL,NULL);
  1162. return( FALSE );
  1163. }
  1164. if (MiniSetup) {
  1165. return(TRUE);
  1166. }
  1167. #endif
  1168. } else if( _wcsicmp( Pid30Site, szPidOemId ) == 0 ) {
  1169. //
  1170. // This is OEM
  1171. //
  1172. CdType = CDOem;
  1173. if (!EulaComplete && !KeyPresent) {
  1174. DisplayPidDialog = TRUE;
  1175. } else {
  1176. //
  1177. // The Pid was specified during winnt32.
  1178. // Set the pid globals and build the product id string
  1179. //
  1180. if (!SetPid30FromAnswerFile() ) {
  1181. DisplayPidDialog = TRUE;
  1182. goto finish;
  1183. }
  1184. DisplayPidDialog = FALSE;
  1185. }
  1186. } else {
  1187. //
  1188. // This is a bogus site assume CD Retail
  1189. //
  1190. CdType = CDRetail;
  1191. wcsncpy( Pid30Site, L"000", MAX_PID30_SITE+1 );
  1192. Pid30Site[ MAX_PID30_SITE ] = (WCHAR)'\0';
  1193. if (!EulaComplete && !KeyPresent) {
  1194. DisplayPidDialog = TRUE;
  1195. } else {
  1196. //
  1197. // The Pid was specified during winnt32.
  1198. // Set the pid globals and build the product id string
  1199. //
  1200. if (!SetPid30FromAnswerFile()) {
  1201. DisplayPidDialog = TRUE;
  1202. goto finish;
  1203. }
  1204. DisplayPidDialog = FALSE;
  1205. }
  1206. }
  1207. } else {
  1208. //
  1209. // If it doesn't contain the Site, then it is a CD retail,
  1210. // and the appropriate Pid dialog must be displayed.
  1211. //
  1212. CdType = CDRetail;
  1213. wcsncpy( Pid30Site, L"000", MAX_PID30_SITE+1 );
  1214. Pid30Site[ MAX_PID30_SITE ] = (WCHAR)'\0';
  1215. if (!EulaComplete && !KeyPresent) {
  1216. DisplayPidDialog = TRUE;
  1217. } else {
  1218. //
  1219. // The Pid was specified during winnt32.
  1220. // Set the pid globals and build the product id string
  1221. //
  1222. if (!SetPid30FromAnswerFile()) {
  1223. DisplayPidDialog = TRUE;
  1224. goto finish;
  1225. }
  1226. DisplayPidDialog = FALSE;
  1227. }
  1228. }
  1229. finish:
  1230. //
  1231. // Don't remove the Setup\Pid here. See MiniSetupGetCdType
  1232. // Delete Setup\PidList since it is no longer needed
  1233. //
  1234. Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1235. L"SYSTEM\\Setup",
  1236. 0,
  1237. MAXIMUM_ALLOWED,
  1238. &Key );
  1239. if( Error == ERROR_SUCCESS ) {
  1240. // pSetupRegistryDelnode( Key, L"Pid" );
  1241. pSetupRegistryDelnode( Key, L"PidList" );
  1242. RegCloseKey( Key );
  1243. }
  1244. return( TRUE );
  1245. }