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.

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