Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

VFP6... GETDIR() and hidden folders

Status
Not open for further replies.

GriffMG

Programmer
Mar 4, 2002
6,320
FR
Just been dealing with a little support issue on a, very, remote system - nearer to MikeL than me - an old app
written in VFP6 (Started in 2002!).

User retiring, new user, new laptop, WFH, Windows 11... trying to locate the Sage Accounts data so that customers can
be read directly from there.

The app has a browse button to locate the folder (C:\ProgramData\sage\accounts\2022\company.000\accdata) but there is a
problem. C:\ProgramData is a hidden folder and VFP6 can't 'see' it via GETDIR().

In VFP7 and above you can specify three parameters and then VFP uses the Windows api to select a folder, but not back in
VFP6.

Anyone got a good workaround for this - obviously I *could* upgrade the app to VFP9, but I would rather not... well not
right now.

I have solved the instance in question by starting the search further down the tree so to speak - past ProgramData


Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0
 
Hi Mike

It might be, could it be, I'm not saying it is, but I called the function thusly, the parameters are not in
the same order - and it worked perfectly

Code:
	** Old way
	**M.FILENAME = GETDIR("G:\SAGE\COMPANY.001\ACCDATA\","Select Folder")

	** new function
	**
	m.FILENAME = SelDirDlg("Select Folder!","G:\SAGE\COMPANY.001\ACCDATA\")

** edit, just checked with c:\ in case....

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0
 
Instead of

Code:
IF TYPE('oBrowseObject') = 'O' AND ! ISNULL(oBrowseObject)
	FOR EACH item IN oBrowseObject.ParentFolder.Items
		IF item.name == oBrowseObject.title
			cPathToReturn = Item.Path
			EXIT
		ENDIF
	ENDFOR
ENDIF

You should be able to use the slightly more succinct

Code:
IF TYPE('oBrowseObject') = 'O' AND ! ISNULL(oBrowseObject)
    cPathToReturn = oBrowseObject.Self.Path
ENDIF
 
I'll try that.

Seems to work, thank you.

I will see if I can pass that on to the author, although after 24 years, he may have lost interest...

** EDIT ** Ed Rauh, the author, passed away some 4 years ago.


Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0
 
Shell.Application only stores some of the system paths. Just like environment variables also only contain some of the system paths. The core function to retrieve any system path (since Vista) is what Doug Hennig described here:
In your case needing to find the common application data folder, that also is known as ProgramData, not only on Win10 or 11, where it is in C:\ProgramData. That's compatible with Windows versions back to XP. So GetEnv("ProgramData") is sufficient. The fear adminstrators fiddle with such environment variables is unreasonable, as that would cause all kind of problems with software relying on them to be set as the OS initiallizes them.

Just once more, if admins agree to setup a new environment variable for you, you also can get that, and don't need the user to find the subdirectory thats within common application data. It would make things not only easier than using the right way to get the common applicaiton data path from an OS function, you also don't need to search for the actual subdirectory you need from there.

And also note, once a Windows API function is available on a Windows version, it's available to all VFP versions which have the DECLARE DLL command. You mainly depend on the OS version to make use of API functions and CLSID enumerations or what is available within shell.application. That all does not depend on the VFP version but the OS/Windows version. The only way code using such fuctions does not work on VFP6 is, if some functions to convert a portion of bytes into a number is using non-VFP6 functions.

Chriss

Edit: Teh reason I tallk of common application data aka ProgramData instead of local application data aka AppData is, that the local application data is within the user profile, so it's a per user application data folder, and I'm sure since you find sage data in C:\ProgramData it means what you look for is the common application data path and that's also GetEnv('ProgramData') for older windows versions.

It was/is this path for different OS versions:
[pre]Win 95/98/Me C:\Windows\All Users\Application Data
Windows NT4 C:\WinNT\Profiles\All Users\Application Data
Windows 2000/XP/2003 C:\Documents and Settings\All Users\Application Data
[/pre]

I don't know, but still bet even on XP, where it is within the "All Useres" profile, Getenv('ProgrmData') would still work. But since Vista it is not within the All Users profile or the POublic user profile, it's a separate fixed folder.

If you still want ot go for that path by API, that's the KNOWNFOLDERID FOLDERID_ProgramData, GUID {62AB5D82-FDC1-4DC3-A9DD-070D1D495D97}. And unless Microsoft will make an incompatible change to the system folder API functions, it will hold true forever for Vista and later. Not, that it alwas is and will be "C:\ProgramData", but that it will be put into the system environment variable %ProgramData%.
 
Shell.Application only stores some of the system paths.

That sounds right. When I tried to get the paths for all CSIDLs from 1 to 43, it returned about five and then crashed.

But when I did the same with my GetSpecial() function, it returend 35 distinct paths, with values of 2 to 43 with several gaps.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
>with my GetSpecial() function, it returend 35 distinct paths, with values of 2 to 43 with several gaps.

That's because

1) SHGetPathFromIDList cannot handle virtual folders (quite a few of the special folders are in fact virtual folders)
2) Certain PIDL values are unused, and thus essentially invalid when passed to SHGetSpecialFolderLocation

Doug Hennig's function (which is pretty much the same thing) suffers the same problem

(If you use my code to iterate through all the values, you should see better results, although some of the results might initially appear a bit odd such as

[tt]::{21EC2020-3AEA-1069-A2DD-08002B30309D}[/tt]

but the shell knows what to do with them - just try Start -> Run and paste in the odd values, then hit OK

Or, in code:

Code:
oShe =  CreateObject("shell.application")
oShe.open("::{21EC2020-3AEA-1069-A2DD-08002B30309D}")
)

BTW, I am also not quite sure what "Shell.Application only stores some of the system paths" means, given that shell.application understands every single special folder PIDL that I am aware of. Perhaps it is the public ShellSpecialFolderConstants enumeration that is being referred to; this does not reflect quite all the available PIDLs (although it is not far off), but that doesn't mean shell.application does not handle those not included in that enumeration.

For completeness sake I attach an Excel spreadsheet that documents all the special folder PIDLs that I am aware of
 
 https://files.engineering.com/getfile.aspx?folder=d14e0df0-eeb6-40c7-b1ae-1a811414c68f&file=SpecialFoldersList.xlsx
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top