TheSwamp

Code Red => .NET => Topic started by: shers on October 28, 2015, 01:35:49 AM

Title: Relative Path problem
Post by: shers on October 28, 2015, 01:35:49 AM
Hi,

I have problem with the relative path in code to find a file.  The first time it works. In the same AutoCAD session, the second time, the path changes to C:\Users\xyz\AppData\Roaming\Autodesk\AutoCAD 2012 - English\R18.2\enu. Is there any solution to this problem please?

Thanks
Title: Re: Relative Path problem
Post by: Kerry on October 28, 2015, 02:30:21 AM

How are you trying to find the file ??
Title: Re: Relative Path problem
Post by: kpblc on October 28, 2015, 02:52:19 AM
What findfile function retrns?
And what is the code? What do you try to find? Maybe 'second time' document is newly created document? Try to save it.
Title: Re: Relative Path problem
Post by: shers on October 28, 2015, 04:36:55 AM
It is to pick the file from a particular location. For example,

string strFile = ".\\test\\abc.txt";

But it goes to the AutoCAD roaming folder.
Title: Re: Relative Path problem
Post by: kpblc on October 28, 2015, 05:15:58 AM
Try this:
Code: [Select]
(defun checkfile (file / _kpblc-conv-string-to-list)
  ;; (checkfile  ".\\test\\abc.txt")
  (defun _kpblc-conv-string-to-list (string separator / i)
    (cond
      ((= string "") nil)
      ((vl-string-search separator string)
       ((lambda (/ pos res)
          (while (setq pos (vl-string-search separator string))
            (setq res    (cons (substr string 1 pos) res)
                  string (substr string (+ (strlen separator) 1 pos))
                  ) ;_ end of setq
            ) ;_ end of while
          (reverse (cons string res))
          ) ;_ end of lambda
        )
       )
      ((wcmatch (strcase string) (strcat "*" (strcase separator) "*"))
       ((lambda (/ pos res _str prev)
          (setq pos  1
                prev 1
                _str (substr string pos)
                ) ;_ end of setq
          (while (<= pos (1+ (- (strlen string) (strlen separator))))
            (if (wcmatch (strcase (substr string pos (strlen separator))) (strcase separator))
              (setq res    (cons (substr string 1 (1- pos)) res)
                    string (substr string (+ (strlen separator) pos))
                    pos    0
                    ) ;_ end of setq
              ) ;_ end of if
            (setq pos (1+ pos))
            ) ;_ end of while
          (if (< (strlen string) (strlen separator))
            (setq res (cons string res))
            ) ;_ end of if
          (if (or (not res) (= _str string))
            (setq res (list string))
            (reverse res)
            ) ;_ end of if
          ) ;_ end of lambda
        )
       )
      (t (list string))
      ) ;_ end of cond
    ) ;_ end of defun

  (car
    (vl-remove nil
               (mapcar
                 (function
                   (lambda (x)
                     (findfile (strcat (vl-string-right-trim "\\" x) "\\" (vl-string-left-trim ".\\" file)))
                     ) ;_ end of lambda
                   ) ;_ end of function
                 (vl-remove "" (_kpblc-conv-string-to-list (getenv "ACAD") ";"))
                 ) ;_ end of mapcar
               ) ;_ end of vl-remove
    ) ;_ end of car
  ) ;_ end of defun
Code won't convert 'normal' relative path (like "..\\..\\..\\abc.txt") to 'absolute path.
Title: Re: Relative Path problem
Post by: Kerry on October 28, 2015, 06:03:58 AM
Try this:
Code: [Select]
(defun checkfile (file / _kpblc-conv-string-to-list)
  ;; (checkfile  ".\\test\\abc.txt")
 
Code won't convert 'normal' relative path (like "..\\..\\..\\abc.txt") to 'absolute path.

sresh is working in .NET, not vlisp
Title: Re: Relative Path problem
Post by: Kerry on October 28, 2015, 06:06:34 AM
It is to pick the file from a particular location. For example,

string strFile = ".\\test\\abc.txt";

But it goes to the AutoCAD roaming folder.

in isolation, this is almost useless
please provide some compilable code to demonstrate the issue.
Do you really expect others to guess as well as generate a possible code ??
Title: Re: Relative Path problem
Post by: Kerry on October 28, 2015, 06:11:21 AM

sresh,
Is the current drawing saved. ??
If so, where is it saved.

Perhaps it's defaulting to the user folder because it doesn't know where the .\xxx is ?
Title: Re: Relative Path problem
Post by: kpblc on October 28, 2015, 07:00:34 AM
Try this:
Code: [Select]
(defun checkfile (file / _kpblc-conv-string-to-list)
  ;; (checkfile  ".\\test\\abc.txt")
 
Code won't convert 'normal' relative path (like "..\\..\\..\\abc.txt") to 'absolute path.

sresh is working in .NET, not vlisp
Ah, sorry.
Title: Re: Relative Path problem
Post by: Kerry on October 28, 2015, 07:01:38 AM
:)
no problems.
Title: Re: Relative Path problem
Post by: Keith Brown on October 28, 2015, 08:19:39 AM
As Kerry said it is difficult to diagnose without some example code.  That being said this is what I use to make a path relative.  I didnt write the code but found it on http://www.stackoverflow.com (http://www.stackoverflow.com)

Code - C#: [Select]
  1. /// <summary>
  2. /// Creates a relative path from one file or folder to another.
  3. /// </summary>
  4. /// <remarks>Found at http://stackoverflow.com/questions/275689/how-to-get-relative-path-from-absolute-path </remarks>
  5. /// <param name="fromPath">
  6. /// Contains the directory that defines the start of the relative path.
  7. /// </param>
  8. /// <param name="toPath">Contains the path that defines the endpoint of the relative path.</param>
  9. /// <returns>The relative path from the start directory to the end path.</returns>
  10. /// <exception cref="ArgumentNullException"></exception>
  11. /// <exception cref="UriFormatException"></exception>
  12. /// <exception cref="InvalidOperationException"></exception>
  13. public static string MakeRelativePath(string fromPath, string toPath)
  14. {
  15.         if (string.IsNullOrEmpty(fromPath)) throw new ArgumentNullException(nameof(fromPath));
  16.         if (string.IsNullOrEmpty(toPath)) throw new ArgumentNullException(nameof(toPath));
  17.  
  18.         var fromUri = new Uri(fromPath);
  19.         var toUri = new Uri(toPath);
  20.  
  21.         if (fromUri.Scheme != toUri.Scheme) { return toPath; } // path can't be made relative.
  22.  
  23.         var relativeUri = fromUri.MakeRelativeUri(toUri);
  24.         var relativePath = Uri.UnescapeDataString(relativeUri.ToString());
  25.  
  26.         if (toUri.Scheme.ToUpperInvariant() == "FILE")
  27.         {
  28.                 relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
  29.         }
  30.  
  31.         return relativePath;
  32. }
Title: Re: Relative Path problem
Post by: Jeff H on October 28, 2015, 09:27:05 AM
Sounds like you got Automatic save turned on and that's after its first save
Title: Re: Relative Path problem
Post by: n.yuan on October 28, 2015, 09:35:40 AM
You'd better explain the relative path ".\xxxxx\xxxx.xxx" is RELATIVE to WHAT: current AutoCAD working directory? current drawing's directory? the location of .NET dll that uses this "relative path"? If the said file in that relative path can be searchable via AutoCAD' supporting paths?

Since you post in .NET forum, I assume the "relative path" would mean RELATIVE to the location of the .NET dll that uses this relative path. IN this case, you can use System.Reflection.Assembly.GetExecutingAssemly().Location to determine the location of running DLL, then you can determine the full path of the "relative path" accordingly.
Title: Re: Relative Path problem
Post by: CADbloke on October 28, 2015, 05:04:23 PM
Here's what I used recently to deal with relative / absolute paths: https://github.com/CADbloke/CodeLinker/blob/master/CodeLinker/PathMaker.cs (Great minds, eh Keith? ... line 17 in that)

I agree with Norman - you're not making sense. You have given us no context. What do you expect the path to be relative to? You may as well ask us "what's that on my desk just to my left?"

Relative to AutoCAD? AppDomain.CurrentDomain.BaseDirectory may be of help.

You'd better explain the relative path ".\xxxxx\xxxx.xxx" is RELATIVE to WHAT: current AutoCAD working directory? current drawing's directory? the location of .NET dll that uses this "relative path"? If the said file in that relative path can be searchable via AutoCAD' supporting paths?

Since you post in .NET forum, I assume the "relative path" would mean RELATIVE to the location of the .NET dll that uses this relative path. IN this case, you can use System.Reflection.Assembly.GetExecutingAssemly().Location to determine the location of running DLL, then you can determine the full path of the "relative path" accordingly.
Title: Re: Relative Path problem
Post by: Keith Brown on October 28, 2015, 05:16:22 PM
Here's what I used recently to deal with relative / absolute paths: https://github.com/CADbloke/CodeLinker/blob/master/CodeLinker/PathMaker.cs (https://github.com/CADbloke/CodeLinker/blob/master/CodeLinker/PathMaker.cs) (Great minds, eh Keith? ... line 17 in that)


I looked at mine again earlier this morning and noticed that I was documenting the exceptions (kinda) that were being thrown instead of handling them.  I decided to go ahead and wrap it all up in a try/catch block similar to yours and return the toPath if there was an error same as you.


One quick comment about your code.  Your try/catch block encompasses your argument null exceptions.  Won't they be caught by your catch block which I assume you don't want?  Or since you are throwing them they won't be caught?  I have never tried that before to see what would happen.


This is what I came up with for mine earlier.

P.S.  If you use resharper then look in to Exceptional (https://exceptional.codeplex.com/) as an Addin.  It can force you to either document all exceptions or make sure that you catch them.


Code - C#: [Select]
  1. /// <summary>
  2. /// Creates a relative path from the destination file/folder to the source file/folder to another.
  3. /// </summary>
  4. /// <remarks>Found at http://stackoverflow.com/questions/275689/how-to-get-relative-path-from-absolute-path </remarks>
  5. /// <param name="fromPath">
  6. /// Contains the directory that defines the start of the relative path.
  7. /// </param>
  8. /// <param name="toPath">Contains the path that defines the endpoint of the relative path.</param>
  9. /// <returns>The relative path from the start directory to the end path.</returns>
  10. /// <exception cref="ArgumentNullException"><paramref name="fromPath"/> or <paramref name="toPath"/> is <see langword="null" />.</exception>
  11. public static string MakeRelativePath(string fromPath, string toPath)
  12. {
  13.    if (string.IsNullOrEmpty(fromPath)) throw new ArgumentNullException(nameof(fromPath));
  14.    if (string.IsNullOrEmpty(toPath)) throw new ArgumentNullException(nameof(toPath));
  15.  
  16.    var relativePath = toPath;
  17.  
  18.    try
  19.    {
  20.       var fromUri = new Uri(fromPath);
  21.       var toUri = new Uri(toPath);
  22.  
  23.       if (fromUri.Scheme != toUri.Scheme)
  24.       {
  25.          return toPath;
  26.       } // path can't be made relative.
  27.  
  28.       var relativeUri = fromUri.MakeRelativeUri(toUri);
  29.       relativePath = Uri.UnescapeDataString(relativeUri.ToString());
  30.  
  31.       if (toUri.Scheme.ToUpperInvariant() == "FILE")
  32.       {
  33.          relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
  34.       }
  35.    }
  36.    // ReSharper disable ExceptionNotDocumentedOptional
  37.    catch (ArgumentNullException exception)
  38.    {
  39.       Log.Logger.Error(exception, "Unable to determine the relative path, the path variables passed to the URI are null."); // Should never happen.
  40.    }
  41.    catch (UriFormatException exception)
  42.    {
  43.       Log.Logger.Error(exception, "Unable to determine the relative path, an invalid Uniform Resource Identifier is detected.");
  44.    }
  45.    catch (InvalidOperationException exception)
  46.    {
  47.       Log.Logger.Error(exception, "Unable to determine the relative path, the instance represents a relative URI and this property is valid only for absolute URI's.");
  48.    }
  49.    // ReSharper restore ExceptionNotDocumentedOptional
  50.    return relativePath;
  51. }
Title: Re: Relative Path problem
Post by: CADbloke on October 28, 2015, 06:55:08 PM
One quick comment about your code.  Your try/catch block encompasses your argument null exceptions.  Won't they be caught by your catch block which I assume you don't want?  Or since you are throwing them they won't be caught?  I have never tried that before to see what would happen.
Ordinarily, yes but in this case Linker.Crash(Exception e, string message) handles all the problems in those apps. In the command line app it just rants to the log and crashes, in the GUI app it shows a message box, rants to the log and crashes. Actually, now that I think of it, the GUI just crashes too. Uh. Fixing that.

P.S.  If you use resharper then look in to Exceptional (https://exceptional.codeplex.com/) as an Addin.  It can force you to either document all exceptions or make sure that you catch them.
I do use that, and yes, it's a good 'un. For those who have never seen it ...
(https://dl.dropboxusercontent.com/u/5115091/Swamppix/Exceptional01.png?raw=1])
Title: Re: Relative Path problem
Post by: MexicanCustard on October 29, 2015, 07:48:55 AM
I was purposely avoiding answering the OP because of the ambiguity of his question.  Now that we're just guessing and throwing code out there, I'll share my two cents.

Code - C#: [Select]
  1. var relativePath = new Uri(fromPath).MakeRelativeUri(new Uri(toPath)); //This has %20 for spaces
  2. var pathName = relativePath.ToString().Replace("%20", " ");
Title: Re: Relative Path problem
Post by: Jeff H on October 29, 2015, 11:25:37 AM
Have no idea why done this way but its all relative(waka waka) anyways.

Code - C#: [Select]
  1.  public static class FileSystemInfoExtensions
  2.     {
  3.  
  4.  
  5.         public static bool HasParent(this DirectoryInfo directInfo, DirectoryInfo parentDirectInfo)
  6.         {
  7.             return FileSystemInfoHasParent(directInfo.Parent, parentDirectInfo);
  8.         }
  9.  
  10.         public static bool HasParent(this FileInfo fInfo, DirectoryInfo parentDirectInfo)
  11.         {
  12.      
  13.             return FileSystemInfoHasParent(fInfo.Directory, parentDirectInfo);
  14.         }
  15.  
  16.         private static bool FileSystemInfoHasParent(DirectoryInfo thisParentDirectInfo, DirectoryInfo parentDirectInfo)
  17.         {
  18.             string parent = parentDirectInfo.FullName.TrimEnd(Path.DirectorySeparatorChar);
  19.             while (thisParentDirectInfo != null)
  20.             {
  21.                 if (thisParentDirectInfo.FullName.Equals(parent, StringComparison.InvariantCultureIgnoreCase))
  22.                 {
  23.                     return true;
  24.                 }
  25.                 thisParentDirectInfo = thisParentDirectInfo.Parent;
  26.             }
  27.             return false;
  28.         }
  29.  
  30.         public static string GetRelativePathTo(this FileSystemInfo fromPath, FileSystemInfo toPath)
  31.         {
  32.             int fromAttr = GetPathAttribute(fromPath);
  33.             int toAttr = GetPathAttribute(toPath);
  34.  
  35.             StringBuilder path = new StringBuilder(260); // MAX_PATH
  36.             if (PathRelativePathTo(
  37.                 path,
  38.                 fromPath.FullName,
  39.                 fromAttr,
  40.                 toPath.FullName,
  41.                 toAttr) == 0)
  42.             {
  43.                 throw new ArgumentException("Paths must have a common prefix");
  44.             }
  45.             return path.ToString();
  46.         }
  47.  
  48.         public static string GetRelativePathTo(this FileSystemInfo fromPath, string toPath)
  49.         {
  50.             int fromAttr = GetPathAttribute(fromPath);
  51.             int toAttr = GetPathAttribute(toPath);
  52.  
  53.             StringBuilder path = new StringBuilder(260); // MAX_PATH
  54.             if (PathRelativePathTo(
  55.                 path,
  56.                 fromPath.FullName,
  57.                 fromAttr,
  58.                 toPath,
  59.                 toAttr) == 0)
  60.             {
  61.                 throw new ArgumentException("Paths must have a common prefix");
  62.             }
  63.             return path.ToString();
  64.         }
  65.  
  66.  
  67.  
  68.  
  69.         private static int GetPathAttribute(FileSystemInfo path)
  70.         {
  71.             if (!path.Exists) throw new FileNotFoundException();
  72.             return String.IsNullOrEmpty(path.Extension) ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL;
  73.  
  74.         }
  75.         private static int GetPathAttribute(string path)
  76.         {
  77.             DirectoryInfo di = new DirectoryInfo(path);
  78.             if (di.Exists)
  79.             {
  80.                 return FILE_ATTRIBUTE_DIRECTORY;
  81.             }
  82.  
  83.             FileInfo fi = new FileInfo(path);
  84.             if (fi.Exists)
  85.             {
  86.                 return FILE_ATTRIBUTE_NORMAL;
  87.             }
  88.  
  89.             throw new FileNotFoundException();
  90.         }
  91.  
  92.  
  93.  
  94.  
  95.         private const int FILE_ATTRIBUTE_DIRECTORY = 0x10;
  96.         private const int FILE_ATTRIBUTE_NORMAL = 0x80;
  97.  
  98.         [DllImport("shlwapi.dll", SetLastError = true)]
  99.         private static extern int PathRelativePathTo(StringBuilder pszPath,
  100.             string pszFrom, int dwAttrFrom, string pszTo, int dwAttrTo);
  101.  
  102.     }
  103.