In my code I wish to send http request and present it in fiddler - WinHttpReq.SetProxy(2, '127.0.0.1:8888'); if fiddle is up,
if fiddler is down dost esnd it to fiddler , I tried try..except this way:
[Setup] AppName=Test AppVersion=1.5 DefaultDirName={pf}\test
[Code]
var
WinHttpReq: Variant;
function ShowInFiddler(Param: String): String;
begin
try
WinHttpReq.SetProxy(2, '127.0.0.1:8888');
except MsgBox('Hello.', mbInformation, MB_OK);
end;
end;
function InitializeSetup(): Boolean;
begin
WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
WinHttpReq.Open('GET', 'http://publishers-xxxx.databssint.com/', false);
ShowInFiddler ('');
WinHttpReq.Send(); end;
but the exception doesn't work, can anybody help?
This isn't a bug in Inno Setup, because the SetProxy function doesn't check if the proxy is availible. The function will raise an exception if you call it with wrong parameters.
So if your proxy is down you should catch the exception of the Send function and e.g. use the default proxy settings to continue.
For example:
var
WinHttpReq: Variant;
function InitializeSetup(): Boolean;
begin
WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
WinHttpReq.Open('GET', 'http://publishers-xxxx.databssint.com/', false);
WinHttpReq.SetProxy(2, '127.0.0.1:8888');
try
// first try connecting via given proxy
WinHttpReq.Send();
except
// proxy failed, use default settings
WinHttpReq.SetProxy(0);
try
WinHttpReq.Send();
Result := true;
except
// conncetion failed, handle error here
ShowExceptionMessage();
end;
end;
end;
Keep in mind, that the debugger will paused by default on an exception (proxy is down). This will not happen in runtime.
Hope it helps.
Related
I want to verify if user has Docker installed in their system.
If it is installed proceed further otherwise display an error message.
Previously I was looking at the registry group in Windows but it's not the correct way.
I want to check if cmd gives correct output for command docker.
function GetHKLM: Integer;
begin
if IsWin64 then
Result := HKLM64
else
Result := HKLM32;
end;
function GetHKU: Integer;
begin
if IsWin64 then
Result := HKCU64
else
Result := HKCU32;
end;
function InitializeSetup: Boolean;
begin
// Opening the setup installer initially
Result := True;
//if the docker is present in the machine registry return True else checking user registry
if not RegKeyExists(GetHKLM, 'SOFTWARE\Docker Inc.') then
begin
if not RegKeyExists(GetHKU, 'Software\Docker Inc.') then
begin
// return False to prevent installation to continue
Result := False;
// Display that you need to install docker.
SuppressibleMsgBox('<Docker not found!>', mbCriticalError, MB_OK, IDOK);
end;
end;
end;
How do I do this with just cmd? Instead of checking registry.. How can I run the command line and verify the output?
for etc:
function checkdocker() :Boolean;
var
dockerfound: string;
begin
Result :=
ShellExecute(application.handle, 'docker', nil, nil, SW_MAXIMIZE)
end;
function InitializeSetup: Boolean;
begin
Result := True;
if not checkdocker then;
SuppressibleMsgBox('<Docker not found!>', mbCriticalError, MB_OK, IDOK);
else
#continue
end;
To answer your literal question: Just use Exec and check the result code:
function CheckDocker: Boolean;
var
ResultCode: Integer;
begin
Result :=
Exec('docker', '', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and
(ResultCode = 0);
if Result then Log('Succeeded executing docker')
else Log('Failed to execute docker');
end;
(based on How to get an output of an Exec'ed program in Inno Setup?)
Though there's more efficient way to check if docker.exe executable is in a search path. Use FileSearch. See How can I check SQLCMD.EXE if it is installed on client in Inno Setup.
I am looking for a code for Inno Setup, that I can use to make my setup verify my permission to install the program. This code must check a text file on a web server.
If the file has the value "False", the setup has to cancel an installation and save the value in a registry file to cancel it always when Internet connection is not available.
If the file has the value "True", the setup will continue to install, and it will delete the registry file value if it exists.
If there is no Internet and the registry value does not exist the setup will continue to install.
Use InitializeSetup event function to trigger your check using HTTP request.
[Code]
const
SubkeyName = 'Software\My Program';
AllowInstallationValue = 'Allow Installation';
function IsInstallationAllowed: Boolean;
var
Url: string;
WinHttpReq: Variant;
S: string;
ResultDWord: Cardinal;
begin
try
WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
Url := 'https://www.example.com/can_install.txt';
WinHttpReq.Open('GET', Url, False);
WinHttpReq.Send('');
if WinHttpReq.Status <> 200 then
begin
RaiseException(
'HTTP Error: ' + IntToStr(WinHttpReq.Status) + ' ' + WinHttpReq.StatusText);
end
else
begin
S := Trim(WinHttpReq.ResponseText);
Log('HTTP Response: ' + S);
Result := (CompareText(S, 'true') = 0);
if RegWriteDWordValue(
HKLM, SubkeyName, AllowInstallationValue, Integer(Result)) then
Log('Cached response to registry')
else
Log('Error caching response to registry');
end;
except
Log('Error: ' + GetExceptionMessage);
if RegQueryDWordValue(HKLM, SubkeyName, AllowInstallationValue, ResultDWord) then
begin
Log('Online check failed, using cached result');
Result := (ResultDWord <> 0);
end
else
begin
Log('Online check failed, no cached result, allowing installation by default');
Result := True;
end;
end;
if Result then Log('Can install')
else Log('Cannot install');
end;
function InitializeSetup(): Boolean;
begin
Result := True;
if not IsInstallationAllowed then
begin
MsgBox('You cannot install this', mbError, MB_OK);
Result := False;
end;
end;
I have a need to retrieve a path to be used for some stuffs in the installer according an other application previously installed on the system.
This previous application hosts a service and only provides one registry key/value hosting this information: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\APPLICATION hosting the value ImagePath which Data is "E:\TestingDir\Filename.exe".
I need a way to only extract the installation path (E:\TestingDir) without the Filename.exe file.
Any suggestion?
thanks a lot
You can achieve this using a scripted constant.
You define a function that produces the value you need:
[Code]
function GetServiceInstallationPath(Param: string): string;
var
Value: string;
begin
if RegQueryStringValue(
HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Services\APPLICATION',
'ImagePath', Value) then
begin
Result := ExtractFileDir(Value);
end
else
begin
Result := { Some fallback value }
end;
end;
And then you refer to it using {code:GetServiceInstallationPath} where you need it (like in the [Run] section).
For example:
[Run]
Filename: "{code:GetServiceIntallationPath}\SomeApp.exe"
Actually, you probably want to retrieve the value in InitializeSetup already, and cache the value in a global variable for use in the scripted constant. And abort the installation (by returning False from InitializeSetup), in case the other application is not installed (= the registry key does not exist).
[Code]
var
ServiceInstallationPath: string;
function InitializeSetup(): Boolean;
var
Value: string;
begin
if RegQueryStringValue(
HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Services\APPLICATION',
'ImagePath', Value) then
begin
ServiceInstallationPath := ExtractFileDir(Value);
Log(Format('APPLICATION installed to %s', [ServiceInstallationPath]));
Result := True;
end
else
begin
MsgBox('APPLICATION not installed, aborting installation', mbError, MB_OK);
Result := False;
end;
end;
function GetServiceInstallationPath(Param: string): string;
begin
Result := ServiceInstallationPath;
end;
See also a similar question: Using global string script variable in Run section in Inno Setup.
Solved this way:
[code]
var
ServiceInstallationPath: string;
function MyProgCheck(): Boolean;
var
Value: string;
begin
if RegQueryStringValue(
HKEY_LOCAL_MACHINE, 'SYSTEM\ControlSet001\Services\JLR STONE VCATS TO MES',
'ImagePath', Value) then
begin
ServiceInstallationPath := ExtractFileDir(Value);
Result := True;
end
else
begin
Result := False;
end;
end;
and in the [RUN] section I put as check the TRUE condition or FALSE condition on this function according the needs...Thanks everybody answering!
My application requires .NET Framework to be installed so I run .NET installation in PrepareToIntall event function. While the installation is running I would like to display some simple message on Wizard.
I found How to set the status message in [Code] Section of Inno install script? but the solution there doesn't work for me.
I tried
WizardForm.StatusLabel.Caption := CustomMessage('InstallingDotNetMsg');
and also
WizardForm.PreparingLabel.Caption := CustomMessage('InstallingDotNetMsg');
EDIT
I have to do this in PrepareToInstall function, because I need to stop the setup when .net installation fails.
Code looks like this right now:
function PrepareToInstall(var NeedsRestart: Boolean): String;
var
isDotNetInstalled : Boolean;
errorCode : Integer;
errorDesc : String;
begin
isDotNetInstalled := IsDotNetIntalledCheck();
if not isDotNetInstalled then
begin
//WizardForm.PreparingLabel.Caption := CustomMessage('InstallingDotNetMsg');
WizardForm.StatusLabel.Caption := CustomMessage('InstallingDotNetMsg');
ExtractTemporaryFile('dotNetFx40_Full_x86_x64.exe');
if not ShellExec('',ExpandConstant('{tmp}\dotNetFx40_Full_x86_x64.exe'),'/passive /norestart', '', SW_HIDE, ewWaitUntilTerminated, errorCode) then
begin
errorDesc := SysErrorMessage(errorCode);
MsgBox(errorDesc, mbError, MB_OK);
end;
isDotNetInstalled := WasDotNetInstallationSuccessful();
if not isDotNetInstalled then
begin
Result := CustomMessage('FailedToInstalldotNetMsg');
end;
end;
end;
Any Ideas how to achieve this?
The StatusLabel is hosted by the InstallingPage wizard page while you're on PreparingPage page in the PrepareToInstall event method. So that's a wrong label. Your attempt to set the text to the PreparingLabel was correct, but failed because that label is hidden by default (it is shown when you return non empty string as a result to the event method).
But you can show it for a while (you are using ewWaitUntilTerminated flag, so your installation is synchronous, thus it won't hurt anything):
[Code]
function PrepareToInstall(var NeedsRestart: Boolean): String;
var
WasVisible: Boolean;
begin
// store the original visibility state
WasVisible := WizardForm.PreparingLabel.Visible;
try
// show the PreparingLabel
WizardForm.PreparingLabel.Visible := True;
// set a label caption
WizardForm.PreparingLabel.Caption := CustomMessage('InstallingDotNetMsg');
// do your installation here
finally
// restore the original visibility state
WizardForm.PreparingLabel.Visible := WasVisible;
end;
end;
Another solution is to use CreateOutputProgressPage to display a progress page over the top of the Preparing to Install page. See the CodeDlg.iss example script included with Inno for an example of the usage; it's fairly straightforward.
My Delphi 2010 app uploads stuff using multi-threading, uploaded data is POSTed to a PHP/web application which requires login, so I need to use a shared/global cookies manager (I'm using Indy10 Revision 4743) since TIdCookieManager is not thread-safe :(
Also, server side, session id is automatically re-generated every 5 minutes, so I must keep both the global & local cookie managers in sync.
My code looks like this:
TUploadThread = class(TThread)
// ...
var
GlobalCookieManager : TIdCookieManager;
procedure TUploadThread.Upload(FileName : String);
var
IdHTTP : TIdHTTP;
TheSSL : TIdSSLIOHandlerSocketOpenSSL;
TheCompressor : TIdCompressorZLib;
TheCookieManager : TIdCookieManager;
AStream : TIdMultipartFormDataStream;
begin
ACookieManager := TIdCookieManager.Create(IdHTTP);
// Automatically sync cookies between local & global Cookie managers
#TheCookieManager.OnNewCookie := pPointer(Cardinal(pPointer( procedure(ASender : TObject; ACookie : TIdCookie; var VAccept : Boolean)
begin
OmniLock.Acquire;
try
GlobalCookieManager.CookieCollection.AddCookie(ACookie, TIdHTTP(TIdCookieManager(ASender).Owner).URL{IdHTTP.URL});
finally
OmniLock.Release;
end; // try/finally
VAccept := True;
end )^ ) + $0C)^;
// ======================================== //
IdHTTP := TIdHTTP.Create(nil);
with IdHTTP do
begin
HTTPOptions := [hoForceEncodeParams, hoNoParseMetaHTTPEquiv];
AllowCookies := True;
HandleRedirects := True;
ProtocolVersion := pv1_1;
IOHandler := TheSSL;
Compressor := TheCompressor;
CookieManager := TheCookieManager;
end; // with
OmniLock.Acquire;
try
// Load login info/cookies
TheCookieManager.CookieCollection.AddCookies(GlobalCookieManager.CookieCollection);
finally
OmniLock.Release;
end; // try/finally
AStream := TIdMultipartFormDataStream.Create;
with Stream.AddFile('file_name', FileName, 'application/octet-stream') do
begin
HeaderCharset := 'utf-8';
HeaderEncoding := '8';
end; // with
IdHTTP.Post('https://www.domain.com/post.php', AStream);
AStream.Free;
end;
But it doesn't work! I'm getting this exception when calling AddCookies()
Project MyEXE.exe raised exception class EAccessViolation with message
'Access violation at address 00000000. Read of address 00000000'.
I also tried using assign(), ie.
TheCookieManager.CookieCollection.Assign(GlobalCookieManager.CookieCollection);
But I still get the same exception, usually here:
TIdCookieManager.GenerateClientCookies()
Anyone knows how to fix this?
Don't use an anonymous procedure for the OnNewCookie event. Use a normal class method instead:
procedure TUploadThread.NewCookie(ASender: TObject; ACookie : TIdCookie; var VAccept : Boolean);
var
LCookie: TIdCookie;
begin
LCookie := TIdCookieClass(ACookie.ClassType).Create;
LCookie.Assign(ACookie);
OmniLock.Acquire;
try
GlobalCookieManager.CookieCollection.AddCookie(LCookie, TIdHTTP(TIdCookieManager(ASender).Owner).URL);
finally
OmniLock.Release;
end;
VAccept := True;
end;
Or:
procedure TUploadThread.NewCookie(ASender: TObject; ACookie : TIdCookie; var VAccept : Boolean);
begin
OmniLock.Acquire;
try
GlobalCookieManager.CookieCollection.AddServerCookie(ACookie.ServerCookie, TIdHTTP(TIdCookieManager(ASender).Owner).URL);
finally
OmniLock.Release;
end;
VAccept := True;
end;
Then use it like this:
procedure TUploadThread.Upload(FileName : String);
var
IdHTTP : TIdHTTP;
TheSSL : TIdSSLIOHandlerSocketOpenSSL;
TheCompressor : TIdCompressorZLib;
TheCookieManager : TIdCookieManager;
TheStream : TIdMultipartFormDataStream;
begin
IdHTTP := TIdHTTP.Create(nil);
try
...
TheCookieManager := TIdCookieManager.Create(IdHTTP);
TheCookieManager.OnNewCookie := NewCookie;
with IdHTTP do
begin
HTTPOptions := [hoForceEncodeParams, hoNoParseMetaHTTPEquiv];
AllowCookies := True;
HandleRedirects := True;
ProtocolVersion := pv1_1;
IOHandler := TheSSL;
Compressor := TheCompressor;
CookieManager := TheCookieManager;
end; // with
OmniLock.Acquire;
try
// Load login info/cookies
TheCookieManager.CookieCollection.AddCookies(GlobalCookieManager.CookieCollection);
finally
OmniLock.Release;
end;
TheStream := TIdMultipartFormDataStream.Create;
try
with TheStream.AddFile('file_name', FileName, 'application/octet-stream') do
begin
HeaderCharset := 'utf-8';
HeaderEncoding := '8';
end;
IdHTTP.Post('https://www.domain.com/post.php', TheStream);
finally
TheStream.Free;
end;
finally
IdHTTP.Free;
end;
end;
If I had to guess, I'd say your problem is in here somewhere:
// Automatically sync cookies between local & global Cookie managers
#TheCookieManager.OnNewCookie := pPointer(Cardinal(pPointer( procedure(ASender : TObject; ACookie : TIdCookie; var VAccept : Boolean)
begin
OmniLock.Acquire;
try
GlobalCookieManager.CookieCollection.AddCookie(ACookie, TIdHTTP(TIdCookieManager(ASender).Owner).URL{IdHTTP.URL});
finally
OmniLock.Release;
end; // try/finally
VAccept := True;
end )^ ) + $0C)^;
I'm not sure what the $0C magic number is there for, but I bet all those casts are there because you had a heck of a time getting the compiler to accept this. It gave you type errors saying you couldn't assign the one thing to the other.
Those type errors are there for a reason! If you hack your way around the type system, things are very likely to break. Try turning that anonymous method into a normal method on TUploadThread and assign it that way, and see if it doesn't work better.
Responding to the comment:
Thank you guys, I converted to a normal method, but I'm still getting
exceptions in AddCookies(), last one happened in the line that reads
FRWLock.BeginWrite; in this procedure
TIdCookies.LockCookieList(AAccessType: TIdCookieAccess):
TIdCookieList;
If your error is an Access Violation with Read of address 00000000, that's got a very specific meaning. It means you're trying to do something with an object that's nil.
When you get that, break to the debugger. If the error's taking place on the line you said it's happening on, then it's almost certain that either Self or FRWLock is nil at this point. Check both variables and figure out which one hasn't been constructed yet, and that'll point you to the solution.