Groups | Blog | Home
all groups > visual studio .net general > october 2007 >

visual studio .net general : MakeRelativePath()


Ivo Beltchev
10/21/2007 3:18:25 PM
GetCurrentDirectory + PathRelativePathTo?

[quoted text, click to view]
Andrew Chalk
10/21/2007 4:48:46 PM
Is their any built-in Win32 function that returns the relative path to a
file given the applications current working directory?

Many thanks

Vladimir Scherbina
10/22/2007 12:00:00 AM
Current directory value can be differ in comparison to directory where the
application is executing.

Usually, applications set the curr dir to their home dir, this often can be
seen in MS code. So, correct answer is: one need to analyze the path to
executable by invoking GetModuleFileName and obtaining the working dir. But,
in order to avoid overhead, it's better to use the first cmd line parameter,
which is pointing to the path to executable.

[quoted text, click to view]
GetCurrentDirectory + PathRelativePathTo?

[quoted text, click to view]

Tony Proctor
10/22/2007 12:00:00 AM
Not sure the other respondents have correctly understood your question
Andrew. Can I just check?

Do you mean you want to take a full path specification and convert it to a
relative one - relative to some second, arbitrary full directory path?

For instance, c:\Dir1\Dir2\x.y relative to c:\Dir1 is easy (Dir2\x.y, or
..\Dir2\x.y) but do you want something that can cope with the general case
(which may be up from the root as well as down from the root, or even on a
different drive)?

Tony Proctor

[quoted text, click to view]

Chris Becke
10/22/2007 12:00:00 AM

[quoted text, click to view]

If by the first cmd line parameter you mean the parameter arg[0], arg[0]
does not need to be a cannonical path.

At the core of the Win32 process launch mechanism is an API CreateProcess
that takes two parameters. One is a path to the exe file to launch, the
other is the command line, including the first parameter. As a result,
if/when both parameters are used, arg[0] can be anything at all, not even
slightly related to the exe executed.

J de Boyne Pollard
10/22/2007 4:47:16 AM
VS> Current directory value can be differ in comparison to directory
VS> where the application is executing.

No, it cannot. *By definition*, the directory where the program is
executing is the current directory. You are conflating the current
directory (which was what M. Chalk asked about) with the path to the
executable program image file (which wasn't what M. Chalk asked about).
Andrew Chalk
10/22/2007 9:00:06 AM
You have it right. Is there:

char * MakeRelativePath(CurrentDir, AbsolutePathOfTargetDir)

Given our current directory and the full path to a target directory, return
the relative path from the former to the latter.

Thanks

- A

[quoted text, click to view]

Andrew Chalk
10/22/2007 9:09:35 AM
That looks like it.

Many thanks.

[quoted text, click to view]
GetCurrentDirectory + PathRelativePathTo?

[quoted text, click to view]

Ivo Beltchev
10/22/2007 9:27:52 AM
My assumption was that "current working directory" in the original =
message is the same as the current directory. It may also mean the =
directory of the executable, in which case GetModuleFileName can be =
used. It may also mean the directory from which the exe is launched, =
which may differ from the current directory or the exe directory. Then =
the OP has to call GetCurrentDirectory as soon as the exe is launched =
before the directory changes.

I'm also assuming that the OP is intelligent enough to know that a =
relative path is not always possible, for example if the two paths are =
on different volumes or servers. Then PathRelativePathTo will return an =
error code and he'll need some workaround, like using a full path =
instead.

Ivo


[quoted text, click to view]
Tony Proctor
10/23/2007 12:00:00 AM
There is a PathRelativePathTo API in shlwapi.dll. I think it's already been
mentioned in this thread now though so I guess you don't need me to point it
:-)

I noticed you cross-posted to a vsnet group too. I'm afraid I don't know
what the non-API .Net equivalent is

Tony Proctor

[quoted text, click to view]

Pops
10/23/2007 2:39:15 AM
[quoted text, click to view]

Andrew, I quickly pulled some "path" related c/c++ functions from my
pathlib.cpp library, and put this test demo "Relative.cpp" example.

Hope this helps

--
HLS

// File: V:\local\wc5\common\relative.cpp
// comple: CL relative.cpp" /W3 /GX /MD /D "_AFXDLL"

#include <stdio.h>
#include <afx.h>

typedef struct _SPLITFILEPARTS {
char drive[_MAX_DRIVE]; // WIN32 defines this as 3
char dir[_MAX_DIR]; // WIN32 defines this as 256
char fname[_MAX_FNAME]; // WIN32 defines this as 256
char ext[_MAX_EXT]; // WIN32 defines this as 256
} SPLITFILEPARTS, *PSLITFILEPATHS;

char *ExtractFilePath(char *dest, const char *s,
const BOOL noDrive = FALSE);
char *ExtractFileName(char *dest, const char *s,
const BOOL noExt = FALSE);

BOOL ExtractFileParts(const char *s, SPLITFILEPARTS &sf)
{
ZeroMemory(&sf,sizeof(sf));
if (s == NULL) return FALSE;
_splitpath(s, sf.drive, sf.dir, sf.fname,sf.ext);
return TRUE;
}

char *ExtractFileName(char *dest, const char *s,
const BOOL noExt /* = FALSE */)
{
SPLITFILEPARTS sf;
if (!ExtractFileParts(s,sf)) return dest;
if (noExt) sf.ext[0] = 0;
_makepath(dest,"","",sf.fname,sf.ext);
return dest;
}

CString ExtractFileName(const char *s)
{
CString q;
char *p = q.GetBuffer(MAX_PATH);
ExtractFileName(p, s);
q.ReleaseBuffer();
return q;
}

char *ExtractFilePath(char *dest, const char *s,
const BOOL noDrive /* = FALSE */)
{
SPLITFILEPARTS sf;
if (!ExtractFileParts(s,sf)) return dest;
if (noDrive) sf.drive[0] = 0;
_makepath(dest,sf.drive,sf.dir,"","");
return dest;
}

CString ExtractFilePath(const char *s)
{
CString q;
char *p = q.GetBuffer(MAX_PATH);
ExtractFilePath(p, s);
q.ReleaseBuffer();
return q;
}

CString ExtractFileDrive(const char *s)
{
if (s == NULL) {
return "";
}
CString q;
char *p = q.GetBuffer(MAX_PATH);
SPLITFILEPARTS sf;
ExtractFileParts(s,sf);
_makepath(p, sf.drive,"","","");
q.ReleaseBuffer();
return q;
}


CString ExtractFilePathNoDrive(const char *s)
{
CString q;
char *p = q.GetBuffer(MAX_PATH);
ExtractFilePath(p,s,TRUE);
q.ReleaseBuffer();
return q;
}

void SplitDirs(char *Path, char *Dirs[], int &DirCount)
{

int i = 0;
int j = 0;
while (Path[i]) {
if ((Path[i] == '\\') || (Path[i] == '/')) {
Path[i] = 0;
Dirs[j] = &Path[i+1];
j++;
}
i++;
}
DirCount = j-1;
}

/*
* ExtractRelativePath()
* given BaseName and DestName, return relative path
* if BaseName empty, then relative path is compared against
* current directory
*
*/

CString ExtractRelativePath(const CString &BaseName,
const CString &DestName)
{
char BasePath[MAX_PATH];
char DestPath[MAX_PATH];

strcpy(BasePath,BaseName);
if (BaseName.IsEmpty()) {
GetCurrentDirectory(sizeof(BasePath),BasePath);
}

if (_stricmp(ExtractFileDrive(BasePath),
ExtractFileDrive(DestName))) {
return DestName;
}

strcpy(BasePath,ExtractFilePathNoDrive(BasePath));
strcpy(DestPath,ExtractFilePathNoDrive(DestName));

char *BaseDirs[130];
char *DestDirs[130];
int BaseDirCount = 0;
int DestDirCount = 0;

SplitDirs(BasePath, BaseDirs, BaseDirCount);
SplitDirs(DestPath, DestDirs, DestDirCount);

int i = 0;
while ((i < BaseDirCount) && (i < DestDirCount)) {
if (_stricmp(BaseDirs[i], DestDirs[i]) != 0) break;
i++;
}
CString Result = ".\\";
for (int j = i; j < BaseDirCount; j++)
Result += "..\\"; // Do not localize
for (int k = i; k < DestDirCount; k++) {
Result += CString(DestDirs[k]) + "\\"; // Do not localize
}
Result += ExtractFileName(DestName);
return Result;
}

//--------------------------------------------
// MAIN
//---------------------------------------------
void main(char argc, char *argv[])
{

CString base = ""; // assume current directory
CString dest = "v:\\local\\wc5\\common";
// expecting ".\\common"
printf("rel path: %s\n",ExtractRelativePath(base,dest));

Andrew Chalk
10/25/2007 6:04:18 PM
Thanks!
[quoted text, click to view]

AddThis Social Bookmark Button