You are here

CSIDL Redirection (ASAP)

19 posts / 0 new
Last post
digitxp
digitxp's picture
Offline
Last seen: 11 years 4 months ago
Joined: 2007-11-03 18:33
CSIDL Redirection (ASAP)

I need to get SMPlayer working and out of the door before tomorrow (I know I'm a procrastinating dev :P) because SMPlayer still hogs CPU and crashes. I was thinking that since SMPlayer uses CSIDL to get folder paths, I could redirect CSIDL like haustin said he would implement into PortableApps.nsh (BTW what happened to it?).
I found a WinAPI article about it, but I'm not entirely sure if it's safe to use. Does it only change it in its own enviroment like the Enviroment Variables, or does it affect the entire system?
Please help and thanks in advance!
Edit: Another WinAPI article

wraithdu
Offline
Last seen: 9 years 7 months ago
Developer
Joined: 2007-06-27 20:22
This looks like a permanent

This looks like a permanent redirect unless you change it back. Not sure if admin rights are needed for this. *Probably* not if you're redirecting a user's folder.

This is classified as a "method", I'm not sure how that works in NSIS / AutoIt yet. I'll see if I can figure something out.

EDIT - that Redirect method is Vista only. I don't know how to use it yet, but the IKnownFolderManager interface (of which Redirect is a method) is Vista only.

digitxp
digitxp's picture
Offline
Last seen: 11 years 4 months ago
Joined: 2007-11-03 18:33
Darn

I guess Vista won't be supported Sad
Now SMPlayer is going to be bulky Sad

Insert original signature here with Greasemonkey Script.

wraithdu
Offline
Last seen: 9 years 7 months ago
Developer
Joined: 2007-06-27 20:22
It doesn't matter anyway. As

It doesn't matter anyway. As far as I can tell, there's no way to call that Redirect method. Even in AutoIt which has COM Object support (NSIS does not), I cannot find a class to load the IKnownFolderManager interface, so the methods that it covers are unavailable. I'm sure there's a way to do it in a real programming language however.

digitxp
digitxp's picture
Offline
Last seen: 11 years 4 months ago
Joined: 2007-11-03 18:33
Well

on the upside that can't be the only way to redirect...
I'll search.

Insert original signature here with Greasemonkey Script.

m2
Offline
Last seen: 11 years 11 months ago
Joined: 2006-12-12 12:00
I'm pretty sure that it's

I'm pretty sure that it's stored somewhere in registry, but I highly recommend to skip it.
-It's gonna mess up local programs.
-In case of a crash / system restart while running etc. these problems won't be temporary. You'll permanently screw host computer.
-It can cause system instability.

Instead, I suggest a hook on SHGetFolderPath. I can offer some help with it.

"Those people who think they know everything are a great annoyance to those of us who do." Asimov

digitxp
digitxp's picture
Offline
Last seen: 11 years 4 months ago
Joined: 2007-11-03 18:33
sure

some help would do great.

Insert original signature here with Greasemonkey Script.

m2
Offline
Last seen: 11 years 11 months ago
Joined: 2006-12-12 12:00
Mail me at [removed by mod Tim]

Please, nobody reply to this post until digitxp contacts me and I remove my email.
EDIT: I didn't receive any email from digitxp, but lococobra at portablefreeware.com found another solution.
I suggest to do the other solution well. It will take more time, but should be less error prone.

"Those people who think they know everything are a great annoyance to those of us who do." Asimov

digitxp
digitxp's picture
Offline
Last seen: 11 years 4 months ago
Joined: 2007-11-03 18:33
Uh...

You posted when I was asleep ;)...
But that'll work too.
Edit: I already tried Enviroment Variables, but it didn't work Sad

Insert original signature here with Greasemonkey Script.

m2
Offline
Last seen: 11 years 11 months ago
Joined: 2006-12-12 12:00
Maybe you made a mistake

Maybe you made a mistake somewhere?
Or maybe it behaves differently for some CSIDL values?
Can you post the code that didn't work?

"Those people who think they know everything are a great annoyance to those of us who do." Asimov

wraithdu
Offline
Last seen: 9 years 7 months ago
Developer
Joined: 2007-06-27 20:22
Env vars have no effect on

Env vars have no effect on the csidl values, at least not on any tests I have tried. I have some AutoIt code I can post if you wanna give it a shot...

m2
Offline
Last seen: 11 years 11 months ago
Joined: 2006-12-12 12:00
Please, do it. int __cdecl

Please, do it.
int __cdecl _tmain(int argc, TCHAR ** argv)
{
TCHAR buf[MAX_PATH]={0};
if(FAILED(SHGetFolderPath( 0,CSIDL_PERSONAL|CSIDL_FLAG_CREATE,0,0,buf)))
_tprintf(_T("Failed, error=%d"),GetLastError());
_putts(buf);
return 0;
}

This C code reacts to %USERPROFILE% changes.

"Those people who think they know everything are a great annoyance to those of us who do." Asimov

digitxp
digitxp's picture
Offline
Last seen: 11 years 4 months ago
Joined: 2007-11-03 18:33
Hm...

Perhaps I only tried %USERPROFILE% and not %HOMEDRIVE%%HOMEPATH% or %SYSTEMDRIVE%%HOMEPATH% or %APPDATA%\.. or something. The code is just like any redirection code...

Insert original signature here with Greasemonkey Script.

wraithdu
Offline
Last seen: 9 years 7 months ago
Developer
Joined: 2007-06-27 20:22
Are your %USERPROFILE%

Are your %USERPROFILE% changes permanent or temporary? We're talking temporary environment changes in this context, so that may make a difference.

AutoIt:

#include 

;*********************************************************
;* SHGetFolderPath Global Constants                             *
;* combine Global Constants using BitOR()                       *
;*********************************************************
Global Const $CSIDL_DESKTOP = 0x0000
Global Const $CSIDL_INTERNET = 0x0001
Global Const $CSIDL_PROGRAMS = 0x0002
Global Const $CSIDL_CONTROLS = 0x0003
Global Const $CSIDL_PRINTERS = 0x0004
Global Const $CSIDL_PERSONAL = 0x0005
Global Const $CSIDL_FAVORITES = 0x0006
Global Const $CSIDL_STARTUP = 0x0007
Global Const $CSIDL_RECENT = 0x0008
Global Const $CSIDL_SENDTO = 0x0009
Global Const $CSIDL_BITBUCKET = 0x000A
Global Const $CSIDL_STARTMENU = 0x000B
Global Const $CSIDL_MYDOCUMENTS = 0x000C
Global Const $CSIDL_MYMUSIC = 0x000D
Global Const $CSIDL_MYVIDEO = 0x000E
Global Const $CSIDL_DIRECTORY = 0x0010
Global Const $CSIDL_DRIVES = 0x0011
Global Const $CSIDL_NETWORK = 0x0012
Global Const $CSIDL_NETHOOD = 0x0013
Global Const $CSIDL_FONTS = 0x0014
Global Const $CSIDL_TEMPLATES = 0x0015
Global Const $CSIDL_COMMON_STARTMENU = 0x016
Global Const $CSIDL_COMMON_PROGRAMS = 0x0017
Global Const $CSIDL_COMMON_STARTUP = 0x0018
Global Const $CSIDL_COMMON_DESKTOPDIRECTORY = 0x0019
Global Const $CSIDL_APPDATA = 0x001A
Global Const $CSIDL_PRINTHOOD = 0x001B
Global Const $CSIDL_LOCAL_APPDATA = 0x001C
Global Const $CSIDL_ALTSTARTUP = 0x001D
Global Const $CSIDL_COMMON_ALTSTARTUP = 0x001E
Global Const $CSIDL_COMMON_FAVORITES = 0x001F
Global Const $CSIDL_INTERNET_CACHE = 0x0020
Global Const $CSIDL_COOKIES = 0x0021
Global Const $CSIDL_HISTORY = 0x0022
Global Const $CSIDL_COMMON_APPDATA = 0x0023
Global Const $CSIDL_WINDOWS = 0x0024
Global Const $CSIDL_SYSTEM = 0x0025
Global Const $CSIDL_PROGRAM_FILES = 0x0026
Global Const $CSIDL_MYPICTURES = 0x0027
Global Const $CSIDL_PROFILE = 0x0028
Global Const $CSIDL_SYSTEMX86 = 0x0029
Global Const $CSIDL_PROGRAM_FILESX86 = 0x002A
Global Const $CSIDL_PROGRAM_FILES_COMMON = 0x002B
Global Const $CSIDL_PROGRAM_FILES_COMMONX86 = 0x002C
Global Const $CSIDL_COMMON_TEMPLATES = 0x002D
Global Const $CSIDL_COMMON_DOCUMENTS = 0x002E
Global Const $CSIDL_COMMON_ADMINTOOLS = 0x002F
Global Const $CSIDL_ADMINTOOLS = 0x0030
Global Const $CSIDL_CONNECTIONS = 0x0031
Global Const $CSIDL_COMMON_MUSIC = 0x0035
Global Const $CSIDL_COMMON_PICTURES = 0x0036
Global Const $CSIDL_COMMON_VIDEO = 0x0037
Global Const $CSIDL_RESOURCES = 0x0038
Global Const $CSIDL_RESOURCES_LOCALIZED = 0x0039
Global Const $CSIDL_COMMON_OEM_LINKS = 0x003A
Global Const $CSIDL_CDBURN_AREA = 0x003B
Global Const $CSIDL_COMPUTERSNEARME = 0x003D

; combine with CSIDL_ value to force folder creation in SHGetFolderPath()
Global Const $CSIDL_FLAG_CREATE = 0x8000
; combine with CSIDL_ value to return an unverified folder path
Global Const $CSIDL_FLAG_DONT_VERIFY = 0x4000
; combine with CSIDL_ value to insure non-alias versions of the pidl
Global Const $CSIDL_FLAG_NO_ALIAS = 0x1000
; combine with CSIDL_ value to indicate per-user init (eg. upgrade)
Global Const $CSIDL_FLAG_PER_USER_INIT = 0x0800
; mask for all possible flag values
Global Const $CSIDL_FLAG_MASK = 0xFF00

; dwFlags values for use with SHGetFolderPath
; current value for user, verify it exists
Global Const $SHGFP_TYPE_CURRENT = 0x0000
; default value
Global Const $SHGFP_TYPE_DEFAULT = 0x0001

Func _WinAPI_SHGetFolderPath($nFolder, $dwFlags = $SHGFP_TYPE_CURRENT)
	Local $folder
	
	$folder = DllCall("shell32.dll", "int", "SHGetFolderPath", _
			"hwnd", Chr(0), _
			"int", $nFolder, _
			"ptr", Chr(0), _
			"dword", $dwFlags, _
			"str", "" _
			)
	Return $folder[5]
EndFunc

ConsoleWrite(_WinAPI_SHGetFolderPath(BitOR($CSIDL_FLAG_NO_ALIAS, $CSIDL_APPDATA)) & @CRLF)
ConsoleWrite(EnvGet("APPDATA") & @CRLF)
EnvSet("APPDATA", "C:\test")
ConsoleWrite(EnvGet("APPDATA") & @CRLF)
ConsoleWrite(_WinAPI_SHGetFolderPath(BitOR($CSIDL_FLAG_NO_ALIAS, $CSIDL_APPDATA)) & @CRLF)
m2
Offline
Last seen: 11 years 11 months ago
Joined: 2006-12-12 12:00
I'll quote my own words from

I'll quote my own words from the topic I linked to previously:
However, be careful when you do it this way, i.e. getting "My Documents" fails unless "%USERPROFILE%\My Documents" exists...and I guess that exact folder name is language specific. This can lead to instable work of the program. I'm sure it can be made to work well, however doing this well is much more complicated than what you posted.
In your case %USERPROFILE%\Application Data has to exist, then everything works.

So First, you have to determine all directories that have to be created (By using all CSIDL values, better option would be using all KNOWNFOLDERID values because CSIDL may not be enough for some "Vista or later" programs)
Then you have to find where are their localized names stored in the registry.
Then create these folders in \Data and write a launcher that renames them on startup if locale changed.

"Those people who think they know everything are a great annoyance to those of us who do." Asimov

wraithdu
Offline
Last seen: 9 years 7 months ago
Developer
Joined: 2007-06-27 20:22
Well, I retried my example

Well, I retried my example first with $CSIDL_FLAG_CREATE, then after manually creating "C:\test". In all trials, EnvGet("APPDATA") returned "C:\test" correctly, and SHGetFolderPath returned "C:\Users\Erik\AppData\Roaming" (Vista laptop).

So I don't see where the existance of "C:\test" made any difference.

m2
Offline
Last seen: 11 years 11 months ago
Joined: 2006-12-12 12:00
Maybe Vista changed the

Maybe Vista changed the behaviour, it totally undocumented. Pardon Try the following batch (assumes your test program to be named a.exe):

@echo off
set userprofile=c:\test
md c:\test\AppData
md c:\test\AppData\Roaming
a.exe
rd /q /s c:\test\AppData

And try it w/out the "create" flag. In my case, when folder exists, it doesn't change anything, it's needed in case that it doesn't. But you cannot assume that app uses this flag, that's why I said to create %USERPROFILE%\Application Data.

"Those people who think they know everything are a great annoyance to those of us who do." Asimov

wraithdu
Offline
Last seen: 9 years 7 months ago
Developer
Joined: 2007-06-27 20:22
Ok, very strange

Ok, very strange results:

EnvGet("APPDATA") = C:\Users\Erik\AppData\Roaming
EnvGet("USERPROFILE") = c:\test
CSIDL_APPDATA = c:\test\AppData\Roaming
CSIDL_LOCAL_APPDATA = c:\test\AppData\Local
CSIDL_PROFILE = C:\Users\Erik

BTW, there's a CSIDL_FLAG_DONT_VERIFY so you don't have to create the directories (for testing purposes).

So it seems that CSIDL_*APPDATA uses the environment var %USERPROFILE%, while CSIDL_PROFILE and environment var %APPDATA% do not. Could MS make this any more confusing?

m2
Offline
Last seen: 11 years 11 months ago
Joined: 2006-12-12 12:00
BTW, there's a

BTW, there's a CSIDL_FLAG_DONT_VERIFY so you don't have to create the directories (for testing purposes).
For testing purposes - OK, but you need to make it work with all possible sets of flags.
So it seems that CSIDL_*APPDATA uses the environment var %USERPROFILE%, while CSIDL_PROFILE and environment var %APPDATA% do not. Could MS make this any more confusing?
That's why they didn't document how does it work. :D:D

There are still 2 ways. Either play with env vars, but it looks like a daunting task. And will require huge amount of testing, practically with every Windows version.
Hook is a very dirty solution and sometimes antiviruses don't like it. But it can be done in a few hours.

"Those people who think they know everything are a great annoyance to those of us who do." Asimov

Log in or register to post comments