How to set a global environment variable from Inno Setup installer? - environment-variables

How do I set a global environment variable in Inno Setup?
Background: I am using the Inno install utility and need to set a global environment variable before I do the actual install.

Try this:
[Registry]
Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName: "VARIABLE_NAME"; \
ValueData: "new_value"; Flags: preservestringtype
You might need to add this:
[Setup]
; Tell Windows Explorer to reload the environment
ChangesEnvironment=yes
Alternatively try:
[Run]
Filename: "{app}\MyProg.exe"; BeforeInstall: SetEnvPath
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
function SetEnvironmentVariable(lpName: string; lpValue: string): BOOL;
external 'SetEnvironmentVariable{#AW}#kernel32.dll stdcall';
procedure SetEnvPath;
begin
if not SetEnvironmentVariable('VARIABLE_NAME', 'new_value') then
MsgBox(SysErrorMessage(DLLGetLastError), mbError, MB_OK);
end;
Reference: Inno Setup Frequently Asked Questions - Setting Environment Variables
If the variable change is not propagated (see Environment variable not recognized [not available] for [Run] programs in Inno Setup)
[Run]
...; AfterInstall: RefreshEnvironment
[Code]
const
SMTO_ABORTIFHUNG = 2;
WM_WININICHANGE = $001A;
WM_SETTINGCHANGE = WM_WININICHANGE;
type
WPARAM = UINT_PTR;
LPARAM = INT_PTR;
LRESULT = INT_PTR;
function SendTextMessageTimeout(hWnd: HWND; Msg: UINT;
wParam: WPARAM; lParam: PAnsiChar; fuFlags: UINT;
uTimeout: UINT; out lpdwResult: DWORD): LRESULT;
external 'SendMessageTimeoutA#user32.dll stdcall';
procedure RefreshEnvironment;
var
S: AnsiString;
MsgResult: DWORD;
begin
S := 'Environment';
SendTextMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
PAnsiChar(S), SMTO_ABORTIFHUNG, 5000, MsgResult);
end;
More details:
Inno Setup: Setting a System Environment Variable
Under more modern (in other words, proper) operating systems, such as
Windows 2000, XP, and Windows 2003 Server, environment variables are
stored in the Registry under the following key:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\
Environment
Variables are added by creating a new value under this key or by
modifying a value if it already exists. To delete a variable, you
simply delete its Registry value, unless you are removing part of an
expanded value, such as PATH, in which case you only remove the part
you want.
At this point, Windows will not be aware of your changes unless you
log off or reboot. To get around this, SetEnv will broadcast a
WM_SETTINGCHANGE to all of the windows in the system. This allows
other running applications—for example, Explorer.exe—to be notified of
your change. If you run SetEnv from a command prompt, this will not
update the environment variable for the current DOS window. This is
mainly due to the fact that a process (SetEnv) cannot change the
environment of its parent (The Command Prompt). However, any new
DOS/Command Prompts that you open will show the new variable/value.

The solutions in #Adrian's answer (actually copied from #TLama's answer to similar question) are correct for many situations.
But it won't work for [Run] tasks with runasoriginaluser flag (what is implied by postinstall flag). I.e. the variable won't be propagated to an application run with common "Run My Program" check box on the "Finished" page.
The reason is that the tasks with runasoriginaluser are executed by a un-elevated hidden parent process of the Inno Setup installer. The SetEnvironmentVariable will change environment for the installer, but not for its parent process. Unfortunately, the parent process of the installer cannot be controlled (imo).
As a workaround, to set the variable for the runasoriginaluser tasks, you have to inject an intermediate process between the installer parent process and the task, and have the intermediate process set the variable.
Such an intermediate process can easily be the cmd.exe with its set command:
[Run]
Filename: "{cmd}"; Parameters: "/C set MYVAR=MyValue & ""{app}\MyProg.exe"""; \
Description: "Run My Program"; Flags: postinstall runhidden
The runhidden flag hides the cmd.exe console window, not the application (assuming it's a GUI application). If it's a console application, use start to start it in its own (visible) console window.

What would be wrong with running two setup.exe with the first one doing the setting of the environment variables, and the second doing the things needed for the true setup. The first one would be run with setup.exe /VERYSILENT
I am doing to add an system wide environment variable:
[Setup]
; Tell Windows Explorer to reload the environment
ChangesEnvironment=True
[Registry]
Root: "HKLM"; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; ValueName: "EGPL_GeoLibrarian_Drive"; ValueData: "L"; Flags: createvalueifdoesntexist preservestringtype

Related

Invoking shell scripts on Windows under MSYS using Command

I am trying to invoke commands in Rust (1.0 beta 3) on Windows 7 in an MSYS2 environment, but I cannot understand how to do it.
Suppose that you have this very simple script called myls in your home folder:
#!/bin/bash
ls
And now create a simple program in Rust that calls the script:
use std::process::Command;
use std::path::Path;
fn main()
{
let path_linux_style = Path::new("~/myls").to_str().unwrap();
let path_win_style = Path::new("C:\\msys64\\home\\yourname\\myls").to_str().unwrap();
let out_linux = Command::new(path_linux_style).output();
let out_win = Command::new(path_win_style).output();
match out_linux
{
Ok(_) => println!("Linux path is working!"),
Err(e) => println!("Linux path is not working: {}", e)
}
match out_win
{
Ok(_) => println!("Win path is working!"),
Err(e) => println!("Win path is not working: {}", e)
}
}
Now, if you try to execute it, you will get the following output:
Linux path is not working: The system cannot find the file specified.
(os error 2)
Win path is not working: %1 is not a valid Win32 application.
(os error 193)
So I am not able to invoke any command in MSYS environment.
How can I solve it?
EDIT:
I noticed that if I invoke an executable, the problem doesn't happen, so it seems to be related to invocation of bash script. Anyway, it's quite annoying since it makes compiling projects depending on external C/C++ code (that need to launch configure script) tricky to get to work.
The Windows example doesn't work because Windows isn't a Unix. On Unix-like systems, the #! at the beginning of a script is recognized, and it invokes the executable at the given path as the interpreter. Windows doesn't have this behavior; and even if it did, it wouldn't recognize the path name to the /bin/bash, as that path name is one that msys2 emulates, it is not a native path name.
Instead, you can explicitly execute the script you want using the msys2 shell, by doing something like the following (alter the path as appropriate, I have msys32 installed since it's a 32 bit VM)
let out_win = Command::new("C:\\msys32\\usr\\bin\\sh.exe")
.arg("-c")
.arg(path_win_style)
.output();

Is there a handy tool for just localizing APKs (resources.arsc) besides apktool?

I wanted to localize my Android 4.0.4 (3G) Pad into Uighur language.
I decompiled, added a new values-ug-rCN translation in res folder, compiled back to get resources.arsc file.
All APKs went fine excep Phone.apk.
I can decompile to get xmls, but when compiling, it gave me the following errors:
(The error was reproduced using the latest ApkTool1.5.2, both with/without installing framework.apk)
E:\apktool152\x>apktool.bat if framework-res.apk
I: Framework installed to: C:\Documents and Settings\Administrator\apktool\frame
work\1.apk
E:\apktool152\x>apktool d Phone.apk
I: Baksmaling...
I: Loading resource table...
W: Skipping "android" package group
I: Loaded.
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: C:\Documents and Settings\Administrator\apk
tool\framework\1.apk
I: Loaded.
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Done.
I: Copying assets and libs...
E:\apktool152\x>apktool b Phone
I: Checking whether sources has changed...
I: Smaling...
I: Checking whether resources has changed...
I: Building resources...
E:\apktool152\x\Phone\res\values-de\strings.xml:194: error: Multiple substitutio
ns specified in non-positional format; did you mean to add the formatted="false"
attribute?
E:\apktool152\x\Phone\res\values-de\strings.xml:195: error: Unexpected end tag s
tring
E:\apktool152\x\Phone\res\values-es\strings.xml:194: error: Multiple substitutio
ns specified in non-positional format; did you mean to add the formatted="false"
attribute?
E:\apktool152\x\Phone\res\values-es\strings.xml:195: error: Unexpected end tag s
tring
E:\apktool152\x\Phone\res\values-es-rUS\strings.xml:197: error: Multiple substit
utions specified in non-positional format; did you mean to add the formatted="fa
lse" attribute?
E:\apktool152\x\Phone\res\values-es-rUS\strings.xml:198: error: Unexpected end t
ag string
E:\apktool152\x\Phone\res\values-it\strings.xml:194: error: Multiple substitutio
ns specified in non-positional format; did you mean to add the formatted="false"
attribute?
E:\apktool152\x\Phone\res\values-it\strings.xml:195: error: Unexpected end tag s
tring
aapt: warning: string 'modem_power' has no default translation in E:\apktool152\
x\Phone\res; found: en_GB zh_CN
aapt: warning: string 'modem_power_summary' has no default translation in E:\apk
tool152\x\Phone\res; found: en_GB zh_CN
Exception in thread "main" brut.androlib.AndrolibException: brut.androlib.Androl
ibException: brut.common.BrutException: could not exec command: [aapt, p, --min-
sdk-version, 15, --target-sdk-version, 15, -F, C:\DOCUME~1\ADMINI~1\LOCALS~1\Tem
p\APKTOOL187345540728029844.tmp, -0, arsc, -I, C:\Documents and Settings\Adminis
trator\apktool\framework\1.apk, -S, E:\apktool152\x\Phone\res, -M, E:\apktool152
\x\Phone\AndroidManifest.xml]
at brut.androlib.Androlib.buildResourcesFull(Androlib.java:358)
at brut.androlib.Androlib.buildResources(Androlib.java:283)
at brut.androlib.Androlib.build(Androlib.java:206)
at brut.androlib.Androlib.build(Androlib.java:176)
at brut.apktool.Main.cmdBuild(Main.java:228)
at brut.apktool.Main.main(Main.java:79)
Caused by: brut.androlib.AndrolibException: brut.common.BrutException: could not
exec command: [aapt, p, --min-sdk-version, 15, --target-sdk-version, 15, -F, C:
\DOCUME~1\ADMINI~1\LOCALS~1\Temp\APKTOOL187345540728029844.tmp, -0, arsc, -I, C:
\Documents and Settings\Administrator\apktool\framework\1.apk, -S, E:\apktool152
\x\Phone\res, -M, E:\apktool152\x\Phone\AndroidManifest.xml]
at brut.androlib.res.AndrolibResources.aaptPackage(AndrolibResources.jav
a:357)
at brut.androlib.Androlib.buildResourcesFull(Androlib.java:336)
... 5 more
Caused by: brut.common.BrutException: could not exec command: [aapt, p, --min-sd
k-version, 15, --target-sdk-version, 15, -F, C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\
APKTOOL187345540728029844.tmp, -0, arsc, -I, C:\Documents and Settings\Administr
ator\apktool\framework\1.apk, -S, E:\apktool152\x\Phone\res, -M, E:\apktool152\x
\Phone\AndroidManifest.xml]
at brut.util.OS.exec(OS.java:89)
at brut.androlib.res.AndrolibResources.aaptPackage(AndrolibResources.jav
a:355)
... 6 more
E:\apktool152\x>
I just wanted to translate the xmls inside values, and compile back to get resources.arsc.
I can go past the errors relevant to values xmls, by removing de, es, it translations if need be.
But I don't know the other errors.
So how can I solve this problem?
Or is there another alternative tools just for the task?
I switched to a modefied version of ApkTool called something like ApkTool 1.5 b-sf found in a Chinese site, and after installing framework-res.apk, it complied correctly!
Hope this helps some people.

delphi application has permissions issues. Why?

Delphi 2010
Windows 7 - 64 bit.
I have an app which is reasonably trivial. It is a database app. It starts, finds it's current directory, looks for a database file IN THAT DIRECTORY, opens it, and displays some data. It works fine on my dev computer. I take it to another computer, also Windows 7, 64 bit, and I get an error. (Specifically from the database library - Component Ace - saying that a column doesn't exist). I have to believe this is a generic access error. When I right click on the desktop icon, and choose RUN AS ADMINISTRATOR, it runs fine. I have not explicitly locked anything down. I am on the computer as the Admin user. It is Admin that has installed the app. I am trying to distribute this app to multiple people. The install routine I am using is InnoSetup. What type of permission problem as I running into?
For completeness sake, I am including the INNO SETUP.iss file.
Thanks
GS
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "DocAssist"
#define MyAppVerName "DocAssist 3.2"
#define MyAppPublisher "GS"
#define MyAppExeName "DocAssist.exe"
[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={{6F34D198-14A0-4398-8E82-34232956CC5B}
AppName={#MyAppName}
AppVerName={#MyAppVerName}
AppPublisher={#MyAppPublisher}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
OutputDir=D:\Projects\DocAssist\DISTR
OutputBaseFilename=DocAssistV3Setup
Compression=lzma
SolidCompression=yes
AppCopyright=GS
VersionInfoVersion=3.2
[Languages]
Name: english; MessagesFile: compiler:Default.isl
[Tasks]
; Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked
Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons};
[Files]
Source: D:\Projects\DocAssist\DISTR\DocAssist.exe; DestDir: {app}; Flags: ignoreversion
Source: D:\Projects\DocAssist\DISTR\DocAssist.ABS; DestDir: {app}; Flags: ignoreversion
Source: D:\Projects\DocAssist\DISTR\StopWords.txt; DestDir: {app}; Flags: ignoreversion
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
Source: DocAssist Version 3_2.pdf; DestDir: {app}; Flags: isreadme
; Add-in dll
Source: D:\Projects\DocAssist\DISTR\DocAssistCom.dll; DestDir: {app}; Flags: regserver
Source: D:\Projects\DocAssist\DISTR\gdiplus.dll; DestDir: {app}; Flags: ignoreversion
[Icons]
Name: {group}\{#MyAppName}; Filename: {app}\{#MyAppExeName}
Name: {group}\{cm:UninstallProgram,{#MyAppName}}; Filename: {uninstallexe}
Name: {commondesktop}\{#MyAppName}; Filename: {app}\{#MyAppExeName}; Tasks: desktopicon
[Run]
Filename: {app}\{#MyAppExeName}; Description: {cm:LaunchProgram,{#MyAppName}}; Flags: nowait postinstall skipifsilent
[Registry]
Root: HKLM; Subkey: SOFTWARE\DocAssist; ValueType: none; Permissions: admins-full; Flags: uninsdeletekey createvalueifdoesntexist;
Root: HKLM; Subkey: SOFTWARE\DocAssist; ValueType: string; ValueName: InstallDir; ValueData: {app}; Permissions: admins-full; Flags: uninsdeletekey createvalueifdoesntexist
You should not write to files in your program files directory. This has been deprecated since Windows 95, but starting with Windows Vista it has become more strict and writing there is not allowed by default, unless you are an administrator.
There are many other places you can write to, and App Data is a commonly used folder, as is My Documents. You can use the SHGetSpecialFolderLocation api to find the exact location of these special folders (because it ma differ per installation).
B.t.w. if you have to use the application directory, resort to Application.ExeName or ParamStr(0) rather than on the current directory.

Check if psqlodbc has been unistalled or not from the system

Im working on software that required psqlodbc drivers and postgresSQl 9.0 database,
we have a installer designed using delphi 7 to install both psqlodbc and postgreSQl 9 silently
one after the other on click of a single button, here everything runs fine,
but the problem is during uninstall,
i first want to unistall psqlodbc and then postgreSQl 9 also on a sinlge button click,
i want to run the postgreSQl 9 unistaller using shellpApi only after psqlodbc has been unstalled,
as of now im checking for 'cmd.exe' is running or not to start postgreSQl uninstaller, but sometimes after unstalling psqlodbc the 'cmd.exe' remain n the postgreSQl unistaller cannot be executed,
so any please tell me
how to check if psqlodbc uninstall process is completely.
the files are
1.psqlodbc.msi
2.postgresql-9.0.2-1-windows.exe
install/uninstall is handled wit bat file
thanks in advanced:)
You can check registry if driver is available. When it is installed you will get:
c:\tmp\pg>reg query "hklm\SOFTWARE\ODBC\ODBCINST.INI\PostgreSQL ANSI"
! REG.EXE VERSION 3.0
HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\PostgreSQL ANSI
APILevel REG_SZ 1
ConnectFunctions REG_SZ YYN
Driver REG_SZ C:\Program Files\psqlODBC\0900\bin\psqlodbc30a.dll
DriverODBCVer REG_SZ 03.00
FileUsage REG_SZ 0
Setup REG_SZ C:\Program Files\psqlODBC\0900\bin\psqlodbc30a.dll
SQLLevel REG_SZ 1
UsageCount REG_DWORD 0x1
And when you unistall it you will get (localized version):
c:\tmp\pg>reg query "hklm\SOFTWARE\ODBC\ODBCINST.INI\PostgreSQL ANSI"
Błąd: system nie może odnaleźć określonego klucza rejestru lub wartości.
c:\tmp\pg>
(this menas: Error: system cannot find key or value in registry)
See: reg /? on how to use it and for return code you can use in batch.
You can also search registry uninstall information under HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall
I got how to check if psqlodbc has been uninstalled completely so that i can start unistalling postgres
For that i found the solution
On stackoverflow itself
function TForm1.ExecAndWait(const CommandLine: string) : Boolean;
var
StartupInfo: Windows.TStartupInfo; // start-up info passed to process
ProcessInfo: Windows.TProcessInformation; // info about the process
ProcessExitCode: Windows.DWord; // process's exit code
begin
// Set default error result
Result := False;
// Initialise startup info structure to 0, and record length
FillChar(StartupInfo, SizeOf(StartupInfo), 0);
StartupInfo.cb := SizeOf(StartupInfo);
// Execute application commandline
if Windows.CreateProcess(nil, PChar(CommandLine),
nil, nil, False, 0, nil, nil,
StartupInfo, ProcessInfo) then
begin
try
// Now wait for application to complete
if Windows.WaitForSingleObject(ProcessInfo.hProcess, INFINITE)
= WAIT_OBJECT_0 then
// It's completed - get its exit code
if Windows.GetExitCodeProcess(ProcessInfo.hProcess,
ProcessExitCode) then
// Check exit code is zero => successful completion
if ProcessExitCode = 0 then
Result := True;
finally
// Tidy up
Windows.CloseHandle(ProcessInfo.hProcess);
Windows.CloseHandle(ProcessInfo.hThread);
end;
end;
end;
so step # 1
if ExecAndWait('msiexec /x C:\psqlodbc09\psqlodbc.msi') then
begin
//uninstall postgresNow...!!
end;

How do I configure a ASAPI DLL for Delphi in Apache 2.X?

I'm trying to understand ISAPI as run under Apache 2.x. I've created a simple DLL using Delphi XE to test with based on a tutorial I found.
I've added these lines to my Apache httpd.conf file.
ScriptAlias /Delphi/ "C:/Delphi/bin/"
<Directory "C:/Delphi/bin/">
AddHandler isapi-handler .dll
AllowOverride None
Options ExecCGI
Order allow,deny
Allow from all
</Directory>
The isapi_module is loaded.
I've placed the DLL in C:\Delphi\bin.
When I call it with the following URL (case is correct);
http://127.0.0.1/Delphi/ISAPI_Test1.dll
I get a 403 error and the Apache Error Log has this line.
... [error] [client 127.0.0.1] attempt to invoke directory as script: C:/Delphi/bin/
I expect the dll to simply use the default handler:
procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
Response.SendRedirect (Request.Referer);
end;
Question 1: What is my specific issue here?
Question 2: Can anybody point me to a step by step tutorial or book for getting a basic skelton working? I've got too many holes in my understanding at this point.
Thank you.
For this subject, look at serverfault.com, for example, this question: apache attempt to invoke directory as script

Resources