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

867 Views Asked by At

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);
}

2

There are 2 best solutions below

5
Barmak Shemirani On BEST ANSWER

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:

enter image description here

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.

2
Andrew Henle On

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.