Portable Purebasic on a memory stick
Posted: Fri Oct 29, 2021 9:32 am
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:
*) I've renamed all Purebasic.exe to Purebasic.xex, so they can't be accidently started from the USB memory stick
Purebasic.ini:
)* 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
BTW the tool iplements shortcuts for the find/replace dialog 
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*
Purebasic.ini:
Code: Select all
Config= *
Default= 546
Shift= 546-
Alt= 573
Shift+Alt= 573-
Ctrl= 573-
Win= 573
Shift+Win= 573-
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
