283 lines
8.6 KiB
Plaintext
283 lines
8.6 KiB
Plaintext
; Script generated by the Inno Setup Script Wizard.
|
|
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
|
|
|
#define MyAppName "Studio"
|
|
#define MyAppVersion "1.0"
|
|
#define MyAppPublisher "UVC"
|
|
#define MyAppExeName "ProgramLauncher.exe"
|
|
#define MyAppAssocName MyAppName + " File"
|
|
#define MyAppAssocExt ".myp"
|
|
#define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt
|
|
|
|
[Setup]
|
|
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
|
|
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
|
AppId={{8268FFE4-0A54-4812-8500-B2660BC5956D}
|
|
AppName={#MyAppName}
|
|
AppVersion={#MyAppVersion}
|
|
;AppVerName={#MyAppName} {#MyAppVersion}
|
|
AppPublisher={#MyAppPublisher}
|
|
DefaultDirName={localappdata}\UVC\{#MyAppName}
|
|
UninstallDisplayIcon={app}\{#MyAppExeName}
|
|
ChangesAssociations=yes
|
|
DisableProgramGroupPage=yes
|
|
DisableDirPage=no
|
|
; Uncomment the following line to run in non administrative install mode (install for current user only).
|
|
;PrivilegesRequired=lowest
|
|
OutputDir=C:\Users\SJM\Desktop
|
|
OutputBaseFilename=StudioSetup
|
|
SetupIconFile=C:\Users\SJM\Desktop\업데이트 기능\TestIcon.ico
|
|
SolidCompression=yes
|
|
WizardStyle=modern
|
|
|
|
[Languages]
|
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
|
Name: "korean"; MessagesFile: "compiler:Languages\Korean.isl"
|
|
|
|
[Tasks]
|
|
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
|
|
|
[Files]
|
|
Source: "C:\Users\SJM\Desktop\업데이트 기능\Launcher_Studio\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
|
Source: "C:\Users\SJM\Desktop\업데이트 기능\Launcher_Studio\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
|
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
|
|
|
[Registry]
|
|
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocExt}\OpenWithProgids"; ValueType: string; ValueName: "{#MyAppAssocKey}"; ValueData: ""; Flags: uninsdeletevalue
|
|
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}"; ValueType: string; ValueName: ""; ValueData: "{#MyAppAssocName}"; Flags: uninsdeletekey
|
|
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"
|
|
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""
|
|
Root: HKCU; Subkey: "Software\UVC\{#MyAppName}"; \
|
|
ValueType: string; ValueName: "InstallPath"; ValueData: "{app}"; Flags: uninsdeletekey
|
|
|
|
[Icons]
|
|
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
|
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
|
|
|
[Run]
|
|
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
|
|
|
[UninstallDelete]
|
|
Type: filesandordirs; Name: "{app}"
|
|
|
|
[Code]
|
|
const
|
|
WM_COPYDATA = $004A;
|
|
|
|
type
|
|
TProcessInfoSet = record
|
|
PathSet: TStringList;
|
|
NameSet: TStringList;
|
|
end;
|
|
|
|
// -------------------- StudioInstaller 메시지 전송 --------------------
|
|
function RegisterWindowMessage(lpString: AnsiString): LongWord;
|
|
external 'RegisterWindowMessageA@user32.dll stdcall';
|
|
|
|
procedure NotifyStudioInstaller(const msg: AnsiString);
|
|
var
|
|
msgID: LongWord;
|
|
begin
|
|
msgID := RegisterWindowMessage(msg);
|
|
if msgID <> 0 then
|
|
begin
|
|
PostMessage($FFFF, msgID, 0, 0);
|
|
end;
|
|
end;
|
|
|
|
|
|
// -------------------- PowerShell 실행 및 결과 추출 --------------------
|
|
function ExecAndGetLines(const CommandLine: string; var Lines: TArrayOfString): Boolean;
|
|
var
|
|
TempFile: string;
|
|
Success: Boolean;
|
|
ResultCode: Integer;
|
|
begin
|
|
TempFile := ExpandConstant('{tmp}\ps_output.txt');
|
|
|
|
Success := Exec(
|
|
'powershell.exe',
|
|
'-Command "$ErrorActionPreference = ''SilentlyContinue''; Get-Process | ForEach-Object { $p = $_; $path = ''''; try { $path = $p.Path } catch {}; ''{0}|{1}'' -f $path, $p.Name } | Out-File -Encoding UTF8 ''' + TempFile + '''"',
|
|
'',
|
|
SW_HIDE,
|
|
ewWaitUntilTerminated,
|
|
ResultCode);
|
|
|
|
if Success then
|
|
Result := LoadStringsFromFile(TempFile, Lines)
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
// -------------------- 유틸리티 --------------------
|
|
function PosEx(const SubStr, S: string; Offset: Integer): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := 0;
|
|
for i := Offset to Length(S) - Length(SubStr) + 1 do
|
|
begin
|
|
if Copy(S, i, Length(SubStr)) = SubStr then
|
|
begin
|
|
Result := i;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function SplitString(const S, Delimiter: string): TArrayOfString;
|
|
var
|
|
PosStart, PosDelim, Index: Integer;
|
|
begin
|
|
SetArrayLength(Result, 0);
|
|
PosStart := 1;
|
|
Index := 0;
|
|
repeat
|
|
PosDelim := PosEx(Delimiter, S, PosStart);
|
|
if PosDelim > 0 then
|
|
begin
|
|
SetArrayLength(Result, Index + 1);
|
|
Result[Index] := Copy(S, PosStart, PosDelim - PosStart);
|
|
PosStart := PosDelim + Length(Delimiter);
|
|
Inc(Index);
|
|
end
|
|
else
|
|
begin
|
|
SetArrayLength(Result, Index + 1);
|
|
Result[Index] := Copy(S, PosStart, Length(S));
|
|
Break;
|
|
end;
|
|
until False;
|
|
end;
|
|
|
|
// -------------------- 실행 중 프로세스 집합 구성 --------------------
|
|
function GetRunningProcessSets: TProcessInfoSet;
|
|
var
|
|
Lines: TArrayOfString;
|
|
I: Integer;
|
|
Parts: TArrayOfString;
|
|
Path, Name: string;
|
|
begin
|
|
Result.PathSet := TStringList.Create;
|
|
Result.PathSet.CaseSensitive := False;
|
|
Result.PathSet.Sorted := True;
|
|
Result.PathSet.Duplicates := dupIgnore;
|
|
|
|
Result.NameSet := TStringList.Create;
|
|
Result.NameSet.CaseSensitive := False;
|
|
Result.NameSet.Sorted := True;
|
|
Result.NameSet.Duplicates := dupIgnore;
|
|
|
|
if not ExecAndGetLines('', Lines) then
|
|
Exit;
|
|
|
|
for I := 0 to GetArrayLength(Lines) - 1 do
|
|
begin
|
|
Parts := SplitString(Lines[I], '|');
|
|
if GetArrayLength(Parts) = 2 then
|
|
begin
|
|
Path := LowerCase(Trim(Parts[0]));
|
|
Name := LowerCase(Trim(Parts[1]) + '.exe');
|
|
|
|
if Path <> '' then
|
|
Result.PathSet.Add(Path)
|
|
else
|
|
Result.NameSet.Add(Name);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure FreeProcessSet(var ProcSet: TProcessInfoSet);
|
|
begin
|
|
ProcSet.PathSet.Free;
|
|
ProcSet.NameSet.Free;
|
|
end;
|
|
|
|
// -------------------- 실행 중 여부 판단 --------------------
|
|
function IsFileRunningOptimized(const TargetFile: string; const ProcSet: TProcessInfoSet): Boolean;
|
|
var
|
|
LowerPath: string;
|
|
FileName: string;
|
|
begin
|
|
LowerPath := LowerCase(TargetFile);
|
|
FileName := LowerCase(ExtractFileName(TargetFile));
|
|
Result := (ProcSet.PathSet.IndexOf(LowerPath) <> -1) or
|
|
(ProcSet.NameSet.IndexOf(FileName) <> -1);
|
|
end;
|
|
|
|
function IsExcluded(const FileName: string): Boolean;
|
|
begin
|
|
Result := (LowerCase(FileName) = 'unins000.exe');
|
|
end;
|
|
|
|
// -------------------- 디렉터리 재귀 탐색 --------------------
|
|
function HasRunningFilesInDir(const DirPath: string; const ProcSet: TProcessInfoSet): Boolean;
|
|
var
|
|
FindRec: TFindRec;
|
|
FullPath, Extension: string;
|
|
begin
|
|
Result := False;
|
|
|
|
if FindFirst(DirPath + '\*', FindRec) then
|
|
begin
|
|
repeat
|
|
if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY) <> 0 then
|
|
begin
|
|
if (FindRec.Name <> '.') and (FindRec.Name <> '..') then
|
|
begin
|
|
if HasRunningFilesInDir(DirPath + '\' + FindRec.Name, ProcSet) then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
FullPath := DirPath + '\' + FindRec.Name;
|
|
Extension := LowerCase(ExtractFileExt(FindRec.Name));
|
|
|
|
if (Extension = '.exe') and not IsExcluded(FindRec.Name) then
|
|
begin
|
|
if IsFileRunningOptimized(FullPath, ProcSet) then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
until not FindNext(FindRec);
|
|
FindClose(FindRec);
|
|
end;
|
|
end;
|
|
|
|
// -------------------- Entry Point --------------------
|
|
function InitializeUninstall(): Boolean;
|
|
var
|
|
ProcSet: TProcessInfoSet;
|
|
begin
|
|
ProcSet := GetRunningProcessSets;
|
|
|
|
if HasRunningFilesInDir(ExpandConstant('{app}'), ProcSet) then
|
|
begin
|
|
MsgBox('프로그램 실행 중인 파일이 감지되었습니다. 모든 관련 프로그램을 종료한 후 다시 시도하세요.', mbError, MB_OK);
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := True;
|
|
|
|
FreeProcessSet(ProcSet);
|
|
end;
|
|
|
|
// -------------------- 인스톨/언인스톨 완료 시 StudioInstaller에 알림 --------------------
|
|
procedure CurStepChanged(CurStep: TSetupStep);
|
|
begin
|
|
if CurStep = ssPostInstall then
|
|
NotifyStudioInstaller('INSTALL_COMPLETE');
|
|
end;
|
|
|
|
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
|
|
begin
|
|
if CurUninstallStep = usPostUninstall then
|
|
NotifyStudioInstaller('UNINSTALL_COMPLETE');
|
|
end; |