mirror of https://github.com/lianthony/NT4.0
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.
585 lines
13 KiB
585 lines
13 KiB
//
|
|
// APPWIZ.C Application installation wizard CPL
|
|
//
|
|
// Copyright (C) Microsoft, 1994,1995 All Rights Reserved.
|
|
//
|
|
// History:
|
|
// ral 5/23/94 - First pass
|
|
// ral 8/09/94 - Clean up
|
|
// 3/20/95 [stevecat] - NT port & real clean up, unicode, etc.
|
|
//
|
|
//
|
|
#include "appwiz.h"
|
|
#include <cpl.h>
|
|
#ifdef WINNT
|
|
//
|
|
// (tedm) Header files for Setup
|
|
//
|
|
#include <setupapi.h>
|
|
#include <syssetup.h>
|
|
#endif
|
|
|
|
TCHAR const c_szPIF[] = TEXT(".pif");
|
|
TCHAR const c_szLNK[] = TEXT(".lnk");
|
|
|
|
#ifdef WX86
|
|
|
|
BOOL
|
|
IsWx86Enabled(
|
|
VOID
|
|
)
|
|
|
|
//
|
|
// Consults the registry to determine if Wx86 is enabled in the system
|
|
// NOTE: this should be changed post SUR to call kernel32 which maintanes
|
|
// this information, Instead of reading the registry each time.
|
|
//
|
|
|
|
{
|
|
LONG Error;
|
|
HKEY hKey;
|
|
WCHAR ValueBuffer[MAX_PATH];
|
|
DWORD ValueSize;
|
|
DWORD dwType;
|
|
|
|
Error = RegOpenKeyW(HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Control\\Wx86",
|
|
&hKey
|
|
);
|
|
|
|
if (Error != ERROR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
ValueSize = sizeof(ValueBuffer);
|
|
Error = RegQueryValueExW(hKey,
|
|
L"cmdline",
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)ValueBuffer,
|
|
&ValueSize
|
|
);
|
|
RegCloseKey(hKey);
|
|
|
|
return (Error == ERROR_SUCCESS &&
|
|
dwType == REG_SZ &&
|
|
ValueSize &&
|
|
*ValueBuffer
|
|
);
|
|
|
|
}
|
|
#endif
|
|
|
|
BOOL APIENTRY LibMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
|
|
{
|
|
if( dwReason == DLL_PROCESS_ATTACH )
|
|
{
|
|
hInstance = hDll;
|
|
|
|
g_cxIcon = GetSystemMetrics(SM_CXICON);
|
|
g_cyIcon = GetSystemMetrics(SM_CYICON);
|
|
|
|
DisableThreadLibraryCalls(hDll);
|
|
|
|
#ifdef WX86
|
|
bWx86Enabled = IsWx86Enabled();
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LONG CALLBACK CPlApplet(HWND hwnd, UINT Msg, LPARAM lParam1, LPARAM lParam2 )
|
|
{
|
|
UINT nStartPage;
|
|
// not currently used by chicago LPNEWCPLINFO lpNewCPlInfo;
|
|
LPTSTR lpStartPage;
|
|
|
|
switch (Msg)
|
|
{
|
|
case CPL_INIT:
|
|
return TRUE;
|
|
|
|
case CPL_GETCOUNT:
|
|
return 1;
|
|
|
|
case CPL_INQUIRE:
|
|
#define lpCPlInfo ((LPCPLINFO)lParam2)
|
|
lpCPlInfo->idIcon = IDI_CPLICON;
|
|
lpCPlInfo->idName = IDS_NAME;
|
|
lpCPlInfo->idInfo = IDS_INFO;
|
|
lpCPlInfo->lData = 0;
|
|
#undef lpCPlInfo
|
|
break;
|
|
|
|
case CPL_DBLCLK:
|
|
InstallCPL(hwnd, 0);
|
|
break;
|
|
|
|
case CPL_STARTWPARMS:
|
|
nStartPage = 0;
|
|
lpStartPage = (LPTSTR)lParam2;
|
|
|
|
if (*lpStartPage)
|
|
{
|
|
while (*lpStartPage && (*lpStartPage != TEXT(',')))
|
|
{
|
|
nStartPage *= 10;
|
|
nStartPage += *lpStartPage++ - TEXT('0');
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure that the requested starting page is less than the max page
|
|
// for the selected applet.
|
|
|
|
if (nStartPage >= MAX_PAGES) return FALSE;
|
|
|
|
InstallCPL(hwnd, nStartPage);
|
|
|
|
return TRUE; // return non-zero to indicate message handled
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
} // CPlApplet
|
|
|
|
|
|
//
|
|
// This is the addpage which gets called back by external components (yay)
|
|
//
|
|
|
|
BOOL CALLBACK _AddExternalPage(HPROPSHEETPAGE hpage, LPARAM lParam)
|
|
{
|
|
PROPSHEETHEADER FAR * ppsh = (PROPSHEETHEADER FAR *)lParam;
|
|
|
|
if( hpage && ( ppsh->nPages < MAX_PAGES ) )
|
|
{
|
|
ppsh->phpage[ppsh->nPages++] = hpage;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Adds a page to a property sheet.
|
|
//
|
|
|
|
void AddPage(LPPROPSHEETHEADER ppsh, UINT id, DLGPROC pfn, LPWIZDATA lpwd)
|
|
{
|
|
if (ppsh->nPages < MAX_PAGES)
|
|
{
|
|
PROPSHEETPAGE psp;
|
|
|
|
psp.dwSize = sizeof(psp);
|
|
psp.dwFlags = PSP_DEFAULT;
|
|
psp.hInstance = hInstance;
|
|
psp.pszTemplate = MAKEINTRESOURCE(id);
|
|
psp.pfnDlgProc = pfn;
|
|
psp.lParam = (LPARAM)lpwd;
|
|
|
|
ppsh->phpage[ppsh->nPages] = CreatePropertySheetPage(&psp);
|
|
|
|
if (ppsh->phpage[ppsh->nPages])
|
|
ppsh->nPages++;
|
|
}
|
|
} // AddPage
|
|
|
|
|
|
//
|
|
// Main control panel entry point. Displays a property sheet with
|
|
//
|
|
|
|
void InstallCPL(HWND hwnd, UINT nStartPage)
|
|
{
|
|
WIZDATA wd;
|
|
HPROPSHEETPAGE rPages[MAX_PAGES];
|
|
PROPSHEETHEADER psh;
|
|
int iPrshtResult;
|
|
|
|
memset(&wd, 0, sizeof(wd));
|
|
|
|
psh.dwSize = sizeof(psh);
|
|
psh.dwFlags = PSH_PROPTITLE;
|
|
psh.hwndParent = hwnd;
|
|
psh.hInstance = hInstance;
|
|
psh.pszCaption = MAKEINTRESOURCE(IDS_NAME);
|
|
psh.nPages = 0;
|
|
psh.nStartPage = nStartPage;
|
|
psh.phpage = rPages;
|
|
|
|
//
|
|
// If there's no net install list then we'll decrement the start page
|
|
// by 1 so that the tab numbers can remain constant.
|
|
//
|
|
|
|
if (AppListGetInfName(&wd))
|
|
{
|
|
AddPage(&psh, DLG_APPLIST, AppListDlgProc, &wd);
|
|
}
|
|
else
|
|
{
|
|
if (psh.nStartPage > 0)
|
|
{
|
|
psh.nStartPage--;
|
|
}
|
|
}
|
|
|
|
AddPage(&psh, DLG_INSTUNINSTALL, InstallUninstallDlgProc, &wd);
|
|
|
|
#ifdef WINNT
|
|
//
|
|
// (tedm)
|
|
//
|
|
// Setup on NT is completely different. No calling into 16-bit DLLs, etc.
|
|
// Just ask the system setup module for its optional components page.
|
|
//
|
|
SetupCreateOptionalComponentsPage(_AddExternalPage,(LPARAM)&psh);
|
|
#else
|
|
// Have (16-bit) SETUPX add the Optional Components page
|
|
SHAddPages16( NULL, TEXT("SETUPX.DLL,SUOCPage"), _AddExternalPage,
|
|
(LPARAM)&psh );
|
|
|
|
// Have (16-bit) SETUPX add the Emergency Boot Disk page
|
|
SHAddPages16( NULL, TEXT("SETUPX.DLL,SUEBDPage"), _AddExternalPage,
|
|
(LPARAM)&psh );
|
|
#endif
|
|
|
|
iPrshtResult = PropertySheet(&psh);
|
|
|
|
switch(iPrshtResult)
|
|
{
|
|
case ID_PSRESTARTWINDOWS:
|
|
case ID_PSREBOOTSYSTEM:
|
|
RestartDialog(hwnd, NULL,
|
|
iPrshtResult == ID_PSRESTARTWINDOWS ?
|
|
EW_RESTARTWINDOWS : EW_REBOOTSYSTEM);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Common code used by the Link and Setup wizards to initialize the
|
|
// property sheet header and wizard data.
|
|
//
|
|
|
|
void InitWizHeaders(LPPROPSHEETHEADER ppd,
|
|
HPROPSHEETPAGE *rPages,
|
|
LPWIZDATA lpwd, int iBmpID)
|
|
{
|
|
lpwd->hbmpWizard = LoadBitmap(hInstance, MAKEINTRESOURCE(iBmpID));
|
|
|
|
ppd->dwSize = sizeof(*ppd);
|
|
ppd->dwFlags = PSH_PROPTITLE | PSH_WIZARD;
|
|
ppd->hwndParent = lpwd->hwnd;
|
|
ppd->hInstance = hInstance;
|
|
ppd->pszCaption = NULL;
|
|
ppd->nPages = 0;
|
|
ppd->nStartPage = 0;
|
|
ppd->phpage = rPages;
|
|
}
|
|
|
|
|
|
//
|
|
// Called when a wizard is dismissed. Cleans up any garbage left behind.
|
|
//
|
|
|
|
void FreeWizData(LPWIZDATA lpwd)
|
|
{
|
|
if (lpwd->hbmpWizard)
|
|
{
|
|
DeleteObject(lpwd->hbmpWizard);
|
|
lpwd->hbmpWizard = NULL;
|
|
}
|
|
}
|
|
|
|
typedef struct _WIZPAGE {
|
|
int id;
|
|
DLGPROC pfn;
|
|
} WIZPAGE;
|
|
|
|
|
|
//
|
|
// Common code used by the Link Wizard, Setup Wizard, and App Wizard (PIF
|
|
// wizard).
|
|
//
|
|
|
|
BOOL DoWizard(LPWIZDATA lpwd, int iIDBitmap, WIZPAGE wp[], int PageCount)
|
|
{
|
|
HPROPSHEETPAGE rPages[MAX_PAGES];
|
|
PROPSHEETHEADER psh;
|
|
int i;
|
|
HWND hwndTemp = lpwd->hwnd;
|
|
BOOL bResult = FALSE;
|
|
|
|
InitWizHeaders(&psh, rPages, lpwd, iIDBitmap);
|
|
|
|
for (i = 0; i < PageCount; i++)
|
|
{
|
|
AddPage(&psh, wp[i].id, wp[i].pfn, lpwd);
|
|
}
|
|
|
|
bResult = PropertySheet(&psh);
|
|
lpwd->hwnd = hwndTemp;
|
|
FreeWizData(lpwd);
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
//
|
|
// Link Wizard
|
|
//
|
|
|
|
BOOL LinkWizard(LPWIZDATA lpwd)
|
|
{
|
|
static WIZPAGE wp[] = {
|
|
{DLG_BROWSE, BrowseDlgProc},
|
|
{DLG_PICKFOLDER, PickFolderDlgProc},
|
|
{DLG_GETTITLE, GetTitleDlgProc},
|
|
{DLG_PICKICON, PickIconDlgProc},
|
|
{DLG_WHICHCFG, PickConfigDlgProc},
|
|
{DLG_RMOPTIONS, ConfigOptionsDlgProc} };
|
|
|
|
return(DoWizard(lpwd, IDB_SHORTCUTBMP, wp, ARRAYSIZE(wp)));
|
|
}
|
|
|
|
|
|
BOOL SetupWizard(LPWIZDATA lpwd)
|
|
{
|
|
static WIZPAGE wp[] = {
|
|
{DLG_SETUP, SetupDlgProc},
|
|
{DLG_SETUPBROWSE, BrowseDlgProc} };
|
|
BOOL fResult;
|
|
|
|
lpwd->dwFlags |= WDFLAG_SETUPWIZ;
|
|
fResult = DoWizard(lpwd, IDB_INSTALLBMP, wp, ARRAYSIZE(wp));
|
|
lpwd->dwFlags &= ~WDFLAG_SETUPWIZ;
|
|
return(fResult);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
BOOL MSDOSPropOnlyWizard(LPWIZDATA lpwd)
|
|
{
|
|
static WIZPAGE wp[] = { {DLG_RMOPTIONS, ConfigOptionsDlgProc} };
|
|
lpwd->dwFlags |= WDFLAG_PIFPROP;
|
|
|
|
return(DoWizard(lpwd, IDB_DOSCONFIG, wp, ARRAYSIZE(wp)));
|
|
}
|
|
|
|
|
|
// BUGBUG -- WHAT THE HECK DO I DO ABOUT hAPPINSTANCE HERE?????
|
|
|
|
//
|
|
// RUNDLL entry point to create a new link. An empty file has already been
|
|
// created and is the only parameter passed in lpszCmdLine.
|
|
//
|
|
|
|
void WINAPI NewLinkHere_Common(HWND hwnd, HINSTANCE hAppInstance, LPTSTR lpszCmdLine, int nCmdShow)
|
|
{
|
|
WIZDATA wd;
|
|
TCHAR szFolder[MAX_PATH];
|
|
|
|
memset(&wd, 0, sizeof(wd));
|
|
|
|
wd.hwnd = hwnd;
|
|
wd.dwFlags |= WDFLAG_LINKHEREWIZ | WDFLAG_DONTOPENFLDR;
|
|
wd.lpszOriginalName = lpszCmdLine;
|
|
|
|
lstrcpyn(szFolder, lpszCmdLine, ARRAYSIZE(szFolder));
|
|
|
|
PathRemoveFileSpec(szFolder);
|
|
|
|
wd.lpszFolder = szFolder;
|
|
|
|
//
|
|
// If the filename passed in is not valid then we'll just silently fail.
|
|
//
|
|
|
|
if (PathFileExists(lpszCmdLine))
|
|
{
|
|
if (!LinkWizard(&wd))
|
|
{
|
|
DeleteFile(lpszCmdLine);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#define lpwd (&wd)
|
|
WIZERROR(TEXT("APPWIZ ERORR: Bogus file name passed to NewLinkHere"));
|
|
WIZERROR(lpszCmdLine);
|
|
#undef lpwd
|
|
}
|
|
}
|
|
|
|
void WINAPI NewLinkHere(HWND hwndStub, HINSTANCE hAppInstance, LPSTR lpszCmdLine, int nCmdShow)
|
|
{
|
|
#ifdef UNICODE
|
|
UINT iLen = lstrlenA(lpszCmdLine)+1;
|
|
LPWSTR lpwszCmdLine;
|
|
|
|
lpwszCmdLine = (LPWSTR)LocalAlloc(LPTR,iLen*SIZEOF(WCHAR));
|
|
if (lpwszCmdLine)
|
|
{
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
lpszCmdLine, -1,
|
|
lpwszCmdLine, iLen);
|
|
NewLinkHere_Common( hwndStub,
|
|
hAppInstance,
|
|
lpwszCmdLine,
|
|
nCmdShow );
|
|
LocalFree(lpwszCmdLine);
|
|
}
|
|
#else
|
|
NewLinkHere_Common( hwndStub,
|
|
hAppInstance,
|
|
lpszCmdLine,
|
|
nCmdShow );
|
|
#endif
|
|
}
|
|
|
|
void WINAPI NewLinkHereW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow)
|
|
{
|
|
#ifdef UNICODE
|
|
NewLinkHere_Common( hwndStub,
|
|
hAppInstance,
|
|
lpwszCmdLine,
|
|
nCmdShow );
|
|
#else
|
|
UINT iLen = WideCharToMultiByte(CP_ACP, 0,
|
|
lpwszCmdLine, -1,
|
|
NULL, 0, NULL, NULL)+1;
|
|
LPSTR lpszCmdLine;
|
|
|
|
lpszCmdLine = (LPSTR)LocalAlloc(LPTR,iLen);
|
|
if (lpszCmdLine)
|
|
{
|
|
WideCharToMultiByte(CP_ACP, 0,
|
|
lpwszCmdLine, -1,
|
|
lpszCmdLine, iLen,
|
|
NULL, NULL);
|
|
NewLinkHere_Common( hwndStub,
|
|
hAppInstance,
|
|
lpszCmdLine,
|
|
nCmdShow );
|
|
LocalFree(lpszCmdLine);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Entry point called from PIFMGR.DLL. We'll only display the MS-DOS options
|
|
// page for the specified hProps.
|
|
//
|
|
// NOTE: In this instance we want to LocalAlloc the wizard data since
|
|
// we're being called from a 16-bit application (with limited stack).
|
|
// Note that LPTR zero-initializes the block.
|
|
//
|
|
|
|
PIFWIZERR WINAPI AppWizard(HWND hwnd, INT hProps, UINT dwAction)
|
|
{
|
|
LPWIZDATA lpwd = (LPWIZDATA)LocalAlloc(LPTR, sizeof(WIZDATA));
|
|
PIFWIZERR err = PIFWIZERR_SUCCESS;
|
|
|
|
if (!lpwd)
|
|
{
|
|
return(PIFWIZERR_OUTOFMEM);
|
|
}
|
|
|
|
lpwd->hProps = hProps;
|
|
lpwd->hwnd = hwnd;
|
|
|
|
switch (dwAction)
|
|
{
|
|
case WIZACTION_UICONFIGPROP:
|
|
if (!MSDOSPropOnlyWizard(lpwd))
|
|
{
|
|
err = PIFWIZERR_USERCANCELED;
|
|
}
|
|
break;
|
|
|
|
case WIZACTION_SILENTCONFIGPROP:
|
|
err = ConfigRealModeOptions(lpwd, NULL, CRMOACTION_DEFAULT);
|
|
break;
|
|
|
|
case WIZACTION_CREATEDEFCLEANCFG:
|
|
err = ConfigRealModeOptions(lpwd, NULL, CRMOACTION_CLEAN);
|
|
break;
|
|
|
|
default:
|
|
err = PIFWIZERR_INVALIDPARAM;
|
|
}
|
|
|
|
LocalFree((LPVOID)lpwd);
|
|
return(err);
|
|
}
|
|
|
|
|
|
//
|
|
// Called directly by Cabinet
|
|
//
|
|
|
|
BOOL ConfigStartMenu(HWND hwnd, BOOL bDelete)
|
|
{
|
|
if (bDelete)
|
|
{
|
|
return(RemoveItemsDialog(hwnd));
|
|
}
|
|
else
|
|
{
|
|
WIZDATA wd;
|
|
|
|
memset(&wd, 0, sizeof(wd));
|
|
|
|
wd.hwnd = hwnd;
|
|
wd.dwFlags |= WDFLAG_DONTOPENFLDR;
|
|
|
|
return(LinkWizard(&wd));
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// This is a generic function that all the app wizard sheets call
|
|
// to do basic initialization.
|
|
//
|
|
|
|
LPWIZDATA InitWizSheet(HWND hDlg, LPARAM lParam, DWORD dwFlags)
|
|
{
|
|
LPPROPSHEETPAGE ppd = (LPPROPSHEETPAGE)lParam;
|
|
LPWIZDATA lpwd = (LPWIZDATA)ppd->lParam;
|
|
HWND hBmp = GetDlgItem(hDlg, IDC_WIZBMP);
|
|
|
|
lpwd->hwnd = hDlg;
|
|
|
|
SetWindowLong(hDlg, DWL_USER, lParam);
|
|
|
|
SendMessage(hBmp, STM_SETIMAGE,
|
|
IMAGE_BITMAP, (LPARAM)lpwd->hbmpWizard);
|
|
|
|
return(lpwd);
|
|
}
|
|
|
|
void CleanUpWizData(LPWIZDATA lpwd)
|
|
{
|
|
//
|
|
// Release any INewShortcutHook.
|
|
//
|
|
|
|
if (lpwd->pnshhk)
|
|
{
|
|
lpwd->pnshhk->lpVtbl->Release(lpwd->pnshhk);
|
|
lpwd->pnshhk = NULL;
|
|
}
|
|
|
|
return;
|
|
}
|