Spetial folders

BlitzMax Forums/BlitzMax Programming/Spetial folders

ziggy(Posted 2005) [#1]
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'


Sarge(Posted 2005) [#2]
shell32
http://www.mentalis.org/apilist/SHGetSpecialFolderLocation.shtml


ziggy(Posted 2005) [#3]
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?


Sarge(Posted 2005) [#4]
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.


Difference(Posted 2005) [#5]
This is for Blitz3D/Blitz+, see if it works in BlitzMax

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






Sarge(Posted 2005) [#6]
No matter what code i use for this i keep getting this error

Unhandled Exepcetion: "Unhandled Memory Exepcetion Error"


ziggy(Posted 2005) [#7]
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.


ziggy(Posted 2005) [#8]
Is there any documentation about using windows API in Blitzmax?


Difference(Posted 2005) [#9]
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



ziggy(Posted 2005) [#10]
Thanks peter! It was the address of the buffer... ufff, well done :)


ziggy(Posted 2005) [#11]
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



Difference(Posted 2005) [#12]
You are right. (but wont trim$() fix that ? )


ziggy(Posted 2005) [#13]
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


Difference(Posted 2005) [#14]
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?


ziggy(Posted 2005) [#15]
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?


Difference(Posted 2005) [#16]
"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...


ziggy(Posted 2005) [#17]
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.


Difference(Posted 2005) [#18]
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



ziggy(Posted 2005) [#19]
Great! Easily solved :)