Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1155 lines
30 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"
#pragma hdrstop
typedef enum {
CDRetail,
CDOem,
CDSelect
} CDTYPE;
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";
PCWSTR szPidOemId = L"OEM";
//
// Flag indicating whether to display the product id dialog.
//
BOOL DisplayPidDialog = TRUE;
//
// Product ID.
//
WCHAR ProductId[MAX_PRODUCT_ID+1];
WCHAR Pid20Rpc[MAX_PID20_RPC+1];
WCHAR Pid20Site[MAX_PID20_SITE+1];
WCHAR Pid20SerialChk[MAX_PID20_SERIAL_CHK+1];
WCHAR Pid20Random[MAX_PID20_RANDOM+1];
PWSTR* Pid20Array = NULL;
//
// Address of the original edit control's window procedure
//
WNDPROC OldWndLongEditPid;
//
// Pid related flags
//
// BOOL DisplayPidCdDialog;
// BOOL DisplayPidOemDialog;
PCWSTR
GetRandomDigitsFromExistingPid(
)
/*++
Routine Description:
Find a Pid in Pid20Array whose first 15 characters match the ones stored
in Pid20Rpc, Pid20Site and Pid20SerialChk in this order, and return
a pointer to the random digits of the Pid found.
Arguments:
None.
Return Value:
PCWSTR - Returns a pointer to a 5-digit string that contains the 5 digits
of an existing Pid in Pid20Array, or NULL if Pid20Array doesn't
contain a Pid with PartialPid as prefix.
--*/
{
PWSTR p;
ULONG i,n;
WCHAR Buffer[MAX_PID20_RPC + MAX_PID20_SITE + MAX_PID20_SERIAL_CHK + 1];
if( Pid20Array != NULL ) {
n = MAX_PID20_RPC + MAX_PID20_SITE + MAX_PID20_SERIAL_CHK;
wcscpy( Buffer, Pid20Rpc );
wcscat( Buffer, Pid20Site );
wcscat( Buffer, Pid20SerialChk );
for( i = 0; ( p = Pid20Array[i] ) != NULL; i++ ) {
if( _wcsnicmp( p, Buffer, n ) == 0 ) {
return( p + n );
}
}
}
return( NULL );
}
DWORD
GenerateRandomNumber(
IN DWORD Seed
)
/*++
Routine Description:
Generate a random number.
Arguments:
Seed - Seed for random-number generator. Don't use system time as
a seed, because this routine uses the time as an additional
seed. Instead, use something that depends on user input.
A great seed would be derived from the difference between the
two timestamps seperated by user input. A less desirable
approach would be to sum the characters in several user
input strings.
Return Value:
Returns a random number.
--*/
{
NTSTATUS Status;
LARGE_INTEGER Time;
KERNEL_USER_TIMES KernelUserTimes;
DWORD r1,r2,r3;
//
// Generate 3 pseudo-random numbers using the Seed parameter, the
// system time, and the user-mode execution time of this process as
// random number generator seeds.
//
Status = NtQuerySystemTime(&Time);
//
// Don't bother with error conditions, as this function will return
// as random number, the sum of the 3 numbers generated.
//
// if(!NT_SUCCESS(Status)) {
// return(Status);
// }
//
Status = NtQueryInformationThread(
NtCurrentThread(),
ThreadTimes,
&KernelUserTimes,
sizeof(KernelUserTimes),
NULL
);
//
// Don't bother with error conditions, as this function will return
// as random number, the sum of the 3 numbers generated.
//
// if(!NT_SUCCESS(Status)) {
// return(Status);
// }
//
srand(Seed);
r1 = ((DWORD)rand() << 16) + (DWORD)rand();
srand(Time.LowPart);
r2 = ((DWORD)rand() << 16) + (DWORD)rand();
srand(KernelUserTimes.UserTime.LowPart);
r3 = ((DWORD)rand() << 16) + (DWORD)rand();
return( r1 + r2 + r3 );
}
VOID
BuildProductIdString(
VOID
)
/*++
Routine Description:
Build a string based on the global Pid20 variables, and
save it in the global variable ProductId.
Arguments:
None.
Return Value:
TRUE if the Pid was saved in the registry.
--*/
{
wcscpy( ProductId, Pid20Rpc );
wcscat( ProductId, Pid20Site );
wcscat( ProductId, Pid20SerialChk );
wcscat( ProductId, Pid20Random );
}
BOOL
ValidateSerialChk(
IN PCWSTR PidString
)
/*++
Routine Description:
Validates the string passed as argument, than represents the
6-digit serial number and the Check digit on a Pid.
Arguments:
PidString - a 7-digit string that corresponding to the serial number
and check digit on a Pid.
Return Value:
TRUE if the string is valid.
--*/
{
ULONG i;
ULONG Result;
if( (wcslen( PidString ) != MAX_PID20_SERIAL_CHK) ||
!isdigit( PidString[MAX_PID20_SERIAL_CHK - 1] ) ||
(PidString[MAX_PID20_SERIAL_CHK - 1] - (WCHAR)'0' == 0) ||
(PidString[MAX_PID20_SERIAL_CHK - 1] - (WCHAR)'0' >= 8)
) {
return( FALSE );
}
for( i = 0, Result = 0; i < MAX_PID20_SERIAL_CHK; i++ ) {
if( !isdigit( PidString[i] ) ) {
return( FALSE );
}
Result += PidString[i] - (WCHAR)'0';
}
return((Result % 7) == 0);
}
BOOL
ValidateCDRetailSite(
IN PCWSTR PidString
)
/*++
Routine Description:
Validates the string passed as argument, that represents the
3-digit Site on a CD Retail Pid.
The following numbers are invalid sites: 333, 444, 555, 666,
777, 888 and 999.
Arguments:
PidString - a 3-digit string corresponding to the Site on a Pid.
Return Value:
TRUE if the string is valid.
--*/
{
ULONG Site;
if( wcslen( PidString ) != MAX_PID20_SITE ) {
return( FALSE );
}
Site = wcstoul( PidString, NULL, 10 );
return( ( Site != 333 ) &&
( Site != 444 ) &&
( Site != 555 ) &&
( Site != 666 ) &&
( Site != 777 ) &&
( Site != 888 ) &&
( Site != 999 ) );
}
BOOL
ValidateOemRandom(
IN PCWSTR PidString
)
/*++
Routine Description:
Validates the string passed as argument, that represents the
5-digit random number on a OEM Pid (COA).
All characters on the string must be digits.
This function is only called during unattended mode setup, to
validate an OEM Pid specified in the unattended script file.
Arguments:
PidString - a 5-digit string corresponding to the random number
on a OEM Pid.
Return Value:
TRUE if the string is valid.
--*/
{
ULONG i;
if( lstrlen( PidString ) != MAX_PID20_RANDOM ) {
return( FALSE );
}
for( i = 0; i < MAX_PID20_RANDOM; i++ ) {
if( !isdigit( PidString[i] ) ) {
return( FALSE );
}
}
return( TRUE );
}
BOOL
ValidateOemSerialChk(
IN PCWSTR PidString
)
/*++
Routine Description:
Validates the string passed as argument, that represents the
6-digit serial number and the Check digit on a OEM Pid (COA).
The first digit must be 0, and the string must pass the mod 7
algorithm provided by Microsoft.
Arguments:
PidString - a 7-digit string that corresponding to the serial number
and check digit on a OEM Pid.
Return Value:
TRUE if the string is valid.
--*/
{
return( (PidString[0] == (WCHAR)'0') &&
ValidateSerialChk(PidString) );
}
BOOL
ValidateOemRpc(
IN PCWSTR PidString
)
/*++
Routine Description:
Validates the string passed as argument, that represents the
first 5-digits (Rpc) on a OEM Pid (COA).
The first 3 digits represent the julian date the COA was printed.
001-366 inclusive (allowing for a leap year) are valid.
000 and 367-999 are invalid.
The last two digits represent the year.
95, 96, 97, 98, 99, 00, 01, 02 and 03 are valid years.
04-94 are invalid years.
Arguments:
PidString - a 5-digit string that corresponding to the Rpc number
on a OEM Pid.
Return Value:
TRUE if the string is valid.
--*/
{
WCHAR DateString[4];
WCHAR YearString[3];
ULONG Date;
ULONG Year;
if( wcslen( PidString ) != MAX_PID20_RPC ) {
return( FALSE );
}
DateString[0] = PidString[0];
DateString[1] = PidString[1];
DateString[2] = PidString[2];
DateString[3] = (WCHAR)'\0';
YearString[0] = PidString[3];
YearString[1] = PidString[4];
YearString[2] = (WCHAR)'\0';
Date = wcstoul( DateString, NULL, 10 );
Year = wcstoul( YearString, NULL, 10 );
return( ((Date >= 1) && (Date <= 366)) &&
!((Year >= 4) && (Year <= 94)) );
}
LONG
EditInteger(
IN HWND hWnd,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
This routine preprocesses the messages that are sent to the edit
controls in the Pid dialogs. It ensures that only digits and are
accepted by the edit controls.
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.
--*/
{
switch( msg ) {
case WM_CHAR:
if( ( wParam == ( WCHAR )'\t' ) || ( wParam == ( WCHAR )'\b' ) ) {
//
// If tab or backspace, let the old edit control's WinProc
// deal with it.
//
break;
}
if( wParam < ( WCHAR )'0' || wParam > ( WCHAR )'9' ) {
//
// Reject characters that are not decimal digits
//
return( TRUE );
}
break;
}
//
// Call the old window routine to deal with everything else...
//
return( CallWindowProc( OldWndLongEditPid, hWnd, msg, wParam, lParam ) );
}
BOOL
CALLBACK
PidCDDlgProc(
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;
switch(msg) {
case WM_INITDIALOG: {
if( UiTest ) {
//
// If testing the wizard, make sure that the PidOEM page is
// displayed
//
CdType = CDRetail;
DisplayPidDialog = TRUE;
}
//
// Subclass the edit control so that the user is allowed to type
// only decimal digits when providing the Pid.
// Note that it is enough to save the original address of only one
// of the Pid edit controls, since it is the same for all edit controls.
//
OldWndLongEditPid = (WNDPROC)GetWindowLong( GetDlgItem( hdlg, IDT_EDIT_PID1 ),
GWL_WNDPROC );
SetWindowLong( GetDlgItem( hdlg, IDT_EDIT_PID1 ),
GWL_WNDPROC,
(LONG)EditInteger );
SetWindowLong( GetDlgItem( hdlg, IDT_EDIT_PID2 ),
GWL_WNDPROC,
(LONG)EditInteger );
//
// Limit the maximum number of characters in the edit controls
//
SendDlgItemMessage(hdlg,IDT_EDIT_PID1,EM_LIMITTEXT,MAX_PID20_SITE,0);
SendDlgItemMessage(hdlg,IDT_EDIT_PID2,EM_LIMITTEXT,MAX_PID20_SERIAL_CHK,0);
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:
if(DisplayPidDialog && CdType == CDRetail) {
SetWizardButtons(hdlg,WizPageProductIdCd);
SetupSetLargeDialogFont(hdlg,IDT_STATIC_1);
SendDlgItemMessage(hdlg,IDT_EDIT_PID1,EM_SETSEL,0,-1);
SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
} else {
SetWindowLong(hdlg,DWL_MSGRESULT,-1);
break;
}
if(Unattended) {
UnattendSetActiveDlg(hdlg,IDD_PID_CD);
}
break;
case PSN_WIZNEXT:
case PSN_WIZFINISH:
if( ( GetDlgItemText(hdlg,IDT_EDIT_PID1,Pid20Site,MAX_PID20_SITE+1) != MAX_PID20_SITE ) ||
!ValidateCDRetailSite( Pid20Site ) ) {
//
// Tell user that the Pid is not valid, and
// don't allow next page to be activated.
//
if (Unattended) {
UnattendErrorDlg( hdlg, IDD_PID_CD );
} // if
MessageBoxFromMessage(hdlg,MSG_PID_IS_INVALID,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
if(!UiTest) {
SetWindowLong(hdlg,DWL_MSGRESULT,-1);
}
} else if ( ( GetDlgItemText(hdlg,IDT_EDIT_PID2,Pid20SerialChk,MAX_PID20_SERIAL_CHK+1) != MAX_PID20_SERIAL_CHK ) ||
!ValidateSerialChk( Pid20SerialChk ) ) {
//
// Tell user that the Pid is not valid, and
// don't allow next page to be activated.
//
if (Unattended) {
UnattendErrorDlg( hdlg, IDD_PID_CD );
} // if
MessageBoxFromMessage(hdlg,MSG_PID_IS_INVALID,NULL,IDS_ERROR,MB_OK|MB_ICONSTOP);
SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID2));
if(!UiTest) {
SetWindowLong(hdlg,DWL_MSGRESULT,-1);
}
} else {
ULONG RandomNumber;
ULONG Seed;
PCWSTR q;
//
// The Pid is valid. Geneate Pid20Random.
//
if( ( q = GetRandomDigitsFromExistingPid() ) != NULL ) {
wcscpy( Pid20Random, q );
} else {
//
// BUGBUG - Generate a better seed
//
Seed = GetTickCount();
RandomNumber = GenerateRandomNumber( Seed );
swprintf( Pid20Random, L"%05u", RandomNumber % 100000 );
}
BuildProductIdString();
//
// Since the Pid is already built, don't let this dialog
// be displayed in the future.
//
// DisplayPidDialog = FALSE;
//
// Allow next page to be activated.
//
SetWindowLong(hdlg,DWL_MSGRESULT,0);
}
break;
case PSN_KILLACTIVE:
WizardKillHelp(hdlg);
SetWindowLong(hdlg,DWL_MSGRESULT, FALSE);
break;
case PSN_HELP:
WizardBringUpHelp(hdlg,WizPageProductIdCd);
break;
default:
break;
}
break;
default:
return(FALSE);
}
return(TRUE);
}
BOOL
CALLBACK
PidOemDlgProc(
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;
switch(msg) {
case WM_INITDIALOG: {
if( UiTest ) {
//
// If testing the wizard, make sure that the PidOEM page is
// displayed
//
CdType = CDOem;
DisplayPidDialog = TRUE;
}
//
// Subclass the edit control so that the user is allowed to type
// only decimal digits when providing the Pid.
// Note that it is enough to save the original address of only one
// of the Pid edit controls, since it is the same for all edit controls.
//
OldWndLongEditPid = (WNDPROC)GetWindowLong( GetDlgItem( hdlg, IDT_EDIT_PID1 ), GWL_WNDPROC );
SetWindowLong( GetDlgItem( hdlg, IDT_EDIT_PID1 ),
GWL_WNDPROC,
(LONG)EditInteger );
SetWindowLong( GetDlgItem( hdlg, IDT_EDIT_PID2 ),
GWL_WNDPROC,
(LONG)EditInteger );
SetWindowLong( GetDlgItem( hdlg, IDT_EDIT_PID3 ),
GWL_WNDPROC,
(LONG)EditInteger );
//
// Limit the maximum number of characters in the edit controls
//
SendDlgItemMessage(hdlg,IDT_EDIT_PID1,EM_LIMITTEXT,MAX_PID20_RPC,0);
SendDlgItemMessage(hdlg,IDT_EDIT_PID2,EM_LIMITTEXT,MAX_PID20_SERIAL_CHK,0);
SendDlgItemMessage(hdlg,IDT_EDIT_PID3,EM_LIMITTEXT,MAX_PID20_RANDOM,0);
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:
if(DisplayPidDialog && CdType == CDOem) {
SetWizardButtons(hdlg,WizPageProductIdCd);
SetupSetLargeDialogFont(hdlg,IDT_STATIC_1);
SendDlgItemMessage(hdlg,IDT_EDIT_PID1,EM_SETSEL,0,-1);
SetFocus(GetDlgItem(hdlg,IDT_EDIT_PID1));
} else {
SetWindowLong(hdlg,DWL_MSGRESULT,-1);
break;
}
if(Unattended) {
UnattendSetActiveDlg( hdlg, IDD_PID_OEM );
}
break;
case PSN_WIZNEXT:
case PSN_WIZFINISH:
if( ( GetDlgItemText(hdlg,IDT_EDIT_PID1,Pid20Rpc,MAX_PID20_RPC+1) != MAX_PID20_RPC ) ||
!ValidateOemRpc( Pid20Rpc ) ){
//
// 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) {
SetWindowLong(hdlg,DWL_MSGRESULT,-1);
}
} else if ( ( GetDlgItemText(hdlg,IDT_EDIT_PID2,Pid20SerialChk,MAX_PID20_SERIAL_CHK+1) != MAX_PID20_SERIAL_CHK ) ||
!ValidateOemSerialChk( Pid20SerialChk ) ) {
//
// 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_PID2));
if(!UiTest) {
SetWindowLong(hdlg,DWL_MSGRESULT,-1);
}
} else if ( GetDlgItemText(hdlg,IDT_EDIT_PID3,Pid20Random,MAX_PID20_RANDOM+1) != MAX_PID20_RANDOM ) {
//
// 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_PID3));
if(!UiTest) {
SetWindowLong(hdlg,DWL_MSGRESULT,-1);
}
} else {
//
// The Pid is valid.
//
BuildProductIdString();
//
//
// Since the Pid is already built, don't let this dialog
// be displayed in the future.
//
// DisplayPidDialog = FALSE;
// Allow next page to be activated.
//
SetWindowLong(hdlg,DWL_MSGRESULT,0);
}
break;
case PSN_KILLACTIVE:
WizardKillHelp(hdlg);
SetWindowLong( hdlg, DWL_MSGRESULT, FALSE );
break;
case PSN_HELP:
WizardBringUpHelp(hdlg,WizPageProductIdCd);
break;
default:
break;
}
break;
default:
return(FALSE);
}
return(TRUE);
}
BOOL
InitializePid20Array(
)
/*++
Routine Description:
Build the array that contains all Pid20 found in the machine
during textmode setup.
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] = DuplicateString( 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;
//
// First create an array with the Pids found during textmode setup
//
InitializePid20Array();
//
// Get the Pid from HKEY_LOCAL_MACHINE\SYSTEM\Setup\Pid
//
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
szPidKeyName,
0,
KEY_READ,
&Key );
if( Error != ERROR_SUCCESS ) {
LogItem1( LogSevFatalError,
MSG_LOG_PID_CANT_READ_PID,
MSG_LOG_X_PARAM_RETURNED_WINERR,
szRegOpenKeyEx,
Error,
szPidKeyName );
return( FALSE );
}
cbData = sizeof(Data);
Error = RegQueryValueEx( Key,
szPidValueName,
0,
&Type,
( LPBYTE )Data,
&cbData );
RegCloseKey( Key );
if( (Error != ERROR_SUCCESS) ) {
LogItem1( LogSevFatalError,
MSG_LOG_PID_CANT_READ_PID,
MSG_LOG_X_PARAM_RETURNED_WINERR,
szRegQueryValueEx,
Error,
szPidValueName );
return( FALSE );
}
//
// Do some validation of the value read
//
if( ( Type != REG_SZ ) ||
( ( ( StringLength = wcslen( Data ) ) != 0 ) &&
( StringLength != MAX_PID20_RPC ) &&
( StringLength != MAX_PID20_RPC + MAX_PID20_SITE )
// && ( StringLength != MAX_PID20_RPC + MAX_PID20_SITE + MAX_PID20_SERIAL_CHK)
// && ( StringLength != MAX_PRODUCT_ID )
)
) {
LogItem1( LogSevFatalError,
MSG_LOG_PID_CANT_READ_PID,
MSG_LOG_PID_INVALID_PID,
szRegQueryValueEx,
Type,
StringLength );
return( FALSE );
}
//
// Find out the kind of product we have:
// CD Retail, OEM or Select
//
if( StringLength > MAX_PID20_RPC ) {
//
// If the Pid contains the Site, then find out what it is
//
p = Data + MAX_PID20_RPC;
wcsncpy( Pid20Site, p, MAX_PID20_SITE );
Pid20Site[MAX_PID20_SITE] = (WCHAR)'\0';
if( _wcsicmp( Pid20Site, szPidSelectId ) == 0 ) {
//
// This is a Select CD
//
CdType = CDSelect;
DisplayPidDialog = FALSE;
wcsncpy( Pid20Rpc, Data, MAX_PID20_RPC );
Pid20Rpc[ MAX_PID20_RPC ] = (WCHAR)'\0';
//
// Generate Pid20SerialChk and Pid20Random
//
//
// BUGBUG - Generate a better seed
//
Seed = GetTickCount();
RandomNumber = GenerateRandomNumber( Seed );
swprintf( Pid20SerialChk, L"%06u", RandomNumber % 1000000 );
//
// Generate the check digit
//
ChkDigit = 0;
for( i=0; i < MAX_PID20_SERIAL_CHK-1; i++ ) {
ChkDigit += Pid20SerialChk[i] - (ULONG)((WCHAR)'0');
}
ChkDigit = 7 - ChkDigit % 7;
Pid20SerialChk[ MAX_PID20_SERIAL_CHK - 1] = (WCHAR)(ChkDigit + (ULONG)'0');
Pid20SerialChk[ MAX_PID20_SERIAL_CHK ] = (WCHAR)'\0';
//
// Generate Pid20Random
//
//
// BUGBUG - Generate a better seed
//
Seed = GetTickCount() + ChkDigit;
RandomNumber = GenerateRandomNumber( Seed );
swprintf( Pid20Random, L"%05u", RandomNumber % 100000 );
BuildProductIdString();
} else if( _wcsicmp( Pid20Site, szPidOemId ) == 0 ) {
//
// This is OEM
//
CdType = CDOem;
DisplayPidDialog = TRUE;
Pid20Rpc[0] = (WCHAR)'\0';
Pid20SerialChk[0] = (WCHAR)'\0';
Pid20Random[0] = (WCHAR)'\0';
} else {
//
// This is a bogus site assume CD Retail
//
CdType = CDRetail;
wcsncpy( Pid20Rpc, Data, MAX_PID20_RPC );
Pid20Rpc[ MAX_PID20_RPC ] = (WCHAR)'\0';
Pid20Site[ 0 ] = (WCHAR)'\0';
Pid20SerialChk[ 0 ] = (WCHAR)'\0';
Pid20Random[ 0 ] = (WCHAR)'\0';
}
} else {
//
// If it doesn't contain the Site, then it is a CD retail,
// and the appropriate Pid dialog must be displayed.
//
CdType = CDRetail;
DisplayPidDialog = TRUE;
wcsncpy( Pid20Rpc, Data, MAX_PID20_RPC );
Pid20Rpc[ MAX_PID20_RPC ] = (WCHAR)'\0';
Pid20Site[ 0 ] = (WCHAR)'\0';
Pid20SerialChk[ 0 ] = (WCHAR)'\0';
Pid20Random[ 0 ] = (WCHAR)'\0';
}
//
// Delete Setup\Pid and Setup\PidList since they are no longer needed
//
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
L"SYSTEM\\Setup",
0,
MAXIMUM_ALLOWED,
&Key );
if( Error == ERROR_SUCCESS ) {
RegistryDelnode( Key, L"Pid" );
RegistryDelnode( Key, L"PidList" );
RegCloseKey( Key );
}
return( TRUE );
}