Basic application template

Share your advanced PureBasic knowledge/code with the community.
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Basic application template

Post by Mistrel »

This is a basic application template for PureBasic to get you started quickly.

When the program first starts it checks to see if a folder has been created for it in the os application data folder. If it has not the program creates this folder. The same check is repeated for the basic user.ini file.

The user.ini file saves the last x/y position and width/height of the main window on event #PB_Event_CloseWindow.

There are also a few extra functions that might come in handy.

This code uses the Win32 API so it is not cross-platform (sorry!).

Some snippets may have been lifted from code posted somewhere on the PB forum, I don't remember. Please credit yourself if you see your code.

Constants.pbi

Code: Select all

Enumeration
	#WB_AppData
	#WB_MainWindow
EndEnumeration

; Titles
#WB_AppName="Application Name"

; Config Files
#WB_UserINI="User.ini"
Globals.pbi

Code: Select all

Declare.s GetApplicationDataDirectory() ; Found in Functions.pbi

AppData.s=GetApplicationDataDirectory()+#WB_AppName+"\"
Functions.pbi

Code: Select all

;//
;// String functions
;//

; Strip file extension from string
Procedure.s StripExt(String.s)
	For i=0 To Len(String)-1
		n.s=Mid(String, Len(String)-i, 1)
		If n="."
			a.s=Left(String,(Len(String)-i)-1)
			ProcedureReturn a
		EndIf
	Next i
EndProcedure

;//
;// Message Boxes
;//

; Error box then close application
Procedure ErrorClose(Msg.s)
	Msg.s+Chr(13)+Chr(10)
	MessageBox_(#Null, Msg.s,"Error", #MB_ICONERROR) 
	End
EndProcedure

; Procedure Error(File.s, Line.l, Msg.s)
; 	Msg.s+Chr(13)+Chr(10)
; 	Msg.s+StripExt(GetFilePart(File.s))+" line "+Str(Line.l)+Chr(13)+Chr(10)
; 	MessageBox_(#Null, Msg.s,"Error", #MB_ICONERROR) 
; 	End
; EndProcedure

;//
;// Registry functons
;//

; Get Windows registry key value
Procedure.s GetKeyValue(topKey.l,sKey$,sValue$)
	Protected lType.l,lpcbData.l,hKey.l,lpData$,path$
	lpData$=Space(2048+1)
	lpcbData=Len(lpData$)-1
	If RegOpenKeyEx_(topKey,sKey$,#Null,#KEY_READ,@hKey)=#ERROR_SUCCESS
		RegQueryValueEx_(hKey,sValue$,#Null,@lType,@lpData$,@lpcbData)
		RegCloseKey_(hKey)
	EndIf
	ProcedureReturn Trim(lpData$)
EndProcedure

;//
;// Special folders
;//

Procedure.s SpecialFolderLocation(csidl.l)
	Protected location$,pidl.l
	If SHGetSpecialFolderLocation_(#Null,csidl,@pidl)=#ERROR_SUCCESS
		location$=Space(#MAX_PATH)
		If SHGetPathFromIDList_(pidl,@location$)
			If Right(location$,1)<>"\"
				location$+"\"
			EndIf
		EndIf
		If pidl
			CoTaskMemFree_(pidl) ; Instead of messing with com imalloc free and whatnot.
		EndIf
	EndIf
	ProcedureReturn Trim(location$)
EndProcedure

Procedure.s GetProgramFilesDir()
	Protected os.l,value$,path$
	os=OSVersion()
	If os>#PB_OS_Windows_ME
		path$=SpecialFolderLocation(#CSIDL_PROGRAM_FILES)
	Else
		value$=GetKeyValue(#HKEY_LOCAL_MACHINE,"Software\Microsoft\Windows\Currentversion","ProgramFilesDir")
		If value$<>""
			path$=value$
			If Right(value$,1)<>"\"
				path$+"\"
			EndIf
		EndIf
	EndIf
	If FileSize(path$)<>-2
		If CreateDirectory(path$)=#False
			path$=""
		EndIf
	EndIf
	ProcedureReturn path$
EndProcedure

Procedure.s GetApplicationDataDirectory()
	Protected path$
	path$=SpecialFolderLocation(#CSIDL_APPDATA)
	If path$="" ;Needed since Windows 95 do not support CSIDL_APPDATA "out of the box".
		path$=GetProgramFilesDir()+"Application Data\"
	EndIf
	If FileSize(path$)<>-2
		If CreateDirectory(path$)=#False
			path$=""
		EndIf
	EndIf
	ProcedureReturn path$
EndProcedure

Procedure.s GetTempDirectory()
	Protected path$,pathlen.l,result.l
	path$=Space(2048+1)
	result=GetTempPath_(Len(path$)-1,@path$)
	If (result=0) Or (result>Len(path$))
		path$=""
	Else
		If Right(path$,1)<>"\"
			path$+"\"
		EndIf
		If FileSize(path$)<>-2
			If CreateDirectory(path$)=#False
				path$=""
			EndIf
		EndIf
	EndIf
	ProcedureReturn path$
EndProcedure 

; Procedure.s GetMyDocumentsDirectory()
;  Protected path$
;  path$=SpecialFolderLocation(#CSIDL_PERSONAL) ;My Documents\ folder, use this rather than the other CSIDL
;  If FileSize(path$)<>-2
;   If CreateDirectory(path$)=#False
;    path$=""
;   EndIf
;  EndIf
;  ProcedureReturn path$
; EndProcedure

;//
;// INI functions
;//

Procedure.s INI_ReadString(FileName.s,Section.s,KeyName.s,Defaultval.s)
	If OpenLibrary(0,"kernel32.dll")
		n.s=Space(1024)
		FileName.s=GetCurrentDirectory()+""+FileName.s
		CallFunctionFast(GetFunction(0,"GetPrivateProfileStringA"),Section.s,KeyName.s,Defaultval.s,n.s,Len(n.s),FileName.s)
	Else
		ErrorClose("There was an error while calling kernel32.dll.")
	EndIf
	CloseLibrary(0)
	ProcedureReturn n.s
EndProcedure

Procedure INI_WriteString(FileName.s,Section.s,KeyName.s,Value.s)
	If OpenLibrary(0,"kernel32.dll")
		FileName.s=GetCurrentDirectory()+""+FileName.s
		CallFunctionFast(GetFunction(0,"WritePrivateProfileStringA"),Section.s,KeyName.s,Value.s,FileName.s)
	Else
		ErrorClose("There was an error while calling kernel32.dll.")
	EndIf
	CloseLibrary(0)
EndProcedure
	 
Procedure.l INI_ReadInteger(FileName.s,Section.s,KeyName.s,Defaultval.l)
	n.l=Val(INI_ReadString(FileName.s,Section.s,KeyName.s,Str(Defaultval.l)))
	ProcedureReturn n.l
EndProcedure

Procedure INI_WriteInteger(FileName.s,Section.s,KeyName.s,Value.l)
	INI_WriteString(FileName.s,Section.s,KeyName.s,Str(Value.l))
EndProcedure

;//
;// World Builder INI functions
;//

Procedure SetupWBuilderINI()
	If FileSize(#WB_UserINI)<0
		INI_WriteInteger(#WB_UserINI,"WindowPositions","Reset",1) ; Reset window positions
		INI_WriteString(#WB_UserINI,"WindowPositions","MainWindow","0,0,800,600") ; Window positions x,y,w,h
	EndIf
EndProcedure

;//
;// End of program functions
;//

Procedure Cleanup()
	INI_WriteInteger(#WB_UserINI,"WindowPositions","Reset",0)
	wx.s=Str(WindowX(#WB_MainWindow))
	wy.s=Str(WindowY(#WB_MainWindow))
	ww.s=Str(WindowWidth(#WB_MainWindow))
	wh.s=Str(WindowHeight(#WB_MainWindow))
	INI_WriteString(#WB_UserINI,"WindowPositions","MainWindow",wx.s+","+wy.s+","+ww.s+","+wh.s)
EndProcedure
Application.pb

Code: Select all

XIncludeFile "Constants.pbi"
XIncludeFile "Globals.pbi"
XIncludeFile "Functions.pbi"

; Program start
Debug "Program Start"

; Verify that the application data directory exists
If Not ExamineDirectory(#WB_AppData,AppData.s,"*.*")
	CreateDirectory(AppData.s)
EndIf
SetCurrentDirectory(AppData.s) ; Set the current directory to the os application folder
If FileSize(#WB_UserINI)=-1 ; Check ini files
	SetupWBuilderINI() ; If one does Not exist rebuild it (in the current directory)
EndIf

; Position the main window. If 'Reset=1' then center it on the screen
s.s=INI_ReadString(#WB_UserINI,"WindowPositions","MainWindow","0,0,800,600")
If INI_ReadInteger(#WB_UserINI,"WindowPositions","Reset",1)=1
	x=GetSystemMetrics_(#SM_CXSCREEN)/2-Val(StringField(s.s,3,","))/2
	y=GetSystemMetrics_(#SM_CYSCREEN)/2-Val(StringField(s.s,4,","))/2
Else
	x=Val(StringField(s.s,1,","))
	y=Val(StringField(s.s,2,","))
EndIf

OpenWindow(#WB_MainWindow,x,y,Val(StringField(s.s,3,",")),Val(StringField(s.s,4,",")),"Main Window",#PB_Window_SystemMenu|#PB_Window_SizeGadget)
If CreateGadgetList(WindowID(#WB_MainWindow))
	main_window_mdi=MDIGadget(#PB_Any,0,0,0,0,1,2,#PB_MDI_AutoSize|#PB_MDI_NoScrollBars|#PB_MDI_BorderLess )
	CreateMenu(#WB_MainWindow, WindowID(#WB_MainWindow))
  MenuTitle("File")
  MenuTitle("Tools")
  MenuItem(0,"Tool 1")
  MenuItem(1,"Tool 2")
	MenuTitle("Windows")
	MenuTitle("Help")
EndIf

Repeat
	event=WaitWindowEvent()
	Select event
	  Case #PB_Event_CloseWindow
	  	Cleanup()
	    End
	EndSelect
ForEver
milan1612
Addict
Addict
Posts: 894
Joined: Thu Apr 05, 2007 12:15 am
Location: Nuremberg, Germany
Contact:

Post by milan1612 »

Why don't you use the crossplatform Preferences library to save your settings?
Windows 7 & PureBasic 4.4
kinglestat
Enthusiast
Enthusiast
Posts: 746
Joined: Fri Jul 14, 2006 8:53 pm
Location: Malta
Contact:

Post by kinglestat »

its a nice effort, thanks
I may not help with your coding
Just ask about mental issues!

http://www.lulu.com/spotlight/kingwolf
http://www.sen3.net
Seldon
Enthusiast
Enthusiast
Posts: 405
Joined: Fri Aug 22, 2003 7:12 am
Location: Italia

Post by Seldon »

Thank you. That's more or less the same template I use for my programs, but you've added some good points. A little note: I experienced that if your program window is iconized, WindowX() and WindowY() return both "-32000" as value. So you should check it and not to save such values, because when you run your program again, it'll be launched as iconized and it won't be possibile to show the window back even if you try to push the title icon in the task-bar (that's happening for me under XP Home). Actually I don't know if that is a bug or a Windows thing...
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Post by Mistrel »

Seldon wrote:A little note: I experienced that if your program window is iconized, WindowX() and WindowY() return both "-32000" as value.
I don't know what you mean by iconized. Can you give an example?
Seldon
Enthusiast
Enthusiast
Posts: 405
Joined: Fri Aug 22, 2003 7:12 am
Location: Italia

Post by Seldon »

By 'iconized' I mean when you press the most left button in the window title bar: the window is hidden and you get its title in the task-bar.
Post Reply