Search code examples
cwinapidirectorycodeblocksappdata

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


Solution

  • 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.