C++ 在Visual Studio 2019中保存时ReadDirectoryChangesW文件名出现问题

C++ 在Visual Studio 2019中保存时ReadDirectoryChangesW文件名出现问题,c++,windows,visual-studio,visual-studio-2019,C++,Windows,Visual Studio,Visual Studio 2019,我正在使用ReadDirectoryChangesW检测目录中的.hlsl文件何时更改。使用Notepad/Notepad++/VSCode保存文件时效果很好,但是当我尝试在VisualStudio2019中保存文件时,会得到一个奇怪的输出。文件夹名称保留,但文件名和扩展名乱七八糟 这就是我的代码的外观。它在应用程序启动时调用的单独线程上运行 void ShaderReloadWatcher::BeginWatching() { m_thread = std::thread(&S

我正在使用ReadDirectoryChangesW检测目录中的.hlsl文件何时更改。使用Notepad/Notepad++/VSCode保存文件时效果很好,但是当我尝试在VisualStudio2019中保存文件时,会得到一个奇怪的输出。文件夹名称保留,但文件名和扩展名乱七八糟

这就是我的代码的外观。它在应用程序启动时调用的单独线程上运行

void ShaderReloadWatcher::BeginWatching()
{
    m_thread = std::thread(&ShaderReloadWatcher::WatchShaderDirectory, this);
}
线程主循环:

void ShaderReloadWatcher::WatchShaderDirectory()
{
    LPCTSTR shaderDir = "../Source/Shaders";
    HANDLE shaderFolderHandle = CreateFile(
        shaderDir,
        GENERIC_READ,
        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
        OPEN_EXISTING,
        FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
        NULL);

    char notifyBuffer[1024];

    OVERLAPPED ovl = { 0 };
    ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    DWORD error = ReadDirectoryChangesW(
        shaderFolderHandle,
        &notifyBuffer,
        sizeof(notifyBuffer),
        TRUE,
        FILE_NOTIFY_CHANGE_LAST_WRITE,
        NULL, &ovl, NULL);


    while (true)
    {
        DWORD result = WaitForSingleObject(ovl.hEvent, 0);

        switch (result)
        {
        case WAIT_TIMEOUT:
        {
            break;
        }

        case WAIT_OBJECT_0:
        {
            DWORD bytesTransferred;
            GetOverlappedResult(shaderFolderHandle, &ovl, &bytesTransferred, FALSE);

            OnDirectoryFileChange(notifyBuffer);

            ResetEvent(ovl.hEvent);

            DWORD error = ReadDirectoryChangesW(
                shaderFolderHandle,
                &notifyBuffer,
                sizeof(notifyBuffer),
                TRUE,
                FILE_NOTIFY_CHANGE_LAST_WRITE,
                NULL, &ovl, NULL);

            break;
        }

        }
    }

    CloseHandle(shaderFolderHandle);
}
OnDirectoryFileChange:

void ShaderReloadWatcher::OnDirectoryFileChange(char* buffer)
{
    DWORD offset = 0;
    FILE_NOTIFY_INFORMATION* fileNotifyInfo = nullptr;
    char fileName[1024];

    do 
    {
        memset(fileName, NULL, sizeof(fileName));
        fileNotifyInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(&buffer[offset]);

        WideCharToMultiByte(CP_ACP, NULL, fileNotifyInfo->FileName, fileNotifyInfo->FileNameLength / sizeof(WCHAR), fileName, sizeof(fileName), NULL, NULL);

        printf("%s\n", fileName);

        offset += fileNotifyInfo->NextEntryOffset;
    } while (fileNotifyInfo->NextEntryOffset != 0);
}
我了解到,由于文本编辑器如何写入文件,它会多次打印,所以这是意料之中的

然而,当使用VisualStudio保存时,我得到了这个

D3D11\sfpwwek3.vs4~
D3D11
D3D11
D3D11
D3D11
文件夹名D3D11看起来不错,但文件名完全是胡言乱语。每次都是不同的胡言乱语:

D3D11\5uuwurye.nel~
D3D11
D3D11
D3D11
D3D11
编码设置为西欧CP1252,我尝试过使用不同的编码,比如Unicode CP65001,但仍然得到相同的结果

我已经观察了fileNotifyInfo->FileName值,它从一开始就似乎是乱七八糟的,因此导致此问题的WideCharToMultiByte转换似乎没有什么问题


非常感谢您对理解此问题的任何帮助,谢谢

问题解决了-感谢@Ted Lyngmo

我只是在听写更改,似乎VisualStudio首先在写临时文件名,然后将其重命名为正确的文件名。我添加了文件名,现在输出如下:

D3D11\cn42zizu.cht~
D3D11\cn42zizu.cht~
D3D11
D3D11\light_pixel.hlsl~RF62be0e8e.TMP
D3D11\light_pixel.hlsl~RF62be0e8e.TMP
D3D11\light_pixel.hlsl
D3D11\light_pixel.hlsl~RF62be0e8e.TMP
D3D11
D3D11\cn42zizu.cht~
D3D11\light_pixel.hlsl
D3D11
D3D11\light_pixel.hlsl~RF62be0e8e.TMP
D3D11

很多信息,但是正确的名字在那里

可能是临时文件名吗?它们通常由随机字符生成。如果在关闭VS时让程序运行,它会变成可识别的东西吗?也许您也应该打开对所有目录更改的嗅探功能,以便更清楚地了解发生了什么。循环是错误的,为什么您要以异步模式而不是同步模式打开文件夹,文件名-不是以0终止的-因此使用%s是错误的。你没有检查errors@TedLyngmo我只是通过添加FILE\u NOTIFY\u CHANGE\u FILE\u NAME标志进行了尝试,似乎您是正确的!它现在输出更多的内容,包括正确的文件名。谢谢大家!@很好-@RbMm我再看一眼这个环,谢谢。文件名0已终止,因为在复制值之前,我正在将memset设置为NULL。在打印输出中,您可能希望在输出中包含File\u NOTIFY\u INFORMATION::Action字段的值,以便查看哪个事件是写入,哪个事件是重命名,例如:printf%u:%s\n,fileNotifyInfo->Action,fileName;仅供参考,您不需要WideChartMultiByte,如果使用%S、%ls或%ws而不是%S,printf可以打印Unicode字符串,例如:printf%u:%.*S\n,fileNotifyInfo->Action,fileNotifyInfo->FileNameLength/sizeofWCHAR,fileNotifyInfo->FileName;或者您可以只使用wprintf,例如:wprintfL%u:%.*s\n,fileNotifyInfo->Action,fileNotifyInfo->FileNameLength/sizeofWCHAR,fileNotifyInfo->FileName@雷米·勒博谢谢你。我需要字符串转换供以后使用,但是知道printf适用于unicode字符串非常有用,我以后会记住它的!
D3D11\cn42zizu.cht~
D3D11\cn42zizu.cht~
D3D11
D3D11\light_pixel.hlsl~RF62be0e8e.TMP
D3D11\light_pixel.hlsl~RF62be0e8e.TMP
D3D11\light_pixel.hlsl
D3D11\light_pixel.hlsl~RF62be0e8e.TMP
D3D11
D3D11\cn42zizu.cht~
D3D11\light_pixel.hlsl
D3D11
D3D11\light_pixel.hlsl~RF62be0e8e.TMP
D3D11