# VBForums UtilityBank > UtilityBank - Components >  [VB6] Class: PathLinks - Tame App.Path Under Vista+

## dilettante

*Title*

PathLinks


*Description*

A VB6 self-instantiating Class to be used once (elevated) after application installation to:
Pre-Vista: Create any necessary empty data subfolders under App.Path.Vista+: Relocate your App.Path data subfolders to the user R/W "Public" folder.
The purpose is to let your setup install your application into Program Files, yet let all users run your application and let it read and write files in the data subfolders _without changing your application program logic!_

This is one way to solve the "App.Path problem" for installed VB6 applications.


*Features*
Under Windows XP or earlier, nothing new is done except to create empty data subfolders under App.Path on the first run.Under Windows Vista or later, if the first run is done elevated your data subfolders under App.Path are relocated to "Public" and symlinks are dropped into App.Path so your program can automagically find them!Source form in-Project Class, no DLL need be created.  The compiler instantiates a global instance of the Class so you don't have to.

*Author Name*

Bob Riemersma


*System Requirements*

Windows 95 with Desktop Update or later.

Under Windows Vista or later the "Public" special folder must not have been relocated off the "Program Files" drive!


*License Info*

Public domain.

Use at your own risk for any purpose: private, commercial, governmental, educational, or institutional.  _Absolutely no warranty or offer of support!_


*Misc. Notes*
Don't try to create an instance of PathLinks.  A global instance named PathLinks is automatically created by the compiler.If your "Public" folder has been relocated to a different drive from where your App.Path is then any pre-existing data subfolders in the list passed to PathLinks.Publish() will fail on the move attempt!Do not "publish" subfolders under App.Path that contain DLLs, OCXs, etc.  This is just for data and data folders you need read/write access to for any user running your program.Data files placed "naked" right under App.Path without a subfolder can not be helped by PathLinks.  If necessary rewrite your program to use these from inside a subfolder.Create your setup package as you would on Windows 2000 or XP.  Include any data files in the package, to be deployed to a subfolder under App.Path as always.The only extra step after installing is a user must run your program elevated one time before anyone uses it normally.Once again, pre-Vista PathLinks does nothing except create empty data subfolders for you as required.  From there your program runs as always.Exception: If your program tries to MakeDir an empty work folder under App.Path it may fail under this scheme.  Let PathLinks create your empty folder under App.Path or else add error checking around your MakeDir statements.You could also write a separate small program that just calls PathLinks.Publish() to be run elevated right after installing.  Then your actual application program or programs will not need PathLinks in them at all!

*Tested On*

Windows XP SP3, Windows Vista SP2, Windows 7 RC.


*The Demo*

PathLinks is included here as a demonstration project.  Note that there is a demojunk subfolder with one text file in it.  This is used to demonstrate that data put into an App.Path data subfolder by your setup does indeed get moved to the "Public" folder when run elevated under Vista+ the first run.

To run the demo:
Open the Project and compile it.Run the program under Vista or later, note that it prompts the user to run it as administrator for this first run.Run the program elevated.  Close it.Run the program unelevated.  Click the buttons to test its ability to write and read data in the defined data subfolders.  Close it.Note that the data subfolders are no longer in the App.Path folder.  Use Windows Explorer to look inside the "Public" special folder (try C:\Users\Public for most systems) to see where the app data folders have been moved to.  Also note the symlinks pointing to these new folders that were created in the App.Path folder.
Also consider packaging the compiled program and installing it and running it on XP and Windows 7 test systems.


*General usage*

Add PathLinks.cls to your program's Project.  Add initialization code similar to that you can see in the demo's Module1.bas module.  Compile, test, create a setup package.  Add instructions telling the user to run the program _once_ elevated under Vista or later.


*Closing Comments*

This is *not* the "right way" to handle this issue.  However a lot of programmers may find it an elegant alternative to "the right way."  It only requires minimal changes to an existing program, which will seem to "see" App.Path as working as always.

The source code in PathLinks.cls contains a block of comments documenting its usage in more detail.

----------


## dilettante

Wouldn't you know it!  I introduced a glitch.

Stay tuned for a re-posted corrected version.

----------


## dilettante

Sorry, duty called.  Such is the life when you do contract work on the side!

I regret putting this out there with such fanfare and then pulling the rug out from under it this way.  But the bugs that cropped up have been squashed and a few changes (maybe even improvements) were made:
PathLinks is no longer created as an automatic global object.  It really has no use past program initialization and we may as well let the code get unloaded after initial use.  The demo has been updated to reflect this.There should no longer be a limitation that requires your special folder Public to be on the Program Files drive.The glitch that caused things like .MDB files moved from App.Path subfolders to Public subfolders by PathLinks to retain read-only security has been corrected.

Please give it a try to help uncover any remaining bugs and spot any useful missing features.

Thanks.

----------


## dilettante

Here is a small update.  It hasn't changed PathLinks but the demo adds a simple Task Dialog wrapper to display an announcement with the UAC Shield icon.  Now if the user Oks this the program reruns itself with elevation.

----------


## dilettante

I've been wavering on whether to post a corrected version that addresses a couple of bugs.  I'm beginning to wonder if it wouldn't be better just to create a 2.0 version that uses CommonAppData and sets the ACL instead of this approach that uses Public.

Since people have looked at what I've posted so far though, it seems only right to put a version correcting some bugs here first.

The biggest flaw in the earlier versions was that it left _current directory_ set wrong even though I had meant to reset it to its original value.  That won't happen anymore.


When looking at the demo project, note that the entire "application" is in the Form1 code.  Everything else is meant to (a.) set up Common Controls 6.x, (b.) provide Task Dialogs in Vista or later, and (c.) do this "PathLinks" thing.

Version 1.2 above left out Task Dialog support, so it might be simpler to look at even though it still has the current directory bug.

If you want to use 1.3 without Task Dialogs, just change the call to STDlg.TaskDialog() to a MsgBox() call instead.  Then remove the STDlg.cls module since you won't be using it anymore.  MsgBox() dialogs just look sort of old-timey and Win 3.1-ish on newer versions of Windows.


Using Public instead of CommonAppData did two things: (1.) unlike CommonAppData, Public files and folders aren't hidden which some people see as a bonus; (2.) since Public files and folders don't default to "owner" security unlike CommonAppData, they provide a read/write location for all files and users without the need to alter the security ACL on them.

The second reason was the big one, but a CommonAppData version of PathLinks could handle that.

----------


## dilettante

Yet another version.

This one corrects a few minor bugs, but more importantly it adds the ability to handle moving and linking to data files in App.Path.  Yes now PathLinks handles files in the application's Program Files folder, not just in subfolders under it.


After testing the demo from within its Project folder (i.e. after compiling rather than after creating a PDW Setup and installing it) you'll want to:
Delete the three symlinks from the Project folder.Delete the folder "temp" (and the symlink it contains) from the Project folder.Copy the demojunkfile.txt back to the Project folder from the Public subfolder.Copy the demojunk folder back.Delete the Public subfolder for your application.
When creating a PDW Setup be sure you add a few files:
The manifest (under $(AppPath)).The demojunkfile.txt (under $(AppPath)).The somestuff.txt file (under $(AppPath)\demojunk).
The demojunkfile.txt is new for this version, otherwise these rules apply to testing previous versions as well.


Be sure to read the comments at the head of PathLinks.cls, there is some important info there.

For example files to be relocated by PathLinks need to have an extension, because the "." is used to figure out of it is dealing with a file or a folder.  This means that folders should not have a "." or PathLinks will try to treat them as files!

We need this because when PathLinks is relocating files and folders those files and folders might not exist yet, so it can't simply test the item for "IsFolder" as you normally would.

----------


## dilettante

If it helps any, here's a screenshot showing the three files you need to add manually when using the PDW to package the demo project after compiling it.

Be sure to note the Install Location for the somestuff.txt file!

Though the demo never actually uses somestuff.txt it is included here to show that PathLinks moves the file, as it does with demojunkfile.txt as well.

----------


## dilettante

Ok, here is *PathLinks 2.0* that I suggested earlier.

It is roughly identical to PathLinks 1.4 above, with some major changes:
The list of files and folders provided to PathLinks.Publish() is now relocated to CommonAppData (ProgramData) instead of Public.The ACL on the subfolder created under ProgramData for the application is changed, giving Full Control to the Users group.
This is where a program written to "follow the rules" would put its data, and you can have it with no rewrite.  All you'd need to do is add the PathLinks class and its related code as previously described, providing the list of files and folders to relocate.  Then run your application after installation _one time_ with elevation.

As before, these actions are only taken on Vista or later.  Earlier Windows versions don't have a convenient symlink that is easy to manipulate.


*Caution:*

This code is now setting an ACL in a very sensitive part of the filesystem.  It isn't doing anything a proper installer for a properly designed program wouldn't do, but you want to get it right!

The demo was tested to make sure it doesn't screw up, _but_...

... during development I had a bug and I ended up setting the ACL on the ProgramData folder itself!  This required a System Restore (and I was lucky to have a fairly recent Restore Point).  Be careful if you tamper with the logic in PathLinks.


When in doubt, try it out.

By that I mean that you'll want to be sure to test your installer and your "first run" on a clean test machine (which you ought to be doing anyway) instead of on a machine you use for normal purposes.

Some sort of VM is usually the most convenient.

----------


## dilettante

*Note:*

In both PathLinks 1.4 and 2.0, a file that is installed into App.Path and relocated can be read or written, however this doesn't mean that your application can create _new_ files directly under App.Path because this is still under the protected Program Files folder.

If you need to create new files these should be created in a relocated folder _under_ App.Path, example:

Open App.Path & "\foldername\filename.txt" For Output as #intFile

... where "foldername" was a folder relocated by PathLinks.

Trying:

Open App.Path & "\filename.txt" For Output as #intFile

... will either cause an exception or will create the file under the virtualized path (depending on your application manifest, etc.).

----------

