📄 setup.cpp
字号:
/*=============================================================================
Filer.cpp: Unreal installer/filer.
Copyright 1997-1999 Epic Games, Inc. All Rights Reserved.
Revision history:
* Created by Tim Sweeney.
=============================================================================*/
// System includes.
#pragma warning( disable : 4201 )
#define STRICT
#include <windows.h>
#include <commctrl.h>
#include <shlobj.h>
#include <io.h>
#include <direct.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
#include "Res\resource.h"
// Unreal includes.
#include "SetupPrivate.h"
#include "USetupDefinitionWindows.h"
#include "Window.h"
/*-----------------------------------------------------------------------------
Globals.
-----------------------------------------------------------------------------*/
// Package implementation.
IMPLEMENT_PACKAGE(Setup)
// Functions.
class WWizardPage* NewAutoPlayPage( class WFilerWizard* InOwner, UBOOL ShowInstallOptions );
class FInstallPoll GNoPoll;
// Memory allocator.
#include <malloc.h>
#include "FMallocAnsi.h"
FMallocAnsi Malloc;
// Error handler.
#include "FOutputDeviceWindowsError.h"
FOutputDeviceWindowsError Error;
// Feedback.
#include "FFeedbackContextWindows.h"
FFeedbackContextWindows Warn;
// File manager.
#include "FFileManagerWindows.h"
FFileManagerWindows FileManager;
// Config.
#include "FConfigCacheIni.h"
/*-----------------------------------------------------------------------------
Helpers.
-----------------------------------------------------------------------------*/
// HRESULT checking.
#define verifyHRESULT(fn) {HRESULT hRes=fn; if( hRes!=S_OK ) appErrorf( TEXT(#fn) TEXT(" failed (%08X)"), hRes );}
#define verifyHRESULTSlow(fn) if(fn){}
void regSet( HKEY Base, FString Dir, FString Key, FString Value )
{
guard(regSet);
HKEY hKey = NULL;
check(RegCreateKeyX( Base, *Dir, &hKey )==ERROR_SUCCESS);
check(RegSetValueExX( hKey, *Key, 0, REG_SZ, (BYTE*)*Value, (Value.Len()+1)*sizeof(TCHAR) )==ERROR_SUCCESS);
check(RegCloseKey( hKey )==ERROR_SUCCESS);
unguard;
}
UBOOL regGet( HKEY Base, FString Dir, FString Key, FString& Str )
{
guard(regGetFString);
HKEY hKey = NULL;
if( RegOpenKeyX( Base, *Dir, &hKey )==ERROR_SUCCESS )
{
TCHAR Buffer[4096]=TEXT("");
DWORD Type=REG_SZ, BufferSize=sizeof(Buffer);
if
( RegQueryValueExX( hKey, *Key, 0, &Type, (BYTE*)Buffer, &BufferSize )==ERROR_SUCCESS
&& Type==REG_SZ )
{
Str = Buffer;
return 1;
}
}
Str = TEXT("");
return 0;
unguard;
}
SQWORD FreeSpace( const TCHAR* Folder )
{
guard(FreeSpace);
if( appStrlen(Folder) && appIsAlpha(Folder[0]) )
{
TCHAR Root[]=TEXT("C:") PATH_SEPARATOR;
Root[0] = Folder[0];
DWORD SectorsPerCluster=0, BytesPerSector=0, FreeClusters=0, TotalClusters=0;
GetDiskFreeSpaceX( Root, &SectorsPerCluster, &BytesPerSector, &FreeClusters, &TotalClusters );
return (QWORD)BytesPerSector * (QWORD)SectorsPerCluster * (QWORD)FreeClusters;
}
else return 0;
unguard;
}
//
// Remove a directory if it's empty. Returns error.
//
static UBOOL IsDrive( const TCHAR* Path )
{
if( appStricmp(Path,TEXT(""))==0 )
return 1;
else if( appToUpper(Path[0])!=appToLower(Path[0]) && Path[1]==':' && Path[2]==0 )
return 1;
else if( appStricmp(Path,TEXT("\\"))==0 )
return 1;
else if( appStricmp(Path,TEXT("\\\\"))==0 )
return 1;
else if( Path[0]=='\\' && Path[1]=='\\' && !appStrchr(Path+2,'\\') )
return 1;
else if( Path[0]=='\\' && Path[1]=='\\' && appStrchr(Path+2,'\\') && !appStrchr(appStrchr(Path+2,'\\')+1,'\\') )
return 1;
else
return 0;
}
UBOOL RemoveEmptyDirectory( FString Dir )
{
for( ; ; )
{
if( Dir.Right(1)==PATH_SEPARATOR )
Dir = Dir.LeftChop(1);
if( IsDrive(*Dir) )
break;
TArray<FString> List = GFileManager->FindFiles( *(Dir * TEXT("*")), 1, 1 );
if( List.Num() )
break;
if( !GFileManager->DeleteDirectory( *Dir, 1, 0 ) )
return 0;
while( Dir.Len() && Dir.Right(1)!=PATH_SEPARATOR )
Dir = Dir.LeftChop(1);
}
return 1;
}
void LocalizedFileError( const TCHAR* Key, const TCHAR* AdviceKey, const TCHAR* Filename )
{
guard(LocalizedError);
const TCHAR* Str = appGetSystemErrorMessage();
FString Msg = FString::Printf( TEXT("%s: %s (%s)\n\n%s"), LocalizeError(Key), Filename, Str, LocalizeError(AdviceKey) );
appErrorf( *Msg );
unguard;
}
/*-----------------------------------------------------------------------------
Install wizard.
-----------------------------------------------------------------------------*/
// Filer wizard.
class WFilerWizard : public WWizardDialog
{
DECLARE_WINDOWCLASS(WFilerWizard,WWizardDialog,Setup)
// Config info.
WLabel LogoStatic;
FWindowsBitmap LogoBitmap;
USetupDefinitionWindows* Manager;
// Constructor.
WFilerWizard()
: LogoStatic ( this, IDC_Logo )
, Manager ( new(UObject::CreatePackage(NULL,MANIFEST_FILE), TEXT("Setup"))USetupDefinitionWindows )
{
guard(WFilerWizard::WFilerWizard);
Manager->Init();
if( Manager->Uninstalling )
Manager->CreateRootGroup();
unguard;
}
// WWindow interface.
void OnInitDialog()
{
guard(WFilerWizard::OnInitDialog);
// Dialog init.
WWizardDialog::OnInitDialog();
Manager->hWndManager = hWnd;
SendMessageX( *this, WM_SETICON, ICON_BIG, (WPARAM)LoadIconIdX(hInstance,IDICON_Setup1) );
if( Manager->Logo==TEXT("") || !Manager->LocateSourceFile( Manager->Logo ) )
{
Manager->Logo = TEXT("..\\Help\\Logo.bmp");//!!for setup
if( GFileManager->FileSize(*Manager->Logo)<=0 )
Manager->Logo = TEXT("Logo.bmp");//!!for uninstaller
}
LogoBitmap.LoadFile( *Manager->Logo );
SendMessageX( LogoStatic, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)LogoBitmap.GetBitmapHandle() );
// Windows init.
verifyHRESULT(CoInitialize(NULL));
unguard;
}
// WFilerWizard interface.
void OnFinish()
{
guard(WFilerWizard::OnFinish);
WWizardDialog::OnFinish();
Manager->PreExit();
unguard;
}
};
/*-----------------------------------------------------------------------------
Product information.
-----------------------------------------------------------------------------*/
// Product information box.
class WProductInfo : public WDialog
{
DECLARE_WINDOWCLASS(WProductInfo,WDialog,Setup)
// Variables.
USetupProduct* SetupProduct;
WLabel ProductText;
WLabel VersionText;
WLabel DeveloperText;
WButton ProductHolder;
WUrlButton Product;
WUrlButton Version;
WUrlButton Developer;
// Constructor.
WProductInfo( WWindow* InOwner, USetupDefinition* Manager, USetupProduct* InSetupProduct )
: WDialog ( TEXT("ProductInfo"), IDDIALOG_ProductInfo, InOwner )
, SetupProduct ( InSetupProduct )
, ProductText ( this, IDC_ProductText )
, VersionText ( this, IDC_VersionText )
, DeveloperText ( this, IDC_DeveloperText )
, ProductHolder ( this, IDC_ProductHolder )
, Product ( this, TEXT(""), IDC_Product )
, Version ( this, TEXT(""), IDC_Version )
, Developer ( this, TEXT(""), IDC_Developer )
{}
// WDialog interface.
void LanguageChange()
{
guard(WProductInfo::LanguageChange);
//!!super::languagechange
// Product text.
Product .URL = SetupProduct->ProductURL;
Version .URL = SetupProduct->VersionURL;
Developer.URL = SetupProduct->DeveloperURL;
Product .SetText( *SetupProduct->LocalProduct );
Developer.SetText( *SetupProduct->Developer );
Version .SetText( *SetupProduct->Version );
// General text.
ProductText .SetText(Localize("IDDIALOG_ProductInfo","IDC_ProductText"));
VersionText .SetText(Localize("IDDIALOG_ProductInfo","IDC_VersionText"));
DeveloperText .SetText(Localize("IDDIALOG_ProductInfo","IDC_DeveloperText"));
ProductHolder .SetText(Localize("IDDIALOG_ProductInfo","IDC_ProductHolder"));
unguard;
}
};
/*-----------------------------------------------------------------------------
Failed requirement.
-----------------------------------------------------------------------------*/
// A password dialog box.
class WFailedRequirement : public WDialog
{
DECLARE_WINDOWCLASS(WFailedRequirement,WDialog,Setup)
// Controls.
WCoolButton OkButton;
WProductInfo ProductInfo;
WLabel FailedText;
FString Title;
FString Message;
// Constructor.
WFailedRequirement( WWindow* InOwnerWindow, USetupDefinition* Manager, USetupProduct* InProduct, const TCHAR* InTitle, const TCHAR* InMessage )
: WDialog ( TEXT("FailedRequirement"), IDDIALOG_FailedRequirement, InOwnerWindow )
, FailedText ( this, IDC_FailedMessage )
, OkButton ( this, IDOK, FDelegate(this,(TDelegate)EndDialogTrue) )
, ProductInfo ( this, Manager, InProduct )
, Title ( InTitle )
, Message ( InMessage )
{}
void OnInitDialog()
{
guard(WFailedRequirement::OnInitDialog);
WDialog::OnInitDialog();
SetText( *Title );
ProductInfo.OpenChildWindow( IDC_ProductInfoHolder, 1 );
ProductInfo.LanguageChange();
ProductInfo.ProductHolder.SetText( Localize("IDDIALOG_FailedRequirement","IDC_ProductHolder") );
FailedText.SetText( LineFormat(*Message) );
unguard;
}
};
/*-----------------------------------------------------------------------------
Install components.
-----------------------------------------------------------------------------*/
// Base of components page.
class WFilerPageComponentsBase : public WWizardPage
{
DECLARE_WINDOWCLASS(WFilerPageComponentsBase,WWizardPage,Setup)
WFilerWizard* Owner;
WFilerPageComponentsBase( const TCHAR* InText, INT InID, WFilerWizard* InOwner )
: WWizardPage( InText, InID, InOwner )
, Owner( InOwner )
{}
virtual void OnGroupChange( class FComponentItem* Group )=0;
};
// An component list item.
class FComponentItem : public FHeaderItem
{
public:
// Variables.
WFilerPageComponentsBase* OwnerComponents;
USetupGroup* SetupGroup;
UBOOL Forced;
// Constructors.
FComponentItem( WFilerPageComponentsBase* InOwnerComponents, USetupGroup* InSetupGroup, WPropertiesBase* InOwnerProperties, FTreeItem* InParent )
: FHeaderItem ( InOwnerProperties, InParent, 1 )
, OwnerComponents ( InOwnerComponents )
, SetupGroup ( InSetupGroup )
, Forced ( 0 )
{
guard(FComponentItem::FComponentItem);
// Get subgroups.
Sorted = SetupGroup->Manager->Uninstalling;
for( TArray<USetupGroup*>::TIterator It(SetupGroup->Subgroups); It; ++It )
if( (*It)->Visible )
Children.AddItem( new(TEXT("FComponentItem"))FComponentItem(OwnerComponents,*It,OwnerProperties,this) );
Expandable = Children.Num()>0;
unguard;
}
FRect GetCheckboxRect()
{
guard(FComponentItem::GetCheckboxRect);
return FRect(GetRect()-GetRect().Min).Right(16).Inner(FPoint(0,1))+FPoint(0,1);
unguard;
}
// FTreeItem interface.
UBOOL Greyed()
{
guard(FComponentItem::Greyed);
if( SetupGroup->Manager->Uninstalling )
return Forced;
else
for( FComponentItem* Item=(FComponentItem*)Parent; Item; Item=(FComponentItem*)Item->Parent )
if( !Item->SetupGroup->Selected )
return 1;
return 0;
unguard;
}
void Draw( HDC hDC )
{
guard(FComponentItem::Draw);
FHeaderItem::Draw( hDC );
DWORD GreyedFlags = SetupGroup->Manager->Uninstalling ? (DFCS_INACTIVE|DFCS_CHECKED) : (DFCS_INACTIVE);
DrawFrameControl( hDC, GetCheckboxRect()+GetRect().Min, DFC_BUTTON, DFCS_BUTTONCHECK|(Greyed()?GreyedFlags:0)|(SetupGroup->Selected?DFCS_CHECKED:0) );
unguard;
}
void ToggleSelection()
{
guard(FTreeItem::ToggleSelection);
if( SetupGroup->Optional && !Greyed() )
{
SetupGroup->Selected = !SetupGroup->Selected;
OwnerComponents->OnGroupChange( this );
InvalidateRect( OwnerProperties->List, NULL, 0 );
UpdateWindow( OwnerProperties->List );
}
unguard;
}
void OnItemDoubleClick()
{
guard(FTreeItem::OnItemDoubleClick);
ToggleSelection();
unguard;
}
void OnItemLeftMouseDown( FPoint P )
{
guard(FComponentItem::OnItemLeftMouseDown);
if( GetCheckboxRect().Inner(FPoint(-1,-1)).Contains(P) )
ToggleSelection();
else
FHeaderItem::OnItemLeftMouseDown( P );
unguard;
}
void OnItemSetFocus()
{
guard(FComponentItem::OnItemSetFocus);
FHeaderItem::OnItemSetFocus();
OwnerComponents->OnGroupChange( this );
unguard;
}
QWORD GetId() const
{
guard(FConfigItem::GetId);
return (INT)this;
unguard;
}
virtual FString GetCaption() const
{
guard(FConfigItem::GetText);
return SetupGroup->Caption;
unguard;
}
};
// Group properties.
class WComponentProperties : public WProperties
{
DECLARE_WINDOWCLASS(WComponentProperties,WProperties,Setup)
FComponentItem Root;
WComponentProperties( WFilerPageComponentsBase* InComponents )
: WProperties( NAME_None, InComponents )
, Root( InComponents, InComponents->Owner->Manager->RootGroup, this, NULL )
{
ShowTreeLines = 0;
}
FTreeItem* GetRoot()
{
return &Root;
}
};
/*-----------------------------------------------------------------------------
Install wizard pages.
-----------------------------------------------------------------------------*/
// Progess.
class WFilerPageProgress : public WWizardPage, public FInstallPoll
{
DECLARE_WINDOWCLASS(WFilerPageProgress,WWizardPage,Setup)
// Variables.
WFilerWizard* Owner;
USetupDefinition* Manager;
WLabel InstallText;
WLabel InstallingText;
WLabel ProgressText;
WLabel TotalText;
WLabel Installing;
WProgressBar Progress;
WProgressBar Total;
UBOOL Finished;
UBOOL CancelFlag;
// Constructor.
WFilerPageProgress( WFilerWizard* InOwner, const TCHAR* Template )
: WWizardPage ( Template, IDDIALOG_FilerPageProgress, InOwner )
, Owner ( InOwner )
, Manager ( InOwner->Manager )
, InstallText ( this, IDC_InstallText )
, InstallingText( this, IDC_InstallingText )
, ProgressText ( this, IDC_ProgressText )
, TotalText ( this, IDC_TotalText )
, Installing ( this, IDC_Installing )
, Progress ( this, IDC_Progress )
, Total ( this, IDC_Total )
, Finished ( 0 )
, CancelFlag ( 0 )
{}
// FInstallPoll interface.
UBOOL Poll( const TCHAR* Label, SQWORD LocalBytes, SQWORD LocalTotal, SQWORD RunningBytes, SQWORD TotalBytes )
{
guard(WWizardPageProgress::Poll);
static TCHAR Saved[256]=TEXT("");
if( appStricmp(Label,Saved)!=0 )
{
Installing.SetText( Label );
appStrcpy( Saved, Label );
}
Progress.SetProgress( LocalBytes, LocalTotal );
Total.SetProgress( RunningBytes, TotalBytes );
MSG Msg;
while( PeekMessageX(&Msg,NULL,0,0,1) )
DispatchMessageX(&Msg);
UpdateWindow( *this );
if( CancelFlag )
if( MessageBox( *OwnerWindow, *FString::Printf(LocalizeGeneral(TEXT("CancelPrompt")),*Manager->LocalProduct), LocalizeGeneral(TEXT("InstallCancel")), MB_YESNO )==IDYES )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -