Permanent customized folder icons with InnoSetup in any computer - installation

I have modified some folder icons and I am including these folders in my InnoSetup installation. The problem is that once my program is installed, my customized folder icons are gone and what I see is just the oldfashioned "yellow" Windows folder icons.
EDIT
The answer was provided by the user TLama. It worked in my computer at first. I had some problems with different Windows versions at different computers. I will write now my working code after having tried sucessfully in several computer systems.
Icons used:
Ico1.ico
Ico2.ico
Ico3.ico
Modified folder icons:
c:\FDR1
c:\FDR2\FDR3
Step 1:
I have used the software "Folder icon changer" to have my icon in place for the three folders I wanted changed. You may use any other free software too. After execution, a desktop.ini appeared in each of the newly changed icon folders. For instance, the FDR1 has the content:
[.Shellclassinfo]
Iconfile=F:\Resource\Icons\Ico1.ico
Iconindex= 0
Step 2:
I have then erased the path above and saved "Ico1.ico" into the directory "c:\FDR1" I had just modified :
[.Shellclassinfo]
Iconfile=Ico1.ico
Iconindex= 0
I did the same for the Ico2.ico (inside the FDR2) and the Ico3.ico (inside the FDR3). The "Icon1, 2 and 3" and "desktop.ini" file attributes were all set to hidden. But, it is important NOT to set the icon properties to "read only".
Step 3:
Inside Inno repeat TLama's suggestion.
#define OutputDirectory_1 "c:\FDR1"
#define OutputDirectory_2 "c:\FDR2"
#define OutputDirectory_3 "c:\FDR2\FDR3"
[Dirs]
Name: {#OutputDirectory_1}; Attribs: system
Name: {#OutputDirectory_2}; Attribs: system
Name: {#OutputDirectory_3}; Attribs: system
[Files]
Source: "c:\FDR1\Ico1.ico"; DestDir: {#OutputDirectory_1}; Attribs: hidden system
Source: "c:\FDR2\Ico2.ico"; DestDir: {#OutputDirectory_2}; Attribs: hidden system
Source: "c:\FDR2\FDR3\Ico3.ico"; DestDir: {#OutputDirectory_3}; Attribs: hidden system
Step 4:
Compile !
Now, your folder icons will permanently work in any computer and system !!

Your target folder should have either read only or system attribute configured. To create such folder you can use, like Miral mentioned, [Dirs] section and its attributes. This will have an advantage, that after you run the installation process, InnoSetup automatically notifies Shell about changes, so the folder icon will be changed without an extra notification function call.
; this is a defined preprocessor variable used to simplify the script
; management; this variable contains the path, where the icon will be
; applied (it's used twice in a script, so it's easier to manage that
; from one place)
#define OutputDirectory "d:\TargetDirectory"
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
OutputDir=userdocs:Inno Setup Examples Output
[Files]
; here you need to use "hidden" and "system" values in Attribs parameter
; to include into the Desktop.ini file hidden and system file attributes
Source: "Desktop.ini"; DestDir: {#OutputDirectory}; Attribs: hidden system
[Dirs]
; here you need to use either "readonly" or "system" value in Attribs parameter
; to setup to the output directory read only or system file directory attribute
Name: {#OutputDirectory}; Attribs: readonly
Important:
Don't forget that you have to compile the script using CTRL + F9 before running, whenever you change the content of your input Desktop.ini file as well as when you change the value of the preprocessor path variable (I've been missing this few times and then wondering about the setup package content).

In order to activate custom folder icons you have to programmatically set the "read-only" attribute of the folder containing the desktop.ini file. (You can't do this from Explorer, but you can via the command line and from Inno.)
[Dirs]
Name: {app}; Attribs: readonly
Note that the path inside the desktop.ini file must be valid on the user's filesystem; you may want to use an [Ini] entry to create or modify this file to suit the installation path.
(This doesn't actually make the folder read-only -- this attribute is treated differently on folders by Windows because only files can meaningfully be read-only.)

Related

vim: Changing directory where views are saved on Windows 7

I've recently learnt about folding in vim and that you can use :mkview to save the folds in a document. However, vim is trying to save views in the C:\Program Files (x86)\vim\ directory path, which needs Admin privileges to save to... as this is a corporate Win7 work machine, I need to convince vim it wants to save views elsewhere.
Is there a command I need to include in my _vimrc file to get vim to save the views elsewhere? Or another way to control this behaviour?
Set viewdir.
From :help mkview :
When [file] is omitted or is a number from 1 to 9, a name is generated and 'viewdir' prepended.
:help 'viewdir' gives:
*'viewdir'* *'vdir'*
'viewdir' 'vdir' string (default for Amiga, MS-DOS, OS/2 and Win32:
"$VIM/vimfiles/view",
for Unix: "~/.vim/view",
for Macintosh: "$VIM:vimfiles:view"
for VMS: "sys$login:vimfiles/view"
for RiscOS: "Choices:vimfiles/view")
global
{not available when compiled without the |+mksession|
feature}
Name of the directory where to store files for |:mkview|.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.

Create a hardlink with Inno Setup

I have thousand of own installers that requires a critical dll file for uninstallation step, this dll file sizes about 2 mb then to avoid unnecessary disk space (2mb*100 installers) I would like to store the file once in {cf} then make a hardlink for the next installers that requires that file.
I could create a hardlink in Inno Setup without the need of external apps such as mklink.exe usage?
This is a brief example of what I have, all my installers follow the same "structure":
[Files]
; VCL Styles
Source: {tmp}\uninstall.vsf; DestDir: {app}; \
Flags: ignoreversion
Source: {tmp}\uninstall.dll; DestDir: {app}; \
Flags: ignoreversion uninsneveruninstall
; Temp files
Source: {tmp}\*; DestDir: {tmp}; Excludes: uninstall.dll, uninstall.vsf; \
Flags: recursesubdirs createallsubdirs ignoreversion
; Program
Source: {app}\*; DestDir: {app}; \
Flags: recursesubdirs createallsubdirs ignoreversion
As you could see, I'm moving the uninstall.dll to {app}, but what I would like to do is: If doesn't exists, copy the uninstall.dll file to {cf}\InnoSetup\uninstall.dll filepath and make a hardlink to {app}\uninstall.dll, if already exists the file then just make the hardlink, nothing more, I won't still store the uninstall.dll file in {app}\uninstall.dll, just I want a symbolic reference because the uninstall.dll file should never be uninstalled.
How I could do it?
Inno Setup does not support creating hardlinks natively.
I wouldn't consider the mklink an external application. It's a built-in Windows tool. So if you do not need to support Windows XP, you can safely rely on it. Or you can fallback to installing the DLL regularly, if the mklink is not available.
Or use the CreateHardLink function from the Code section.
#define MyApp "MyApp"
#define UninstallDll "uninstall.dll"
[Files]
Source: "{#UninstallDll}"; DestDir: "{cf}\{#MyApp}"; \
Flags: ignoreversion uninsneveruninstall
[Code]
function CreateHardLink(lpFileName, lpExistingFileName: string;
lpSecurityAttributes: Integer): Boolean;
external 'CreateHardLinkW#kernel32.dll stdcall';
procedure CurStepChanged(CurStep: TSetupStep);
var
ExistingFile, NewFile: string;
begin
if CurStep = ssPostInstall then
begin
ExistingFile := ExpandConstant('{cf}\{#MyApp}\{#UninstallDll}');
NewFile := ExpandConstant('{app}\{#UninstallDll}');
if CreateHardLink(NewFile, ExistingFile, 0) then
begin
Log('Hardlink created');
end
else
if FileCopy(ExistingFile, NewFile, False) then
begin
// FAT file system?
Log('Hardlink could not be created, file copied instead');
end
else
begin
MsgBox('Cannot install {#UninstallDll}', mbError, MB_OK);
end;
end;
end;
(Tested on Unicode version of Inno Setup – The only version as of Inno Setup 6)
And do not forget to delete the file when uninstalling:
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usUninstall then
begin
if DeleteFile(ExpandConstant('{app}\{#UninstallDll}')) then
begin
Log('File deleted');
end
else
begin
Log('Cannot delete file');
end;
end;
end;
You can of course use also the [UninstallDelete] entry. I just like to uninstall the file using the same technology used to install it.
Your question title is "Create a hardlink with Inno Setup".
The CreateHardLink creates a hardlink. A hardlink is another reference to the same contents. Basically the hardlink is indistinguishable from the original file (even the original file is a hardlink actually). Both original file and the hardlink are just references to the same contents. If you delete the original file (or the new hardlink), you actually remove just one reference to the contents. The contents is still preserved. The contents is removed with the last reference only. The hardlink does not occupy an additional space on the disk (the contents is stored only once).
For details see Hard link article on Wikipedia.
While the mklink creates a symlink (aka symbolic link) by default. A symlink is like a shortcut, it's a reference to the original file (not contents). It's a file on its own, that contains a path to the target file. The symlink has a size of its own (occupied by the reference to the target file). If you remove the original file, the symlink still exists (because there's no reference to the symlink from the original file), but becomes invalid (the contents is gone). Again, it's similar to a shortcut.
For details see Symbolic link article on Wikipedia.
You can create a hardlink with the mklink, if you add the /H switch:
/H Creates a hard link instead of a symbolic link.
If you want to create the symlink instead of the hardlink, it's a different question (though the answer is simple, use the CreateSymbolicLink function). Though again, note that the hardlink does not occupy additional space on the disk, what seems to be your concern. So I believe you should keep using the CreateHardLink function.

Inno Setup creating an unwanted empty folder with value in DefaultDirName

Inno Setup installer is creating an unwanted empty folder using my initial value of DefaultDirName, even though I have set WizardForm.DirEdit.Text = 'c:\preferredinstalldir' in CurStepChanged (curStep = ssInstall). The installer puts the files in the right installation folder, but because I have to assign a dummy value to DefaultDirName, it creates that dummy folder. I have tried using a {code:xx} function for the DefaultDirName but since the actually folder I want hasn't been determined until the wizard runs, I seem to need a placeholder folder (but I don't want it created!)
AppId = {code:GetAppId}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppCopyright={#MyAppCopyright}
VersionInfoCopyright={#MyAppCopyright}
AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL}
DefaultDirName={code:GetFilesDestDir} //this says error path not valid, no root/unc etc etc because the function has no path set yet
DefaultDirName=c:\mydummyfolder //this creates a dummy folder even though the files are installed correctly to location i set later in CurStepChanged (I assign WizardForm.DirEdit.Text := InstallPath )
DisableDirPage=yes
DefaultGroupName=SomeName
DisableProgramGroupPage=yes
OutputBaseFilename=mysetup_setup
Compression=lzma
SolidCompression=yes
UsePreviousAppDir=no
UsePreviousLanguage=no
UninstallFilesDir = {code:GetFilesDestDir}\uninst
.............
function GetFilesDestDir(def:string): string;
begin
if InstallPathSet then
begin
Result := InstallPath;
end
end;
I've seen this question here
Inno Script: Strange Empty Folder
but it wasn't answered and I couldn't post a comment.
I think I've found the solution, setting CreateAppDir=no seems to do the trick.At least its no longer creating an empty folder at the initial dummy location.
I cannot reproduce what you describe.
Changing WizardForm.DirEdit.Text in CurStepChanged(ssInstall) has no effect at all. It's too late.
Anyway, just change the value sooner. For example in the InitializeWizard or CurPageChanged.

What determines the location of the 'pathdef.m' file on Windows?

http://www.mathworks.com/support/solutions/en/data/1-5YQCPR/index.html?product=ML says:
By default, the 'pathdef.m' file may be located in either the
'$MATLABROOT/toolbox/local' directory or the '$USERPATH' directory,
where $MATLABROOT and $USERPATH are the directories displayed after
entering the commands matlabroot (e.g. C:\Program Files\MATLAB\R2013b) and userpath (e.g. C:\Users\francky\Documents\MATLAB)
So, what determines the location of the pathdef.m file on Windows (matlabroot vs. userpath)?
According to this help page:
By default, pathdef.m is in matlabroot/toolbox/local.
However, there is apparently more to it than that.
If we add matlabpath to the top of matlabrc.m, it will tell use the search path before it has even "set up" the search path:
MATLABPATH
C:\Program Files (x86)\MATLAB\R2013a\toolbox\local
>>
So the only thing on the path is matlabroot/toolbox/local and that's where MATLAB will find pathdef.m by default. Right? I thought so, but a simple test with a pathdef.m in userpath proved that in fact userpath was the first priority for pathdef.m. Why? Because in MATLAB, the working directory takes priority over anything on the matlabpath, and the startup folder is determined by userpath!
There are multiple ways to specify the startup working directory, with and without the use of userpath's functional form. I just verified that changing the "Start in:" property of the Windows shortcut will prevent the pathdef.m in the default userpath from running. You can achieve the same change in startup folder with the userpath(path) syntax, but then what would be the difference between the startup path and userpath unless you use the shortcut "Start in:" method?
To add to the confusion, the last line of the default pathdef.m under matlabroot/toolbox/local is p = [userpath,p];, so after matlabrc.m adds this to the path on startup, MATLAB will then give userpath precedence over matlabroot, if ther is a pathdef.m under userpath.

Create more than 1 uninstaller in a NSIS Section

Can a NSIS Section create more than 1 uninstaller?
My installer can install plugins for 3 different versions of an Application - therefore theres 3 different directories where the installer will install the files.
In each of those directories I want to add an uninstaller file that will remove only the files in that directory.
Each of the 3 uninstall files are created within the same Section area, is this invalid? How can I get my script to create 3 uninstallers(if possible)?
The following Section only creates one uninstaller, the last one(Version 10 uninstaller):
Section "Install Plugin Files" MainSetup
CheckInstallVers8:
IntCmp $installVers8 1 InstallVersion8 CheckInstallVers9 InstallVersion8
CheckInstallVers9:
IntCmp $installVers9 1 InstallVersion9 CheckInstallVers10 InstallVersion9
CheckInstallVers10:
IntCmp $installVers10 1 InstallVersion10 MainInstallation InstallVersion10
InstallVersion8:
# install plugins...
SetOutPath $VERS8DIR
writeUninstaller "${APPNAME} Uninstall.exe"
GoTo CheckInstallVers9
InstallVersion9:
SetOutPath $VERS9DIR
writeUninstaller "${APPNAME} Uninstall.exe"
GoTo CheckInstallVers10
InstallVersion10:
SetOutPath $VERS10DIR
writeUninstaller "${APPNAME} Uninstall.exe"
SectionEnd
You can call WriteUninstaller as many times as you want but you should use the full path name (writeUninstaller "$VERSxDIR\${APPNAME} Uninstall.exe")
You did not post a full script so it is hard to tell what is wrong with the logic (You might want to use LogicLib.nsh so you can do {IF}s) but you should be able to "MessageBox debug" your way to the solution.
One thing you did not talk about that might be relevant is the uninstaller logic. If the 3 uninstallers all do the exact same task then this is not an issue but I'd expect at least a difference in the uninstaller registry registration.
There are two ways to deal with this:
Tag data to the end of the uninstaller (or a .ini in the same directory)
Use !system to call makensis.exe and generate uninstallers at compile time that you include as normal Files
A different solution that might be relevant for plugins in sub-directories is to use a component page in the uninstaller and only delete the uninstaller when all 3 plugins have been removed...

Resources