How to get current directory using C language on Windows? - c

Can anyone tell me how to get the path of the current working directory on Windows?

The Windows API function GetCurrentDirectory will give you the current directory for the current process.
Alternatively, you may want to use the function getcwd or _getcwd, especially if you seek compatibility with POSIX platforms such as Linux.
Here is an example for using the function GetCurrentDirectory:
#include <windows.h>
int main( void )
{
TCHAR tszBuffer[MAX_PATH];
DWORD dwRet;
dwRet = GetCurrentDirectory( MAX_PATH, tszBuffer );
if ( dwRet == 0 )
{
//TODO: handle error
}
// The buffer now contains the path of the
// current directory and can be inspected.
}
MAX_PATH is defined when you #include <windows.h>.
TCHAR is just a typedef for char if you are compiling in ASCII mode, or for a wide-character WCHAR if you are compiling in UNICODE mode. DWORD is just a typedef for an unsigned long. These typedefs are declared when you #include <windows.h>.
Here is an example for using the function getcwd:
#include <stdio.h>
#include <direct.h>
// Microsoft wants us to use _getcwd instead of getcwd, which breaks POSIX
// compatibility. See the following link for more information:
// https://stackoverflow.com/questions/7582394/strdup-or-strdup
// Therefore we must disable the compiler warning if we want to use getcwd
// to maintain POSIX compatibility. This is accomplished with the following
// line.
#pragma warning(disable : 4996)
// We can't use the constant MAX_PATH in this program because it is not
// defined. This is because we have not included windows.h. Since MAX_PATH
// has the value 260, we will use that value.
#define BUF_SIZE 260
int main()
{
char buffer[BUF_SIZE];
char *p;
p = getcwd( buffer, BUF_SIZE );
if ( p == NULL )
{
//TODO: handle error
}
printf( "The current directory is: %s", buffer );
}
In contrast to the function GetCurrentDirectory, the functions getcwd and _getcwd allow you to pass NULL as the buffer parameter. In that case, it will allocate the memory for you with malloc and return a pointer to that memory buffer. Therefore, you must call free when you are finished with the buffer, to prevent a memory leak. Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <direct.h>
// Microsoft wants us to use _getcwd instead of getcwd, which breaks POSIX
// compatibility. See the following link for more information:
// https://stackoverflow.com/questions/7582394/strdup-or-strdup
// Therefore we must disable the compiler warning if we want to use getcwd
// to maintain POSIX compatibility. This is accomplished with the following
// line.
#pragma warning(disable : 4996)
int main()
{
char *p;
p = getcwd( NULL, 0 );
if ( p == NULL )
{
//TODO: handle error
}
printf( "The current directory is: %s", p );
free( p );
}

Related

Why Dll can't export a function with parameter type FILE*

THis is the Dll code
#ifdef HELLO_EXPORTS
#define CLASS_DECLSPEC __declspec(dllexport)
#else
#define CLASS_DECLSPEC __declspec(dllimport)
#endif
CLASS_DECLSPEC FILE* GetStdout() {
return stdout;
}
CLASS_DECLSPEC void dump_code(FILE* fd, const void* data, size_t len)
{
unsigned char* p = (unsigned char*)data;
size_t i;
for(i = 1; i < len + 1; ++i){
fprintf(fd, "0x%.2x, ", p[i-1]);
if((i%16)==0) fprintf(fd, "\n");
}
fprintf(fd, "\n");
}
This is the test code:
#include <stdio.h>
#include <stdlib.h>
#include "dump.h"
int main(){
char data[] = {
0x1f,0xc2,0x8b,0x08,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xc3,0x8d,0xc2,0x90,0x3d
};
dump_code(GetStdout(), data, 16);
//dump_code(stdout, data, 16);
}
If I directly use stdout: dump_code(stdout, data, 16);, the program will crash in _lock_file.
But it will ok to use GetStdout() instead of stdout.
Don't pass FILE * pointers between two copies of libc. You need to link the exe and the dll against the exact same version of libc as a dynamic link library or it won't work.
The general tradition on Windows is don't even try to make this kind of thing work. For every export that would return allocated memory there is another export to free that memory, and more complex things either aren't done at all or done using COM to provide cleanup routines.
OP has now commented that he built with /MTd, which decodes to multi-threaded, static library, and switching to /MDd, which decodes to multi-threaded dll-version-specific library (which is in a .dll) fixed the problem, as expected. When switching to release, /MD must be used instead of /MT or the same problem will reoccur.

How can I create a directory and make a file in %appdata% path of windows in C language

I successfully created a directory or folder and I also managed to create a file in that directory but how can create a directory and a file in the user's appdata local if I don't know what is their username or their user folder name? thanks!
I used codeblocks
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main()
{
int check;
char* dirname = "C:/Pyromagne";
check = mkdir(dirname);
FILE* fp;
fp = fopen("C:/Pyromagne/test.pyr", "w+");
fputs("Pyromagne\n", fp);
fputs("qwertyuiop", fp);
fclose(fp);
FILE* ffpp;
char user[25];
char pass[25];
char uuser[25];
ffpp = fopen("C:/Pyromagne/test.pyr", "r");
strcpy(uuser, fgets(user, 255, (FILE*)ffpp));
printf("%s\n", uuser);
strcpy(uuser, fgets(user, 255, (FILE*)ffpp));
printf("%s\n", uuser);
fclose(ffpp);
}
Under MSYS2/UCRT, I recently (like yesterday...) used SHGetFolderPathA() to obtain a user's profile directory in C code.
It's worked so far in limited unit testing on a Windows Server 2016 AWS installation after being compiled with whatever GCC version comes with the latest MSYS2/UCRT installation. (The system is currently shut down and I'm on vacation so i can't check details)
This might work in your environment:
char buffer[ MAX_PATH ] = { 0 };
HRESULT result = SHGetFolderPathA( NULL, CSIDL_APPDATA, NULL, 0, buffer );
if ( result != S_OK )
{
//handle error
}
Somewhat off-topic, I have grown to prefer MSYS2/UCRT over the alternatives.
SHGetKnownFolderPath obtains the Unicode path to AppData, Documents, etc.
KNOWNFOLDERID for "C:\Users\MyName\AppData\Local" is FOLDERID_LocalAppData
This function needs additional libraries for CoTaskMemFree, KNOWNFOLDERID, and SHGetKnownFolderPath
gcc file.c libole32.a libuuid.a libshell32.a
Using MinGW, 64-bit, gcc version 4.8.3, SHGetKnownFolderPath does not appear to be in libshell32.a. The command line nm libshell32.a does not list this function either. So in MinGW, we have to load this function manually as follows:
#define _WIN32_WINNT 0x0600
#include <stdio.h>
#include <Windows.h>
#include <shlobj.h>
//add libraries for libole32.a and libuuid.a
HRESULT MySHGetKnownFolderPath
(const KNOWNFOLDERID* const id, DWORD flags, HANDLE token, PWSTR* str)
{
typedef HRESULT(WINAPI* lpf)(const KNOWNFOLDERID* const, DWORD, HANDLE, PWSTR*);
HMODULE lib = LoadLibraryW(L"shell32.dll");
if (!lib) return E_FAIL;
lpf fnc = (lpf)GetProcAddress(lib, "SHGetKnownFolderPath");
HRESULT result = fnc ? fnc(id, flags, token, str) : E_FAIL;
FreeLibrary(lib);
return result;
}
int main(void)
{
wchar_t* temp;
if SUCCEEDED(MySHGetKnownFolderPath(&FOLDERID_LocalAppData, 0, NULL, &temp))
{
wchar_t path[1024];
swprintf(path, 1024, L"%s\\_add_new_dir", temp);
CoTaskMemFree(temp); //free this memory as soon as possible
wprintf(L"path: %s\n", path); //CreateDirectoryW(path, NULL);
}
return 0;
}
Additionally, you can use getenv or _wgetenv (Unicode version)
#include <stdio.h>
#include <Windows.h>
int main(void)
{
wprintf(L"%s\n", _wgetenv(L"LOCALAPPDATA"));
wprintf(L"%s\n", _wgetenv(L"APPDATA"));
wprintf(L"%s\n", _wgetenv(L"USERPROFILE"));
wchar_t buf[1024];
swprintf(buf, 1024, L"%s\\_add_new_dir", _wgetenv(L"LOCALAPPDATA"));
wprintf(L"buf: %s\n", buf); //CreateDirectoryW(buf, NULL);
return 0;
}
To add the libraries in Code::Blocks, click Menu -> Settings -> Compiler, it should bring up this window:
Then click the "Add" button, find MinGW installation folder, the libraries should be at
C:\My_MinGW_folder\mingw\lib\libole32.a
or
C:\My_MinGW_folder\mingw\lib32\libole32.a (for 32-bit program)
You can figure out which libraries you need by looking at documentation for the function. For example SHGetKnownFolderPath says it needs "shell32.lib" (for Visual Studio) MinGW uses "libshell32.a" instead.

How to Override A C System Call?

So the problem is the following. The project needs to intercept all file IO
operations, like open() and close(). I am trying to add printf() before calling the corresponding open() or close(). I am not supposed to rewrite the source code by changing open() or close() to myOpen() or myClose() for example. I have been trying to use LD_PRELOAD environment variable. But the indefinite loop problem came up. My problem is like this one.
int open(char * path,int flags,int mode)
{
// print file name
printf("open :%s\n",path);
return __open(path,flags,mode);
}
Yes, you want LD_PRELOAD.
You need to create a shared library (.so) that has code for all functions that you want to intercept. And, you want to set LD_PRELOAD to use that shared library
Here is some sample code for the open function. You'll need to do something similar for each function you want to intercept:
#define _GNU_SOURCE
#include <dlfcn.h>
int
open(const char *file,int flags,int mode)
{
static int (*real_open)(const char *file,int flags,int mode) = NULL;
int fd;
if (real_open == NULL)
real_open = dlsym(RTLD_NEXT,"open");
// do whatever special stuff ...
fd = real_open(file,flags,mode);
// do whatever special stuff ...
return fd;
}
I believe RTLD_NEXT is easiest and may be sufficient. Otherwise, you could add a constructor that does dlopen once on libc
UPDATE:
I am not familiar with C and I got the following problems with gcc. "error: 'NULL' undeclared (first use in this function)",
This is defined by several #include files, so try #include <stdio.h>. You'll need that if you want to call printf.
"error: 'RTLD_NEXT' undeclared (first use in this function)",
That is defined by doing #include <dlfcn.h> [as shown in my example]
and "symbol lookup error: ./hack_stackoverflow.so: undefined symbol: dlsym".
From man dlsym, it says: Link with -ldl So, add -ldl to the line that builds your .so.
Also, you have to be careful to prevent infinite recursion if the "special stuff" does something that loops back on your intercept function.
Notably, you want to call printf. If you intercept the write syscall, bad things may happen.
So, you need to keep track of when you're already in one of your intercept functions and not do anything special if already there. See the in_self variable.
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
ssize_t
write(int fd,const void *buf,size_t len)
{
static ssize_t (*real_write)(int fd,const void *buf,size_t len) = NULL;
static int in_self = 0;
ssize_t err;
if (real_write == NULL)
real_write = dlsym(RTLD_NEXT,"write");
++in_self;
if (in_self == 1)
printf("mywrite: fd=%d buf=%p len=%ld\n",fd,buf,len);
err = real_write(fd,buf,len);
if (in_self == 1)
printf("mywrite: fd=%d buf=%p err=%ld\n",fd,buf,err);
--in_self;
return err;
}
The above works okay for single threaded programs/environments, but if you're intercepting an arbitrary one, it could be multithreaded.
So, we'd have to initialize all the real_* pointers in a constructor. This is a function with a special attribute that tells the dynamic loader to call the function ASAP automatically.
And, we have to put in_self into thread local storage. We do this by adding the __thread attribute.
You may need to link with -lpthread as well as -ldl for the multithreaded version.
Edit: We also have to preserve the correct errno value
Putting it all together:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <errno.h>
static int (*real_open)(const char *file,int flags,int mode) = NULL;
static ssize_t (*real_write)(int fd,const void *buf,size_t len) = NULL;
__attribute__((constructor))
void
my_lib_init(void)
{
real_open = dlsym(RTLD_NEXT,"open");
real_write = dlsym(RTLD_NEXT,"write");
}
int
open(const char *file,int flags,int mode)
{
int fd;
// do whatever special stuff ...
fd = real_open(file,flags,mode);
// do whatever special stuff ...
return fd;
}
ssize_t
write(int fd,const void *buf,size_t len)
{
static int __thread in_self = 0;
int sverr;
ssize_t ret;
++in_self;
if (in_self == 1)
printf("mywrite: fd=%d buf=%p len=%ld\n",fd,buf,len);
ret = real_write(fd,buf,len);
// preserve errno value for actual syscall -- otherwise, errno may
// be set by the following printf and _caller_ will get the _wrong_
// errno value
sverr = errno;
if (in_self == 1)
printf("mywrite: fd=%d buf=%p ret=%ld\n",fd,buf,ret);
--in_self;
// restore correct errno value for write syscall
errno = sverr;
return ret;
}

how to set a FILE** variable to stdout?

Mockup of my production code:
/* version 1 */
#include <stdio.h>
FILE** fout = &stdout;
int main() {
fprintf( *fout, "hello\n" );
}
Works fine under gcc, but reportedly fails to compile under mingw (lvalue required as unary '&' operand).
I have seen Is setting a FILE* equal to stdout portable?; I understand that
/* version 2 */
#include <stdio.h>
int main() {
FILE* fout = stdout;
fprintf( fout, "hello\n" );
}
would be perfectly valid. However, I need to preset a global variable. Unfortunately,
/* version 3 */
#include <stdio.h>
FILE* fout = stdout;
int main() {
fprintf( fout, "hello\n" );
}
is not suitable to replace version 1; it does not even compile under gcc (line 2: initializer element is not constant).
Any idea how to get stdout into a variable that is initialized before main() starts?
In Linux (glibc), stdout is defined like this:
extern struct _IO_FILE *stdout;
So, you can do whatever you need with that.
However, on MinGW, stdout is defined like this, in stdio.h:
#define stdout (&_iob[STDOUT_FILENO])
Alas, that's not something you can take the address of, and, as you discovered, it's not something you can use in a global initializer. :-(
The root of the problem is that the C standard says that these should be macros, which means any portable program should make no assumptions about what's inside. So, I'm afraid, there is no easy way to avoid doing reading stdout programmatically. This sort of thing is why many libraries require a lib_initialize() function that must be called before anything else.
C++ does permit constructors for global variables, and these are automatically called before main, even for libraries. It is possible, with gcc, to hack a C program to do the same, but that's an evil trick and I can't remember how to do it off the top of my head.
I'd just do this:
#include <stdio.h>
FILE* fout = NULL;
int my_library_function() {
if (!fout)
fout = stdout;
fprintf( fout, "hello\n" );
}
That isn't a big efficiency problem: you'd have to load fout anyway, and a compare with zero is pretty cheap.
According to the C standard (7.21.1), stdout is a macro which is an expression of type "pointer to FILE". It is not necessarily a global variable. It is not portable C to take its address --- it works in gcc but not in mingw, as you saw.
Use the second version of your code --- this is portable.
The third would be OK too if you moved the initialization of fout inside main:
/* version 3 */
#include <stdio.h>
FILE* fout;
int main() {
fout = stdout;
fprintf( fout, "hello\n" );
}
This initialization cannot be combined with the declaration of fout, as stdout is not (at least, not necessarily) a constant expression.
If you want to have a FILE ** pointer, use:
/* version 4 */
#include <stdio.h>
FILE* mystdout;
FILE** fout = &mystdout;
int main() {
mystdout = stdout;
fprintf( *fout, "hello\n" );
}
but again the initialization of mystdout cannot be at its declaration, for the same reason.
I don't think that this is a very good idea, as file descriptors are not generally portable. Also, it makes the implementation of library functions quite low-level, or you'll have a hard time synchronizing file descriptors and FILE pointers.
However, as #JoachimWuttke explicitly asked, here's what I had in mind in my previous comment:
/* version 5 */
#include <stdio.h>
#include <unistd.h>
int fdout = 1;
void use(FILE *fout)
{
fdout = fileno(fout);
}
void printing() {
const char msg[] = "hello\n";
write(fdout, msg, sizeof(msg)-1);
}
int main() {
printing(); // this one goes to stdout
FILE *f = fopen("output.txt", "wt");
use(f);
printing(); // this one goes to "output.txt"
printing(); // this one too
fclose(f);
use(stdout);
printing(); // this one goes to stdout too
return 0;
}

MAC address using C

I am trying to write some C code which extracts the MAC no of a computer and prints it. Following is my code.
#ifndef WINVER
#define WINVER 0x0600
#endif
#include <stdlib.h>
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <assert.h>
#pragma comment(lib, "IPHLPAPI.lib")
// BYTE has been typedefined as unsigned char
// DWORD has been typedefined as 32 bit unsigned long
static void PrintMACaddress(unsigned char MACData[])
{
printf("MAC Address: %02X-%02X-%02X-%02X-%02X-%02X\n",
MACData[0], MACData[1], MACData[2], MACData[3], MACData[4], MACData[5]);
}
// Fetches the MAC address and prints it
static void GetMACaddress(void){
IP_ADAPTER_ADDRESSES AdapterInfo[16]; // Allocate information for up to 16 NICs
DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer
// Arguments for GetAdapterAddresses:
DWORD dwStatus = GetAdaptersAddresses(0, 0, NULL, AdapterInfo, &dwBufLen);
// [out] buffer to receive data
// [in] size of receive data buffer
assert(dwStatus == ERROR_SUCCESS); // Verify return value is valid, no buffer overflow
PIP_ADAPTER_ADDRESSES pAdapterInfo = AdapterInfo; // Contains pointer to current adapter info
do {
PrintMACaddress(pAdapterInfo->Address); // Print MAC address
pAdapterInfo = pAdapterInfo->Next; // Progress through linked list
}while(pAdapterInfo); // Terminate if last adapter
}
int main(){
GetMACaddress();
return 0;
}
But when I run my code it gives the following error :
Error : undefined reference to `GetAdaptersAddresses#20'
All though the GetAdaptersAddresses() function is included in iphlpapi.h library.
I also tried running the code using the GetAdaptersInfo() function but also gives the same kind of error.
I am using CodeBlocks to compile my code using the GNU GCC C++ 98 compiler version.
The operating system which I am working on is Windows 7.
Can anybody point out the reason for this kind of error.
GCC does not support #pragma comment and there is no equivalent. You will need to update your project settings to specifically link with the Iphlpapi.lib library.

Resources