【问题标题】:How can I create a directory and make a file in %appdata% path of windows in C language如何在 C 语言的 windows 的 %appdata% 路径中创建目录并创建文件
【发布时间】: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") 函数,我需要哪些库?

标签: c winapi directory codeblocks 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?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-25
  • 2010-11-25
  • 1970-01-01
  • 1970-01-01
  • 2017-07-17
  • 1970-01-01
  • 2014-03-08
相关资源
最近更新 更多