Portable Purebasic on a memory stick

Share your advanced PureBasic knowledge/code with the community.
User avatar
Michael Vogel
Addict
Addict
Posts: 2807
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Portable Purebasic on a memory stick

Post by Michael Vogel »

I am using mutliple Purebasic versions on a memory stick which can be used to write program also on other PC's than mine. To handle this easily I did wrote a starter program which selects a Purebasic version just by holding the shift or ctrl key while executing the starter.

Some things have to be done that everything works fine:

Directory Structure:

Code: Select all

 E:\....\Pure		containing the Purebasic.exe and Purebasic.ini (see below) and all 'global' preference files
 E:\....\Pure.531	contains the installation of Purebasic 5.31 (32 bit) and 'local' preference files*
 E:\....\Pure.531-	contains the installation of Purebasic 5.31 (64 bit) and 'local' preference files*
 :
 E:\....\Pure.600-	contains the installation of Purebasic 6.00 (64 bit) and 'local' preference files*
*) I've renamed all Purebasic.exe to Purebasic.xex, so they can't be accidently started from the USB memory stick

Purebasic.ini:

Code: Select all

Config=		*
Default=	546
Shift=		546-
Alt=		573
Shift+Alt=	573-
Ctrl=		573-
Win=		573
Shift+Win=	573-
)* when the Purebasic.ini contains the line Config=*, the FIRST instance of purebasic will use 'global' preferences (Preferences, Tools and Templates) instead of the 'locals' (otherwise the different purebasic instances would overwrite the configuration settings)

Source of Purebasic.exe

Code: Select all

; Define Globals

	#MyTitle="-pbtool-"
	#MyExe="purebasic.xex"
	#MyFix=0


	EnableExplicit

	Global Path.s
	Global Config.s
	Global s.s
	Global n
	Global WinID
	Global DialogHandle

	Enumeration
		#Null
		#Shift
		#Control
		#ShiftAndControl
		#Alt
	EndEnumeration

	; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	#Q=#DOUBLEQUOTE$

	#MonkeyStart=6000
	#MonkeyKey=#MOD_ALT

	; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	#SearchLenx=64
	#SearchClass="WindowClass_7"
	#SearchName="Find/Replace"

	; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Enumeration
		#Nil
		#FixSearch
		#FixReplace
		#FixEnd
	EndEnumeration

	CompilerIf #MyFix
		Global MyFixGadget
		Global Dim MyFixHandle(#FixReplace)
		Global Dim MyFixState(#FixReplace)

	CompilerEndIf


	; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	#ShortcutNumber=12
	#ShortcutEvents=2
	#ShortcutTooltip=3
	#ShortcutFix=#ShortcutNumber-2
	#ShortcutPrefix=" "+"›"+" "
	#ShortcutLength=4;		

	Structure ShortcutType
		Handle.i
		Name.s
		Key.b
		Action.b
	EndStructure

	Global ShowShortcuts
	Global KeysRegistered

	Global Dim Shortcut.ShortcutType(#ShortcutNumber)

	Enumeration
		#CheckBox
		#Button
	EndEnumeration

	DataSection
		Data.s "Search for: "    	         		: Data.b #Nil,#Checkbox;		1
		Data.s "Replace with: "             		: Data.b 'E', #Button;			2
		Data.s "Case Sensitive" 				: Data.b 'C', #Checkbox;		3
		Data.s "Don't search in Comments" 	: Data.b 'M', #Checkbox;		4
		Data.s "Whole Words only" 			: Data.b 'W', #Checkbox;		5
		Data.s "Don't search in Strings"		: Data.b 'S', #Checkbox;		6
		Data.s "Search inside Selection only"	: Data.b 'L', #Checkbox;		7
		Data.s "Find Next"					: Data.b 'N', #Button;		8
		Data.s "Find previous"				: Data.b 'P', #Button;			9
		Data.s "Close"						: Data.b 'O', #Button;		10
		Data.s "Replace"						: Data.b 'R', #Button;			11
		Data.s "Replace All"					: Data.b 'A', #Button;		12
	EndDataSection

	; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; EndDefine
; Define Dialog

	Procedure.s GetObjectName(Handle)

		Protected s.s

		If Handle
			s=Space(#SearchLenx)
			GetWindowText_(Handle,@s,#SearchLenx)
		EndIf

		ProcedureReturn s

	EndProcedure
	Procedure.s GetObjectClass(Handle)

		Protected s.s

		If Handle
			s=Space(#SearchLenx)
			GetClassName_(Handle,@s,#SearchLenx)
		EndIf

		ProcedureReturn s

	EndProcedure
	
	Procedure SetDialogText(handle,reset)

		Protected n,m
		Protected s.s,t.s

		handle=GetWindow_(handle,#GW_CHILD)

		CompilerIf #MyFix
			If reset
				MyFixGadget=#Null
				MyFixHandle(#FixSearch)=#Nil
				MyFixHandle(#FixReplace)=#Nil
			EndIf
		CompilerEndIf

		While handle
			t=GetObjectName(handle)
			s=GetObjectClass(handle)
			Debug Str(handle)+": "+s+", '"+t+"'"

			If s="PureContainer"
				SetDialogText(handle,0)
				;Break

			ElseIf s="Button"
				n=#ShortcutNumber
				While n

					If ShowShortcuts;								Shortcuts anzeigen (an Text anhängen)
						If t=Shortcut(n)\Name
							Shortcut(n)\Handle=handle
							; Debug "A "+Str(n)+": "+Str(handle)+", "+t
							If n>=#ShortcutTooltip;					Kein Platz beim Text "Replace with:"
								SetWindowText_(Handle,t+#ShortcutPrefix+Chr(Shortcut(n)\Key))
								InvalidateRgn_(Handle,0,0)
							EndIf
						EndIf

					Else;											Shortcuts ausblenden
						If t=Shortcut(n)\Name;						nicht sichtbar (beim ersten Dialog-Aufruf)
							Shortcut(n)\Handle=handle
	
						ElseIf FindString(t,#ShortcutPrefix);			noch sichtbar (Find, wegen 'Replace All' und 'Replace')
							If Shortcut(n)\Name=Left(t,Len(t)-#ShortcutLength)
								Shortcut(n)\Handle=handle
								SetWindowText_(Handle,Shortcut(n)\Name)
								InvalidateRgn_(Handle,0,0)
							EndIf
						EndIf

					EndIf
					n-1
				Wend

				: CompilerIf #MyFix :

			ElseIf s="ComboBox"
				MyFixGadget+1
				If MyFixGadget<#FixEnd
					MyFixHandle(MyFixGadget)=handle
					Debug "CB"+Str(MyFixGadget)+" = "+Str(handle)
				EndIf

				: CompilerEndIf :

			EndIf

			handle=GetWindow_(handle,#GW_HWNDNEXT)
		Wend

	EndProcedure
	Procedure DoAction(n)

		Protected i,handle

		handle=Shortcut(n)\Handle

		If handle
			; SetWindowText_(handle,">Click<") : InvalidateRgn_(Handle,0,0)
			Select Shortcut(n)\Action

			Case #CheckBox
				If IsWindowEnabled_(handle)
					SendMessage_(handle,#BM_SETCHECK,Bool(SendMessage_(handle,#BM_GETCHECK,#Null,#Null)=0),#Null)
				EndIf

			Case #Button
				Debug "Button "+Str(n)+": "+Str(handle)

				CompilerIf #MyFix
					;If n>#ShortcutFix;				Shortcut für 'Replace' oder 'Replace All'
					For i=#FixSearch To #FixReplace
						If MyFixState(i)
							SendMessage_(MyFixHandle(i),#CB_SETCURSEL,0,0)
						EndIf
						MyFixState(i)=Bool(SendMessage_(MyFixHandle(i),#CB_GETCURSEL,0,0)<0)
					Next i
					;EnableWindow_(ReplaceHandle,0)
					;EndIf
				CompilerEndIf

				SendMessage_(handle,#BM_CLICK,1,0)

				CompilerIf #MyFix
					;If n>#ShortcutFix;				Shortcut für 'Replace' oder 'Replace All'
					For i=#FixSearch To #FixReplace
						SendMessage_(MyFixHandle(i),#CB_SETCURSEL,0,0)
					Next i
					;EnableWindow_(ReplaceHandle,1)
					;EndIf
				CompilerEndIf

			EndSelect
		EndIf

	EndProcedure

; EndDefine
; Define Starter & Keys

	Macro RegisterKeys()

		; Protected n

		If KeysRegistered=#False
			KeysRegistered=#True
			Debug "Register..."

			RegisterHotKey_(WinID,#MonkeyStart,#MonkeyKey,#VK_X)
			For n=1 To #ShortcutNumber
				RegisterHotKey_(WinID,#MonkeyStart+n,#MonkeyKey,Shortcut(n)\Key)
			Next n
		EndIf

	EndMacro
	Macro UnregisterKeys()

		; Protected n

		If KeysRegistered
			KeysRegistered=#False
			Debug "Unregister..."

			For n=#MonkeyStart To #MonkeyStart+#ShortcutNumber
				UnregisterHotKey_(WinID,n)
			Next n
		EndIf

	EndMacro

	Procedure ProcessActive();(ProcessName.s)

		Protected handle
		Protected prec.processentry32
		Protected result

		handle=CreateToolhelp32Snapshot_(#TH32CS_SNAPPROCESS,0)
		If handle<>#INVALID_HANDLE_VALUE
			prec\dwSize=SizeOf(prec)
			If Process32First_(handle,prec)
				; ProcessName=LCase(ProcessName)
				Repeat
					If LCase(GetFilePart(PeekS(@Prec\szexefile)))=#MyExe; ProcessName
						result=#True
						Break
					EndIf
				Until Not Process32Next_(handle,prec)
			EndIf
			CloseHandle_(handle)
		EndIf

		ProcedureReturn result

	EndProcedure

; EndDefine
; Define Main

	Path=GetPathPart(ProgramFilename())

	If OpenPreferences(Path+"Purebasic.ini")
		s=StringField(".Shift.Ctrl.Shift+Ctrl.Alt.Shift+Alt.Ctrl+Alt...Shift+Win.Ctrl+Win..Alt+Win",1+(GetKeyState_(#VK_SHIFT)&128)>>7 + (GetKeyState_(#VK_CONTROL)&128)>>6 + (GetKeyState_(#VK_MENU)&128)>>5 + (GetKeyState_(#VK_LWIN)&128)>>4,".")
		; MessageRequester(s,ReadPreferenceString(s,""))
		If s="" : s="Default" : EndIf
		s=ReadPreferenceString(s,"")
		;s=ReadPreferenceString(Trim(Mid("Shift  ControlBirdie Alt",n*7-6,7)),s)

		n=Bool(ProcessActive()=#Null And ReadPreferenceString("Config","")="*")
		ClosePreferences()

		If Len(s)
			If n
				Config="/P "+#Q+Path+"PureBasic.prefs"+#Q+" /T "+#Q+Path+"Templates.prefs"+#Q+" /A "+#Q+Path+"Tools.prefs"+#Q+" "
			EndIf
			Path+"..\Pure."+s
		EndIf
	EndIf

	;Path="C:\Tools\Programmer\Pure.561\"
	s=PeekS(GetCommandLine_())
	;MessageRequester(Str(n),#Q+Path+ "\Purebasic.xex"+#Q+" /Portable "+Trim(Mid(s,FindString(s,#Q,2)+1)))
	
	SetCurrentDirectory(Path)

	CompilerIf #PB_Compiler_Unicode
		s=#MyExe+" /Portable "+Config+Trim(Mid(s,FindString(s,#Q,2)+1))
		Path=Space(Len(s))
		PokeS(@Path,s,-1,#PB_Ascii)
		; 	Protected n,m,show
		; 	n=@temp
		; 	m=n
		; 	Repeat
		; 		show=PeekC(n)
		; 		PokeA(m,show)
		; 		n+2
		; 		m+1
		; 	Until show=0

	CompilerElse
		Path=#MyExe+" /Portable "+Config+Trim(Mid(s,FindString(s,#Q,2)+1))

	CompilerEndIf

	WinExec_(Path,#SW_SHOW)

	If FindWindow_(#Null,#MyTitle)=#Null

		;MessageRequester(":)","NEW INSTANCE")
		;WinID=OpenWindow(0,0,0,0,0,#MyTitle)

		WinID=OpenWindow(0,0,0,0,0,#MyTitle,#PB_Window_BorderLess|#PB_Window_Invisible)

	
		#HWND_MESSAGE=-3
		SetParent_(WinID,#HWND_MESSAGE); Events abwickeln, aber nicht in Taskbar anzeigen
		;SetWindowLong_(WinID,#GWL_EXSTYLE,GetWindowLong_(WinID,#GWL_EXSTYLE)|#WS_EX_TOOLWINDOW); Fenster nicht in Taskleiste anzeigen

		AddWindowTimer(#Null,#Null,100)

		; RegisterHotKey_(WinID,#MonkeyStart,#MonkeyKey,#VK_X)
		For n=1 To #ShortcutNumber
			With Shortcut(n)
				Read.s \Name
				Read.b \Key
				Read.b \Action
				; RegisterHotKey_(WinID,#MonkeyStart+n,#MonkeyKey,\Key)
			EndWith
		Next n


		Repeat
			Select WaitWindowEvent()

			Case #PB_Event_CloseWindow

			Case #WM_HOTKEY
				n=EventwParam()-#MonkeyStart
				Select n
				Case #Null
					ShowShortcuts!1
					SetDialogText(DialogHandle,1)
				Case #ShortcutEvents To #ShortcutNumber
					; SetWindowText_(handle,"Key "+Str(n)+": "+Str(Shortcut(n)\Handle)) : Delay(100)
					DoAction(n)
				EndSelect

			Case #PB_Event_Timer
				n=GetForegroundWindow_()
				If n<>DialogHandle
					DialogHandle=n
					Debug Hex(DialogHandle)+": "+GetObjectClass(DialogHandle)+", "+Left(GetObjectName(DialogHandle),12)
					If GetObjectClass(DialogHandle)=#SearchClass And Left(GetObjectName(DialogHandle),12)=#SearchName
						RegisterKeys()
						; Debug DialogHandle
						Delay(25);	Fensterinhalt noch nicht gleich aufgebaut (10ms ist zu wenig)
						SetWindowText_(DialogHandle,"Find/Replace by Michael Vogel")
						SetDialogText(DialogHandle,1)
					Else
						UnregisterKeys()
					EndIf
				EndIf
				If ProcessActive()=#Null; ProcessActive(#MyExe)=#Null
					; UnregisterKeys()
					; Debug ":)"
					End
				EndIf

			EndSelect

		ForEver

	EndIf

; EndDefine

BTW the tool iplements shortcuts for the find/replace dialog :)
BarryG
Addict
Addict
Posts: 4175
Joined: Thu Apr 18, 2019 8:17 am

Re: Portable Purebasic on a memory stick

Post by BarryG »

Why not just each version in its own folder (like you've already done) but uses a batch file in each folder to launch with the "/portable" switch? Way less complicated and no risk of any version overwriting settings of any other version.
User avatar
Michael Vogel
Addict
Addict
Posts: 2807
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Portable Purebasic on a memory stick

Post by Michael Vogel »

Yes could be done, of course... :lol:
I am using my starter from a menu (wonderbar) so I just select the version I need by holding shift (or ctrl or alt...). But I like to have one 'global' set of preferences because for usual a change will be seen in all versions then. So if change an editor preference in 5.31 and start 5.71 the next day, the settings will be updated. The other reason for this menu is that I do 99% by the keyboard not the mouse - so shortcuts for the find/replace dialog speed up programming :wink:
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Portable Purebasic on a memory stick

Post by netmaestro »

That would make a great alternative to profanity when you're exasperated - "What, it won't fit through the door? Well, portable purebasic on a memory stick!"
BERESHEIT
Post Reply