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
1531 lines
42 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pid.c
|
|
|
|
Abstract:
|
|
|
|
Product id routines.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 6-Feb-1995
|
|
|
|
Revision History:
|
|
|
|
13-Sep-1995 (t-stepl) - Check for unattended install
|
|
|
|
--*/
|
|
|
|
#include "setupp.h"
|
|
#include <spidgen.h>
|
|
#include <pencrypt.h>
|
|
#pragma hdrstop
|
|
|
|
CDTYPE CdType;
|
|
|
|
//
|
|
// Constants used for logging that are specific to this source file.
|
|
//
|
|
PCWSTR szPidKeyName = L"SYSTEM\\Setup\\Pid";
|
|
PCWSTR szPidListKeyName = L"SYSTEM\\Setup\\PidList";
|
|
PCWSTR szPidValueName = L"Pid";
|
|
PCWSTR szPidSelectId = L"270";
|
|
#if 0
|
|
// msdn no longer exists.
|
|
PCWSTR szPidMsdnId = L"335";
|
|
#endif
|
|
PCWSTR szPidOemId = L"OEM";
|
|
PCWSTR szFinalPidKeyName = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
|
|
PCWSTR szFinalPidValueName = L"ProductId";
|
|
PCWSTR szSkuProfessionalFPP = L"B23-00079";
|
|
PCWSTR szSkuProfessionalCCP = L"B23-00082";
|
|
PCWSTR szSkuProfessionalSelect = L"B23-00305";
|
|
PCWSTR szSkuProfessionalEval = L"B23-00084";
|
|
PCWSTR szSkuServerFPP = L"C11-00016";
|
|
PCWSTR szSkuServerCCP = L"C11-00027";
|
|
PCWSTR szSkuServerSelect = L"C11-00222";
|
|
PCWSTR szSkuServerEval = L"C11-00026";
|
|
PCWSTR szSkuServerNFR = L"C11-00025";
|
|
PCWSTR szSkuAdvServerFPP = L"C10-00010";
|
|
PCWSTR szSkuAdvServerCCP = L"C10-00015";
|
|
PCWSTR szSkuAdvServerSelect = L"C10-00098";
|
|
PCWSTR szSkuAdvServerEval = L"C10-00014";
|
|
PCWSTR szSkuAdvServerNFR = L"C10-00013";
|
|
PCWSTR szSkuDTCFPP = L"C49-00001";
|
|
PCWSTR szSkuDTCSelect = L"C49-00023";
|
|
PCWSTR szSkuUnknown = L"A22-00001";
|
|
PCWSTR szSkuOEM = L"OEM-93523";
|
|
|
|
//
|
|
// Flag indicating whether to display the product id dialog.
|
|
//
|
|
BOOL DisplayPidDialog = TRUE;
|
|
|
|
//
|
|
// Product ID.
|
|
//
|
|
WCHAR ProductId[MAX_PRODUCT_ID+1];
|
|
|
|
|
|
PWSTR* Pid20Array = NULL;
|
|
|
|
//
|
|
// pid 30 product id
|
|
//
|
|
WCHAR Pid30Text[5][MAX_PID30_EDIT+1];
|
|
WCHAR ProductId20FromProductId30[MAX_PRODUCT_ID+1];
|
|
WCHAR Pid30Rpc[MAX_PID30_RPC+1];
|
|
WCHAR Pid30Site[MAX_PID30_SITE+1];
|
|
BYTE DigitalProductId[DIGITALPIDMAXLEN];
|
|
|
|
//
|
|
// global variable used for subclassing.
|
|
//
|
|
WNDPROC OldPidEditProc[5];
|
|
|
|
|
|
//
|
|
// Pid related flags
|
|
//
|
|
// BOOL DisplayPidCdDialog;
|
|
// BOOL DisplayPidOemDialog;
|
|
|
|
//
|
|
// forward declarations
|
|
//
|
|
|
|
CDTYPE
|
|
MiniSetupGetCdType(
|
|
LPCWSTR Value
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the right CD type during Mini-Setup. PidGen changes the channel ID
|
|
for the value at HKLM\Software\Microsoft\Windows NT\CurrentVersion!ProductId,
|
|
we have to preserve and rely on the value at HKLM\SYSTEM\Setup\Pid!Pid
|
|
|
|
Return Value:
|
|
|
|
the CdType.
|
|
|
|
--*/
|
|
|
|
{
|
|
CDTYPE RetVal;
|
|
WCHAR TmpPid30Site[MAX_PID30_SITE+1];
|
|
HKEY Key = NULL;
|
|
DWORD cbData;
|
|
WCHAR Data[ MAX_PATH + 1];
|
|
DWORD Type;
|
|
|
|
cbData = sizeof(Data);
|
|
if ( ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
szPidKeyName,
|
|
0,
|
|
KEY_READ,
|
|
&Key ) == ERROR_SUCCESS ) &&
|
|
( RegQueryValueEx( Key,
|
|
szPidValueName,
|
|
0,
|
|
&Type,
|
|
( LPBYTE )Data,
|
|
&cbData ) == ERROR_SUCCESS ) )
|
|
{
|
|
wcsncpy(TmpPid30Site, Data + MAX_PID30_RPC, MAX_PID30_SITE+1);
|
|
}
|
|
else
|
|
{
|
|
if (Value != NULL)
|
|
{
|
|
wcsncpy(TmpPid30Site, Value, MAX_PID30_SITE+1);
|
|
}
|
|
else
|
|
{
|
|
TmpPid30Site[0] = L'\0';
|
|
}
|
|
}
|
|
|
|
TmpPid30Site[MAX_PID30_SITE] = (WCHAR)'\0';
|
|
|
|
if (_wcsicmp( TmpPid30Site, szPidSelectId ) == 0) {
|
|
RetVal = CDSelect;
|
|
} else if( _wcsicmp( TmpPid30Site, szPidOemId ) == 0 ) {
|
|
RetVal = CDOem;
|
|
} else {
|
|
RetVal = CDRetail;
|
|
}
|
|
|
|
if (Key != NULL)
|
|
{
|
|
RegCloseKey(Key);
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
PCWSTR GetStockKeepingUnit(
|
|
PWCHAR pMPC,
|
|
UINT ProductType,
|
|
CDTYPE CdType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This returns the Stock Keeping Unit based off the MPC.
|
|
|
|
Arguments:
|
|
|
|
pMPC - pointer to 5 digit MPC code, null terminated.
|
|
ProductType - Product type flag, tells us if this is a workataion or server sku.
|
|
CdType - one of CDTYPE enum
|
|
|
|
Return Value:
|
|
|
|
Returns pointer to sku.
|
|
If no match found returns szSkuUnknown.
|
|
|
|
--*/
|
|
{
|
|
// check for eval
|
|
if (!_wcsicmp(Pid30Rpc,EVAL_MPC) || !_wcsicmp(Pid30Rpc,DOTNET_EVAL_MPC)){
|
|
// this is eval media ...
|
|
if (ProductType == PRODUCT_WORKSTATION){
|
|
return (szSkuProfessionalEval);
|
|
} // else
|
|
// else it is server or advanced server. I don't think that at this point
|
|
// we can easily tell the difference. Since it's been said that having the
|
|
// correct sku is not critically important, I shall give them both the sku
|
|
// code of server
|
|
return (szSkuServerEval);
|
|
}
|
|
|
|
// check for NFR
|
|
if (!_wcsicmp(Pid30Rpc,SRV_NFR_MPC)){
|
|
return (szSkuServerNFR);
|
|
}
|
|
if (!_wcsicmp(Pid30Rpc,ASRV_NFR_MPC)){
|
|
return (szSkuAdvServerNFR);
|
|
}
|
|
|
|
if (CdType == CDRetail) {
|
|
if (!_wcsicmp(Pid30Rpc,L"51873")){
|
|
return (szSkuProfessionalFPP);
|
|
}
|
|
if (!_wcsicmp(Pid30Rpc,L"51874")){
|
|
return (szSkuProfessionalCCP);
|
|
}
|
|
if (!_wcsicmp(Pid30Rpc,L"51876")){
|
|
return (szSkuServerFPP);
|
|
}
|
|
if (!_wcsicmp(Pid30Rpc,L"51877")){
|
|
return (szSkuServerCCP);
|
|
}
|
|
if (!_wcsicmp(Pid30Rpc,L"51879")){
|
|
return (szSkuAdvServerFPP);
|
|
}
|
|
if (!_wcsicmp(Pid30Rpc,L"51880")){
|
|
return (szSkuAdvServerCCP);
|
|
}
|
|
if (!_wcsicmp(Pid30Rpc,L"51891")){
|
|
return (szSkuDTCFPP);
|
|
}
|
|
} else if (CdType == CDSelect) {
|
|
if (!_wcsicmp(Pid30Rpc,L"51873")){
|
|
return (szSkuProfessionalSelect);
|
|
}
|
|
if (!_wcsicmp(Pid30Rpc,L"51876")){
|
|
return (szSkuServerSelect);
|
|
}
|
|
if (!_wcsicmp(Pid30Rpc,L"51879")){
|
|
return (szSkuAdvServerSelect);
|
|
}
|
|
if (!_wcsicmp(Pid30Rpc,L"51891")){
|
|
return (szSkuDTCSelect);
|
|
}
|
|
}
|
|
|
|
return (szSkuUnknown);
|
|
}
|
|
|
|
BOOL
|
|
ValidateAndSetPid30(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Using the Pid30Text global variables, check if we have a valid id.
|
|
This generates the pid30 digital product id and pid20 string id, which
|
|
we set into DigitalProductId and ProductId20FromProductId30 globals
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if pid was valid. Set's the globals correctly on success, zero's them out on failure
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR tmpPid30String[5+ 5*MAX_PID30_EDIT];
|
|
BOOL rc;
|
|
PCWSTR pszSkuCode;
|
|
|
|
// Since we require a PID in the Select media too, we need to fill the string
|
|
wsprintf( tmpPid30String, L"%s-%s-%s-%s-%s",
|
|
Pid30Text[0],Pid30Text[1],Pid30Text[2],Pid30Text[3],Pid30Text[4]);
|
|
|
|
pszSkuCode = GetStockKeepingUnit( Pid30Rpc, ProductType, CdType);
|
|
|
|
*(LPDWORD)DigitalProductId = sizeof(DigitalProductId);
|
|
rc = SetupPIDGenW(
|
|
tmpPid30String, // [IN] 25-character Secure CD-Key (gets U-Cased)
|
|
Pid30Rpc, // [IN] 5-character Release Product Code
|
|
pszSkuCode, // [IN] Stock Keeping Unit (formatted like 123-12345)
|
|
(CdType == CDOem), // [IN] is this an OEM install?
|
|
ProductId20FromProductId30, // [OUT] PID 2.0, pass in ptr to 24 character array
|
|
DigitalProductId, // [OUT] pointer to binary PID3 buffer. First DWORD is the length
|
|
NULL); // [OUT] optional ptr to Compliance Checking flag (can be NULL)
|
|
|
|
|
|
#ifdef PRERELEASE
|
|
SetupDebugPrint2(L"Pidgen returns for PID:%s and MPC:%s\n", tmpPid30String, Pid30Rpc);
|
|
#endif
|
|
if (!rc) {
|
|
#ifdef PRERELEASE
|
|
SetupDebugPrint1(L"Pidgen returns %d for PID.n", rc);
|
|
#endif
|
|
ZeroMemory(Pid30Text[0],5*(MAX_PID30_EDIT+1));
|
|
}
|
|
else
|
|
{
|
|
if (*ProductId20FromProductId30 == L'\0')
|
|
{
|
|
SetupDebugPrint(L"ProductId20FromProductId30 is empty after call into pidgen and pidgen returns OK\n");
|
|
}
|
|
if (*DigitalProductId == 0)
|
|
{
|
|
SetupDebugPrint(L"DigitalProductId is empty after call into pidgen and pidgen returns OK\n");
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
LRESULT
|
|
CALLBACK
|
|
PidEditSubProc(
|
|
IN HWND hwnd,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Edit control subclass routine, sets the focus to the correct edit box when the user enters text.
|
|
This routine assumes that the pid controls ids are in sequential order.
|
|
|
|
Arguments:
|
|
|
|
Standard window proc arguments.
|
|
|
|
Returns:
|
|
|
|
Message-dependent value.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD len, id;
|
|
|
|
//
|
|
// eat spaces
|
|
//
|
|
if ((msg == WM_CHAR) && (wParam == VK_SPACE)) {
|
|
return(0);
|
|
}
|
|
|
|
if ((msg == WM_CHAR)) {
|
|
//
|
|
// First override: if we have the max characters in the current edit
|
|
// box, let's post the character to the next box and set focus to that
|
|
// control.
|
|
//
|
|
if ( ( (len = (DWORD)SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0)) == MAX_PID30_EDIT) &&
|
|
((wParam != VK_DELETE) && (wParam != VK_BACK)) ) {
|
|
//
|
|
// set the focus to the next edit control and post the character
|
|
// to that edit control
|
|
//
|
|
if ((id = GetDlgCtrlID(hwnd)) < IDT_EDIT_PID5 ) {
|
|
DWORD start, end;
|
|
SendMessage(hwnd, EM_GETSEL, (WPARAM)&start,(LPARAM)&end);
|
|
if (start == end) {
|
|
HWND hNext = GetDlgItem(GetParent(hwnd),id+1);
|
|
SetFocus(hNext);
|
|
SendMessage(hNext, EM_SETSEL, (WPARAM)-1,(LPARAM)-1);
|
|
PostMessage( GetDlgItem(GetParent(hwnd),id+1), WM_CHAR, wParam, lParam );
|
|
return(0);
|
|
}
|
|
|
|
}
|
|
//
|
|
// Second override: if the user hit's a delete key and they are at the
|
|
// the start of an edit box, then post the delete to the previous edit
|
|
// box.
|
|
//
|
|
} else if ( (len == 0) &&
|
|
((id = GetDlgCtrlID(hwnd)) > IDT_EDIT_PID1) &&
|
|
((wParam == VK_DELETE) || (wParam == VK_BACK) )) {
|
|
//
|
|
// set the focus to the previous edit control and post the command
|
|
// to that edit control
|
|
//
|
|
HWND hPrev = GetDlgItem(GetParent(hwnd),id-1);
|
|
SetFocus(hPrev);
|
|
SendMessage(hPrev, EM_SETSEL, (WPARAM)MAX_PID30_EDIT-1,(LPARAM)MAX_PID30_EDIT);
|
|
PostMessage( hPrev, WM_CHAR, wParam, lParam );
|
|
return(0);
|
|
//
|
|
// Third override: if posting this message will give us the maximum
|
|
// characters in our in the current edit box, let's post the character
|
|
// to the next box and set focus to that control.
|
|
//
|
|
} else if ( (len == MAX_PID30_EDIT-1) &&
|
|
((wParam != VK_DELETE) && (wParam != VK_BACK)) &&
|
|
((id = GetDlgCtrlID(hwnd)) < IDT_EDIT_PID5) ) {
|
|
DWORD start, end;
|
|
SendMessage(hwnd, EM_GETSEL, (WPARAM)&start,(LPARAM)&end);
|
|
if (start == end) {
|
|
HWND hNext = GetDlgItem(GetParent(hwnd),id+1);
|
|
//
|
|
// post the message to the edit box
|
|
//
|
|
CallWindowProc(OldPidEditProc[GetDlgCtrlID(hwnd)-IDT_EDIT_PID1],hwnd,msg,wParam,lParam);
|
|
//
|
|
// now set the focus to the next edit control
|
|
//
|
|
SetFocus(hNext);
|
|
SendMessage(hNext, EM_SETSEL, (WPARAM)-1,(LPARAM)-1);
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return(CallWindowProc(OldPidEditProc[GetDlgCtrlID(hwnd)-IDT_EDIT_PID1],hwnd,msg,wParam,lParam));
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
CALLBACK
|
|
Pid30CDDlgProc(
|
|
IN HWND hdlg,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dialog procedure for the CD Retail Pid dialog.
|
|
|
|
Arguments:
|
|
|
|
hWnd - a handle to the dialog proceedure.
|
|
|
|
msg - the message passed from Windows.
|
|
|
|
wParam - extra message dependent data.
|
|
|
|
lParam - extra message dependent data.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if the value was edited. FALSE if cancelled or if no
|
|
changes were made.
|
|
|
|
--*/
|
|
{
|
|
NMHDR *NotifyParams;
|
|
DWORD i,dwRet;
|
|
|
|
switch(msg) {
|
|
|
|
case WM_INITDIALOG: {
|
|
|
|
if( UiTest ) {
|
|
//
|
|
// If testing the wizard, make sure that the PidOEM page is
|
|
// displayed
|
|
//
|
|
CdType = CDRetail;
|
|
DisplayPidDialog = TRUE;
|
|
}
|
|
|
|
|
|
// Disable the IME on the PID edit controls
|
|
for (i = 0; i < 5;i++)
|
|
{
|
|
ImmAssociateContext(GetDlgItem(hdlg, IDT_EDIT_PID1+i), (HIMC)NULL);
|
|
}
|
|
//
|
|
// subclass the edit controls and limit the number of characters
|
|
//
|
|
for (i = 0; i < 5;i++) {
|
|
SendDlgItemMessage(hdlg,IDT_EDIT_PID1+i,EM_LIMITTEXT,MAX_PID30_EDIT,0);
|
|
OldPidEditProc[i] = (WNDPROC)GetWindowLongPtr(GetDlgItem(hdlg, IDT_EDIT_PID1+i),GWLP_WNDPROC);
|
|
SetWindowLongPtr(GetDlgItem(hdlg, IDT_EDIT_PID1+i),GWLP_WNDPROC,(LONG_PTR)PidEditSubProc);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case WM_IAMVISIBLE:
|
|
MessageBoxFromMessage(hdlg,MSG_PID_IS_INVALID,NULL,
|
|
IDS_ERROR,MB_OK|MB_ICONSTOP);
|
|
break;
|
|
case WM_SIMULATENEXT:
|
|
// Simulate the next button somehow
|
|
PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
|
|
NotifyParams = (NMHDR *)lParam;
|
|
|
|
switch(NotifyParams->code) {
|
|
|
|
case PSN_SETACTIVE:
|
|
TESTHOOK(506);
|
|
BEGIN_SECTION(L"Your (Retail) Product Key Page");
|
|
if(DisplayPidDialog && CdType == CDRetail) {
|
|
// Page becomes active, make page visible.
|
|
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
|
|
SetWizardButtons(hdlg,WizPageProductIdCd);
|
|
SendDlgItemMessage(hdlg,IDT_EDIT_PID1,EM_SETSEL,0,-1);
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
|
|
} else {
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
|
|
END_SECTION(L"Your (Retail) Product Key Page");
|
|
break;
|
|
}
|
|
if(Unattended) {
|
|
if (UnattendSetActiveDlg(hdlg,IDD_PID_CD))
|
|
{
|
|
// Page becomes active, make page visible.
|
|
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PSN_WIZNEXT:
|
|
case PSN_WIZFINISH:
|
|
|
|
for (i = 0; i<5; i++) {
|
|
GetDlgItemText(hdlg,IDT_EDIT_PID1+i,Pid30Text[i],MAX_PID30_EDIT+1);
|
|
}
|
|
|
|
if (!ValidateAndSetPid30()) {
|
|
|
|
// failure
|
|
// Tell user that the Pid is not valid, and
|
|
// don't allow next page to be activated.
|
|
//
|
|
if (Unattended) {
|
|
UnattendErrorDlg( hdlg, IDD_PID_CD );
|
|
}
|
|
MessageBoxFromMessage(hdlg,MSG_PID_IS_INVALID,NULL,
|
|
IDS_ERROR,MB_OK|MB_ICONSTOP);
|
|
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
|
|
if(!UiTest) {
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
|
|
}
|
|
} else {
|
|
|
|
|
|
// success
|
|
//
|
|
// Since the Pid is already built, don't let this dialog
|
|
// be displayed in the future.
|
|
//
|
|
// DisplayPidDialog = FALSE;
|
|
|
|
//
|
|
// Allow next page to be activated.
|
|
//
|
|
dwRet = SetCurrentProductIdInRegistry();
|
|
if (dwRet != NOERROR) {
|
|
SetuplogError(
|
|
LogSevError,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PID_CANT_WRITE_PID,
|
|
dwRet,NULL,NULL);
|
|
}
|
|
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,0);
|
|
}
|
|
|
|
break;
|
|
|
|
case PSN_KILLACTIVE:
|
|
WizardKillHelp(hdlg);
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT, FALSE);
|
|
END_SECTION(L"Your (Retail) Product Key Page");
|
|
break;
|
|
|
|
case PSN_HELP:
|
|
WizardBringUpHelp(hdlg,WizPageProductIdCd);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
CALLBACK
|
|
Pid30OemDlgProc(
|
|
IN HWND hdlg,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dialog procedure for the OEM Pid dialog.
|
|
|
|
Arguments:
|
|
|
|
hWnd - a handle to the dialog proceedure.
|
|
|
|
msg - the message passed from Windows.
|
|
|
|
wParam - extra message dependent data.
|
|
|
|
lParam - extra message dependent data.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if the value was edited. FALSE if cancelled or if no
|
|
changes were made.
|
|
|
|
--*/
|
|
{
|
|
NMHDR *NotifyParams;
|
|
DWORD i,dwRet;
|
|
|
|
switch(msg) {
|
|
|
|
case WM_INITDIALOG: {
|
|
|
|
if( UiTest ) {
|
|
//
|
|
// If testing the wizard, make sure that the PidOEM page is
|
|
// displayed
|
|
//
|
|
CdType = CDOem;
|
|
DisplayPidDialog = TRUE;
|
|
}
|
|
|
|
// Disable the IME on the PID edit controls
|
|
for (i = 0; i < 5;i++)
|
|
{
|
|
ImmAssociateContext(GetDlgItem(hdlg, IDT_EDIT_PID1+i), (HIMC)NULL);
|
|
}
|
|
//
|
|
// subclass the edit controls and limit the number of characters
|
|
//
|
|
for (i = 0; i < 5;i++) {
|
|
SendDlgItemMessage(hdlg,IDT_EDIT_PID1+i,EM_LIMITTEXT,MAX_PID30_EDIT,0);
|
|
OldPidEditProc[i] = (WNDPROC)GetWindowLongPtr(GetDlgItem(hdlg, IDT_EDIT_PID1+i),GWLP_WNDPROC);
|
|
SetWindowLongPtr(GetDlgItem(hdlg, IDT_EDIT_PID1+i),GWLP_WNDPROC,(LONG_PTR)PidEditSubProc);
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
case WM_SIMULATENEXT:
|
|
// Simulate the next button somehow
|
|
PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
|
|
break;
|
|
|
|
case WM_IAMVISIBLE:
|
|
MessageBoxFromMessage(hdlg,MSG_PID_OEM_IS_INVALID,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
|
|
break;
|
|
case WM_NOTIFY:
|
|
|
|
NotifyParams = (NMHDR *)lParam;
|
|
|
|
switch(NotifyParams->code) {
|
|
|
|
case PSN_SETACTIVE:
|
|
TESTHOOK(507);
|
|
BEGIN_SECTION(L"Your (OEM) Product Key Page");
|
|
if(DisplayPidDialog && CdType == CDOem) {
|
|
// Page becomes active, make page visible.
|
|
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
SetWizardButtons(hdlg,WizPageProductIdCd);
|
|
SendDlgItemMessage(hdlg,IDT_EDIT_PID1,EM_SETSEL,0,-1);
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
|
|
} else {
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
|
|
END_SECTION(L"Your (OEM) Product Key Page");
|
|
break;
|
|
}
|
|
if(Unattended) {
|
|
if (UnattendSetActiveDlg( hdlg, IDD_PID_OEM ))
|
|
{
|
|
// Page becomes active, make page visible.
|
|
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PSN_WIZNEXT:
|
|
case PSN_WIZFINISH:
|
|
|
|
for (i = 0; i<5; i++) {
|
|
GetDlgItemText(hdlg,IDT_EDIT_PID1+i,Pid30Text[i],MAX_PID30_EDIT+1);
|
|
}
|
|
|
|
|
|
if (!ValidateAndSetPid30()) {
|
|
|
|
// failure
|
|
//
|
|
// Tell user that the Pid is not valid, and
|
|
// don't allow next page to be activated.
|
|
//
|
|
if (Unattended) {
|
|
UnattendErrorDlg( hdlg, IDD_PID_OEM );
|
|
} // if
|
|
MessageBoxFromMessage(hdlg,MSG_PID_OEM_IS_INVALID,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
|
|
if(!UiTest) {
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
|
|
}
|
|
} else {
|
|
|
|
// success
|
|
//
|
|
// The Pid is valid.
|
|
//
|
|
|
|
|
|
//
|
|
//
|
|
// Since the Pid is already built, don't let this dialog
|
|
// be displayed in the future.
|
|
//
|
|
// DisplayPidDialog = FALSE;
|
|
|
|
// Allow next page to be activated.
|
|
//
|
|
dwRet = SetCurrentProductIdInRegistry();
|
|
if (dwRet != NOERROR) {
|
|
SetuplogError(
|
|
LogSevError,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PID_CANT_WRITE_PID,
|
|
dwRet,NULL,NULL);
|
|
}
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,0);
|
|
|
|
}
|
|
break;
|
|
|
|
case PSN_KILLACTIVE:
|
|
WizardKillHelp(hdlg);
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT, FALSE );
|
|
END_SECTION(L"Your (OEM) Product Key Page");
|
|
break;
|
|
|
|
case PSN_HELP:
|
|
WizardBringUpHelp(hdlg,WizPageProductIdCd);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
INT_PTR
|
|
CALLBACK
|
|
Pid30SelectDlgProc(
|
|
IN HWND hdlg,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dialog procedure for the OEM Pid dialog.
|
|
|
|
Arguments:
|
|
|
|
hWnd - a handle to the dialog proceedure.
|
|
|
|
msg - the message passed from Windows.
|
|
|
|
wParam - extra message dependent data.
|
|
|
|
lParam - extra message dependent data.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if the value was edited. FALSE if cancelled or if no
|
|
changes were made.
|
|
|
|
--*/
|
|
{
|
|
NMHDR *NotifyParams;
|
|
DWORD i,dwRet;
|
|
|
|
switch(msg) {
|
|
|
|
case WM_INITDIALOG: {
|
|
|
|
if( UiTest ) {
|
|
//
|
|
// If testing the wizard, make sure that the PidOEM page is
|
|
// displayed
|
|
//
|
|
CdType = CDSelect;
|
|
DisplayPidDialog = TRUE;
|
|
}
|
|
|
|
// Disable the IME on the PID edit controls
|
|
for (i = 0; i < 5;i++)
|
|
{
|
|
ImmAssociateContext(GetDlgItem(hdlg, IDT_EDIT_PID1+i), (HIMC)NULL);
|
|
}
|
|
//
|
|
// subclass the edit controls and limit the number of characters
|
|
//
|
|
for (i = 0; i < 5;i++) {
|
|
SendDlgItemMessage(hdlg,IDT_EDIT_PID1+i,EM_LIMITTEXT,MAX_PID30_EDIT,0);
|
|
OldPidEditProc[i] = (WNDPROC)GetWindowLongPtr(GetDlgItem(hdlg, IDT_EDIT_PID1+i),GWLP_WNDPROC);
|
|
SetWindowLongPtr(GetDlgItem(hdlg, IDT_EDIT_PID1+i),GWLP_WNDPROC,(LONG_PTR)PidEditSubProc);
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
case WM_SIMULATENEXT:
|
|
// Simulate the next button somehow
|
|
PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
|
|
break;
|
|
|
|
case WM_IAMVISIBLE:
|
|
MessageBoxFromMessage(hdlg,MSG_PID_OEM_IS_INVALID,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
|
|
break;
|
|
case WM_NOTIFY:
|
|
|
|
NotifyParams = (NMHDR *)lParam;
|
|
|
|
switch(NotifyParams->code) {
|
|
|
|
case PSN_SETACTIVE:
|
|
TESTHOOK(508);
|
|
BEGIN_SECTION(L"Your (Select) Product Key Page");
|
|
if(DisplayPidDialog && CdType == CDSelect) {
|
|
// Page becomes active, make page visible.
|
|
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
SetWizardButtons(hdlg,WizPageProductIdCd);
|
|
SendDlgItemMessage(hdlg,IDT_EDIT_PID1,EM_SETSEL,0,-1);
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
|
|
} else {
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
|
|
END_SECTION(L"Your (Select) Product Key Page");
|
|
break;
|
|
}
|
|
if(Unattended) {
|
|
if (UnattendSetActiveDlg( hdlg, IDD_PID_SELECT ))
|
|
{
|
|
// Page becomes active, make page visible.
|
|
SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PSN_WIZNEXT:
|
|
case PSN_WIZFINISH:
|
|
|
|
for (i = 0; i<5; i++) {
|
|
GetDlgItemText(hdlg,IDT_EDIT_PID1+i,Pid30Text[i],MAX_PID30_EDIT+1);
|
|
}
|
|
|
|
|
|
if (!ValidateAndSetPid30()) {
|
|
|
|
// failure
|
|
//
|
|
// Tell user that the Pid is not valid, and
|
|
// don't allow next page to be activated.
|
|
//
|
|
if (Unattended) {
|
|
UnattendErrorDlg( hdlg, IDD_PID_SELECT );
|
|
} // if
|
|
MessageBoxFromMessage(hdlg,MSG_PID_OEM_IS_INVALID,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
|
|
SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
|
|
if(!UiTest) {
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
|
|
}
|
|
} else {
|
|
|
|
// success
|
|
//
|
|
// The Pid is valid.
|
|
//
|
|
|
|
|
|
//
|
|
//
|
|
// Since the Pid is already built, don't let this dialog
|
|
// be displayed in the future.
|
|
//
|
|
// DisplayPidDialog = FALSE;
|
|
|
|
// Allow next page to be activated.
|
|
//
|
|
dwRet = SetCurrentProductIdInRegistry();
|
|
if (dwRet != NOERROR) {
|
|
SetuplogError(
|
|
LogSevError,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PID_CANT_WRITE_PID,
|
|
dwRet,NULL,NULL);
|
|
}
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT,0);
|
|
|
|
}
|
|
break;
|
|
|
|
case PSN_KILLACTIVE:
|
|
WizardKillHelp(hdlg);
|
|
SetWindowLongPtr(hdlg,DWLP_MSGRESULT, FALSE );
|
|
END_SECTION(L"Your (Select) Product Key Page");
|
|
break;
|
|
|
|
case PSN_HELP:
|
|
WizardBringUpHelp(hdlg,WizPageProductIdCd);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL
|
|
SetPid30Variables(
|
|
PWSTR Buffer
|
|
)
|
|
{
|
|
LPWSTR ptr;
|
|
UINT i;
|
|
|
|
|
|
//
|
|
// all install cases are the same for pid3.0
|
|
// Check that the string specified on the unattended script file
|
|
// represents a valid 25 digit product id:
|
|
//
|
|
// 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
|
|
// 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
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
|
|
//
|
|
// As a first validation test, we verify that the length is correct,
|
|
// then we check if the "-" characters are in the correct place
|
|
//
|
|
//
|
|
if( ( wcslen( Buffer ) != (4+ MAX_PID30_EDIT*5)) ||
|
|
( Buffer[5] != (WCHAR)L'-' ) ||
|
|
( Buffer[11] != (WCHAR)L'-' ) ||
|
|
( Buffer[17] != (WCHAR)L'-' ) ||
|
|
( Buffer[23] != (WCHAR)L'-' )
|
|
) {
|
|
//
|
|
// The Pid in the unattended script file is invalid.
|
|
//
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
for (i = 0;i<5;i++) {
|
|
//
|
|
// quintet i
|
|
//
|
|
ptr = &Buffer[i*(MAX_PID30_EDIT+1)];
|
|
wcsncpy(Pid30Text[i], ptr, MAX_PID30_EDIT+1 );
|
|
Pid30Text[i][MAX_PID30_EDIT] = (WCHAR)L'\0';
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetPid30FromAnswerFile(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
set the pid3.0 globals based on unattend file parameter, if it exists.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR Buffer[MAX_BUF];
|
|
DWORD dwRet;
|
|
|
|
|
|
if (!GetPrivateProfileString(pwUserData,
|
|
pwProductKey,
|
|
L"",
|
|
Buffer,
|
|
sizeof(Buffer)/sizeof(WCHAR),
|
|
AnswerFile)) {
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!Buffer || !*Buffer) {
|
|
return(FALSE);
|
|
}
|
|
|
|
// Buffer contains the Product ID
|
|
// Is the PID encrypted?
|
|
if (lstrlen(Buffer) > (4 + MAX_PID30_EDIT*5))
|
|
{
|
|
LPWSTR szDecryptedPID = NULL;
|
|
if (ValidateEncryptedPID(Buffer, &szDecryptedPID) == S_OK)
|
|
{
|
|
lstrcpyn(Buffer, szDecryptedPID, sizeof(Buffer)/sizeof(WCHAR));
|
|
}
|
|
if (szDecryptedPID)
|
|
{
|
|
GlobalFree(szDecryptedPID);
|
|
}
|
|
}
|
|
|
|
if ( !SetPid30Variables( Buffer ) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
SetupDebugPrint(L"Found Product key in Answer file.\n");
|
|
//
|
|
// check with pid30 to make sure it's valid
|
|
//
|
|
if (!ValidateAndSetPid30()) {
|
|
return(FALSE);
|
|
}
|
|
|
|
dwRet = SetCurrentProductIdInRegistry();
|
|
if (dwRet != NOERROR) {
|
|
SetuplogError(
|
|
LogSevError,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PID_CANT_WRITE_PID,
|
|
dwRet,NULL,NULL);
|
|
}
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
InitializePid20Array(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build the array that contains all Pid20 found in the machine
|
|
during textmode setup. Even though we are using pid30 now, we still have
|
|
a pid20 string id (pid30 is binary and can't be displayed to the user)
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG Error;
|
|
HKEY Key;
|
|
DWORD cbData;
|
|
WCHAR Data[ MAX_PATH + 1];
|
|
DWORD Type;
|
|
ULONG i;
|
|
ULONG PidIndex;
|
|
ULONG Values;
|
|
WCHAR ValueName[ MAX_PATH + 1 ];
|
|
|
|
Pid20Array = NULL;
|
|
//
|
|
// Get the Pid from HKEY_LOCAL_MACHINE\SYSTEM\Setup\Pid
|
|
//
|
|
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
szPidListKeyName,
|
|
0,
|
|
KEY_READ,
|
|
&Key );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
return( FALSE );
|
|
}
|
|
|
|
Error = RegQueryInfoKey( Key,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Values,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
return( FALSE );
|
|
}
|
|
|
|
Pid20Array = (PWSTR *)MyMalloc( (Values + 1)* sizeof( PWSTR ) );
|
|
|
|
for( i = 0, PidIndex = 0; i < Values; i++ ) {
|
|
Pid20Array[PidIndex] = NULL;
|
|
Pid20Array[PidIndex + 1] = NULL;
|
|
swprintf( ValueName, L"Pid_%u", i );
|
|
cbData = sizeof(Data);
|
|
Error = RegQueryValueEx( Key,
|
|
ValueName,
|
|
0,
|
|
&Type,
|
|
( LPBYTE )Data,
|
|
&cbData );
|
|
if( (Error != ERROR_SUCCESS) ||
|
|
( Type != REG_SZ ) ||
|
|
( wcslen( Data ) != MAX_PRODUCT_ID ) ) {
|
|
continue;
|
|
}
|
|
Pid20Array[PidIndex] = pSetupDuplicateString( Data );
|
|
PidIndex++;
|
|
}
|
|
RegCloseKey( Key );
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOL
|
|
InitializePidVariables(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read from the registry some values created by textmode setup,
|
|
and initialize some global Pid flags based on the values found
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE if the initialization succedded.
|
|
Returns FALSE if the Pid could not be read from the registry
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG Error;
|
|
HKEY Key;
|
|
DWORD cbData;
|
|
WCHAR Data[ MAX_PATH + 1];
|
|
DWORD Type;
|
|
ULONG StringLength;
|
|
PWSTR p;
|
|
DWORD Seed;
|
|
DWORD RandomNumber;
|
|
ULONG ChkDigit;
|
|
ULONG i;
|
|
PCWSTR q;
|
|
BOOLEAN KeyPresent;
|
|
WCHAR KeyBuffer[MAX_BUF];
|
|
|
|
|
|
//
|
|
// find out if product key was entered by the user or not
|
|
// NB : set the answer file (if needed)
|
|
//
|
|
if (!AnswerFile[0])
|
|
SpSetupLoadParameter(pwProductKey, KeyBuffer, sizeof(KeyBuffer)/sizeof(WCHAR));
|
|
|
|
KeyBuffer[0] = 0;
|
|
KeyPresent = ((GetPrivateProfileString(pwUserData, pwProductKey,
|
|
pwNull, KeyBuffer, sizeof(KeyBuffer)/sizeof(WCHAR),
|
|
AnswerFile) != 0) &&
|
|
(KeyBuffer[0] != 0));
|
|
|
|
// First create an array with the Pids found during textmode setup
|
|
//
|
|
if( !(MiniSetup || OobeSetup) ) {
|
|
InitializePid20Array();
|
|
}
|
|
|
|
|
|
//
|
|
// Get the Pid from HKEY_LOCAL_MACHINE\SYSTEM\Setup\Pid
|
|
//
|
|
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
((MiniSetup || OobeSetup) ? szFinalPidKeyName : szPidKeyName),
|
|
0,
|
|
KEY_READ,
|
|
&Key );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
SetuplogError( LogSevFatalError,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PID_CANT_READ_PID, NULL,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_X_PARAM_RETURNED_WINERR,
|
|
szRegOpenKeyEx,
|
|
Error,
|
|
szPidKeyName,
|
|
NULL,NULL);
|
|
return( FALSE );
|
|
}
|
|
|
|
cbData = sizeof(Data);
|
|
Error = RegQueryValueEx( Key,
|
|
((MiniSetup || OobeSetup) ? szFinalPidValueName : szPidValueName),
|
|
0,
|
|
&Type,
|
|
( LPBYTE )Data,
|
|
&cbData );
|
|
RegCloseKey( Key );
|
|
if( (Error != ERROR_SUCCESS) ) {
|
|
SetuplogError( LogSevFatalError,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PID_CANT_READ_PID, NULL,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_X_PARAM_RETURNED_WINERR,
|
|
szRegQueryValueEx,
|
|
Error,
|
|
szPidValueName,
|
|
NULL,NULL);
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// Take care of the mini-setup case first because it's quick.
|
|
// The Pid seeds left behind by textmode are long gone, so
|
|
// we're going to pull out a few rabbits. We'll go read the
|
|
// real Pid (the one gui-mode generated the first time he
|
|
// ran through) and use that to determine which kind of
|
|
// PID to prompt for later on.
|
|
//
|
|
if( MiniSetup || OobeSetup ) {
|
|
|
|
//
|
|
// tuck away the rpc code for later on
|
|
//
|
|
wcsncpy( Pid30Rpc, Data, MAX_PID30_RPC +1 );
|
|
Pid30Rpc[MAX_PID30_RPC] = (WCHAR)'\0';
|
|
|
|
p = Data + (MAX_PID30_RPC + 1);
|
|
wcsncpy(Pid30Site,p,MAX_PID30_SITE+1);
|
|
Pid30Site[MAX_PID30_SITE] = (WCHAR)'\0';
|
|
//
|
|
// Look to see what kind of media we're installing from.
|
|
//
|
|
CdType = MiniSetupGetCdType(Pid30Site);
|
|
|
|
if (CdType == CDSelect)
|
|
{
|
|
goto SelectPid;
|
|
}
|
|
else
|
|
{
|
|
DisplayPidDialog = TRUE;
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Do some validation of the value read
|
|
//
|
|
|
|
if( ( Type != REG_SZ ) ||
|
|
( ( ( StringLength = wcslen( Data ) ) != 0 ) &&
|
|
( StringLength != MAX_PID30_RPC ) &&
|
|
( StringLength != MAX_PID30_RPC + MAX_PID30_SITE )
|
|
)
|
|
) {
|
|
SetuplogError( LogSevFatalError,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PID_CANT_READ_PID, NULL,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PID_INVALID_PID,
|
|
szRegQueryValueEx,
|
|
Type,
|
|
StringLength,
|
|
NULL,NULL);
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// tuck away the rpc code for later on
|
|
//
|
|
wcsncpy( Pid30Rpc, Data, MAX_PID30_RPC +1 );
|
|
Pid30Rpc[MAX_PID30_RPC] = (WCHAR)'\0';
|
|
|
|
//
|
|
// Find out the kind of product we have (by looking at the site code):
|
|
// CD Retail, OEM or Select
|
|
//
|
|
|
|
if( StringLength > MAX_PID30_RPC ) {
|
|
//
|
|
// If the Pid contains the Site, then find out what it is
|
|
//
|
|
p = Data + MAX_PID30_RPC;
|
|
wcsncpy(Pid30Site,p,MAX_PID30_SITE+1);
|
|
|
|
if(_wcsicmp( Pid30Site, szPidSelectId ) == 0) {
|
|
|
|
//
|
|
// This is a Select CD
|
|
//
|
|
SelectPid:
|
|
CdType = CDSelect;
|
|
if (!EulaComplete && !KeyPresent) {
|
|
DisplayPidDialog = TRUE;
|
|
} else {
|
|
//
|
|
// The Pid was specified during winnt32.
|
|
// Set the pid globals and build the product id string
|
|
//
|
|
|
|
if (!SetPid30FromAnswerFile()) {
|
|
DisplayPidDialog = TRUE;
|
|
goto finish;
|
|
}
|
|
DisplayPidDialog = FALSE;
|
|
|
|
}
|
|
/*
|
|
// Old code. previous version of Windows did not require a PID for Select media.
|
|
for (i = 0; i< 5; i++) {
|
|
Pid30Text[i][0] = (WCHAR)L'\0';
|
|
}
|
|
|
|
DisplayPidDialog = FALSE;
|
|
|
|
if (!ValidateAndSetPid30()) {
|
|
SetuplogError( LogSevFatalError,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PID_CANT_READ_PID, NULL,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PID_INVALID_PID,
|
|
szRegQueryValueEx,
|
|
Type,
|
|
StringLength,
|
|
NULL,NULL);
|
|
return( FALSE );
|
|
}
|
|
|
|
if (MiniSetup || OobeSetup) {
|
|
return(TRUE);
|
|
}
|
|
*/
|
|
#if 0
|
|
// msdn media no longer exists (and if it does it should be viewed as retail,
|
|
// so later in this case statement we will fall thru to retail
|
|
} else if (_wcsicmp( Pid30Site, szPidMsdnId ) == 0) {
|
|
|
|
//
|
|
// This is an MSDN CD
|
|
//
|
|
MsdnPid:
|
|
for (i = 0; i< 5; i++) {
|
|
LPWSTR ptr;
|
|
ptr = (LPTSTR) &szPid30Msdn[i*(MAX_PID30_EDIT+1)];
|
|
wcsncpy(Pid30Text[i], ptr, MAX_PID30_EDIT+1 );
|
|
Pid30Text[i][MAX_PID30_EDIT] = (WCHAR)L'\0';
|
|
}
|
|
CdType = CDSelect;
|
|
DisplayPidDialog = FALSE;
|
|
if (!ValidateAndSetPid30()) {
|
|
SetuplogError( LogSevFatalError,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PID_CANT_READ_PID, NULL,
|
|
SETUPLOG_USE_MESSAGEID,
|
|
MSG_LOG_PID_INVALID_PID,
|
|
szRegQueryValueEx,
|
|
Type,
|
|
StringLength,
|
|
NULL,NULL);
|
|
return( FALSE );
|
|
}
|
|
|
|
if (MiniSetup) {
|
|
return(TRUE);
|
|
}
|
|
#endif
|
|
} else if( _wcsicmp( Pid30Site, szPidOemId ) == 0 ) {
|
|
//
|
|
// This is OEM
|
|
//
|
|
CdType = CDOem;
|
|
|
|
if (!EulaComplete && !KeyPresent) {
|
|
DisplayPidDialog = TRUE;
|
|
} else {
|
|
//
|
|
// The Pid was specified during winnt32.
|
|
// Set the pid globals and build the product id string
|
|
//
|
|
if (!SetPid30FromAnswerFile() ) {
|
|
DisplayPidDialog = TRUE;
|
|
goto finish;
|
|
}
|
|
|
|
DisplayPidDialog = FALSE;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// This is a bogus site assume CD Retail
|
|
//
|
|
CdType = CDRetail;
|
|
wcsncpy( Pid30Site, L"000", MAX_PID30_SITE+1 );
|
|
Pid30Site[ MAX_PID30_SITE ] = (WCHAR)'\0';
|
|
|
|
if (!EulaComplete && !KeyPresent) {
|
|
DisplayPidDialog = TRUE;
|
|
} else {
|
|
//
|
|
// The Pid was specified during winnt32.
|
|
// Set the pid globals and build the product id string
|
|
//
|
|
|
|
if (!SetPid30FromAnswerFile()) {
|
|
DisplayPidDialog = TRUE;
|
|
goto finish;
|
|
}
|
|
DisplayPidDialog = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
//
|
|
// If it doesn't contain the Site, then it is a CD retail,
|
|
// and the appropriate Pid dialog must be displayed.
|
|
//
|
|
CdType = CDRetail;
|
|
wcsncpy( Pid30Site, L"000", MAX_PID30_SITE+1 );
|
|
Pid30Site[ MAX_PID30_SITE ] = (WCHAR)'\0';
|
|
|
|
if (!EulaComplete && !KeyPresent) {
|
|
DisplayPidDialog = TRUE;
|
|
} else {
|
|
//
|
|
// The Pid was specified during winnt32.
|
|
// Set the pid globals and build the product id string
|
|
//
|
|
if (!SetPid30FromAnswerFile()) {
|
|
DisplayPidDialog = TRUE;
|
|
goto finish;
|
|
}
|
|
DisplayPidDialog = FALSE;
|
|
}
|
|
}
|
|
|
|
finish:
|
|
//
|
|
// Don't remove the Setup\Pid here. See MiniSetupGetCdType
|
|
// Delete Setup\PidList since it is no longer needed
|
|
//
|
|
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
L"SYSTEM\\Setup",
|
|
0,
|
|
MAXIMUM_ALLOWED,
|
|
&Key );
|
|
|
|
if( Error == ERROR_SUCCESS ) {
|
|
// pSetupRegistryDelnode( Key, L"Pid" );
|
|
pSetupRegistryDelnode( Key, L"PidList" );
|
|
RegCloseKey( Key );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|