如何在 C 语言的 windows 的 %appdata% 路径中创建目录并创建文件

Posted

技术标签:

【中文标题】如何在 C 语言的 windows 的 %appdata% 路径中创建目录并创建文件【英文标题】:How can I create a directory and make a file in %appdata% path of windows in C language 【发布时间】:2022-01-24 03:26:01 【问题描述】:

我成功创建了一个目录或文件夹,并且我还设法在该目录中创建了一个文件,但是如果我不知道他们的用户名或用户文件夹名称是什么,如何在用户的 appdata 本地创建目录和文件?谢谢!

我使用了代码块

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


【问题讨论】:

你可以试试getenv("APPDATA"),这会给你“users/name/appdata/roaming”。你真的应该使用SHGetKnownFolderPath 支持Unicode,特别是对于非英语系统。但我不知道如何在 gcc 中使用 C。 @BarmakShemirani 没那么难:#include &lt;Shlobj.h&gt; PWSTR path; HRESULT hRes = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &amp;path); if (SUCCEEDED(hRes)) /* use path as needed... */ CoTaskMemFree(path); 并确保也链接到 Shell32.lib @RemyLebeau 在 Visual Studio 中很容易,但 MinGW 有一些奇怪的地方。它甚至不会在 c++ 中编译,它在 c 中编译,我链接到 libshell32.a(MinGW 的版本)但得到 "undefined reference" 错误。我可以运行ShellExecute,它也是shell32.lib 函数,它甚至不需要显式链接命令。 @BarmakShemirani - Remy 的代码应该可以在 C 中使用 GCC 编译(至少对我有用,在 Windows 下在 gcc 中编译),但您需要为文件夹 ID 添加 libuuid.a。 @BarmakShemirani getenv("APPDATA")SHGetKnownFolderPath 这两个有什么区别?为了使用getenv("APPDATA") 函数,我需要哪些库? 【参考方案1】:

SHGetKnownFolderPath 获取 AppData、Documents 等的 Unicode 路径

KNOWNFOLDERID 对于"C:\Users\MyName\AppData\Local"FOLDERID_LocalAppData

此函数需要 CoTaskMemFreeKNOWNFOLDERIDSHGetKnownFolderPath 的附加库

gcc file.c libole32.a libuuid.a libshell32.a

使用 MinGW,64 位,gcc 版本 4.8.3,SHGetKnownFolderPath 似乎不在libshell32.a 中。命令行nm libshell32.a 也没有列出这个函数。所以在MinGW中,我们必须手动加载这个函数,如下:

#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;

此外,您可以使用getenv_wgetenv(Unicode 版本)

#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;

要在 Code::Blocks 中添加库,点击菜单 -> 设置 -> 编译器,它应该会弹出这个窗口:

然后点击“添加”按钮,找到MinGW安装文件夹,库应该在

C:\My_MinGW_folder\mingw\lib\libole32.a
or
C:\My_MinGW_folder\mingw\lib32\libole32.a (for 32-bit program)

您可以通过查看该函数的文档来确定您需要哪些库。例如SHGetKnownFolderPath 说它需要“shell32.lib”(对于 Visual Studio)MinGW 使用“libshel​​l32.a”代替。

【讨论】:

我在哪里可以获得这些库? @Pyromagne 查看更新后的答案。注意_wgetenv 方法不需要额外的库 您好 Barmak,关于 mingw,我需要先安装它才能使用该库,还是只下载这些库? 我应该安装什么? MinGW 还是 MinGW-w64? 你能运行这个程序MessageBoxW(0, L"test", 0, 0);吗?还是我为_wgetenv 发布的代码?如果是这样,您已经安装了 GCC 编译器和 MinGW 库,它将位于不同的文件夹中,可能在 c:\ 或 c:\users\myname 下的某个位置。对于 GCC,运行这个程序:void *p; printf("sizeof pointer: %d\n", sizeof(p)); 如果它打印 8,那么你使用的是 64 位版本。如果它打印 4,则您使用的是 32 位版本。对于 Windows 开发,我会推荐 Visual Studio。【参考方案2】:

在MSYS2/UCRT下,我最近(和昨天一样...)使用SHGetFolderPathA()在C代码中获取用户的配置文件目录。

在使用最新 MSYS2/UCRT 安装附带的任何 GCC 版本进行编译后,到目前为止,它已在 Windows Server 2016 AWS 安装上进行有限单元测试。 (系统目前已关闭,我正在休假,所以我无法查看详细信息)

这可能适用于您的环境:

char buffer[ MAX_PATH ] =  0 ;

HRESULT result = SHGetFolderPathA( NULL, CSIDL_APPDATA, NULL, 0, buffer );
if ( result != S_OK )

    //handle error

有点跑题了,我已经成长为更喜欢 MSYS2/UCRT 而不是替代方案。

【讨论】:

理想情况下,您应该使用 W 函数和 Unicode,否则如果用户的用户名中包含仅 Unicode 字符,则配置文件相关路径可能会失败... 你到底用什么IDE?

以上是关于如何在 C 语言的 windows 的 %appdata% 路径中创建目录并创建文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在windows下运行C语言

无法在 Windows 10 上安装 framework-res.apk

使用C语言编写Window的标准动态库如何在Delphi中调用

如何在windows下搭建c语言开发环境,不使用ide。

windows上如何卸载C语言编译器MinGW?

Windows下如何在python中调用c语言程序编译的dll