Is it possible to avoid MAX_PATH limit using WiX variables? - c#

I'm developing a project in WinForms, and I'm on the process of creating an installer using WiX.
But when the installer is going to copy a .dll that comes from a really long path, Visual Studio says this:
'Really long route'\EnterpriseLibrary....\ is too long, the fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
I found articles that talks about MAX_PATH limitations like said in this StackOverflow question related with the Windows API.
I'm working on a big team, and we just discovered this known error, but we are not allowed to shorten or modify the path.
I tried the solution that the link above says, using the \\?\ characters before, so my WixVariables remain like this:
<?define examplesPath="\\?\$(sys.CURRENTDIR)\..\..\ExamplesFolder" ?>
That results to be something like this:
\\?\C:\reallylongpath\files
But it doesn't seem to work for WiX variables.
So my question is:
Is there any way to avoid this 260 characters limitation? If so, how?
Please, I need an answer on this!
EDIT: While I try #Jans' suggestion, I also found that, if I add the \\?\ string to my WiX variable, the error message changes. Now it says:
The system cannot find the file '\\?\Reallylongpath\..\..\andreallylongfile\'
I'm thinking that maybe the \\?\ is not converting the ..\ that I need to use... Any suggestion here?
EDIT2: I found this line at msdn:
A consequence is that \\?\ turns off file name normalization performed by Windows APIs, including removing trailing spaces, expanding ‘.’ and ‘..’
:___(

This is a terrible hack, but you could create a symlink to the real directory. A symlink is like a regular link, except for that it behaves exactly like a real directory.
Suppose you have a really long directory that causes you trouble:
C:\blahblahblah\thisisreallylong\andnotaccessible\blahblahblah\
You can create a symlink to it, that has any name you like, but is considerably shorter. Think of it as an alias. So if you call this on your console, for example in the C:\temp directory:
C:\temp\>mklink /D reallylong C:\blahblahblah\thisisreallylong\andnotaccessible\blahblahblah\
then afterwards, you can access C:\temp\reallylong as if it were your real directory. Note that you need local admin rights to create symlinks.

Related

ASP.NET Publish Error (The specified path, file name, or both are too long)

I am getting an error like the following while publishing a project with Visual Studio:
Copying file Areas\AdminPanel\Content\assets\global\plugins\bootstrap-editable\inputs-ext\wysihtml5\bootstrap-wysihtml5-0.0.2\bootstrap-wysihtml5-0.0.2.css to obj\Release\Package\PackageTmp\Areas\AdminPanel\Content\assets\global\plugins\bootstrap-editable\inputs-ext\wysihtml5\bootstrap-wysihtml5-0.0.2\bootstrap-wysihtml5-0.0.2.css failed. The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
Is there a simple way to solve this problem or should I make the path shorter?
I am working with ASP.NET Web Forms btw.
That is a Windows limitation. You can disable it this way:
Execute 'regedit.exe'
Navigate to
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem"
Find a value named LongPathsEnabled and double-click it. If you don’t see the value listed, you’ll need to create it by right-clicking the FileSystem key, choosing New > DWORD (32-bit) Value, and then naming the new value LongPathsEnabled
Change the value from 0 to 1 in the “Value data” box and then click OK.
After that, you would probably have to restart visual studio.
Windows has a limitation that can be configured. See NicoRiff's answer.
That beeing said, the following string is "only" 173 chars long:
obj\Release\Package\PackageTmp\Areas\AdminPanel\Content\assets\global\plugins\bootstrap-editable\inputs-ext\wysihtml5\bootstrap-wysihtml5-0.0.2\bootstrap-wysihtml5-0.0.2.css
I suggest you, to create a folder in the root of your disc, for example D:/Dev where all your projectes are stored.
Changing the registry would also be an option, but needs to be configured for every developer, which is suboptimal. Generaly you should go for shorter paths. Checkout and Build should be the motto.
When you ship the software you should also minify/bundle your client side scripts. This way you only have one short path bundle.css in your published output.

Deleting long path too long folder from Network Share

I'm trying to delete folders in a shared location on a network using C#. Some of the folder paths are too long for Windows to handle. I've tried multiple options for this. The best one I found was creating a FileSystemObject, adding \\?\ to the path and calling DeleteFolder on the path that I want to delete, which works on my local computer for paths that are too long, because I have mapped drives like C: and G: etc, but when I try to use it on a Network share folder I get either a HRESULT: 0x800A004C (CTL_E_PATHNOTFOUND) or value does not fall within the expected range.
The following is my code:
private static void DeletePathWithLongFileNames(string path)
{
string tmpPath = #"\\?\" + path;
FileSystemObject fso = new FileSystemObject();
fso.DeleteFolder(tmpPath, true);
}
let's say for example, the network + share folder is \\myServer\mySharedFolder\folder1\etc\etc, which would be the path string I'm sending to my delete function
then the tmpPath is showing as "\\\\?\\\\\\myServer\\mySharedFolder\\folder1\\etc\\etc"
I don't know much about UNC so I don't know if this is what is wrong or not. I'm pretty sure there is something wrong with my tmpPath variable, but again I'm not sure. Maybe it's a syntax error But I can't for the life of me figure out what is wrong. Thanks in advance for the help
EDIT: I believe I have found the answer, I am testing it right now. So far it has worked for me. if I run the DeleteFolder method on the following path \\?\UNC\server\sharedFolder\folder1\etc\etc" this seems to work. Now I just have to figure out how to get rid of all those extra slashes.
EDIT 2: This does work, tested it on a Share folder on a network. It just came down to me not understanding UNC paths.
The safe way to delete paths that are too long is to use AlphaFS. AlphaFS is a .NET library providing more complete Win32 file system functionality to the .NET platform than the standard System.IO classes. The most notable deficiency of the standard .NET System.IO is the lack of support of advanced NTFS features, most notably extended length path support (eg. file/directory paths longer than 260 characters).
See Directory Delete: http://alphafs.alphaleonis.com/doc/2.2/api/html/BE179564.htm
Alphaleonis.Win32.Filesystem.Directory.Delete(path)

How to convert DOS path to normal path (.net)

I have a program that tracks changes on a local folder using a FileSystemWatcher object.
The issue is that sometimes, on some environments and situations (I do not know which ones), this watcher gives me an event on a DOS path ("/Hello/How/Are/You" becomes something like "/HE~1/HO~1/AR~1/YO~1").
What I am looking for is a way to force this path back into its full and normal aspect.
Or at least something that can tell me that the path is indeed a DOS path, so I can process the entry differently.
EDIT: it has to work on long paths (+260 chars), so Path.GetFullPath(sShortPath) does not work for me here!
Path.GetFullPath(#"/HE~1/HO~1/AR~1/YO~1") should do what you need.
The best method depends what you are looking for, if you just want to access the file once then the 8byte file names will work for internal file references
if you want to display to the user or store then there are 2 option
Path contains most of the tools you need to manipulate paths
fullPath = Path.GetFullPath(path1);
FileInfo and DirectoryInfo these 2 classes provide persistent access to files and directory information and while they can be created with any valid path both have a Full name property that provides access to the full path
As others said, Path.GetFullPath(sShortPath) works fine if not used on very long paths (+260 chars).
Here is a link I followed that worked for me.
GetLongPathName from kernel32.dll worked fine with me, I just had to change the 255 StringBuilder limit to a higher value to make it work with long paths.

Significance of a PATH explained

This is probably a rudimentary question but I am still kinda new to programming and I've wondered for awhile. I've done multiple projects in Python, C#, and Java, and when I try to use new libraries (especially for Python) people always say to make sure its in the right PATH and such. I just followed an online tutorial on how to install Java on a new computer and it rekindled my question of what a path really is. Is the Path just were the programming language looks for a library in the file system? I get kinda confused on what it's significance is. Again, I'm sorry for the wide question, its just something that I've never quite gotten on my own programming.
EDIT: I just wanted to thank everyone so much for answering my question. I know it was a pretty dumb one now that I've finally figured out what it is, but it really helped me. I'm slowly working through as many C#, Java and Python tutorials as I can find online, and it's nice to know I have somewhere to ask questions :)
The PATH is an environment variable which the shell (or other command interpreter) uses to search for commands. Usually (always?) commands are found with a greedy algorithm, so entries that come first in the PATH are returned first. For example, a command in /usr/local/bin will override a command in /usr/bin given a PATH such as
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
while the purpose is consistent, the syntax is slightly different on WINDOWS - you would use
C:\> ECHO %PATH%
to "echo" your PATH.
First my shell is going to search /usr/local/sbin then /usr/local/bin then /usr/sbin and then /usr/bin before searching /sbin and /bin if the command isn't found then it will report that it couldn't find such a command...
# Like so
$ thisprogramdoesntexist
thisprogramdoesntexist: command not found
Now, on Linux at least, there's also a LD_LIBRARY_PATH which the system will use to search for dynamic libraries (greedily), on Windows I think it just uses the PATH. Finally, Java uses a CLASSPATH which is similar (but used to search for classes and JARs).
On Linux one might add an entry to the PATH like so,
$ export PATH="$PATH:/addNewFolder"
While on Windows you might use
set PATH=%PATH%;c:\addNewFolder
Sometimes, you might manipulate your PATH(s) to enable specific functionality, see update-java-alternatives on Ubuntu for an example.
A PATH is a file directory on your computer. If you need to install a programming language, you might need to put it in your system PATH variable. This means that the system looks to these files for different information, IE where the libraries for the code you are using are.
Hope that helped!
Exactly as other said, PATH is a list of folders that is included in the search -other than the current folder- and you can always access straight away. It's one of the Environment Variables.
For example, we have the python folder in C:\Python27. I'm sure you know that to run a python file, we commonly use python script.py.
What happens is that the command line searches for python.exe in your current folder, and if not found, search it in the folders in the path variable.
To read the path, you can, straightforwardly use:
$ PATH
If you're on windows, like i am, an easy way to deal with this is to just use System Properties. Just type it in the start menu, open it, and go to the 'advanced' tab. Click on the Environment Variables, there! You'll see a PATH variable, and you can modify it as you want.
I myself use more than one version of Python, and to deal with this, i appended all the folders to PATH, and changed my python.exe to pythonversion_number.exe. Problem solved! Now, i can run this in the command line:
$ python26 script.py
$ python33 script2.py
Some further reading on this, if you're interested, here's a good question asked
Hope this helps!
The best resource (so far) about PATH information, you can see in this question:
https://superuser.com/questions/284342/what-are-path-and-other-environment-variables-and-how-can-i-set-or-use-them
Stack Overflow is not the best place to search about this, always check the amazing
https://superuser.com/ for this kind of question.
PATH is a symbolic name usually associated to string values separated by a semicolons (where each string part is a directory name). This symbolic name (and its values) is handled by the operating system and could be modified by the end user through the some command line instruction like SET PATH=........ or through some kind of user interface configuration tool.
It is common practice for tools like compilers or other programming tools to look at this symbolic name and use the list of string values for searching files that are not directly available in the current folder used by the tools.
So, if an installation procedure set the PATH symbol in this way
SET PATH=%path%;C:\PROGRAM FILES\MYTOOLFOLDER;
it means, set the PATH symbol to the previous value (%PATH%) and add another string value to it (C:\PROGRAM FILES\MYTOOLFOLDER).
Then the tool, when it needs to search for a particular file or library, could read the PATH symbol values, split them at the semicolons and iteratively look at the directories listed one by one looking for the file required.
In C# programming, for example, the tool code could contain something like this
string pathSymbol = Environment.GetEnvironmentVariable("PATH");
string[] pathFolders = pathSymbol.Split(';');
foreach(string folder in pathFolders)
{
if(File.Exists(Path.Combine(folder, "mylibrary.dll"))
{
..... do whatever you need to do with the file
}
}
This example assumes a Windows environment.

Directory.SetCurrentDirectory throws PathTooLongException

There are several related questions on stackoverflow but either my situation is different or I am too dumb to relate those to situation. I am hoping someone can help me with this. Further I am not even much of a .NET developer so I apologize in advance for any wrong terminology use.
My scenario is as follows: The tool that is used to deploy our .net application (One Click?) puts it in a directory whose full name exceeds 300 characters. The application uses a third party component -- lets call it dbstore -- that processes the specified file that resides in the application deployment directory.
So far we were using Assembly.GetExecutingAssembly().GetName().CodeBase to construct the fully qualified name of the file to pass to dbstore. But dbstore uses old style APIs and fails when it tries to open the file.
Since dbstore is not expected to change soon, it was recommended that the application chdir to the deployment directory and pass a relative path name in current directory to it. This is also the approach described in the accepted response PathTooLongException in C# code
However I find that Directory.SetCurrentDirectory also throws PathTooLongException. This happens even when I am using UNC path name, e.g a name starting with \\?\0000000000000\...
Am I doing something fundamentally wrong? Is there another function to use?
EDIT: It seems there is no way to achieve what I am looking for. Far as I can tell there is no way to set current directory to a long path.
Do you get a similar result when using Environment.SetCurrentDirectory() ?
If so, you may want to change your directory subfolder after subfolder.
EDIT:
Windows actually sets a limitation of 255 chars for a file path (WinXP) or 260 chars (Vista).
Note that this limitation does not apply for the filesystem, so you can have a file stored in such a long directory path, but Windows Explorer and many Windows services cannot read from such path.
Actually it seems to also include .NET framework methods since you cannot access such files. You may need to write your own filesystem API, but that's a bit too much overhead. Can't you just shorten the file path ? Does Windows offer a shortened way to address a file (like 8 octet file names) ?
Source: http://labnol.blogspot.com/2006/10/limitations-with-long-file-names-on.html

Categories