Find path to active user directory in C - c#

I'm writing a C# program where I have to write some files to a temp folder. In this program, I call an executable from a C project which also needs to write to said temp folder. In C#, I can simply find this with
Directory.GetTempPath();
But in C, I can't seem to find any way of locating it. Do I need to rewrite the C program to take the path as an argument? I would really prefer not to since I'm not very proficient in the language and only barely got it working for my current purpose.
Are there any other, static locations in Windows where it would be appropriate to write temporary files?

My suggestion is to declare the file name relative to a system variable, like %temp% and create there your file as standard file (maybe with a pattern so you can delete it at end of your need), there's also F* tempfile() library function, but I used it only on linux and don't know if it works on windows (it returns you a pointer to a system-defined temp file)

There is a similar function GetTempPath in Win32 API - GetTempPathA MSDN link
You can see how most of C# code is implemented using ReferenceSource. For the GetTempPath() function it calls Win32 API directly.

Related

How to get the calling directory of a C# assembly?

I am trying to write a small build event utility to read the current assembly version of my code.
Thus, I want that executable to be in my %PATH% (or some central location at least) and be able to take a relative path to my target assembly as an argument (to Assembly.LoadFile() it) but Assembly.LoadFile() complains about receiving a relative path.
How can I do:
C:\calling\path>mytool rel\path\to\target.exe
Without having to type C:\devpath\to\mytool.exe every time?
And be able to get the string "C:\calling\path\rel\path\to\target.exe" in mytool.exe?
It turns out that this is a bit of a pain.
A C# assembly requires its support files to be in the same directory as itself so in the simple case, we can't just copy the exe to our chosen directory.
Another possibility is to create a shortcut to the exe and move that to the directory. Unfortunately, despite having an impressive amount of "current" path getters, C# doesn't have a way to know if it's been started through a shortcut.
When invoked from a shortcut in C:\calling\path, all of the following:
Console.WriteLine(Environment.CurrentDirectory);
Console.WriteLine(Directory.GetCurrentDirectory());
Console.WriteLine(Assembly.GetEntryAssembly().Location);
Console.WriteLine(System.AppDomain.CurrentDomain.BaseDirectory);
Console.WriteLine(System.AppContext.BaseDirectory);
//Console.WriteLine(Process.GetCurrentProcess().StartInfo.WorkingDirectory);
Console.WriteLine(Process.GetCurrentProcess().MainModule.FileName);
Console.WriteLine(Environment.GetCommandLineArgs()[0]);
return a variation of "C:\devpath\to". Except for Process.StartInfo which just crashes. You can't get the StartInfo of a process you didn't Process.Start(), including your own.
The only way that appears to work to be able to retrieve "C:\calling\path" is to create a batch file in "C:\inpath" that calls the original assembly directly.
So:
C:\inpath\exe.bat:
C:\devpath\to\mytool.exe %*
C:\devpath\to\mytool.cs:
Console.WriteLine(Environment.CurrentDirectory);
Console.WriteLine(Directory.GetCurrentDirectory());
These 2 will return "C:\calling\path".
Another option could be to add C:\devpath\to itself to the PATH

Baking an external .exe into a C# project [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Embedded a *.exe into a dll
I have a C# project - a class library - that produces a DLL file.
From within itself, this project runs an external .exe file. (Using the standard Process stuff, and it works fine.)
However, my question is: How can I bake the external .exe file into the project, such that the end-consumer will only receive the final DLL file, without ever seeing the .exe file itself?
This will make my client happier, as he will continue receiving one DLL file (as before, before I needed the .exe).
If you are going to launch it as an external process, it needs to exist on disk. It could be embedded in the .dll as a resource and extracted on-demand.
Your best bet would be to make the exe an embedded resource.
If your client needs the .exe at runtime, you'd darn well better make sure he has a copy of the .exe. IMHO...
PS:
You can "trick" the client by embedding your .dll as a resource (as a "Trojan horse"), and then extracting it at runtime. Which, IMHO, would be stupid. Expensive. And risky.
If you need the .exe, ship the .exe. And be explicit about it.
If the client expressly refuses to have an .exe - then your implemention violates the requirements, and you need to go back to the drawing board.
The "exe-as-resource" workaround ... is a lie and a cheat. And it isn't even a very efficient or safe cheat.
ALSO:
Embedded a *.exe into a dll
On a side note, remember that when you pull a file from your resources
to disk and then execute code on it, you may trigger Windows Data
Execution Prevention - basically, Windows tries to automatically
detect if something is supposed to be code or data, and if it looks
like data (which a resource would), then it will prevent that data
from being executed as code.
This becomes a particularly sticky issue if your .NET assembly is
going to be used over a network instead of from a local drive - there
are all sorts of .NET security configurations that might prevent this
from working correctly.

Using WritePrivateProfileString to write path issue

I am using WritePrivateProfileString in c# (through DllImport) to store paths taken from textboxes on the interface. And the .ini file name is hardcoded in my application
string ini_file = ".\\config.ini";
However, when the file writing happens, the configuration file is written to the first path taken from the interface instead of writing it to the exe directory. Which is quite odd.
Debugging shows that the values are sent correctly to the WritePrivateProfileString but it still is written to the wrong location. Anyone knows why is that happenening?
I'd guess that something is changing the working directory of your process, most likely your code in the process. Note that the documentation has this to say:
If the lpFileName parameter does not contain a full path and file name for the file, WritePrivateProfileString searches the Windows directory for the file. If the file does not exist, this function creates the file in the Windows directory.
Now my guess is that this applies if you supply just a file name. Because your file name starts with . I believe that will force the function to start from the current working directory.
Having said all of that, and no matter what the cause of the problem is, you should use a fully-qualified path in order to make sure the file is written where you want it to be written. Whenever you want the file to go in a specific directory, it's always easiest to force that by using fully-qualified paths.
You can find the path to your executable using Application.ExecutablePath and then remove the file name part.
Another point to make is that the same directory as the executable may be a bad choice. If your program is installed under the Program Files directory then the directory which contains the executable will not be generally writeable. I think you should consider using a directory under in the user profile. Look for one of the Environment.SpecialFolder values.
Further to David Heffernan's answer - you can use
Path.GetDirectoryName(Application.ExecutablePath);
to safely get just the running application's folder part.
If you're in a dll rather than an executable, you can use
Path.GetDirectoryName(Assembly.GetAssembly(typeof(MyClass)).CodeBase);
Both require System.IO, and were originally posted here. Second example also requires System.Reflection).
Application data files are supposed to be written to the LocalApplicationData special folder.
string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData);
You typically will not have permissions to write into the Program Files folder etc.

How to know the next temp file to be created in windows?

I am by no means a programmer but currently am wondering if an application creates a temp file that windows names. For example the file it creates is tmp001, is there a way i can take that name tmp001 and ask windows to give me the next temp file it would create before it creates it.
Thanks,
Mike
There is no direct means to get to know the next temporary filename to be created.
For example, programmers use the System.IO.Path.GetTempFileName method, but one can add application-specific prefixes or suffixes in order to make it easier for the application to find its newly created files.
One can even choose to save this temporary file elsewhere than the system Temp folder.
You would need to define a "temp file" much more explicitly in order to answer this question with a "Yes". The problem is that a "temp file" is just something not meant to be kept. It could exist anywhere on the system and be created by a user, application, or service. This would make it nearly (or actually) impossible to answer your question with a "Yes".
If you constrain the definition of a temp file to just the files in the official temp folder (or a subfolder), you still have a problem if you're trying to catch names not generated by windows. Any app could produce a particularly named temp file in that folder, without Windows caring.
If you further constrain the definition to be only those files named by Windows, you might be able to get somewhere. But, does that really meet your needs?
After all of that, maybe it would be better to describe the problem you're trying to solve. There may be a much better (workable) solution that would address the issue.
Typically applications use the Win32 API GetTempFileName to get the temporary directory.
The process of how the temp file is generated is described there.
I'm not sure why you want this info, but perhaps you could for example register for directory changes via a Win32 API like ReadDirectoryChangesW or by using a mini filter driver.
This kind of code just cannot work reliably on a multi-tasking operating system. Another thread in another process might pre-empt yours and claim the file name you are hoping to create.
This is otherwise easy enough to work around, just name your own files instead of relying on Windows doing it for you. Do so in the AppData folder so you'll minimize the risk of another process messing it up.

access denied trying extracting an archive on the windows user temp folder

I'm trying to run a command-line process (which is extraction of a .7z archive) on a file that lies in a temporary folder on the windows user temp directory
(C:\Documents and Settings\User\Local Settings\Temp), using Process in my c# app.
I think the process return error that happens because of "access denied" because I can see a win32Exception with error code 5 when I dig in the prcoess object of .NET.
doing the same on some other location worked fine before, so I guess maybe it's something I'm not supposed to do ? (running a process to use a file on the the %TEMP%)
perhaps I need to pass security somehow?
Assuming that you are using regular .NET (not CF/Silverlight, etc) Accessing files in the user's temp area is entirely expected. I wonder if the problem isn't more that you've accidentally left the file open after creating it, perhaps by not using a "using" or similar?
I probably wouldn't suggest using environment variables (%TEMP% etc) when shelling out to a separate process; ideally you'd pass the full path to the file (less things to get wrong...), making sure to quote any path arguments (in case of space) - i.e. so your args are #"... ""c:\some path\whatever\tmp""..." (if you see what I mean).
Finally, if you are extracting files, you need to think about the existing contents. Path.GetTempFileName() is fine for creating a single file place-holder, but for extracting an archive you probably want to create a directory - guids are handy for this purpoes (while avioding conflicts, and remember to remove it afterwards):
string dir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
running the same process using command-line (cmd) helped to figure out my problem was that I specified path arguments to the process using long-path-name.
Solution to this can be found here:
standard way to convert to short path in .net

Categories