Spetial folders

BlitzMax Forums/BlitzMax Programming/Spetial folders

Does enybody know who the get the path of a spectial folder of windows from BlitzMax? I need to get the path of the program files folder, 'cause I'm making an installation program in BlitzMax as a separated complement to BLIde, but I need to read the 'programs folder' to get the 'default installation path'

shell32
http://www.mentalis.org/apilist/SHGetSpecialFolderLocation.shtml

This is the API declaration I need:

Function SHGetSpecialFolderLocation:Long(hwndOwner:Long, nFolder:Long, pidl:ITEMIDLIST)

The fact is that I need to pass a structure called ITEMIDLIST which is formed by a INT and a BYTE. how can this be done in BlitzMax?
I would preffer no to use C code in the app I'm developing 'cause I want it to be open source and BlitzProgramers friendly.
Any suggestion?

Ziggy this code is not complete yet, the text comes out encrypted, so i am going now. But i will try and finish it tommorow, but if you want to try it out.

'Folders
Const CSIDL_PROGRAMS = 9 'Program Files

'Types
Type SHITEMID
	Field cb:Long
End Type

Type ITEMIDLIST
    Field mkid:SHITEMID = New SHITEMID
End Type

'WinApi Commands
Extern "Win32"
Function SHGetSpecialFolderLocation(hwndOwner, nFolder, pidl:ITEMIDLIST)
Function SHGetPathFromIDList( pidl ,pszPath:String )
End Extern

'Print
Print GetSpecialfolder()

'GetSpecialFolder Function
Function GetSpecialfolder()

	Local idlist:ITEMIDLIST= New ITEMIDLIST
	
	r=SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, idlist)
	
	Local path$=Chr(256)
	r = SHGetPathFromIDList(idlist.mkid.cb, path$)  
	dir$ = Trim(path$)
	Print dir$

End Function


Good Luck.

This is for Blitz3D/Blitz+, see if it works in BlitzMax

.lib "shell32.dll" 
SHGetSpecialFolderLocation%(hwndOwner%,nFolder%,pIdl*):"SHGetSpecialFolderLocation"
SHGetPathFromIDList(pidList, lpBuffer$):"SHGetPathFromIDListA"



Const CSIDL_DESKTOP                 = $0000  ; <desktop>
Const CSIDL_INTERNET                = $0001  ; Internet Explorer (icon on desktop)
Const CSIDL_PROGRAMS                = $0002  ; Start Menu\Programs
Const CSIDL_CONTROLS                = $0003  ; My Computer\Control Panel
Const CSIDL_PRINTERS                = $0004  ; My Computer\Printers
Const CSIDL_PERSONAL                = $0005  ; My Documents
Const CSIDL_FAVORITES               = $0006  ; <user name>\Favorites
Const CSIDL_STARTUP                 = $0007  ; Start Menu\Programs\Startup
Const CSIDL_RECENT                  = $0008  ; <user name>\Recent
Const CSIDL_SENDTO                  = $0009  ; <user name>\SendTo
Const CSIDL_BITBUCKET               = $000a  ; <desktop>\Recycle Bin
Const CSIDL_STARTMENU               = $000b  ; <user name>\Start Menu
Const CSIDL_MYDOCUMENTS             = $000c  ; logical "My Documents" desktop icon
Const CSIDL_MYMUSIC                 = $000d  ; "My Music" folder
Const CSIDL_MYVIDEO                 = $000e  ; "My Videos" folder
Const CSIDL_DESKTOPDIRECTORY        = $0010  ; <user name>\Desktop
Const CSIDL_DRIVES                  = $0011  ; My Computer
Const CSIDL_NETWORK                 = $0012  ; Network Neighborhood
Const CSIDL_NETHOOD                 = $0013  ; <user name>\nethood
Const CSIDL_FONTS                   = $0014  ; windows\fonts
Const CSIDL_TEMPLATES               = $0015
Const CSIDL_COMMON_STARTMENU        = $0016  ; All Users\Start Menu
Const CSIDL_COMMON_PROGRAMS         = $0017  ; All Users\Programs
Const CSIDL_COMMON_STARTUP          = $0018  ; All Users\Startup
Const CSIDL_COMMON_DESKTOPDIRECTORY = $0019  ; All Users\Desktop
Const CSIDL_APPDATA                 = $001a  ; <user name>\Application Data
Const CSIDL_PRINTHOOD               = $001b  ; <user name>\PrintHood
Const CSIDL_LOCAL_APPDATA           = $001c  ; <user name>\Local Settings\Application Data (non roaming)
Const CSIDL_ALTSTARTUP              = $001d  ; non localized startup
Const CSIDL_COMMON_ALTSTARTUP       = $001e  ; non localized common startup
Const CSIDL_COMMON_FAVORITES        = $001f
Const CSIDL_INTERNET_CACHE          = $0020
Const CSIDL_COOKIES                 = $0021
Const CSIDL_HISTORY                 = $0022
Const CSIDL_COMMON_APPDATA          = $0023  ; All Users\Application Data
Const CSIDL_WINDOWS                 = $0024  ; GetWindowsDirectory()
Const CSIDL_SYSTEM                  = $0025  ; GetSystemDirectory()
Const CSIDL_PROGRAM_FILES           = $0026  ; C:\Program Files
Const CSIDL_MYPICTURES              = $0027  ; C:\Program Files\My Pictures
Const CSIDL_PROFILE                 = $0028  ; USERPROFILE
Const CSIDL_SYSTEMX86               = $0029  ; x86 system directory on RISC
Const CSIDL_PROGRAM_FILESX86        = $002a  ; x86 C:\Program Files on RISC
Const CSIDL_PROGRAM_FILES_COMMON    = $002b  ; C:\Program Files\Common
Const CSIDL_PROGRAM_FILES_COMMONX86 = $002c  ; x86 Program Files\Common on RISC
Const CSIDL_COMMON_TEMPLATES        = $002d  ; All Users\Templates
Const CSIDL_COMMON_DOCUMENTS        = $002e  ; All Users\Documents
Const CSIDL_COMMON_ADMINTOOLS       = $002f  ; All Users\Start Menu\Programs\Administrative Tools
Const CSIDL_ADMINTOOLS              = $0030  ; <user name>\Start Menu\Programs\Administrative Tools
Const CSIDL_CONNECTIONS             = $0031  ; Network and Dial-up Connections
Const CSIDL_COMMON_MUSIC            = $0035  ; All Users\My Music
Const CSIDL_COMMON_PICTURES         = $0036  ; All Users\My Pictures
Const CSIDL_COMMON_VIDEO            = $0037  ; All Users\My Video
Const CSIDL_RESOURCES               = $0038  ; Resource Direcotry
Function GetSpecialFolder$(folder_id)
		
Local  idl% = CreateBank (8) 

Local spath$ = String(0 ,260 )
Local nPos


	If SHGetSpecialFolderLocation(0,folder_id,idl) = 0
		
		SHGetPathFromIDList PeekInt( IDL,0), spath$
	
		nPos = Instr( spath, Chr$(0))
	    If nPos > 0 Then           
	    	spath = Left(spath, nPos - 1)
	    End If
		spath = spath + ""
	
	EndIf
	
	FreeBank idl
		
	Return spath
		
End Function


No matter what code i use for this i keep getting this error

Unhandled Exepcetion: "Unhandled Memory Exepcetion Error"

I think the TYPE SHITEMID is formed by a LONG followed by a INT. in addition, I'm not sure if you haved to pass the TYPE or a pointer to the TYPE. I've been testing it, and it seems the code is passing a wrong buffer addres, that's should be the reason why we get garbage, or errors.

Is there any documentation about using windows API in Blitzmax?

Here is a working BlitzMax version. I'm sure it can be "Maxified" a bit more to take out legacy commands.

'WinApi Commands
Extern "Win32"
Function SHGetSpecialFolderLocation(hwndOwner, nFolder, pIdl:Byte  Ptr)
Function SHGetPathFromIDList( pidList ,lpBuffer:Byte  Ptr)
End Extern


Print GetSpecialFolder(CSIDL_PROGRAMS)

Function GetSpecialFolder:String(folder_id) 
		
Local  idl% = CreateBank (8) 
Local  pathbank% = CreateBank (260) 
Local n%
Local sp$

	If SHGetSpecialFolderLocation(0,folder_id,BankBuf(idl)) = 0		
		SHGetPathFromIDList PeekInt( idl,0), BankBuf(pathbank)
		
		For n= 0 To 259
			sp$ = sp$ + Chr(PeekByte(pathbank,n))
		Next
	EndIf
	Return Trim(sp$) + ""
		
End Function


Thanks peter! It was the address of the buffer... ufff, well done :)

Peter, your code isn't taking in cosideration the 0 end string returned by the API.
If function works fine like this:

Function GetSpecialFolder:String(folder_id) 
		
	Local  idl:TBank = CreateBank (8) 
	Local  pathbank:TBank = CreateBank (260) 
	Local n%
	Local sp$

	If SHGetSpecialFolderLocation(0,folder_id,BankBuf(idl)) = 0		
		SHGetPathFromIDList PeekInt( idl,0), BankBuf(pathbank)
		For n= 0 To 259
			local BufByte:byte =PeekByte(pathbank,n)
			if bufbyte <>0 then 
				sp$ = sp$ + Chr(bufbyte)
			else
				exit 
			endif
		Next
	EndIf
	return (trim(sp$) + "")
End Function


You are right. (but wont trim$() fix that ? )

no, trim just removes chr(32) with is blank spaces, not chr(0) with means end of string in a C string. and keep in mind that after the chr(0) char, there will be garbage, so you have to read the buffer only untill you find a byte 0.

As instance:
Local MyVar:String = "Hello" + chr(0) + "this is garbage            "
Print trim(MyVar) + "END"

This code will output: Hello this is garbageEND

Ok, but I still thought that banks where initialized with 0's (resulting in a terminated string)

I'm not arguing, you way is correct, but I'd like to know.

BTW: Do you know how to trim() the BlitzMax way?

You're right :), and you code has helped me A LOT!

but you have to considerate that the buffer is initialized to zero, but you pass a pointer when calling the api, and this pointer can be changed to any other memory address by the API (this new address can be a different one, not initialized to zero). in fact, I did get garbage sometimes untill making the change mentioned. Anyway, you don't need to do this if you're not using API, just your own functions, or if you know the buffer won't be modified by the API.

What do you mean how to trim() the BlitzMax way?

"and this pointer can be changed to any other memory address by the API", - Well no, that would make it unsuable, - but the API can copy any data it wants into the buffer (the bank) that the pointer is pointing to.

Abaut Trim(), the docs say that is's only there for backwards compability, and that you should use "string slicing" or something like that. The docs does not link to or show the new way though...

good to know. :) Anyway, BlitzMax doesn't use zero terminated strings (as long as I know). It uses strings in format pointer +lenght, so if there are zeros in the buffer, there will be zeros in the string, even if you trim it. so, the better choice, trim and stop reading when a zero occurs. I'm not shure if the method ToCString of strings will make a sort of zero based trim over the function, or just creates a zero based string and a pointer to it. I've passed ToCString to apis that were specting a CString, but in the declaration of the API, I have had to declare it as a INT... don't ask me why, but it works fine.

Learning from the "string to buffer" topic, here is a new BlitzMax version that seems to be ok.

'WinApi Commands
Extern "Win32"
Function SHGetSpecialFolderLocation(hwndOwner, nFolder, pIdl:Byte  Ptr)
Function SHGetPathFromIDList( pidList ,lpBuffer:Byte  Ptr)
End Extern


Print GetSpecialFolder(CSIDL_PROGRAMS)

Function GetSpecialFolder:String(folder_id) 
Local  idl% = CreateBank (8) 
Local  pathbank:TBank = CreateBank (260) 
	If SHGetSpecialFolderLocation(0,folder_id,BankBuf(idl)) = 0		
		SHGetPathFromIDList PeekInt( idl,0), BankBuf(pathbank)
		Return String.FromCString(pathbank.Buf()) + ""
	EndIf
End Function


Great! Easily solved :)