NSIS GetVolumeInformation Results - nsis

Ok I found this code from another question asked and I'm a newbie for NSIS. Question Below
!define FILE_SUPPORTS_ENCRYPTION 0x00020000
!define FILE_READ_ONLY_VOLUME 0x00080000
!define FILE_VOLUME_QUOTAS 0x00000020
!macro MakeBitFlagYesNo flags bit outvar
IntOp ${outvar} ${flags} & ${bit}
${IfThen} ${outvar} <> 0 ${|} StrCpy ${outvar} "Yes" ${|}
${IfThen} ${outvar} == 0 ${|} StrCpy ${outvar} "No" ${|}
!macroend
StrCpy $0 "c:\"
System::Call 'Kernel32::GetVolumeInformation(t "$0",t,i ${NSIS_MAX_STRLEN},*i,*i,*i.r1,t,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
!insertmacro MakeBitFlagYesNo $1 ${FILE_SUPPORTS_ENCRYPTION} $2
!insertmacro MakeBitFlagYesNo $1 ${FILE_READ_ONLY_VOLUME} $3
!insertmacro MakeBitFlagYesNo $1 ${FILE_VOLUME_QUOTAS} $4
MessageBox mb_ok "flags=$1 $\nFILE_SUPPORTS_ENCRYPTION=$2$\nFILE_READ_ONLY_VOLUME=$3$\nFILE_VOLUME_QUOTAS=$4"
${EndIf}
Here is what I need to get:
Drive Volume Label:
File System: (Fat32, NTFS, exFat, ...)
Disk Capacity: (7.27TB, 5.59TB, ...)
Free Space: (4.62TB , 632GB, ...)
Allocation Unit Size: (4096b, 16kb, 32kb, ...)
and then I need to use that info in a if then statement
Just not sure how to turn the above code and results into code list below.
I have tried searching google about NSIS and GetVolumeInformation, and with the GetVolumeInformation I could not find out how to get and read results anywhere.
${If} $File_System <> "NTFS"
${EndIf}
${If} $Disk_Capacity < "1.86TB"
${EndIf}
${If} $Free_Space < "1.25TB"
${EndIf}
${If} $Allocation_Unit_Size <> "4096 bytes"
${EndIf}
MessageBox mb_ok "$Drive_Volume_Label$\n$File_System$\n$Disk_Capacity$\n$Free_Space$\n$Allocation_Unit_Size"
And if you could post the answer code for me and then point me where you got the info (the explanation of the) code. This help me learn the code faster if I know what its doing for what I need.
Thanks,
Albert

The code in the answer you found does actually return the name of the file system and then it goes on to tell you that that is probably not the best way to do things. You should use the file system flags if possible. Case in point, Microsofts new file system ReFS supports some of the NTFS features and adds some new reliability features.
!include LogicLib.nsh
StrCpy $9 "c:\"
System::Call 'Kernel32::GetVolumeInformation(t "$9",t.r3,i ${NSIS_MAX_STRLEN},*i,*i,*i.r1,t.r2,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
IntFmt $1 "%#.8x" $1
MessageBox MB_OK " FileSystemFlags=$1 $\n FileSystemName=$2 $\n VolumeName=$3"
${If} $2 == "NTFS"
MessageBox MB_OK "$9 is NTFS"
${Else}
MessageBox MB_OK "$9 is $2 and not NTFS but hopefully you don't care"
${EndIf}
${EndIf}
Your other properties are not exposed by this function which would be obvious if you looked at its documentation on MSDN.
!include LogicLib.nsh
StrCpy $9 "c:\"
System::Call 'Kernel32::GetDiskFreeSpaceEx(t "$9", *l.r1, *l.r2, *l.r3)i.r0' ; This function does not work on Windows 95
${If} $0 <> 0
MessageBox MB_OK " FreeBytesAvailable=$1 $\n TotalNumberOfBytes=$2 $\n TotalNumberOfFreeBytes=$3"
System::Call 'ShLwApi::StrFormatByteSizeW(l $1, w.r4, i ${NSIS_MAX_STRLEN})'
MessageBox MB_OK "Friendly FreeBytesAvailable: $4" ; For display in UI only!
!define /math MYSIZE 0x100000 * 666 ; 666 MiB
${If} $1 L>= ${MYSIZE}
MessageBox MB_OK "Disk quota on $9 allows you to write at least ${MYSIZE} bytes on this volume"
${Else}
MessageBox MB_OK|MB_ICONSTOP "Not enough space on volume, ${MYSIZE} bytes required!"
Quit
${EndIf}
${EndIf}
NSIS already provides a directory page that checks the disk space, use that if possible. Note: You cannot compare numbers of different scales (TB vs GB etc.), you must compare a 64-bit count of bytes.
By allocation unit I assume you are talking about the cluster size?
!include LogicLib.nsh
StrCpy $9 "c:\"
System::Call 'Kernel32::GetDiskFreeSpace(t "$9", *i.r1, *i.r2, *i, *i)i.r0'
${If} $0 <> 0
IntOp $1 $1 * $2
System::Call 'ShLwApi::StrFormatByteSizeW(l $1, w.r3, i ${NSIS_MAX_STRLEN})'
MessageBox MB_OK "Cluster size: $3 ($1 bytes)"
${If} 4096 <> $1
; ...
${EndIf}
${EndIf}
(The reported cluster size is probably the logical size, not the physical size)

Related

Product version string from an exe - nsis

I want to read the product version (optional string) from a given executable (actually from the installer I'm trying to create if it makes any difference), if it is possible at the run-time. This string will be further used to download files from a link.
Thank you very much !
NSIS does not have native support for reading anything other than VS_FIXEDFILEINFO->dwFileVersion so you have to call the Windows API directly:
; Add some version information so we have something to test
VIProductVersion 1.2.3.4
VIAddVersionKey "ProductVersion" "One Two Three Four"
VIAddVersionKey "FileVersion" "Whatever"
VIAddVersionKey "FileDescription" "Whatever"
VIAddVersionKey "LegalCopyright" "(C) Whatever"
!include LogicLib.nsh
Function GetFileVerFirstLangProductVersion
System::Store S
pop $3
push "" ;failed ret
System::Call 'version::GetFileVersionInfoSize(t"$3",i.r2)i.r0'
${If} $0 <> 0
System::Alloc $0
System::Call 'version::GetFileVersionInfo(t"$3",ir2,ir0,isr1)i.r0 ? e'
pop $2
${If} $0 <> 0
${AndIf} $2 = 0 ;a user comment on MSDN said you should check GLE to avoid crash
System::Call 'version::VerQueryValue(i r1,t "\VarFileInfo\Translation",*i0r2,*i0)i.r0'
${If} $0 <> 0
System::Call '*$2(&i2.r2,&i2.r3)'
IntFmt $2 %04x $2
IntFmt $3 %04x $3
System::Call 'version::VerQueryValue(i r1,t "\StringFileInfo\$2$3\ProductVersion",*i0r2,*i0r3)i.r0'
${If} $0 <> 0
pop $0
System::Call *$2(&t$3.s)
${EndIf}
${EndIf}
${EndIf}
System::Free $1
${EndIf}
System::Store L
FunctionEnd
Section
Push "$ExePath" ; Read our own version information in this example
Call GetFileVerFirstLangProductVersion
Pop $0
DetailPrint "ProductVersion=$0"
SectionEnd

nsis refresh environment during setup

During my setup i install redistributables. After installing my program i want to execute the program during the setup. For that the redistributables are needed. But the environment is not refreshed during setup, so i can't start the program. Can i refresh the environtment during the setup, or reread the environment? Or read the system environment which has changed after the redistributable installation?
I need the environment changes made during the installation of the redistributables during the setup.
Thanks for your help.
I had your same issue, that I solved with a workaround, but I came across this solution and I would like to share with you.
This should reload environment variables during setup:
!include LogicLib.nsh
!include WinCore.nsh
!ifndef NSIS_CHAR_SIZE
!define NSIS_CHAR_SIZE 1
!define SYSTYP_PTR i
!else
!define SYSTYP_PTR p
!endif
!ifndef ERROR_MORE_DATA
!define ERROR_MORE_DATA 234
!endif
/*!ifndef KEY_READ
!define KEY_READ 0x20019
!endif*/
Function RegReadExpandStringAlloc
System::Store S
Pop $R2 ; reg value
Pop $R3 ; reg path
Pop $R4 ; reg hkey
System::Alloc 1 ; mem
StrCpy $3 0 ; size
loop:
System::Call 'SHLWAPI::SHGetValue(${SYSTYP_PTR}R4,tR3,tR2,i0,${SYSTYP_PTR}sr2,*ir3r3)i.r0' ; NOTE: Requires SHLWAPI 4.70 (IE 3.01+ / Win95OSR2+)
${If} $0 = 0
Push $2
Push $0
${Else}
System::Free $2
${If} $0 = ${ERROR_MORE_DATA}
IntOp $3 $3 + ${NSIS_CHAR_SIZE} ; Make sure there is room for SHGetValue to \0 terminate
System::Alloc $3
Goto loop
${Else}
Push $0
${EndIf}
${EndIf}
System::Store L
FunctionEnd
Function RefreshProcessEnvironmentPath
System::Store S
Push ${HKEY_CURRENT_USER}
Push "Environment"
Push "Path"
Call RegReadExpandStringAlloc
Pop $0
${IfThen} $0 <> 0 ${|} System::Call *(i0)${SYSTYP_PTR}.s ${|}
Pop $1
Push ${HKEY_LOCAL_MACHINE}
Push "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
Push "Path"
Call RegReadExpandStringAlloc
Pop $0
${IfThen} $0 <> 0 ${|} System::Call *(i0)${SYSTYP_PTR}.s ${|}
Pop $2
System::Call 'KERNEL32::lstrlen(t)(${SYSTYP_PTR}r1)i.R1'
System::Call 'KERNEL32::lstrlen(t)(${SYSTYP_PTR}r2)i.R2'
System::Call '*(&t$R2 "",&t$R1 "",i)${SYSTYP_PTR}.r0' ; The i is 4 bytes, enough for a ';' separator and a '\0' terminator (Unicode)
StrCpy $3 ""
${If} $R1 <> 0
${AndIf} $R2 <> 0
StrCpy $3 ";"
${EndIf}
System::Call 'USER32::wsprintf(${SYSTYP_PTR}r0,t"%s%s%s",${SYSTYP_PTR}r2,tr3,${SYSTYP_PTR}r1)?c'
System::Free $1
System::Free $2
System::Call 'KERNEL32::SetEnvironmentVariable(t"PATH",${SYSTYP_PTR}r0)'
System::Free $0
System::Store L
FunctionEnd
Section
Call RefreshProcessEnvironmentPath
SectionEnd
Source: http://forums.winamp.com/showpost.php?p=3028153&postcount=12

SelectFolderDialog with only drives, no folder selection inside drives

In nsis SelectFolderDialog for folder selection window. But i want to appear or user to select only drives.There should not be selection of folders inside a drive.
So user should get drives like C: D: E: etc
Is there any option to do it?
This only allows you to select paths shorter than 4 characters inside My Computer, if you want to hide the folders in the dialog you need to write a plugin and implement IFolderFilter (WinXP+ only)
#BIF_RETURNONLYFSDIRS 0x00000001
#BIF_NEWDIALOGSTYLE 0x00000040
#BIF_NONEWFOLDERBUTTON 0x00000200
!include LogicLib.nsh
!include WinMessages.nsh
!define /math BFFM_ENABLEOK ${WM_USER} + 101
!define BFFM_SELCHANGED 2
System::Call 'SHELL32::SHGetSpecialFolderLocation(i0,i0x11,*i.r2)i.r0'
System::Get "(i.R0,i.R1,i.R2,i)iR9R9"
Pop $3
System::Call '*(i$hwndparent,i$2,i,t "Hello",i0x241,kr3,i0,i0)i.r1'
System::Call 'SHELL32::SHBrowseForFolder(ir1)i.r0'
Sys_BFFCALLBACK:
${If} $R9 == "callback1"
${If} ${BFFM_SELCHANGED} = $R1
System::Call 'SHELL32::SHGetPathFromIDList(i$R2,t "" R9)'
StrLen $R9 $R9
${IfThen} $R9 > 3 ${|} StrCpy $R9 0 ${|}
SendMessage $R0 ${BFFM_ENABLEOK} 0 $R9
${EndIf}
StrCpy $R9 0 ; return value
System::Call $3
Goto Sys_BFFCALLBACK
${EndIf}
System::Free $3 ; system callback
System::Call 'OLE32::CoTaskMemFree(ir2)' ; BROWSEINFO.pidlRoot
System::Free $1 ; BROWSEINFO
${If} $0 <> 0
System::Call 'SHELL32::SHGetPathFromIDList(i$0,t "" R9)'
MessageBox mb_ok SHBrowseForFolder=$R9
${EndIf}
System::Call 'OLE32::CoTaskMemFree(ir0)' ; pidl result

How can I resize a NSD_SetImageOLE image

I'm using the plugin macro NSD_SetImageOLE from http://nsis.sourceforge.net/NsDialogs_SetImageOLE - And I would like add another macro NSD_SetStretchedImageOLE the same way nsDialog.nsh works.
But I'm not sure is it's even possible, I've found that the resizing of an IPicture can be done by getting the "HBITMAP, BITMAP and BITMAPINFO" and resizing it (quoted from http://www.mofeel.net/958-microsoft-public-vc-mfc/12516.aspx). Anyway, I'm kind of lost trying to covert these methods to NSIS's System::Call style.
I have updated http://nsis.sourceforge.net/mediawiki/images/6/65/NsDialogs_setImageOle.zip with a ${NSD_SetStretchedImageOLE} which encapsulates Anders' code for reusability. I've also changed it to use the control dimensions rather than you having to specify the size yourself.
!ifndef IID_IPicture
!define IID_IPicture {7BF80980-BF32-101A-8BBB-00AA00300CAB}
!endif
!define SRCCOPY 0xCC0020
!include nsDialogs.nsh
!define IMAGEPATH "$sysdir\migwiz\PostMigRes\Web\base_images\Documents.gif" ;"C:\Windows\Web\Wallpaper\Windows\img0.jpg"
!define NEWSIZEW 200
!define NEWSIZEH 100
Page Custom mypagestretchcreate_GDI ; GDI resize
Page Custom mypagestretchcreate_CTL ; Simple control resize
Function mypagestretchcreate_GDI
nsDialogs::Create 1018
Pop $0
System::Call 'oleaut32::OleLoadPicturePath(w "${IMAGEPATH}",i0r2,i0,i0,g"${IID_IPicture}",*i.r9)i.r1'
${If} $1 = 0
System::Call 'user32::GetDC(i0)i.s'
System::Call 'gdi32::CreateCompatibleDC(iss)i.r1'
System::Call 'gdi32::CreateCompatibleBitmap(iss,i${NEWSIZEW},i${NEWSIZEH})i.r2'
System::Call 'user32::ReleaseDC(i0,is)'
System::Call $9->3(*i.r3)i.r4 ; IPicture->get_Handle
${If} $4 = 0
System::Call 'gdi32::SetStretchBltMode(ir1,i4)'
System::Call '*(&i40,&i1024)i.r4' ; BITMAP / BITMAPINFO
System::Call 'gdi32::GetObject(ir3,i24,ir4)'
System::Call 'gdi32::SelectObject(ir1,ir2)i.s'
System::Call '*$4(i40,i.r6,i.r7,i0,i,i.s)' ; Grab size and bits-ptr AND init as BITMAPINFOHEADER
System::Call 'gdi32::GetDIBits(ir1,ir3,i0,i0,i0,ir4,i0)' ; init BITMAPINFOHEADER
System::Call 'gdi32::GetDIBits(ir1,ir3,i0,i0,i0,ir4,i0)' ; init BITMAPINFO
System::Call 'gdi32::StretchDIBits(ir1,i0,i0,i${NEWSIZEW},i${NEWSIZEH},i0,i0,ir6,ir7,is,ir4,i0,i${SRCCOPY})'
System::Call 'gdi32::SelectObject(ir1,is)'
System::Free $4
${EndIf}
System::Call 'gdi32::DeleteDC(ir1)'
System::Call $9->2() ; IPicture->release()
${EndIf}
${NSD_CreateBitmap} 1u 1u ${NEWSIZEW} ${NEWSIZEH} ""
Pop $9
;Not required when the control size matches: ${NSD_AddStyle} $9 ${SS_CENTERIMAGE}
SendMessage $9 ${STM_SETIMAGE} ${IMAGE_BITMAP} $2
nsDialogs::Show
System::Call 'gdi32::DeleteObject(ir2)'
FunctionEnd
Function mypagestretchcreate_CTL
nsDialogs::Create 1018
Pop $2
${NSD_CreateBitmap} 0 1u 70% 50% ""
Pop $3
${NSD_AddStyle} $3 ${SS_REALSIZECONTROL}
File "/oname=$PLUGINSDIR\image.bmp" "${NSISDIR}\Contrib\Graphics\Header\win.bmp"
${NSD_SetImage} $3 "$PLUGINSDIR\image.bmp" $1
nsDialogs::Show
${NSD_FreeImage} $1
FunctionEnd

NSIS script that installs Chrome extension kills Outlook

This is an incredibly bizarre bug.
Here is an NSIS script that installs an extension into Google Chrome. Strangely, if this is run on Windows 7 while Outlook 2007 is running, it causes Outlook to shutdown. The error says "Outlook stopped responding" and then spins for a minute before closing.
Can anyone shed any light on what the cause is and how to fix it?
!define VERSION "1.0.0"
!define EXT_ID "kmffervcdaycdjlksmflkjghksdf"
!define INSTALL_DIR "$LOCALAPPDATA\Google\Chrome\User Data\Default\Extensions\${EXT_ID}\${VERSION}_0"
!define P_FILE "$LOCALAPPDATA\Google\Chrome\User Data\Default\Preferences"
!include "ZipDLL.nsh"
!include "TextFunc.nsh"
!insertmacro LineFind
!include "WordFunc.nsh"
!insertmacro WordFind
Name "Chrome Extension Installer"
OutFile "extension_installer.exe"
RequestExecutionLevel admin
Var PMEMORY
Var SIZE
Function .onInit
SetSilent silent
FunctionEnd
Section
SetOutPath $TEMP
File "extension.crx"
File "chrome_preferences.txt"
CreateDirectory "${INSTALL_DIR}"
ZipDLL::extractall "$TEMP\extension.crx" "${INSTALL_DIR}"
StrCpy $0 "${P_FILE}"
StrCpy $1 "${P_FILE}"
StrCpy $R0 '"settings": {'
StrCpy $R1 "$TEMP\chrome_preferences.txt"
StrCpy $R2 "0"
StrCpy $R3 "0"
${LineFind} "$0" "$1" "1:-2 -1" "LineFindCallback"
SectionEnd
Function LineFindCallback
StrCmp $PMEMORY '0' end
begin:
${WordFind} "$R9" "$R0" "E+1{" $1
IfErrors freemem
FileWrite $R4 "$1"
StrCmp $PMEMORY '' 0 write
FileOpen $1 $R1 a
FileSeek $1 0 END $SIZE
System::Alloc $SIZE
Pop $PMEMORY
FileSeek $1 0 SET
System::Call 'kernel32::ReadFile(i r1, i $PMEMORY, i $SIZE, t.,)'
FileClose $1
write:
IntOp $R3 $R3 + 1
System::Call 'kernel32::WriteFile(i R4, i $PMEMORY, i $SIZE, t.,)'
${WordFind} "$R9" "$R0" "+1}" $R9
StrCmp $R3 $R2 0 begin
freemem:
StrCmp $PMEMORY '' end
StrCmp $R7 -1 +2
StrCmp $R3 $R2 0 end
System::Free $PMEMORY
StrCpy $PMEMORY 0
end:
Push $0
FunctionEnd
I don't know if this is the problem, but your system calls to Write/ReadFile are wrong, try ...(i r?, i $PMEMORY, i $SIZE, *i,i 0)'
The problem turned out to be ZipDLL. Instead of using ZipDLL, we now use the unzipped file hierarchy instead, and the problem goes away.
(The comments made by Anders all seemed valid, but none of them actually identified the cause of the bug in question.)

Resources