I tried to add mp3 audio playback (LAME encoded) to my Inno setup program using Inno Media Player and following #TLama's decription -> https://stackoverflow.com/a/12360780/3838926. I use Windows 7 64bit with Unicode Inno.
Unfortunately it fails: When opening the installer I get the following error message: TDirectShowPlayer error: -2147220890; Searching through Google didn't help.
What do I do wrong? Is it a bug in the program? I'm clueless...
Here's the exact code:
const
EC_COMPLETE = $01;
type
TDirectShowEventProc = procedure(EventCode, Param1, Param2: Integer);
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
// playback is done, so you can e.g. play the stream again, play another
// one using the same code as in InitializeWizard (in that case would be
// better to wrap that in some helper function) or do just nothing
end;
end;
procedure InitializeWizard;
var
ErrorCode: HRESULT;
ErrorText: WideString;
begin
ExtractTemporaryFile('InDeep.mp3');
if DSInitializeAudioFile(ExpandConstant('{tmp}\InDeep.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
DSStopMediaPlay;
end;
InDeep.mp3 is my audio file.
Thanks in advance!!
Related
I have some animations in Exe format, I need to load them inside a panel in Inno Setup.
I have found these about Delphi:
http://www.delphipages.com/forum/archive/index.php/t-200729.html
How to shell to another app and have it appear in a delphi form
How to implement such thing in Inno Setup?
An equivalent code for Inno Setup will be like:
[Code]
function SetParent(hWndChild: HWND; hWndNewParent: HWND): HWND;
external 'SetParent#User32.dll stdcall';
function ShowWindow(hWnd: HWND; nCmdShow: Integer): BOOL;
external 'ShowWindow#User32.dll stdcall';
procedure InitializeWizard();
var
Page: TWizardPage;
ResultCode: Integer;
ProgHandle: HWND;
begin
Page := CreateCustomPage(wpWelcome, 'Test', '');
Exec('notepad.exe', '', '', SW_HIDE, ewNoWait, ResultCode);
while ProgHandle = 0 do
ProgHandle := FindWindowByWindowName('Untitled - Notepad');
SetParent(ProgHandle, Page.Surface.Handle);
ShowWindow(ProgHandle, SW_SHOWMAXIMIZED);
end;
Though I suggest you do not do this. It's an unreliable hack. Display the images by the Pascal Code in the installer itself.
I am using PrivilegesRequired=lowest in my Inno Setup script. If setup is running elevated, i.e. IsAdminLoggedOn or IsPowerUserLoggedOn reports TRUE, how can I determine if the elevated user account is the same account from which setup was launched?
My script can do different things accordingly.
You can use WTSQuerySessionInformation to retrieve an account username for the current Windows logon session.
function WTSQuerySessionInformation(
hServer: THandle; SessionId: Cardinal; WTSInfoClass: Integer;
var pBuffer: DWord; var BytesReturned: DWord): Boolean;
external 'WTSQuerySessionInformationW#wtsapi32.dll stdcall';
procedure WTSFreeMemory(pMemory: DWord);
external 'WTSFreeMemory#wtsapi32.dll stdcall';
procedure RtlMoveMemoryAsString(Dest: string; Source: DWord; Len: Integer);
external 'RtlMoveMemory#kernel32.dll stdcall';
const
WTS_CURRENT_SERVER_HANDLE = 0;
WTS_CURRENT_SESSION = -1;
WTSUserName = 5;
function GetCurrentSessionUserName: string;
var
Buffer: DWord;
BytesReturned: DWord;
QueryResult: Boolean;
begin
QueryResult :=
WTSQuerySessionInformation(
WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSUserName, Buffer,
BytesReturned);
if not QueryResult then
begin
Log('Failed to retrieve username');
Result := '';
end
else
begin
SetLength(Result, (BytesReturned div 2) - 1);
RtlMoveMemoryAsString(Result, Buffer, BytesReturned);
WTSFreeMemory(Buffer);
Log(Format('Retrieved username "%s"', [Result]));
end;
end;
(The code is for Unicode version of Inno Setup – The only version as of Inno Setup 6).
You can then compare the result against GetUserNameString.
You may need to add a domain name into the comparison.
If you need the full account name of the current user (e.g., authority\username format), you can use the GetUserNameExW Windows API function. The below snippet demonstrates how to call this function from Inno Setup:
const
ERROR_MORE_DATA = 234;
function GetUserNameExW(NameFormat: Integer; lpNameBuffer: string; var nSize: DWORD): Boolean;
external 'GetUserNameExW#secur32.dll stdcall';
function GetFullUserName(): string;
var
NumChars: DWORD;
OutStr: string;
begin
result := '';
NumChars := 0;
if (not GetUserNameExW(2, '', NumChars)) and (DLLGetLastError() = ERROR_MORE_DATA) then
begin
SetLength(OutStr, NumChars);
if GetUserNameExW(2, OutStr, NumChars) then
result := Copy(OutStr, 1, NumChars);
end;
end;
(The value 2 passed to the first parameter (NameFormat) in the GetUserNameExW function corresponds to NameSamCompatible in the EXTENDED_NAME_FORMAT enumeration.)
I try to unzip in installation file which I download from my repository. I found this code:
How to get Inno Setup to unzip a file it installed (all as part of the one installation process)
But I need to input from user in custom page about version of application in the repository, download it and try unzip. How send to value from input to ExtractMe('{tmp}\INPUT FROM USER VERSION.zip', '{app}\');
begin
{Page for input Version}
UserPage := CreateInputQueryPage(wpWelcome,
'Number of Version', 'example : 1.8.20',
'Program will download your input');
UserPage.Add('Version:', False);
UserPage.Values[0] := GetPreviousData('Version', '1.8.20');
end;
{Called when the user clicks the Next button}
function NextButtonClick(CurPageID: Integer): Boolean;
var
Version: string;
FileURL: string;
begin
if CurPageID = wpReady then
begin
Version := UserPage.Values[0];
{Download}
FileURL := Format('http://127.0.0.1/repository/ia/ats-apps/ia-client.zip/%s/ia-client.zip-%0:s.zip', [Version]); <-- FROM HERE TO BELOW
idpAddFile(FileURL, ExpandConstant(Format('{tmp}\%s.zip', [Version])));
idpDownloadAfter(wpReady);
end;
Result := True;
end;
procedure unzip(src, target: AnsiString);
external 'unzip#files:unzipper.dll stdcall delayload';
procedure ExtractMe(src, target : AnsiString);
begin
unzip(ExpandConstant(src), ExpandConstant(target));
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
ExtractMe('{tmp}\INPUT FROM USER VERSION.zip', '{app}\'); <--HERE
end;
end;
Thanks for tip.
The same way as you are already using in the NextButtonClick: Read the UserPage.Values[0].
ExtractMe(Format('{tmp}\%s.zip', [UserPage.Values[0]]), '{app}\');
With this code: Install DirectX & VCRedist in freearc default script when progress bar is full & paused after main file extraction I can install DirectX and VCRedist with Inno Setup. But, is it possible to force the installation window of these programs to a certain place on the screen? For example:
It's hardly possible to make an application to start at desired position, unless the application explicitly supports it.
So in general, what you can do is to watch for a certain window to appear and move it afterwards. You can identify the window by its caption (FindWindowByWindowName) or class (FindWindowByClassName). Drawback is that the window will briefly appear on its default position.
[Files]
Source: "DXWebSetup.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
[Run]
Filename: "{tmp}\DXWebSetup.exe"; StatusMsg: "Installing DirectX..."; \
BeforeInstall: StartWaitingForDirectXWindow; \
AfterInstall: StopWaitingForDirectXWindow
[Code]
function SetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc: LongWord): LongWord;
external 'SetTimer#User32.dll stdcall';
function KillTimer(hWnd, nIDEvent: LongWord): LongWord;
external 'KillTimer#User32.dll stdcall';
function GetTickCount: DWord; external 'GetTickCount#kernel32 stdcall';
function SetWindowPos(hWnd: HWND; hWndInsertAfter: HWND; X: Integer; Y: Integer;
cx: Integer; cy: Integer; uFlags: UINT): BOOL;
external 'SetWindowPos#user32.dll stdcall';
const
SWP_NOSIZE = $01;
SWP_NOZORDER = $04;
var
WindowWaitTimer: LongWord;
WindowWaitStarted: DWord;
MoveWindowRunning: Boolean;
procedure MoveDirectXWindowProc(
H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
var
Retry: Boolean;
Handle: HWND;
begin
Handle := FindWindowByWindowName('Installing Microsoft(R) DirectX(R)');
if Handle = 0 then
begin
if DWord(GetTickCount - WindowWaitStarted) < 5000 then
begin
Log('DirectX window not found, will try again shortly');
Retry := True;
end
else
begin
Log('Giving up waiting for DirectX window');
Retry := False;
end
end
else
begin
Log('DirectX window found');
SetWindowPos(
Handle, 0, WizardForm.Left + ScaleX(150), WizardForm.Top + ScaleX(30),
0, 0, SWP_NOSIZE or SWP_NOZORDER);
Retry := False;
end;
if not Retry then
begin
Log('Stopping timer');
KillTimer(0, WindowWaitTimer);
WindowWaitTimer := 0;
end;
end;
procedure StartWaitingForDirectXWindow;
begin
Log('Starting waiting for DirectX window');
WindowWaitTimer := SetTimer(0, 0, 100, CreateCallback(#MoveDirectXWindowProc));
WindowWaitStarted := GetTickCount;
end;
procedure StopWaitingForDirectXWindow;
begin
if WindowWaitTimer <> 0 then
begin
Log('DirectX installer finished, and we are still waiting for its window, stopping');
KillTimer(0, WindowWaitTimer);
WindowWaitTimer := 0;
end
else
begin
Log('DirectX installer finished, and we are no longer waiting for its window');
end;
end;
For CreateCallback function, you need Inno Setup 6. If you are stuck with Inno Setup 5, you can use WrapCallback function from InnoTools InnoCallback library.
Am trying to find out how can I check, if proxy is being used in the computer via Inno Setup.
You can use the WinHttpGetDefaultProxyConfiguration function:
type
WINHTTP_PROXY_INFO = record
AccessType: Cardinal;
Proxy: Cardinal;
ProxyBypass: Cardinal;
end;
function WinHttpGetDefaultProxyConfiguration(var ProxyInfo: WINHTTP_PROXY_INFO): Boolean;
external 'WinHttpGetDefaultProxyConfiguration#winhttp.dll stdcall';
function StrCpyN(S1: string; S2: Cardinal; Max: Cardinal): Cardinal;
external 'StrCpyNW#shlwapi.dll stdcall';
function GetProxy: string;
var
ProxyInfo: WINHTTP_PROXY_INFO;
begin
if WinHttpGetDefaultProxyConfiguration(ProxyInfo) then
begin
SetLength(Result, 1024);
StrCpyN(Result, ProxyInfo.Proxy, Length(Result) - 1);
Result := Trim(Result);
Log('Retrieved proxy information: ' + Result);
end
else
begin
Log('Cannot retrieve proxy information');
end;
end;
Requires Unicode Inno Setup (the only version as of Inno Setup 6).
You can also use netsh winhttp show proxy command.