Opening long file names in Windows using fopen with C - c

I have trouble here using fopen to open files which have paths longer than the 260 characters supported by Windows natively.
I found out about the prefix \\\\?\\ which I need to put in front of the path to be able to handle the file.
My question is: Is this still valid in combination with fopen? I have still trouble to open the files, but I do not find information about it. My paths look like:
\\\\?\\C:\\Deposit\\Source\\Here_Comes_Now_A_List_Of_Many_Subdirs_And_A_Long_File_Name
I am not able to use the Windows API due to the requirement to write a cross-platform tool.

Just to update with the current state: I'm just quoting https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#enable-long-paths-in-windows-10-version-1607-and-later:
Starting in Windows 10, version 1607, MAX_PATH limitations have been
removed from common Win32 file and directory functions. However, you
must opt-in to the new behavior. To enable the new long path behavior,
both of the following conditions must be met: ...
And it is:
1. Having <longPathAware>true</longPathAware> in your application manifest (it was not default in my C++ Visual Studio project). My manifest file looks like this:
<assembly>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</windowsSettings>
</application>
</assembly>
and I have added it into Project Options -> Manifest Tool -> Input and Output -> Additional manifest files in my C++ Visual Studio project.
2. Enabled long paths in Windows (this can be done through registry (in item Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled by setting to 1) or Microsoft says that in Local Group Policy (item Computer Configuration -> Administrative Templates -> System -> Filesystem -> Enable Win32 long paths) - but this does not work for me).
Having both the above configured, you can simply use FILE *f = fopen("../my-very-long-path/my-file.txt") without any limitations (e.g. relative dirs and / with \ replacement work).

You could work around this limitation in a cross-platform way with conditional compilation:
#ifdef WIN32
myFile = _wfopen( ... )
#else
myFile = fopen( ... )
#endif
I think any non-trivial cross-platform project will have to do this somewhere, or else use a library (like SDL) that does.

Related

How to Use MuJoCo on Windows

This is a very easy question, but I'm struggling unreasonably hard to find answers online.
DeepMind just made MuJoCo free, so I decided to download it on my Windows computer and test it out. When I install, however, all I get is a folder.
I've created a different folder (not inside the downloaded folder), and copy pasted the hello.xml and hello.c files from the tutorial into this new folder. However, VSCode has underlined #include "mujoco.h" in red inside hello.c with the warning cannot open source file "mujoco.h".
I assume that I need to add some things to my path or somehow make my compiler able to find the header file. How should I go about doing this?
Overall, I want to be able to run hello.c.
(I have looked at many different links, which I can link here to prove I've researched elsewhere if needed, but most resources online seem to either 1. Assume things will just work / that you have experience with C and library importing 2. Are for Macs/Linux or 3. Are for mujoco-python)
TL;DR
Create empty visual C++ project
Copy the code
Add MuJoCo Header files via VCC++ Directories -> Include Directories (make sure the set the platform to x64)
Add Library Directories of Mujoco installation ("bin" directory) via Linker -> Input -> Additional Library Directories.
Add the library names (glfw3.lib, mujoco200.lib... etc.) via Linker -> General -> Additional Dependencies
Compile
Put the resulting exe into the bin dir of the MuJoCo installation
Create the project
Open Visual Studio File -> New -> Project -> Visual C++ -> Empty Project
Write the Code
stackoverflowMuJoCo -> Source Files -> Add New Item -> C++ File (I called it "main.cpp" but it shouldn't matter)
Copy the code from hello.c into main.cpp
#include "mujoco.h"
#include "stdio.h"
char error[1000];
mjModel* m;
mjData* d;
int main(void)
{
// activate MuJoCo
mj_activate("mjkey.txt");
// load model from file and check for errors
m = mj_loadXML("../model/hello.xml", NULL, error, 1000);
if( !m )
{
printf("%s\n", error);
return 1;
}
// make data corresponding to model
d = mj_makeData(m);
// run simulation for 10 seconds
while( d->time<10 )
mj_step(m, d);
// free model and data, deactivate
mj_deleteData(d);
mj_deleteModel(m);
mj_deactivate();
return 0;
}
*note i downloaded it before deepmind took over it so I still need to use the mj_activate call but you can just ignore it.
Also i change the path to hello.xml because later i am going to copy the executable into the bin dir of the MuJoCo installation(see below)
Add the header files
Right Click on the Project -> Properties
Change Configuration from whatever is selected (most likely Debug/x86) to "All Configurations" and set the Platform to x64*
VCC++ Directories -> Include Directories
Add the include directories of your MuJoCo installation "mujoco200_win64\mujoco200_win64\include" (should be a path like this)
*this makes sure you don't have to repeat the whole process for every configuration.
VSCode has underlined #include "mujoco.h" in red inside hello.c
This should now be gone.
Add the libraries
Right Click on the Project -> Properties
Configuration Properties -> Linker -> Input -> Additional Dependencies
Enter the names of the .lib files located in your "installation" of MuJoCo
Linker -> General -> Additonal Library Directories add the "mujoco200_win64\mujoco200_win64\bin" directory
The compilation should now succeed but the execution will probably fail
Execution and Debugging
At this stage the execution will probably fail with the following errors message.
To solve this you can just copy the outputed exe file stackoverflowMuJoCo\x64\Release\stackOverflowMuJoCo.exe into the bin directory of your MuJoCo installation.
This will make sure it can find the required dll's.
If you want to be able to debug: manually copy all the dll files into the "stackoverflowMuJoCo\x64\Debug" directory.
Warning
The code from the hello world example is passive simulation this means you won't see anything on the screen.
If you want to see something replace the code with this: https://github.com/atabakd/MuJoCo-Tutorials/blob/master/src/0_preliminaries/pd.cpp and add the invertedPendulum.xml to the models directory.
Some notes
There is probably a better/easier workflow but right now I just tried to get it to work. Also I used a different version of MuJoCo than you but it should basically work the same way (except for the activation stuff).
Installing the C version of MuJoCo 2.2.1 on windows and compiling/running code
(A) Installing MuJoCo and loading a model file
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A1) Navigate to https://github.com/deepmind/mujoco/releases
and download the windows installation, mujoco-2.2.1-windows-x86_64.zip
Unzip this file and put it in a good location (e.g., Documents)
A2) Navigate to bin folder and double click “simulate”. This will open up a GUI.
A3) To load a model, go to the model folder and drop an xml, say humanoid.xml onto the open window. If everything worked fine, you should see a humanoid in the window
(B) Compiling the C programs provided by Deepmind
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
B1) Assuming you have done A1) above
B2) Download the Visual Studio Installer (select community version) here: https://visualstudio.microsoft.com/downloads/
Once the installer has downloaded, run it. When prompted to choose programs, choose the one that says “Desktop development with C++” (see screenshot below). Please restart your computer after installation.

B3) Now we will get some additional libraries to compile and create executables for mujoco on windows. Go to https://github.com/glfw/glfw/releases and download the latex version for Windows (usually glfw-3.x.x.bin.WIN64.zip). Unzip the file.
Now we will drag and drop some files from the glfw folder to mujoco
i) Copy the entire include/GLFW subdirectory to mujoco/include/GLFW.
ii) Copy glfw3dll.lib from the subdirectory corresponding into your compiler (here the compiler is lib-vc2022) to mujoco/lib/glfw3dll.lib.
iii) Copy glfw3.dll from the subdirectory corresponding into your compiler (here the compiler is lib-vc2022) to mujoco/bin/glfw3.dll.
B4) We will open the x64 shell to compile and run MuJoCo. Go to: Start (bottom left corner) —> Visual studio —> x64_Native Tools Command Prompt.
From this shell navigate to the sample folder. Then type make or nmake.
B5) Navigate to bin folder. (cd .. followed by cd bin). Then type simulate. Now you can do A3) above.
This video explains these steps: https://youtu.be/u6tNfvLXK-I

vi/vim - custom formatting depending on presence of special file or tag inside code

Question
Is there a simple/reliable way to have VIM, on a project/directory specific base, either detect a special file (ie: custom .vimrc with a couple settings), or to change run-time settings based on the presence of a special tag/string/hash in a comment at the beginning of a c source (.c) or header (.h) file? The string/hash must map to a function/setting in the .vimrc file, and must not contain the actual settings themselves.
Background
I have a mutli-developer project where we all have a common set of code style settings for our various editors (emacs and vim, primarily), and we all adhere strictly to these settings, such as newline style (CR versus CR+LF), indentation (length, hard-tabs versus expanded-as-spaces), and so on.
Problem
I'm creating a few new projects that, for reasons beyond our control (ie: static code analysis tool we have to use), will require different style settings than ours. There are ways to bypass this in the static code analysis tool, but there's a non-technical/legal requirement that we avoid disabling "features" of this tool.
For each of these new projects, I would like to somehow make vi/vim aware of some special flag, either by the presence of a special file in the root of the project's directory structure, or by a special keyword/tag/hash/etc I could put inside a /* C-style block comment */. When vi/vim is aware of the presence of this "trigger", I would want it to invoke a function to override the style settings for newlines, indentation, etc. If this is possible, is it also possible to have several, mutually exclusive such "triggers" so that everyone has a common .vimrc and the project determines which style to utilize?
Question - redux
Is there a straightforward way to accomplish this?
One solution: modelines (:help modeline) for Vim and file variables for Emacs.
Those are special comments you put in your files that are interpreted by your editor. You can use them to set indent style, file encoding, etc.
In my opinion, modelines are ugly noise.
One solution for Vim: .exrc (:help 'exrc').
You can put your project-specific settings in a .exrc file at the root of your project. The manual claims this solution is insecure but I fail to see how normal functioning adult could be beaten by it. YMMV.
One solution for Vim: directory-specific autocommands.
That's the safer alternative mentioned at the end of :help 'exrc' but it requires each contributor to add stuff to his own vimrc so… not that useful I guess.
The definitive solution: editorconfig.
You put your settings in a .editorconfig at the root of your project and let each contributor's IDE/editor deal with it.
... to change run-time settings based on the presence of a special
tag/string/hash in a comment at the beginning of a c source (.c) or
header (.h) file?
Yes, they're called modelines. http://vim.wikia.com/wiki/Modeline_magic
They can appear at the start or end of files.
An example from some C sources of mine:
/* vim:ft=c:expandtab:sw=4:ts=4:sts=4:
*/
See :help modeline in vim for more info.
Central configuration
If it's okay to configure the specific commands / local exceptions centrally, you can put such autocmds into your ~/.vimrc:
:autocmd BufRead,BufNewFile /path/to/dir/* setlocal ts=4 sw=4
It is important to use :setlocal instead of :set, and likewise :map <buffer> ... and :command! -buffer ....
On the other hand, if you want the specific configuration stored with the project (and don't want to embed this in all files via modelines), you have the following two options:
Local config with built-in functionality
If you always start Vim from the project root directory, the built-in
:set exrc
enables the reading of a .vimrc file from the current directory. You can place the :set ts=4 sw=4 commands in there.
Local config through plugin
Otherwise, you need the help of a plugin; there are several on vim.org; I can recommend the localrc plugin (especially with my own enhancements), which even allows local filetype-specific configuration.
Note that reading configuration from the file system has security implications; you may want to :set secure.
I've covered the main alternatives in this answer : https://stackoverflow.com/a/456889/15934 (Yes, your question is almost a duplicate: different formulation, but same solutions).
Modelines are really limited: you have to use a plugin to set things that are not vim options.
.exrc doesn't look behind the current directory
editorconfig is restricted to very specific options: don't expect to forward plugin specifications like where compilation directories are (this is how I support multiple compilation modes with CMake -- others prefer playing with ccache and tuning the CMakeCache, but this doesn't work well when using g++ and clang++ one after the other), how the linter shall be called, your naming conventions...
autocommand don't scale and cannot be ported easily from one directory to the other.
In the end, the best solutions are plugin based IMO: There a plenty plugin solutions see the non exhaustive list at the end of my local_vimrc plugin's README
Note also that since my previous answer, I've initiated another experiment to simplify project management. For instance, I introduce p:variables which are variables shared among all buffers belonging to a project.

prepend the "\\?\" string to the path - DriverPackageUninstall

I used DriverPackageUninstall, to uninstall my driver. For this API I need to give "Inf Path" as the input. And I need to give this path as UNICODE string. To do this, I took the following statement from MSDN as reference.
For a Unicode string, the maximum length is 32,767 characters. If you
use the Unicode version, prepend the "\?\" string to the path. For
general information about the format of file path strings, see Naming
a File in the MSDN Library.
But when I try the same in my code its not working. Can someone give me some examples on how to prepend the "\?\" before the path? Thanks..
UPDATE :
I tried with the below code as sample
#define UNICODE
#define _UNIOCDE
#define WINVER 0x501
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
int main () {
PTCHAR DriverPackageInfPath = TEXT("\\?\\c:\\Documents and Settings\\Desktop\\My.inf");
FILE * Log;
Log = _wfopen( TEXT(DriverPackageInfPath, TEXT("a"));
if ( Log == NULL ) {
MessageBox(NULL, TEXT ( "Unable to open INF file\n" ),
TEXT ( "Installation Error" ), 0 | MB_ICONSTOP );
exit ( 1 );
} else {
printf ("INF file opened successfully\n");
}
return 0;
}
UPDATE:
".\dist\Driver\My.inf" How to add "\\?\" before this kind of paths? "\\?\.\dist\Driver\My.inf" is not working.
You have error in string constant:
TEXT("\\?\\c:\\Documents ...."
should be
TEXT("\\\\?\\c:\\Documents ...."
Read carefully, escape carefully : http://msdn.microsoft.com/en-us/library/windows/hardware/ff552316%28v=vs.85%29.aspx
UPDATE:
From http://msdn.microsoft.com/en-us/library/aa365247.aspx :
Win32 File Namespaces
The Win32 namespace prefixing and conventions are summarized in this section and the following section, with descriptions of how they are used. Note that these examples are intended for use with the Windows API functions and do not all necessarily work with Windows shell applications such as Windows Explorer. For this reason there is a wider range of possible paths than is usually available from Windows shell applications, and Windows applications that take advantage of this can be developed using these namespace conventions.
For file I/O, the "\?\" prefix to a path string tells the Windows APIs to disable all string parsing and to send the string that follows it straight to the file system. For example, if the file system supports large paths and file names, you can exceed the MAX_PATH limits that are otherwise enforced by the Windows APIs. For more information about the normal maximum path limitation, see the previous section Maximum Path Length Limitation.
Because it turns off automatic expansion of the path string, the "\?\" prefix also allows the use of ".." and "." in the path names, which can be useful if you are attempting to perform operations on a file with these otherwise reserved relative path specifiers as part of the fully qualified path.
Win32 Device Namespaces
The "\.\" prefix will access the Win32 device namespace instead of the Win32 file namespace. This is how access to physical disks and volumes is accomplished directly, without going through the file system, if the API supports this type of access. You can access many devices other than disks this way (using the CreateFile and DefineDosDevice functions, for example).
For example, if you want to open the system's serial communications port 1, you can use "COM1" in the call to the CreateFile function. This works because COM1–COM9 are part of the reserved names in the NT namespace, although using the "\.\" prefix will also work with these device names. By comparison, if you have a 100 port serial expansion board installed and want to open COM56, you cannot open it using "COM56" because there is no predefined NT namespace for COM56. You will need to open it using "\.\COM56" because "\.\" goes directly to the device namespace without attempting to locate a predefined alias.
Another example of using the Win32 device namespace is using the CreateFile function with "\.\PhysicalDiskX" (where X is a valid integer value) or "\.\CdRomX". This allows you to access those devices directly, bypassing the file system. This works because these device names are created by the system as these devices are enumerated, and some drivers will also create other aliases in the system. For example, the device driver that implements the name "C:\" has its own namespace that also happens to be the file system.
APIs that go through the CreateFile function generally work with the "\.\" prefix because CreateFile is the function used to open both files and devices, depending on the parameters you use.
If you're working with Windows API functions, you should use the "\.\" prefix to access devices only and not files.
Most APIs won't support "\.\"; only those that are designed to work with the device namespace will recognize it. Always check the reference topic for each API to be sure.
So your relative path can be
\\?\.\dist\driver\My.inf
escaped form is
\\\\?\\.\\dist\\driver\\My.inf
You only need to prepend \\?\ to the path if it is longer than MAX_PATH characters.

fopen fails mysteriously under Windows

Maybe I just have another black out but, this one line is giving me a lot of troubles:
FILE *fp = fopen("data/world.data", "rb");
This works fine under Linux when compiled with GCC. But when I compile it with Visual Studio, it crashes. fp is always NULL. Both the BIN and the EXE are in the exact same directory. Now, to make things even crazier, when I run the EXE using Wine under Linux... it... works...
I have absolutely not a god damn clue what's going on here. Maybe it's some insanely stupid mistake on my side, but I cannot get this thing to run under Windows :/
Also, I have another program which works just fine, there the data files are also contained in a sub directory named data.
EDIT:
To make it clear neither / NOR `\ * do work.
EDIT 2:
OK I've given up on this, maybe someone has fun trying to figure it out, here's ZIP containing the EXE, Debug Data for VS etc.:
https://dl.dropbox.com/u/2332843/Leaf.zip
EDIT 3:
Compiled it with CodeBlocks and MinGW, works like a charm. Guess it has to do something with MSVC or the Project Settings in VS.
It sounds like data isn't a subdirectory of your current directory when you run the program. By default (for x86 targets) VS will build and run your program from either a DEBUG or RELEASE subdirectory of the base directory you've created for the project. You can modify the directory that will be "current" when it runs though (e.g., project | properties | configuration properties | debugging for VS 2008).
Edit: While Windows requires that you use a backslash as a directory separator at the command line, a forward slash works fine in code -- this is not the source of your problem.
In windows you have to write the following:
FILE *fp = fopen("data\\world.data", "rb");
This is like that because the backslash is a special character (so a backslash in a string is written using \ and a quotation symbol is \" and so with other special characters).
Since this issue happens only on windows. I doubt whether the file is really named "world.data". As you know, the default setting for windows hides the file extention. Is its real name world.data.xxx?
Include a line to GetCurrentDirectory(), to see if you are running from the directory you expected.
When I develop in C#/ C++ on visual studio, I normally get to run it from the debug folder. I don't think it matters if forward slash is used in place of backslash in .net.
I happened to have the same problem, and suddenly i figured it out.
That should be your windows fault.
Let's say, FILE *fp = fopen("data/world.data", "rb"); in windows, if you hide the extensions, then you can see the file data/world.data, but actually it maybe /data/world.dat.txt or somewhat.
So please check the extensions.
Hope it helps!
I ran into this today, and it happened because I used "br" instead of "rb" on that mode argument.
The underlying fopen is throwing an exception of some kind, which only registers as a crash. It's not bothering to return the standard NULL response or set the associated error values.
I'm not sure but it may be because you're using slash instead of (an escaped) backslash in the path?

File Operations in Android NDK

I am using the Android NDK to make an application primarily in C for performance reasons, but it appears that file operations such as fopen do not work correctly in Android. Whenever I try to use these functions, the application crashes.
How do I create/write to a file with the Android NDK?
Other answers are correct. You can open a file through the NDK using FILE and fopen, but don't forget to place a permission for it.
In the Android manifest place:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
File IO works fine on Android using JNI. Perhaps you are trying to open a file with a bad path and not checking the return code? I modified the hello-jni example to demonstrate that it is indeed possible to open file and write to it. I hope this helps.
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <string.h>
#include <jni.h>
#include <stdio.h>
/* This is a trivial JNI example where we use a native method
* to return a new VM String. See the corresponding Java source
* file located at:
*
* apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java
*/
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
FILE* file = fopen("/sdcard/hello.txt","w+");
if (file != NULL)
{
fputs("HELLO WORLD!\n", file);
fflush(file);
fclose(file);
}
return (*env)->NewStringUTF(env, "Hello from JNI (with file io)!");
}
Here is the result after running it on my phone (with an SD card):
$ adb -d shell cat /sdcard/hello.txt
HELLO WORLD!
Make sure to use the Java getExternalStorageDirectory() call to get the real path to the sdcard since newer devices don't simply map it to "/sdcard". In that case trying to use a hardcoded location of "/sdcard" will fail.
I can also verify that fopen() works correctly, but not if you're trying to access a file in the application's resources or assets folder. I recommend, to avoid having to reinvent the wheel, that you stick any assets you want shipped with your app in the assets folder, where they'll be packaged up for distribution.
In the assets folder case you need to do one of two things, depending on whether the file was compressed by the packager. Both use the AssetManager methods, and you can get the AssetManager from the context/app. File names are always relative to the assets folder, btw: If your have a file "foo.png" directly in the assets folder, you'd open "foo.png," not something like "assets/foo.png".
If the file wasn't compressed (i.e., it's one of the extensions that doesn't get compressed, like .png), you can get a file descriptor from AssetManager.openFd() and pass it to C++. Then you can use fdopen(dup(fd),"r"); to open the file as a FILE*. Note you must fseek() to the offset, and keep track of the length of the file yourself. You're really getting a file handle to the entire assets package, and your file of interest is only a small part.
If your file is compressed, you need to use the Java streaming reader: AssetManager.open() gives you an InputStream you can use the read the file in. This is a PITA because you can't query (AFAIK) the file size; I run a preprocessing step on my assets folder that generates a list of all the files with their respective sizes so I can know, e.g., how big of a buffer to allocate.
If your file is a resource, you may need to go through the Resource class to access it, though it appears resources are also packed into the same assets package. Resource has an openRawResource() call to get the InputStream and an openRawResourceFd() call to get the file descriptor, as above, though.
Good luck.
I want to add my two cents to the answers here, on top of setting the correct permissions specified in the answer to this question, make sure to give your app permission to access the storage in the OS. The permissions menu could change from phone to phone, an easy way to get to it is by going to the Settings menu and then searching for "Permissions." This will give you a chance to give your app permission to access the storage (ie sdcard directory) from NDK code.

Resources