Set path in Visual Foxpro - visual-foxpro

I want to set path in Visual Foxpro. In such a way that I want to keep exe file on local machine and data\tables on server. How can I do so?

I personally have never liked using SET PATH, especially if you have many "paths" that your application is expecting to use.. If you have a given table / file in multiple locations that are visible with multiple paths that qualify, you may be getting the wrong table, but you won't necessarily know it since the application just runs as normal, finds a table and continues.
Instead, I would suggest one of a few things. Yes, have your application on each user's local machine, but have the person's shortcut have the "START IN" folder pointing to the path on the server where your data is. This way, your application will BE in the folder where the data resides and processes without issue. If no data is on the local machine, during your startup, you could add a messagebox about ... hey... your shortcut should be set to "Start In" setting to X:\SomeShareOnServer\MyVFPDataPath...
If not that, then another avenue I have used is to have your application during startup, add a property to the "_Screen" object which will NEVER loose scope, and set that property to the path you have the data located such as...
_Screen.AddProperty( "cDataPath" )
_Screen.cDataPath = "X:\SomeShareOnServer\MyVFPDataPath\"
Then, in your code, any of your opening tables or SQL queries, use the path variable PLUS the table... something like
if not used( "SomeTable" )
select 0
use ( _Screen.cDataPath + "SomeTable" )
endif
if doing a query, use similar approach
select ST.* ;
from ( _Screen.cDataPath + "SomeTable" ) ST ;
where ST.SomeID = 123;
into cursor C_TmpResult readwrite
So, although the second option may take more effort, especially on an existing application, the first option to make sure the "Start In" path is where the data is might help.
Again, this is my suggestion as I hate chasing down ambiguous -- sometimes it works, but not others. If I can't find a file, I WANT TO KNOW about it and fail outright.
Your call, your app, your environment. But if you DO use the "SET PATH" command, you might want to make sure you use the ADDITIVE command, just in case there are other settings, such as pointing to the a path for forms, classes, report folders... You run a SET PATH without it, and you kill your other paths...
SET PATH TO "X:\SomeShareOnServer\MyVFPDataPath\" ADDITIVE
Also, if you have any spaces in your path in question, MAKE SURE you use quotes around it, otherwise it will fail finding the path you expect and may cause compile error, such as
SET PATH TO X:\Some Share On Server\MyVFPDataPath\ ADDITIVE

You can use VFP's Set Path command
Set Path To m.lcDataFolder
early in your client startup code, i.e. in your project's "main.PRG".
Where the content of the m.lcDataFolder could for example come from something like a custom "myConfig.XML/INI/TXT" containing the desired string, e.g. \\fileServerNameOrIP\sharedDataFolder

Use 'SET DEFAULT TO' to change the current working directory or use explicit full paths as per the answer by #DRapp.

Related

Windows show local path as list in the Environmental Variables pane

I like to modify my Windows environmental variables by opening the Advanced System Settings -> Environmental Variables. I particularly like that when I try to modify the system path (by clicking on System Variables -> Path), that I get a nice, easy to read list of the folders on the path:
However, when I click on the User Variables -> Path, I still get the old dialog, which is not very user friendly:
Is it possible to have Windows always display the list, as is the case for the System variables?
For what its worth, I think I remember seeing the desired behavior on a friend's computer, so I believe it should be possible.
EDIT:
It seems that having a variable as part of the path is the problem. Is there a way to get path list even when the path contains variables?
Context:
When I want to add a program to my path, I will create a new variable that redirects to its path. The reason to do that is simple... Programs typically have compound paths, and so making a consolidated variable seems like a wise decision. For instance, on my machine, I have multiple python instances (sometimes I need an Anaconda installation of Python 3.6, and sometimes I want a version of the bare-bones Python 3.5). To accomodate this, I create environmental variables for the paths to each installation.
Now if I want to switch which version is on my path, I can simply update my path variable from
path=...;%PATH_PYTHON35%
to
path=...;%PATH_PYTHON36A%
See how easy that was?
The problem is that the GUI doesn't seem to like this for the local variables. I can confirm that this is the case because when I remove the variables from the local path, I get the nice list like the System Variables case. However, what is perplexing to me is that the System Variables path DOES include some variables as well:
So I take this to mean that there must be a way of getting the local variables list to pop up, just like the System Variables case...
Guess I'm late to the party, but this works for me:
PATH=C:\DATA\bin;%JAVA_HOME%\bin
whereas this does not work:
PATH=%JAVA_HOME%\bin;C:\DATA\bin
A speculation based on my own observations.
It seems list view is only presented when at least one of the first two entries begins either with a drive letter notation (like C:\) or a specific variable. I'm not sure which variables are considered "valid", but here are a few environmental variables that show up as list:
%USERPROFILE%+%LOCALAPPDATA%;aaa;bbb;
aaa;Q:\%LOCALAPPDATA%;bbb;
These however show up as a string:
%LOCALAPPDATA%+%USERPROFILE%;aaa;bbb;
aaa;bbb;%USERPROFILE%;
Not sure what makes %USERPROFILE% different, but i tried a few other variables instead of %LOCALAPPDATA% (%OS%, %HOMEDRIVE%) - result was the same.

Running programs from command prompt (PATH environment variable)

I'm having some issues when trying to run some programs from the command prompt after adding their executable file paths to the PATH variable. I respected the syntax (; at the end of every path added). Has this ever happened to anyone?
You have not told us what problem you are seeing, but it you append the path to a program at the end of PATH thus:
set PATH=%PATH%;"c:\somewhere_else"
you can find the new path nevers gets seen, since there's a hard upper limit on path length. See for example this SO post
One option is to prepend the new location, bearing in mind this will drop other things off the end:
set PATH="c:\somewhere_else";%PATH%
There are various workrounds. For example, I tend to have a few set_path.bat files in a few different locations that reset my path to what's required for various different tasks.

How can I resolve MSI paths in VBScript?

I am looking for resolving the paths of files in an MSI with or without installing (whichever is faster) from outside an MSI, using VBScript.
I found a similar query using C# instead and Christpher had provided a solution, below: How can I resolve MSI paths in C#?
I am going through the very same pain now but is there anyway to achieve this using WindowsInstaller object in VBScript, rather than go with endless queries through SQL Tables of MSI back and forth to achieve the same. Though any direction would be welcoming as I have tried tested whatever I can with very limited success.
yes there is a solution without installing the msi and using vbscript.
there is a very good example in the Windows Installer SDK called "WiFilVer.vbs"
using that example i've thrown together an quick example script that does exactly what you need.
set installer = CreateObject("WindowsInstaller.Installer")
const READONLY = 0
set db = installer.OpenDataBase("<FULL PATH TO YOUR MSI>", READONLY)
set session = installer.OpenPackage(db, READONLY)
session.DoAction("CostInitialize")
session.DoAction("CostFinalize")
set view = db.OpenView("SELECT File, Directory_, FileName, Component_, Component FROM File,Component WHERE Component=Component_ ORDER BY Directory_")
view.Execute
set record = view.Fetch
do until record is nothing
file = record.StringData(1)
directoryName = record.StringData(2)
fileName = record.StringData(3)
if instr(fileName, "|") then fileName = split(fileName, "|")(1)
wsh.echo(session.TargetPath(directoryName) & fileName)
set record = view.Fetch
loop
just add the path to your MSI file.
tell me if you need a more detailed answer. i will have some more time to answer this in detail this evening.
EDIT the promised background (and why i need to call ConstFinalize)
naveen actually MSDN was the only resource that can give an definitive answer on this, but you need to know where and how to look since windows installer ist IMHO a pretty complex topic.
I really recommend a mix of the msdn installer function reference, the database reference, and the examples from the windows installer SDK (sorry couldn't find a download link, i think its somewhere hidden in the like 3GB windows SDK)
first you need general knowledge of MSIs:
an MSI is actually a relational database.
Everything is stored in tables that relate to each other.
(actually not everything, but i will try to keep it simple ;))
This database is interpreted by the Windows Installer,
this creates a 'Session'
also some parts are dynamically resolved, depending on the system you install the msi on,
like 'special' folders similar to environment variables.
E.g. msi has a "ProgramFilesFolder", where windows generally has %ProgramFiles%.
All dynamic stuff only exists in the Installer session, not the database itself.
In your case there are 3 tables you need to look at, take care of the relations and resolve them.
the 'File' table contains all Files, the 'Component' table tells you which file goes into which directory and the 'Directory' table contains all information about the filesystem structure.
Using a SQL Query i could link the Component and File table to find the directory name (or primary key in database jargon).
But the directory table has relations in itself, its structured like a tree.
take a look at this example directory table (taken from the instEd MSI)
The columns are Directory, Directory_Parent and DefaultDir
InstEdAllUseAppDat InstEdAppData InstEd
INSTALLDIR InstEdPF InstEd
CUBDIR INSTALLDIR hkyb3vcm|Validation
InstEdAppData CommonAppDataFolder instedit.com
CommonAppDataFolder TARGETDIR .
TARGETDIR SourceDir
InstEdPF ProgramFilesFolder instedit.com
ProgramFilesFolder TARGETDIR .
ProgramMenuFolder TARGETDIR .
SendToFolder TARGETDIR .
WindowsFolder_x86_VC.1DEE2A86_2F57_3629_8107_A71DBB4DBED2 TARGETDIR Win
SystemFolder_x86_VC.1DEE2A86_2F57_3629_8107_A71DBB4DBED2 WindowsFolder_x86_VC.1DEE2A86_2F57_3629_8107_A71DBB4DBED2 System
The directory_parent links it to a directory. the DefaultDir contains the actual name.
You could now resolve the tree by yourself and replace all special folders(which in a vbscript would be very tedious)...
...or let the windows installer handle that (just like when installing a msi).
now i have to introduce a new thing: Actions (and Sequences):
when running (installing, removing, repairing) an msi a defined list of actions is performed.
some actions just collect information, some change the actual database.
there are list of actions (called sequences) for various things a msi can do,
like one sequence for installing (called InstallExecuteSequence), one for collecting information from the user (the UI of the MSI: InstallUISequence) or one for adminpoint installations(AdminExecuteSequence).
in our case we don't want to run a whole sequence (which could alter the system or just take to long),
luckily the windows installer lets us run single actions without running a whole sequence.
reading the reference of the directory table on MSDN (the remarks section) you can see which action you need:
Directory resolution is performed during the CostFinalize action
so putting all this together the script is easier to read
* open the msi file
* 'parse' it (providing the session)
* query component and file table
* run the CostFinalize action to resolve directory table (without running the whole MSI)
* get the resolved path with the targetPath function
btw i found the targetPath function by browsing the Installer Reference on MSDN
also i just noticed that CostInitialize is not required. its only required if you want to get the sourcePath of a file.
I hope this makes everything clearer, its very hard to explain since it took me like half a year to understand it myself ;)
And regarding PhilmEs answer:
Yes there are more influences to the resolution of the directory table, like custom actions.
keeping that in mind also the administrative installation might result in different directorys (eg. because different sequence might hold different custom actions).
Components have conditions so maybe a file is not installed at all.
Im pretty sure InstEd doesnt take custom actions into account either.
So yes, there is no 100% solution. Maybe a mix of everything is necessary.
The script given by weberik (deriven from MS SDK VB code) is very good, because it makes it easy to analyse the directory table without an own algorithm (which is a mid-size effort to do it in a loop or with a recursion algorithm).
But it gives not a 100% perfect view for all files, see below.
The method of the script is semi-dynamic (can be extended by other actions), but in effect it gives only the static directory structure, similar to a default administrative install or advanced MSI viewers.
Normally this is enough and what we want.
But be aware, that this is not the 100% solution (Knowing before exact the path of each file afterwards). That does mean, this will not give you always the correct paths in some cases:
You use command line parameters which substitute predefined directory table entries.
The MSI uses custom actions which change paths.
Especially it is not guaranteed, that every file is installed. There may be optional conditions and features and this may depend on the install environment.
In effect, a 100% solution is very very hard to achieve, without installing really. It comes near to reprogram nearly the whole windows installer engine. So simplifications are normally sufficient and accepted.
But you can extend the method to cover custom actions, e.g. with adding a line "session.DoAction(..)" for each additional action needed. Or to include command line parameters.
Sometimes it can be tricky. The easier the structure of the MSI is, the more likely it is that you succeed without more efforts.
Alternative to write an own program:
The question is, what you really want to find out, and if it is really necessary to program it:
If you don't want to write an automatical every-day MSI analyzer maybe the following is sufficient for you:
First tip: install the MSI with "msiexec /a mysetup.msi TARGETDIR="c:\mytestpath" . (similar restrictions as script above by weberik)
If the MSI has not used custom actions to change pathes including forgetting to add to the admin sequence ("forgetting" should be taken as the normal case for 99% or existing setups :-), you get the filestructure like if you install "really" with some special namings for the Windows predefined folders which you will find out easily.
If the administrative install lacks some folders, it is often a better idea of fixing the custom action (adding to the admin sequence) and using this scenario as your primary test case.
The advantage is, that only you limit the dynamics used by admin install. BTW, you can use the same command line params or path settings custom actions as in real install.
Second tip: Google for the InstEd tool , go to the file or component table and you will see the resulting MSI paths in the same static way as with the mentioned VB-script after calling CostInitialize/CostFinalize. For human view such an editor view maybe better.
For automatic testing and improvements or accuracy, you need an own program of course.
For those of you that mentioned snippet given is a good starting point. :-)
The rest of you should live easier with one of the two given methods without programming.

Complex Shortcut Installshield using variables

I need to create a shortcut for my application in Installshield, and the path to do so is:
C:\app\bin\exe.exe -basekey ini -ininame settings.ini -p cal.p -pf s:\pfs\sec_l_oea.pf
This shortcut is essentially split up into three bits:
C:\app\bin\exe.exe
This is the location of a pre existing software that I would like to find using System Search.
-basekey ini -ininame settings.ini -p cal.p -pf
This will always be the same and does not need any variables
s:\pfs\sec_l_oea.pf
The user should have to browse to find this file.
My problem is I don't know how to get the path for part one, I have set up a System Search to hopefully find it, and store it in the "PROWIN" variable, however, how do I access that variable when setting a shortcut?
I could also do with knowing how to take a user variable (from installation) and set the shortcut depending on that for part 3.
Any help is appreciated
Once you have the file stored in a variable/property I think it can be used in multiple places by putting the name in a string with square brackets around it.
Your argument might look something like this:
-basekey ini -ininame settings.ini -p cal.p -pf [PROWIN]
As a side point: In the installshield termanology, dynamically stored values are always strings and they are refered to "properties" not variables, this might help with future searches.

Registry does not like long filename for shell commands or verbs

(if not applicable to SO, please refer to another appropriate place, thanks).
When using the registry to associate file extensions and application, I put in the full filename of my application, but that does not work well, only if I use the 8.3 filename.
for example ( taken from the registry) this works:
[HKEY_CLASSES_ROOT\Toto.Document\shell\myVerb\command]
#="C:\\my\\path\\bin\\Debug\\bin\\myexe_~1.EXE /dde"
[HKEY_CLASSES_ROOT\Toto.Document\shell\myVerb\ddeexec]
#="[myVerb(\"%1\")]"
but this does not work :
[HKEY_CLASSES_ROOT\Toto.Document\shell\myVerb\command]
#="C:\\my\\path\\bin\\Debug\\bin\\myexecutable.EXE /dde"
[HKEY_CLASSES_ROOT\Toto.Document\shell\myVerb\ddeexec]
#="[myVerb(\"%1\")]"
The action is called by right-clicking on the file in Explorer, I get the error :
"Windows cannot find 'c:\users\me\desktop\tata.toto'. Make sure you typed the name correctly, and then try again".
I'm creating the keys programatically with CRegKey and using GetModuleFileName to get the application path.
2 questions :
- I'm probably missing something in my registry entry ? (i've tried quoting the paths, but does not work)
- Can I get the "short" filename ? (searching a little bit seems that GetShortPath should work, but not always!)
Thanks.
Max.
(edit 22/03/2011)
I tried using quotes but it did not work (with /dde)
I decided to use normal parameters instead of /dde and it seems to work nicely with the normal path (not shortened like stated above).
I'm still not certain why when creating a simple MFC SDI project it will write out registry values with the old short name instead of the long name.
Thanks again.
Max.
Try creating the key with another couple of double-quotes (note between .EXE and /dde:
#="C:\\my\\path\\bin\\Debug\\bin\\myexecutable.EXE" "/dde"

Resources