Page 1 of 2

How to add autostart feature for portable program?

Posted: Sun Mar 20, 2011 2:12 pm
by c4s
My program doesn't need an installation so the user can theoretically place the executable where he wants to. Many don't seem to know that they can autostart a program by placing a shortcut in the autostart folder. Since I'm getting more and more requests to add such a feature I'm asking myself how I could add an option for this while keeping it as "portable" as possible.

I know two ways of doing it. Which one would be the best or are there more?
  • Automatically place a shortcut in the autostart folder that points to the current executable
  • Create entry in the registry that points to the current executable

Re: How to add autostart feature for portable program?

Posted: Sun Mar 20, 2011 3:12 pm
by eJan
Most of programs (Antivirus, Players, Audio Mixers..) use Registry autorun feature:
For current user:

Code: Select all

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
For all users:

Code: Select all

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

Re: How to add autostart feature for portable program?

Posted: Sun Mar 20, 2011 3:25 pm
by netmaestro
This is the method I use, code is by Joakim Christiansen. With this procedure all you need to do is implement a menu item for the user to check or clear "Start with Windows" and run this procedure with the state parameter set to 1 or 0. I use it in several of my programs and it's never given me any problems:

Code: Select all

Procedure StartWithWindows(State.b) ; by Joakim Christiansen
  Protected Key.l = #HKEY_CURRENT_USER ;or #HKEY_LOCAL_MACHINE for every user on the machine 
  Protected Path.s = "Software\Microsoft\Windows\CurrentVersion\Run" 
  Protected Value.s = "GmailEnhancer" ;Change into the name of your program 
  Protected String.s = Chr(34)+ProgramFilename()+Chr(34) ;Path of your program 
  Protected CurKey.l 
  If State 
    RegCreateKey_(Key,@Path,@CurKey) 
    RegSetValueEx_(CurKey,@Value,0,#REG_SZ,@String,Len(String)) 
  Else 
    RegOpenKey_(Key,@Path,@CurKey) 
    RegDeleteValue_(CurKey,@Value) 
  EndIf 
  RegCloseKey_(CurKey) 
EndProcedure 

Re: How to add autostart feature for portable program?

Posted: Sun Mar 20, 2011 3:29 pm
by ts-soft
A Portable App should not use the registry! There is no uninstaller.

Re: How to add autostart feature for portable program?

Posted: Sun Mar 20, 2011 4:23 pm
by c4s
ts-soft wrote:A Portable App should not use the registry! There is no uninstaller.
Yes, that is the intention of this thread. I'm asking which method is best for a portable application.
Currently I think it would be best to simply create a shortcut to the executable... What do you think?

@eJan & netmaestro
Honest question: Would you say a portable program should hassle with the registry?

Re: How to add autostart feature for portable program?

Posted: Sun Mar 20, 2011 5:34 pm
by ts-soft
A real portable app starts from a memorystick or something else, so a autostart is useless,
but i think you didn't mean a portable app, you mean a "none usermode compatible" app :mrgreen:

Re: How to add autostart feature for portable program?

Posted: Sun Mar 20, 2011 6:21 pm
by utopiomania
A portable application could very well have an install/uninstall from a menu entry, so that you
could run the app from a memory stick and then decide to install/uninstall it locally from within
the application.

Besides this, a 'start with windows' registry entry would only work if the exe is on a drive that
is accessible to windows on startup, or, you need to install a local exe that will look for your
application on memorysticks after startup.

Re: How to add autostart feature for portable program?

Posted: Sun Mar 20, 2011 7:27 pm
by c4s
I didn't mean that my program is just used on USB sticks etc.! I used the term "portable" to underline that my program doesn't need an installation. Probably most of the users still copy it somewhere on their disk and that's it. These are asking for a autostart feature because they don't know that it's already possible by copying a shortcut into the autostart folder.

The question to me is how I could give them the autostart feature they want to have.

Writing to the registry is generally less accepted - especially for a portable program. ALso it's much harder to edit or remove a registry entry compared to a shortcut. I'm still curious if there is a better solution for this.

Re: How to add autostart feature for portable program?

Posted: Sun Mar 20, 2011 7:57 pm
by Trond
I recommend to create a shortcut in the autostart folder. Because it's simpler to remove from outside the program.

Re: How to add autostart feature for portable program?

Posted: Sun Mar 20, 2011 8:31 pm
by idle
To add to the start up menu.

Code: Select all

Procedure CreateShellLink(PATH$, LINK$, Argument$, DESCRIPTION$, WorkingDirectory$, ShowCommand.l, HotKey.l, IconFile$, IconIndexInFile.l)
  Protected psl.IShellLinkA,ppf.IPersistFile,*mem,len,hres,res.s
  
  CoInitialize_(0)
  If CoCreateInstance_(?CLSID_ShellLink,0,1,?IID_IShellLink,@psl.IShellLinkA) = 0
     
   ;Set_ShellLink_preferences:
   psl\SetPath(PATH$)
   psl\SetArguments(Argument$)
   psl\SetWorkingDirectory(WorkingDirectory$)
   psl\SetDescription(DESCRIPTION$)
   psl\SetShowCmd(ShowCommand)
   psl\SetHotkey(HotKey)
   psl\SetIconLocation(IconFile$, IconIndexInFile)
        
   ;ShellLink_SAVE:
      If psl\QueryInterface(?IID_IPersistFile,@ppf.IPersistFile) = 0
        *mem = AllocateMemory(1000) 
        len = MultiByteToWideChar_(#CP_ACP, 0, LINK$, -1, *mem, 1000)
        res.s = PeekS(*mem,len,#PB_Unicode)
        hres = ppf\Save(res,#True)
        FreeMemory(*mem)
        ppf\Release()
      EndIf
      psl\Release()
   EndIf
   CoUninitialize_()
   ProcedureReturn hres ! 1
   
   DataSection
     CLSID_ShellLink:
       ; 00021401-0000-0000-C000-000000000046
       Data.l $00021401
       Data.w $0000,$0000
       Data.b $C0,$00,$00,$00,$00,$00,$00,$46
     IID_IShellLink:
       ; DEFINE_SHLGUID(IID_IShellLinkA,0x000214EEL, 0, 0);
       ; C000-000000000046
       Data.l $000214EE
       Data.w $0000,$0000
       Data.b $C0,$00,$00,$00,$00,$00,$00,$46
     IID_IPersistFile:
       ; 0000010b-0000-0000-C000-000000000046
       Data.l $0000010b
       Data.w $0000,$0000
       Data.b $C0,$00,$00,$00,$00,$00,$00,$46
   EndDataSection

EndProcedure


Procedure.s GetSpecialFolderLocation(Value.l)
  Protected Folder_ID,SpecialFolderLocation.s
 
  If SHGetSpecialFolderLocation_(0, Value, @Folder_ID) = 0
    SpecialFolderLocation = Space(#MAX_PATH*2)
    SHGetPathFromIDList_(Folder_ID, @SpecialFolderLocation)
    If SpecialFolderLocation
      If Right(SpecialFolderLocation, 1) <> "\"
        SpecialFolderLocation + "\"
      EndIf
    EndIf
    CoTaskMemFree_(Folder_ID)
  EndIf
   ProcedureReturn SpecialFolderLocation.s
EndProcedure

#CSIDL_STARTUP = $7
#CSIDL_APPDATA = $1A

Procedure AddtoStartMenu()
  Protected tpath.s = GetSpecialFolderLocation(#CSIDL_STARTUP) + "MyApp.lnk"
  CreateShellLink(ProgramFilename(),tpath,"","MyApp","",0,0,ProgramFilename(),0)
EndProcedure   


Re: How to add autostart feature for portable program?

Posted: Mon Mar 21, 2011 8:47 am
by Joakim Christiansen
idle wrote:To add to the start up menu.
I was about to post the same code here but when I tested it it wouldn't work on the XP SP3 computer I used. :?
Did you test it? (you probably did)

netmaestro 8)

c4s
I think option 1 is the best for a portable app.

Re: How to add autostart feature for portable program?

Posted: Mon Mar 21, 2011 12:18 pm
by c4s
@idle
Thanks for the code.

@Joakim
I just tested idle's code on XP SP3 and it works. Note that you have to enable Unicode.
I think this code works with both Ascii and Unicode:

Code: Select all

Macro DEFINE_GUID(Name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
CompilerIf Defined(Name, #PB_Variable)
	If SizeOf(Name) = SizeOf(GUID)
		Name\Data1 = l
		Name\Data2 = w1
		Name\Data3 = w2
		Name\Data4[0] = b1
		Name\Data4[1] = b2
		Name\Data4[2] = b3
		Name\Data4[3] = b4
		Name\Data4[4] = b5
		Name\Data4[5] = b6
		Name\Data4[6] = b7
		Name\Data4[7] = b8
	EndIf
CompilerEndIf
EndMacro

Procedure ShortcutCreate(Path.s, Link.s, WorkingDir.s="", Argument.s="", ShowCommand=#SW_SHOWNORMAL, Description.s="", HotKey=#Null, IconFile.s="|", IconIndex=0)
; Path: "C:\PureBasic\purebasic.exe"
; Link: "C:\Documents and Settings\User\Desktop\PureBasic.lnk"
; WorkingDir: "C:\PureBasic\"
; Argument: "%1"
; ShowCommand: #SW_SHOWNORMAL, #SW_SHOWMAXIMIZED or #SW_SHOWMINIMIZED
; Description: "Start PureBasic"
; HotKey: Shortcut of keys for the link
; IconFile: "C:\PureBasic\purebasic.exe"
; IconIndex: 0
	Protected CLSID_ShellLink.GUID, IID_IShellLink.GUID, IID_IPersistFile.GUID
CompilerIf #PB_Compiler_Unicode
	Protected psl.IShellLinkW
CompilerElse
	Protected psl.IShellLinkA
CompilerEndIf
	Protected ppf.IPersistFile
	Protected Result = #False

	DEFINE_GUID(CLSID_ShellLink, $00021401, $0000, $0000, $C0, $00, $00, $00, $00, $00, $00, $46)
CompilerIf #PB_Compiler_Unicode
	DEFINE_GUID(IID_IShellLink, $000214F9, $0000, $0000, $C0, $00, $00, $00, $00, $00, $00, $46)
CompilerElse
	DEFINE_GUID(IID_IShellLink, $000214EE, $0000, $0000, $C0, $00, $00, $00, $00, $00, $00, $46)
CompilerEndIf
	DEFINE_GUID(IID_IPersistFile, $0000010B, $0000, $0000, $C0, $00, $00, $00, $00, $00, $00, $46)

	If Len(WorkingDir) = 0 : WorkingDir = GetPathPart(Path) : EndIf

	If IconFile = "|" : IconFile = Path : EndIf


	CoInitialize_(0)
	If CoCreateInstance_(@CLSID_ShellLink, 0, 1, @IID_IShellLink, @psl) =  #S_OK
		With psl
			\SetPath(Path)
			\SetArguments(Argument)
			\SetWorkingDirectory(WorkingDir)
			\SetDescription(Description)
			\SetShowCmd(ShowCommand)
			\SetHotkey(HotKey)
			\SetIconLocation(IconFile, IconIndex)
		EndWith

		If psl\QueryInterface(@IID_IPersistFile, @ppf) = #S_OK
			If ppf\Save(Link, #True) = #S_OK
				Result = #True
			EndIf
			ppf\Release()
		EndIf
		psl\Release()
	EndIf
	CoUninitialize_()

	ProcedureReturn Result
EndProcedure

Now I'm not sure anymore if an option for creating a program shortcut in the autostart folder is useful at all. Maybe I'm just going to add a text that explains it...

Re: How to add autostart feature for portable program?

Posted: Mon Mar 21, 2011 4:22 pm
by idle
Joakim Christiansen wrote:
idle wrote:To add to the start up menu.
I was about to post the same code here but when I tested it it wouldn't work on the XP SP3 computer I used. :?
Did you test it? (you probably did)
No I didn't test it as posted, my VM wasn't running at the time.

Maybe you'd be better off using the Registry function with the RunOnce key, you will need to write it every time your app quits, since it's a temporary registry entry.

Re: How to add autostart feature for portable program?

Posted: Mon Mar 21, 2011 4:38 pm
by greyhoundcode
Although you don't mean portable in the sense of running exclusively off USB sticks or similar, in those instances where an app is running from removable media one could make use of an auto-run batch script.

Perhaps a complete and non-Registry dependent solution would somehow detect whether it is on the hard-drive or a stick and then make use of an auto run script or shortcuts as appropriate.

Re: How to add autostart feature for portable program?

Posted: Mon Mar 21, 2011 5:23 pm
by idle
The only problem with using autorun is that it's disabled for removable media by default but, it will at least pop up with your app as the default choice highlighting your icon, it just won't automatically start unless it's been enabled by the system policy, think the default behavior was changed in XP SP2 or maybe even earlier.

Also if you use any registry or start menu stuff and the apps on removable media you can't be sure it's going to have the same drive label next time round.

So maybe giving users the choice to create a portable version on a usb with Autorun or add to StartUpMenu for this machine or set the runonce key each time your app quits.

as an example of creating a portable version of your app on a USB

Not tested!

save this autorun.inf
[autorun]
OPEN=MyApp.exe
ICON=MyApp.ico
ACTION=MyApp
LABEL=MyApp

Code: Select all

Procedure MakePortable(MyApp.s)
  strm.s = "Select the USB drive to make " + MyApp + " portable on" 
  MessageRequester(MyApp,strm)
  dir.s = PathRequester(strm,"*.*") 
  If dir <> "" 
      CopyFile(MyApp + ".exe",dir+ MyApp + ".exe")
      fn = CreateFile(#PB_Any,dir+"autorun.inf")
      If fn 
          WriteData(fn,?auto,?eauto-?auto)
          CloseFile(fn)
      EndIf 
      fn = CreateFile(#PB_Any,dir+MyApp+".ico")
      If fn 
          WriteData(fn,?ico,?eico-?ico) 
          CloseFile(fn)
          SetFileAttributes(dir+MyApp+".ico",#PB_FileSystem_Hidden)
     EndIf
 EndIf  
   
DataSection
  Ico: IncludeBinary "icon.ico"
  eIco:
  Auto:IncludeBinary "autorun.inf"
  eAuto:
EndDataSection   
    
EndProcedure   

;Save as autorun.inf
;[autorun]
;OPEN=MyApp.exe
;ICON=MyApp.ico
;ACTION=MyApp
;LABEL=MyApp