Login

Please fill in your details to login.





portable vhd

There is literally no way I'm going to be able to remember how this works.

#Persistent

;------------- MAIN PROGRAM -------------

If !A_IsAdmin
{
  MsgBox, 0, Administrator Rights Required, Sorry, I require LOCAL MACHINE Adminstrator access to mount drives.`n`nClick 'OK' to exit the application.
  Gosub exit
}

; Load initial options from .ini file
IniRead, PlaySounds, settings/settings.ini, Program Options, PlaySounds
IniRead, ShowSplash, settings/settings.ini, Program Options, ShowSplash

; Add tray menu
Menu, Tray, Tip, PortableVHD
Menu, Tray, Icon, icons\loading.ico
Menu, Tray, NoStandard

; Welcome screen
If ShowSplash
{
  SplashImage, images\splash.png, b fs18
  If PlaySounds
  {
    SoundPlay, sounds\startup.wav
  }
  Sleep, 3000
  SplashImage, off
}

Menu, Tray, Tip, PortableVHD - No drives are mounted
Menu, Tray, Icon, icons\unmounted.ico

; Check VHD directory is valid
IfNotExist, vhd
{
  If PlaySounds
  {
    SoundPlay, sounds\notify.wav
  }
  FileCreateDir, vhd
  MsgBox, 0, No VHD folder!, There was no 'vhd' directory so I've made one.`nHowever, there are obviously no VHDs in there!`nYou'll have to create some ...`n`nClick 'OK' to exit the application.
  gosub exit
}
IfNotExist, vhd\*.vhd
{
  If PlaySounds
  {
    SoundPlay, sounds\notify.wav
  }
  MsgBox, 0, No VHDs!, I can't find any VHD's in the VHD folder.`n`nClick 'OK' to exit the application.
  gosub exit
}

; Loop through all files in vhd directory
VHDArray := []                                                  ; Initialise empty array
Loop, Files, vhd\*.vhd
{
  VHDFileName := A_LoopFileName                                 ; Retrieve file name from folder
  VHDFriendlyName := RTrim(VHDFileName, ".vhd")                 ; Construct friendly name from filename
  StringUpper, VHDFriendlyName, VHDFriendlyName , T             ; Uppercase first letter
  VHDFileSize := A_LoopFileSizeMB                               ; Retreive file size in MB
  VHDFileArray := [VHDFileName,VHDFriendlyName,VHDFileSize,0]   ; Create array to hold file information
  VHDArray.insert(VHDFileArray)                                 ; Add item to array from information above
}

; Populate mount / unmount menu from VHDArray
For index, vhd in VHDArray
{
  VHDFriendlyName := vhd[2] ; Need to do this here because can't use arrays in Menu command
  Menu, MountMenu, Add, %VHDFriendlyName%, mountMenuHandler
  Menu, UnmountMenu, Add, %VHDFriendlyName%, unmountMenuHandler
  Menu, UnmountMenu, Disable, %VHDFriendlyName%
}

; Add parent menus
Menu, Tray, Add, Mount, :MountMenu
Menu, Tray, Add, Unmount, :UnmountMenu

; Refresh menu
Menu, Tray, Add, Refresh, refresh ; NOT YET IMPLEMENTED

; Options menu
Menu, Tray, Add, Options, options

; Exit menu
Menu, Tray, Add, Exit, exit

; Is PortableVHD running from a removable drive?

StringLeft, scriptDrive, A_ScriptFullPath, 1
DriveGet, DrivesMounted, List, Removable
If InStr(DrivesMounted, ScriptDrive)
{
  removableDrive := 1
  TrayTip, PortableVHD Warning!, Virtual Hard Disks can't be run from removable drives.  VHD(s) will be copied to local disk during operation., 12, 1
  If PlaySounds
  {
    SoundPlay, sounds\notify.wav
  }
}

; How many drives are mounted? Initially zero.
mounted := 0

return

;--------- END OF MAIN PROGRAM ----------

; Menu handlers
; Need menu handlers because you can't pass parameters

mountMenuHandler:
{
  mount(A_ThisMenuItemPos)
  return
}

unmountMenuHandler:
{
  Unmount(A_ThisMenuItemPos)
  return
}

refresh:
{
  refresh := 1
  return
}

options:
{
  Gui, Options:New
  Gui, Options:+AlwaysOnTop -MinimizeBox -SysMenu
  Gui, Add, Button, x12 y90 w130 h30 gOptionsSaveAndClose,Save and Exit
  
Gui, Add, Button, x162 y90 w130 h30 gOptionsClose,Exit

  Gui, Add, GroupBox, x12 y10 w280 h70 ,Program options
  
Gui, Add, CheckBox, x22 y30 w260 h20 vPlaySounds Checked%PlaySounds%, Play application sounds

  Gui, Add, CheckBox, x22 y50 w260 h20 vShowSplash Checked%ShowSplash%, Show splash screen
  Gui, Show, W305 Center, Options
  return
}

; Functions
; Functions perform the mounting, unmounting and exiting

mount(VHDIndex)
{
  ; Make variables available inside the function
  Global VHDArray
  Global mounted
  Global removableDrive 

  ; Get drive details
  VHDFilename := VHDArray[VHDIndex][1]
  VHDFriendlyName := VHDArray[VHDIndex][2]
  VHDFileSize := VHDArray[VHDIndex][3]
  VHDMounted := VHDArray[VHDIndex][4]

  ;Get list of current drives so we can open new drive later
  DriveGet, driveList, list

  if removableDrive = 1 ; I'm running from a removable drive and VHD must be copied before mounting
  {
    if VHDFilesize > 256 ; VHD is greater than 256MB
    {
      MsgBox, 4, It's a big file!,The VHD is over 256MB in size and as I am running from a removable drive, it could take a long time to mount and unmount.  Do you want to continue?
      IfMsgBox, No
      {
        Return
      }
    }
    ;Remove vhd if it's already in temp folder presumably because of a problem with the script?
    IfExist, %temp%\vhd\%VHDFileName%
    {
      FileDelete, %temp%\vhd\%VHDFileName%
    }

    ;Copy VHD to local disk - can't mount otherwise
    IfNotExist, %temp%\vhd
    {
      FileCreateDir, %temp%\vhd
    }
    FileCopy, %A_ScriptDir%\vhd\%VHDFilename%, %temp%\vhd\%VHDFilename%
    VHDLocation = %temp%\vhd\%VHDFilename%
  }
  else
  {
    VHDLocation = %A_ScriptDir%\vhd\%VHDFilename%
  }

  ; Set environment variable for Diskpart
  EnvSet, mountscript, "%A_ScriptDir%\scripts\mountscript.txt"
  RunWait, %comspec% /c ECHO SELECT VDISK FILE=%VHDLocation% > %mountscript%, ,hide
  RunWait, %comspec% /c ECHO ATTACH VDISK >> %mountscript%, ,hide

  ; Actually mount the disk and increase number of mounted drives
  RunWait, %comspec% /c Diskpart /s %mountscript%, ,hide
  mounted := mounted + 1

  ; Display traytip confirming mounting
  TrayTip, Mounted, %VHDFriendlyName% is successfully mounted. The drive will required unmounting before you can exit PortableVHD., 10, 1

  ; Disable Mount and Enable Unmount for this VHD
  Menu, MountMenu, Disable, %VHDFriendlyName%
  Menu, UnmountMenu, Enable, %VHDFriendlyName%
  Menu, Tray, Disable, Exit ; You are not allowed to exit whilst a disk is mounted

  ; Change tray icon and tip
  Menu, Tray, Icon, icons\mounted.ico
  Menu, Tray, Tip, PortableVHD - Drives are mounted

  ; Set global flag and VHD mounted flag
  drivesMounted := 1
  VHDArray[VHDIndex][4] := 1
  
  ; Wait for new drive to mount and then open it
  ;Sleep, 1000
  DriveGet, newDriveList, list
  Loop, Parse, newDriveList
  {
    IfNotInString, driveList, %A_LoopField%
    {
      newDrive = %A_LoopField%
      run, %newDrive%:\
    }
  }

  return
}

unmount(VHDIndex)
{
  ; Make variables available inside the function
  Global VHDArray
  Global mounted
  Global PlaySounds
  Global removableDrive

  ; Get drive details
  VHDFilename := VHDArray[VHDIndex][1]
  VHDFriendlyName := VHDArray[VHDIndex][2]
  VHDMounted := VHDArray[VHDIndex][4]

  If removableDrive = 1
  {
    ; Confirm that the user wishes to write back the disk image
    overwrite := 0 ;By Default, do not overwrite
    If PlaySounds
    {
      soundplay, sounds\notify.wav
    }
    MsgBox, 3, Overwrite?, The working VHD will be copied back to the PortableVHD directory, overwriting the original disk image.  Are you sure you want this to happen?`n`nChoosing 'Yes' will save your changes.`n`nBy choosing 'No', the VHD will be unmounted and you will LOSE ALL YOUR CHANGES.`n`nIf you choose 'Cancel', no harm will be done and this dialogue will vanish.
    IfMsgBox, Cancel ;I made a mistake!
      Return
    IfMsgBox, No ;I'm happy to lose my changes
      overWrite := 0 ;Do not overwrite
    IfMsgBox, Yes ;I want to save my changes
      overWrite := 1 ;Happy to overwrite
    VHDLocation = %temp%\vhd\%VHDFilename%
  }
  Else
  {
    VHDLocation = %A_ScriptDir%\vhd\%VHDFilename%
  }

  ; Disable application menus during unmount
  Menu, UnmountMenu, Disable, %VHDFriendlyName%
  Menu, Tray, Disable, Exit
  Menu, Tray, Icon, icons\unmounting.ico
  Menu, Tray, Tip, PortableVHD - Unmounting ...

  ; Set environment variable for Diskpart
  EnvSet, mountscript, "%A_ScriptDir%\scripts\mountscript.txt"
  RunWait, %comspec% /c ECHO SELECT VDISK FILE=%VHDLocation% > %mountscript%, ,hide
  RunWait, %comspec% /c ECHO DETACH VDISK >> %mountscript%, ,hide

  ; Actually unmount the disk and decrease number of mounted drives
  RunWait, %comspec% /c Diskpart /s %mountscript%, ,hide
  mounted := mounted - 1

  If removableDrive
  {
    ; If user wants to save changes, do so
    If overWrite = 1
    {
      SplashTextOn, 375, 75, Please wait ...,`nPortableVHD is copying VHD back to application folder.`nThis dialogue will close once complete.
      FileCopy, %temp%\vhd\%VHDFilename%, %A_ScriptDir%\vhd\%VHDFilename%, 1
      SplashTextOff
    } 
  
    ; Remove the VHD from temporary storage
    FileDelete, %temp%\vhd\%VHDFilename%
  }

  ; Tooltip and Reenable menus
  TrayTip, Unmounted, %VHDFriendlyName% is successfully unmounted., 10, 1
  Menu, UnmountMenu, Disable, %VHDFriendlyName%
  Menu, MountMenu, Enable, %VHDFriendlyName%

  ; If there are still drives mounted, put icon and tip back to mounted state
  ; or else, change application state to unmounted and allow exit
  If mounted > 0
  {
    Menu, Tray, Icon, icons\mounted.ico
    Menu, Tray, Tip, PortableVHD - Drives are mounted
  }
  Else
  {
    FileRemoveDir, %temp%\vhd
    Menu, Tray, Enable, Exit
    Menu, Tray, Icon, icons\unmounted.ico
    Menu, Tray, Tip, PortableVHD - No Drives are mounted
    Return
  }
  return
}

exit:
{
  ; Make variables available inside the function
  Global PlaySounds

  TrayTip, Goodbye, Shutting down ..., 10, 1
  If PlaySounds
  {
    SoundPlay, sounds\shutdown.wav
  }
  Sleep, 3000
  ExitApp
}

OptionsSaveAndClose:
{
  Gui, Options:Submit
  IniWrite, %PlaySounds%, settings/settings.ini, Program Options, PlaySounds
  IniWrite, %ShowSplash%, settings/settings.ini, Program Options, ShowSplash
  Return
}

OptionsClose:
{
  Gui, Options:Cancel
  Return
}

Last modified: October 5th, 2021
The Computing Café works best in landscape mode.
Rotate your device.
Dismiss Warning