How to create an image button in Inno Setup? - inno-setup

Is it possible to have an image button in Inno Wizard page instead of a plain Caption Text?
What I would like to accomplish is to create an Off/On image button to mute/play a music while Inno setup is running.
Thanks!

There's no direct support for setting images for buttons in Inno Setup.
So you have to revert to Win32 API.
function LoadImage(hInst: Integer; ImageName: string; ImageType: UINT;
X, Y: Integer; Flags: UINT): THandle;
external 'LoadImageW#User32.dll stdcall';
function ImageList_Add(ImageList: THandle; Image, Mask: THandle): Integer;
external 'ImageList_Add#Comctl32.dll stdcall';
function ImageList_Create(CX, CY: Integer; Flags: UINT;
Initial, Grow: Integer): THandle;
external 'ImageList_Create#Comctl32.dll stdcall';
const
IMAGE_BITMAP = 0;
LR_LOADFROMFILE = $10;
ILC_COLOR32 = $20;
BCM_SETIMAGELIST = $1600 + $0002;
type
BUTTON_IMAGELIST = record
himl: THandle;
margin: TRect;
uAlign: UINT;
end;
function SendSetImageListMessage(
Wnd: THandle; Msg: Cardinal; WParam: Cardinal;
var LParam: BUTTON_IMAGELIST): Cardinal;
external 'SendMessageW#User32.dll stdcall';
function InitializeSetup(): Boolean;
var
ImageList: THandle;
Image: THandle;
ButtonImageList: BUTTON_IMAGELIST;
begin
ImageList := ImageList_Create(16, 16, ILC_COLOR32, 1, 1);
Image := LoadImage(0, 'button.bmp', IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
ImageList_Add(ImageList, Image, 0);
ButtonImageList.himl := ImageList;
SendSetImageListMessage(
WizardForm.NextButton.Handle, BCM_SETIMAGELIST, 0, ButtonImageList);
end;

Related

Playing sound just one time during an Inno Setup install

Thanks to this article posted at Add audio when Splash Screen starts on Inno Setup
the code work like a charm, I just wanted to know what to do so that the music of my installer is only played once.
I donĀ“t want it to be repeated continuously.
Thanks in advance...
Code im using
[Code]
const
BASS_SAMPLE_LOOP = 4;
BASS_UNICODE = $80000000;
BASS_CONFIG_GVOL_STREAM = 5;
const
#ifndef UNICODE
EncodingFlag = 0;
#else
EncodingFlag = BASS_UNICODE;
#endif
type
HSTREAM = DWORD;
function BASS_Init(device: LongInt; freq, flags: DWORD;
win: HWND; clsid: Cardinal): BOOL;
external 'BASS_Init#files:bass.dll stdcall';
function BASS_StreamCreateFile(mem: BOOL; f: string; offset1: DWORD;
offset2: DWORD; length1: DWORD; length2: DWORD; flags: DWORD): HSTREAM;
external 'BASS_StreamCreateFile#files:bass.dll stdcall';
function BASS_ChannelPlay(handle: DWORD; restart: BOOL): BOOL;
external 'BASS_ChannelPlay#files:bass.dll stdcall';
function BASS_SetConfig(option: DWORD; value: DWORD ): BOOL;
external 'BASS_SetConfig#files:bass.dll stdcall';
function BASS_Free: BOOL;
external 'BASS_Free#files:bass.dll stdcall';
procedure InitializeWizard;
var
StreamHandle: HSTREAM;
begin
ExtractTemporaryFile('AudioFile.mp3');
if BASS_Init(-1, 44100, 0, 0, 0) then
begin
StreamHandle := BASS_StreamCreateFile(False,
ExpandConstant('{tmp}\AudioFile.mp3'), 0, 0, 0, 0,
EncodingFlag or BASS_SAMPLE_LOOP);
BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, 2500);
BASS_ChannelPlay(StreamHandle, False);
end;
end;
procedure DeinitializeSetup;
begin
BASS_Free;
end;

InnoSetup - GIF backgroung image? [duplicate]

I would like to have in my installer:
an infinite music loop playback during installation
a window on the background (like the old installations that used to fill the screen with an image and only show the installation window), with a slideshow on that background window
How to do this in InnoSetup ?
If you want to have an installer with a background image slideshow with an infinite music track playback, you can do e.g. the following:
get the recent version of the InnoCallback library for slideshow timer implementation
for music playback get e.g. most recent copy of the Inno Media Player for Unicode Inno Setup
Write a script similar to following, or download the complete project, which includes all necessary files used in the next script code. So the only thing you'd need to do, is to build it in the recent version of Unicode Inno Setup.
Please note, that Inno Media Player is a Unicode library, and so you can use it only with Unicode versions of Inno Setup, not with ANSI ones! There is no support for ANSI versions of Inno Setup...!
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
OutputDir=userdocs:Inno Setup Examples Output
BackColor=clLime
BackColor2=clYellow
WindowVisible=yes
[Files]
Source: "Image1.bmp"; Flags: dontcopy
Source: "Image2.bmp"; Flags: dontcopy
Source: "AudioFile.mp3"; Flags: dontcopy
Source: "MediaPlayer.dll"; Flags: dontcopy
Source: "InnoCallback.dll"; Flags: dontcopy
[Code]
var
TimerID: Integer;
SlideID: Integer;
BackImage: TBitmapImage;
const
EC_COMPLETE = $01;
type
TTimerProc = procedure(Wnd: HWND; Msg: UINT; TimerID: UINT_PTR;
SysTime: DWORD);
TDirectShowEventProc = procedure(EventCode, Param1, Param2: Integer);
function WrapTimerProc(Callback: TTimerProc; ParamCount: Integer): LongWord;
external 'wrapcallback#files:InnoCallback.dll stdcall';
function SetTimer(hWnd: HWND; nIDEvent, uElapse: UINT;
lpTimerFunc: UINT): UINT; external 'SetTimer#user32.dll stdcall';
function KillTimer(hWnd: HWND; uIDEvent: UINT): BOOL;
external 'KillTimer#user32.dll stdcall';
function DSGetLastError(var ErrorText: WideString): HRESULT;
external 'DSGetLastError#files:mediaplayer.dll stdcall';
function DSPlayMediaFile: Boolean;
external 'DSPlayMediaFile#files:mediaplayer.dll stdcall';
function DSStopMediaPlay: Boolean;
external 'DSStopMediaPlay#files:mediaplayer.dll stdcall';
function DSSetVolume(Value: LongInt): Boolean;
external 'DSSetVolume#files:mediaplayer.dll stdcall';
function DSInitializeAudioFile(FileName: WideString;
CallbackProc: TDirectShowEventProc): Boolean;
external 'DSInitializeAudioFile#files:mediaplayer.dll stdcall';
procedure OnMediaPlayerEvent(EventCode, Param1, Param2: Integer);
begin
if EventCode = EC_COMPLETE then
begin
if DSInitializeAudioFile(ExpandConstant('{tmp}\AudioFile.mp3'),
#OnMediaPlayerEvent) then
begin
DSSetVolume(-2500);
DSPlayMediaFile;
end;
end;
end;
procedure OnSlideTimer(Wnd: HWND; Msg: UINT; TimerID: UINT_PTR;
SysTime: DWORD);
begin
case SlideID of
0: SlideID := 1;
1: SlideID := 0;
end;
BackImage.Bitmap.LoadFromFile(
ExpandConstant('{tmp}\Image' + IntToStr(SlideID + 1) + '.bmp'));
end;
procedure StartSlideTimer;
var
TimerCallback: LongWord;
begin
TimerCallback := WrapTimerProc(#OnSlideTimer, 4);
{ third parameter here is the timer's timeout value in milliseconds }
TimerID := SetTimer(0, 0, 5000, TimerCallback);
end;
procedure KillSlideTimer;
begin
if TimerID <> 0 then
begin
if KillTimer(0, TimerID) then
TimerID := 0;
end;
end;
procedure InitializeWizard;
var
ErrorCode: HRESULT;
ErrorText: WideString;
begin
TimerID := 0;
SlideID := 0;
ExtractTemporaryFile('Image1.bmp');
ExtractTemporaryFile('Image2.bmp');
BackImage := TBitmapImage.Create(MainForm);
BackImage.Parent := MainForm;
BackImage.Top := 70;
BackImage.Left := 10;
BackImage.AutoSize := True;
BackImage.Bitmap.LoadFromFile(ExpandConstant('{tmp}\Image1.bmp'));
StartSlideTimer;
ExtractTemporaryFile('AudioFile.mp3');
if DSInitializeAudioFile(ExpandConstant('{tmp}\AudioFile.mp3'),
#OnMediaPlayerEvent) then
begin
DSSetVolume(-2500);
DSPlayMediaFile;
end
else
begin
ErrorCode := DSGetLastError(ErrorText);
MsgBox('TDirectShowPlayer error: ' + IntToStr(ErrorCode) + '; ' +
ErrorText, mbError, MB_OK);
end;
end;
procedure DeinitializeSetup;
begin
KillSlideTimer;
DSStopMediaPlay;
end;
Further resources:
How to make a slideshow in InnoSetup ?
How to play a sound during InnoSetup installation process ?
Creating backgrounds feature:
Did you try Graphical Installer (http://www.graphical-installer.com) ?
It is a professional Inno Setup extension specially for this (creating cool looking installers with background) so creating such installer is matter of few minutes (no coding is required).

How to mute audio (change volume) with BASS library in Inno Setup

This code from Bass Audio Library on/off Button does "Pause", how to change it to "Mute"?
What should I change?
const
BASS_SAMPLE_LOOP = 4;
BASS_ACTIVE_STOPPED = 0;
BASS_ACTIVE_PLAYING = 1;
BASS_ACTIVE_STALLED = 2;
BASS_ACTIVE_PAUSED = 3;
BASS_UNICODE = $80000000;
BASS_CONFIG_GVOL_STREAM = 5;
const
#ifndef UNICODE
EncodingFlag = 0;
#else
EncodingFlag = BASS_UNICODE;
#endif
type
HSTREAM = DWORD;
function BASS_Init(device: LongInt; freq, flags: DWORD;
win: HWND; clsid: Cardinal): BOOL;
external 'BASS_Init#files:bass.dll stdcall';
function BASS_StreamCreateFile(mem: BOOL; f: string; offset1: DWORD;
offset2: DWORD; length1: DWORD; length2: DWORD; flags: DWORD): HSTREAM;
external 'BASS_StreamCreateFile#files:bass.dll stdcall';
function BASS_Start: BOOL;
external 'BASS_Start#files:bass.dll stdcall';
function BASS_Pause: BOOL;
external 'BASS_Pause#files:bass.dll stdcall';
function BASS_ChannelPlay(handle: DWORD; restart: BOOL): BOOL;
external 'BASS_ChannelPlay#files:bass.dll stdcall';
function BASS_SetConfig(option: DWORD; value: DWORD ): BOOL;
external 'BASS_SetConfig#files:bass.dll stdcall';
function BASS_ChannelIsActive(handle: DWORD): DWORD;
external 'BASS_ChannelIsActive#files:bass.dll stdcall';
function BASS_Free: BOOL;
external 'BASS_Free#files:bass.dll stdcall';
var
SoundStream: HSTREAM;
SoundCtrlButton: TNewButton;
procedure SoundCtrlButtonClick(Sender: TObject);
begin
case BASS_ChannelIsActive(SoundStream) of
BASS_ACTIVE_PLAYING:
begin
if BASS_Pause then
SoundCtrlButton.Caption :=
ExpandConstant('{cm:SoundCtrlButtonCaptionSoundOn}');
end;
BASS_ACTIVE_PAUSED:
begin
if BASS_Start then
SoundCtrlButton.Caption :=
ExpandConstant('{cm:SoundCtrlButtonCaptionSoundOff}');
end;
end;
end;
procedure InitializeWizard;
begin
ExtractTemporaryFile('tune.mp3');
if BASS_Init(-1, 44100, 0, 0, 0) then
begin
SoundStream := BASS_StreamCreateFile(False,
ExpandConstant('{tmp}\tune.mp3'), 0, 0, 0, 0,
EncodingFlag or BASS_SAMPLE_LOOP);
BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, 2500);
BASS_ChannelPlay(SoundStream, False);
SoundCtrlButton := TNewButton.Create(WizardForm);
SoundCtrlButton.Parent := WizardForm;
SoundCtrlButton.Left := 8;
SoundCtrlButton.Top := WizardForm.ClientHeight -
SoundCtrlButton.Height - 8;
SoundCtrlButton.Width := 40;
SoundCtrlButton.Caption :=
ExpandConstant('{cm:SoundCtrlButtonCaptionSoundOff}');
SoundCtrlButton.OnClick := #SoundCtrlButtonClick;
end;
end;
procedure DeinitializeSetup;
begin
BASS_Free;
end;
To control volume level, use the BASS_SetConfig with option set to:
BASS_CONFIG_GVOL_STREAM for "stream", created e.g. using the BASS_StreamCreateFile;
BASS_CONFIG_GVOL_MUSIC for "music", created e.g. using BASS_MusicLoad.
The SoundCtrlButtonClick is replacement for the pause/resume implementation of the same-named function from your question.
var
Muted: Boolean;
procedure SoundCtrlButtonClick(Sender: TObject);
begin
if not Muted then
begin
if BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, 0) then
begin
SoundCtrlButton.Caption := 'unmute';
Muted := True;
end;
end
else
begin
if BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, 2500) then
begin
SoundCtrlButton.Caption := 'mute';
Muted := False;
end;
end;
end;

.xm and .s3m file doesn't play in BASS library from Inno Setup, only .mp3

When I choose .mp3 file, it will play when launching setup.exe but when I change it to .xm or .s3m, it doesn't play
[Setup]
AppName=Bass Audio Project
AppVersion=1.0
DefaultDirName={pf}\Bass Audio Project
[Files]
Source: "Bass.dll"; Flags: dontcopy
Source: "tune.xm"; Flags: dontcopy
[CustomMessages]
SoundCtrlButtonCaptionSoundOn=Play
SoundCtrlButtonCaptionSoundOff=Mute
[Code]
const
BASS_SAMPLE_LOOP = 4;
BASS_ACTIVE_STOPPED = 0;
BASS_ACTIVE_PLAYING = 1;
BASS_ACTIVE_STALLED = 2;
BASS_ACTIVE_PAUSED = 3;
BASS_UNICODE = $80000000;
BASS_CONFIG_GVOL_STREAM = 5;
const
#ifndef UNICODE
EncodingFlag = 0;
#else
EncodingFlag = BASS_UNICODE;
#endif
type
HSTREAM = DWORD;
function BASS_Init(device: LongInt; freq, flags: DWORD;
win: HWND; clsid: Cardinal): BOOL;
external 'BASS_Init#files:bass.dll stdcall';
function BASS_StreamCreateFile(mem: BOOL; f: string; offset1: DWORD;
offset2: DWORD; length1: DWORD; length2: DWORD; flags: DWORD): HSTREAM;
external 'BASS_StreamCreateFile#files:bass.dll stdcall';
function BASS_Start: BOOL;
external 'BASS_Start#files:bass.dll stdcall';
function BASS_Pause: BOOL;
external 'BASS_Pause#files:bass.dll stdcall';
function BASS_ChannelPlay(handle: DWORD; restart: BOOL): BOOL;
external 'BASS_ChannelPlay#files:bass.dll stdcall';
function BASS_SetConfig(option: DWORD; value: DWORD ): BOOL;
external 'BASS_SetConfig#files:bass.dll stdcall';
function BASS_ChannelIsActive(handle: DWORD): DWORD;
external 'BASS_ChannelIsActive#files:bass.dll stdcall';
function BASS_Free: BOOL;
external 'BASS_Free#files:bass.dll stdcall';
var
SoundStream: HSTREAM;
SoundCtrlButton: TNewButton;
Muted: Boolean;
procedure SoundCtrlButtonClick(Sender: TObject);
begin
if not Muted then
begin
if BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, 0) then
begin
SoundCtrlButton.Caption := 'Play';
Muted := True;
end;
end
else
begin
if BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, 2500) then
begin
SoundCtrlButton.Caption := 'Mute';
Muted := False;
end;
end;
end;
procedure InitializeWizard;
begin
ExtractTemporaryFile('tune.xm');
if BASS_Init(-1, 44100, 0, 0, 0) then
begin
SoundStream := BASS_StreamCreateFile(False,
ExpandConstant('{tmp}\tune.xm'), 0, 0, 0, 0,
EncodingFlag or BASS_SAMPLE_LOOP);
BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, 2500);
BASS_ChannelPlay(SoundStream, False);
SoundCtrlButton := TNewButton.Create(WizardForm);
SoundCtrlButton.Parent := WizardForm;
SoundCtrlButton.Left := 8;
SoundCtrlButton.Top := WizardForm.ClientHeight -
SoundCtrlButton.Height - 8;
SoundCtrlButton.Width := 40;
SoundCtrlButton.Caption :=
ExpandConstant('{cm:SoundCtrlButtonCaptionSoundOff}');
SoundCtrlButton.OnClick := #SoundCtrlButtonClick;
end;
end;
procedure DeinitializeSetup;
begin
BASS_Free;
end;
What should I do? I want to use to original file which is .xm or .s3m and not the converted one which is .mp3.
As seen on Un4seen, bass.dll supports .xm and .s3m.
Indeed, the BASS_StreamCreateFile returns 0 for both files.
And if you call BASS_ErrorGetCode afterwards, it returns 41 = BASS_ERROR_FILEFORM (unsupported file format).
function BASS_ErrorGetCode(): Integer;
external 'BASS_ErrorGetCode#files:bass.dll stdcall';
SoundStream := BASS_StreamCreateFile(...);
if SoundStream = 0 then
begin
Log(Format('Error playing file, error code = %d', [BASS_ErrorGetCode]));
end;
But as you correctly hinted, you should use the BASS_MusicLoad for MO3 / IT / XM / S3M / MTM / MOD / UMX formats.
type
HMUSIC = DWORD;
function BASS_MusicLoad(
mem: BOOL; f: string; offset: Int64; length, flags, freq: DWORD): HMUSIC;
external 'BASS_MusicLoad#files:bass.dll stdcall';
Replace the BASS_StreamCreateFile call with:
BASS_MusicLoad(
False, ExpandConstant('{tmp}\tune.xm'), 0, 0,
EncodingFlag or BASS_SAMPLE_LOOP, 0)
Semantically, your should also rename the SoundStream variable to Music or similar; and change its type to HMUSIC.

How can I "touch" a file from within an InnoSetup script?

How can I "touch" a file, i.e. update its' last modified time to the current time, from within an InnoSetup (Pascal) script?
Here's the code snippet for the TouchFile function:
[Code]
function CreateFile(
lpFileName : String;
dwDesiredAccess : Cardinal;
dwShareMode : Cardinal;
lpSecurityAttributes : Cardinal;
dwCreationDisposition : Cardinal;
dwFlagsAndAttributes : Cardinal;
hTemplateFile : Integer
): THandle;
#ifdef UNICODE
external 'CreateFileW#kernel32.dll stdcall';
#else
external 'CreateFileA#kernel32.dll stdcall';
#endif
procedure GetSystemTimeAsFileTime(var lpSystemTimeAsFileTime: TFileTime);
external 'GetSystemTimeAsFileTime#kernel32.dll';
function SetFileModifyTime(hFile:THandle; CreationTimeNil:Cardinal; LastAccessTimeNil:Cardinal; LastWriteTime:TFileTime): BOOL;
external 'SetFileTime#kernel32.dll';
function CloseHandle(hHandle: THandle): BOOL;
external 'CloseHandle#kernel32.dll stdcall';
function TouchFile(FileName: String): Boolean;
const
{ Win32 constants }
GENERIC_WRITE = $40000000;
OPEN_EXISTING = 3;
INVALID_HANDLE_VALUE = -1;
var
FileTime: TFileTime;
FileHandle: THandle;
begin
Result := False;
FileHandle := CreateFile(FileName, GENERIC_WRITE, 0, 0, OPEN_EXISTING, $80, 0);
if FileHandle <> INVALID_HANDLE_VALUE then
try
GetSystemTimeAsFileTime(FileTime);
Result := SetFileModifyTime(FileHandle, 0, 0, FileTime);
finally
CloseHandle(FileHandle);
end;
end;

Resources