如何在不覆盖的情况下将多个进程追加到 Windows 终端服务器客户端文件?

How can multiple processes append to a Windows Terminal Server Client file without overwriting?

提问人:Gary 提问时间:11/14/2023 更新时间:11/14/2023 访问量:26

问:

我想在多个进程中运行一个程序,并让该程序将记录追加到同一个文件中。追加在非 Windows Server 上运行到本地文件时有效。当程序在 Windows Server 上运行并使用终端服务器客户端语法写入共享客户端驱动器上的文件时,它不起作用。例如,\tsclient\c\temp\myfile-append.txt。如果我调用 CreateFile() 并将 dwDesiredAccess 设置为 GENERIC_WRITE,则进程 1 中的所有数据都会被进程 2 覆盖,而不是追加到。如果我将 GENERIC_WRITE 替换为 FILE_APPEND_DATA,则会创建文件,但在调用 WriteFile() 时会ERROR_INVALID_PARAMETER。

当我在 Windows Server 上运行时,我看到 WriteFile() 错误,FILE_APPEND_DATA:

process 1:
Running on a Windows Server and Terminal Services are enabled
CreateFile: \\tsclient\c\temp\myfile-write.txt
WriteFile: TEST-6620
WriteFile: TEST-6620
WriteFile: TEST-6620
WriteFile: TEST-6620
**CreateFile: \\tsclient\c\temp\myfile-append.txt
WriteFile: TEST-6620
WriteFile returned ERROR_INVALID_PARAMETER errno:87**
Press return to exit...

process 2:
Running on a Windows Server and Terminal Services are enabled
CreateFile: \\tsclient\c\temp\myfile-write.txt
WriteFile: TEST-9020
WriteFile: TEST-9020
WriteFile: TEST-9020
WriteFile: TEST-9020
**CreateFile: \\tsclient\c\temp\myfile-append.txt
WriteFile: TEST-9020
WriteFile returned ERROR_INVALID_PARAMETER errno:87**
Press return to exit...

myfile-append 已创建,但由于错误而为空。 myfile-write 具有从进程 2 写入的预期最后 4 条记录:

TEST-4424
TEST-4424
TEST-4424
TEST-4424

当我在非 Windows Server 上运行时,没有错误:

process 1
Terminal Services are not enabled so using local files
CreateFile: myfile-write.txt
WriteFile: TEST-8320
WriteFile: TEST-8320
WriteFile: TEST-8320
WriteFile: TEST-8320
CreateFile: myfile-append.txt
WriteFile: TEST-8320
WriteFile: TEST-8320
WriteFile: TEST-8320
WriteFile: TEST-8320
Press return to exit...

process 2
Terminal Services are not enabled so using local files
CreateFile: myfile-write.txt
WriteFile: TEST-11992
WriteFile: TEST-11992
WriteFile: TEST-11992
WriteFile: TEST-11992
CreateFile: myfile-append.txt
WriteFile: TEST-11992
WriteFile: TEST-11992
WriteFile: TEST-11992
WriteFile: TEST-11992
Press return to exit...

myfile-append 正确有 8 条记录,每个进程 4 条:

TEST-24820
TEST-16324
TEST-24820
TEST-16324
TEST-24820
TEST-16324
TEST-24820
TEST-16324

myfile-write 具有从进程 2 写入的预期最后 4 条记录:

TEST-16324
TEST-16324
TEST-16324
TEST-16324

有谁知道我如何让这个程序在多个进程中运行,并让该程序在同一个文件中追加记录,当程序在 Windows Server 上运行时,使用终端服务器客户端语法写入共享客户端驱动器上的文件?

用于在多个进程中运行 ConsoleApplication1.cpp 的 Windows 批处理脚本

@echo off

del \\tsclient\c\temp\myfile-append.txt
del \\tsclient\c\temp\myfile-write.txt

echo Starting process 1
START "process 1" ConsoleApplication1.exe

timeout /t 1

echo Starting process 2
START "process 2" ConsoleApplication1.exe

echo Press return after both processes have finished...
timeout /t -1

echo myfile-append file, should have 8 records, 4 from each process:
type \\tsclient\c\temp\myfile-append.txt

echo myfile-write file, should have last 4 records written from process 2:
type \\tsclient\c\temp\myfile-write.txt

控制台应用程序1.cpp

#define COUNT 4
#define SLEEP 2000
#include <Windows.h>
#include <iostream>
#include <stdlib.h>
#include <fileapi.h>
#include <errhandlingapi.h>

wchar_t filename_local_write[512] = L"myfile-write.txt";
wchar_t filename_local_append[512] = L"myfile-append.txt";
wchar_t filename_ts_write[512] = L"\\\\tsclient\\c\\temp\\myfile-write.txt";
wchar_t filename_ts_append[512] = L"\\\\tsclient\\c\\temp\\myfile-append.txt";
wchar_t* filename_write;
wchar_t* filename_append;

void* myExit(int exitVal);

int main()
{
    int ii;
    char buf[512];
    DWORD rval;
    SECURITY_ATTRIBUTES sa;
    HANDLE hFile = 0;
    DWORD pid;

    // See if Terminal Services are enabled
    OSVERSIONINFOEX osVersionInfo;
    ULONGLONG dwlConditionMask = VerSetConditionMask(0, VER_SUITENAME, VER_AND);
    ZeroMemory(&osVersionInfo, sizeof(osVersionInfo));
    osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
    osVersionInfo.wSuiteMask = VER_SUITE_TERMINAL;
    int tsEnabled = VerifyVersionInfo((POSVERSIONINFOEX)&osVersionInfo, VER_SUITENAME, dwlConditionMask);
    if (tsEnabled) {
        printf("Running on a Windows Server and Terminal Services are enabled\n");
        filename_write = filename_ts_write;
        filename_append = filename_ts_append;
    } else {
        printf("Terminal Services are not enabled so using local files\n");
        filename_write = filename_local_write;
        filename_append = filename_local_append;
    }

    // Use process id as part of the records written so we
    // know what process the records were written from.
    pid = GetCurrentProcessId();

    // Create a file using GENERIC_WRITE

    memset(&sa, 0, sizeof(sa));
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = FALSE;
    printf("CreateFile: %ws\n", filename_write);
    hFile = CreateFileW(
        filename_write,                     // lpFileName
        GENERIC_READ | GENERIC_WRITE,       // dwDesiredAccess
        FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
        &sa,                                // lpSecurityAttributes
        OPEN_ALWAYS,                        // dwCreationDisposition
        FILE_ATTRIBUTE_NORMAL,              // dwFlagsAndAttributes
        NULL);                              // hTemplateFile
    if (hFile == INVALID_HANDLE_VALUE) {
        printf("CreateFile returned INVALID_HANDLE_VALUE errno:%d\n", GetLastError());
        myExit(1);
    }

    // write COUNT records to the file that was created using GENERIC_WRITE
    rval = 0;
    for (ii = 0; ii < COUNT; ii++) {
        sprintf_s(buf, "TEST-%d\n", pid);
        printf("WriteFile: %s", buf);
        if (!WriteFile(hFile, buf, strlen(buf), &rval, NULL)) {
            errno = GetLastError();
            if (errno == ERROR_INVALID_PARAMETER) {
                printf("WriteFile returned ERROR_INVALID_PARAMETER errno:%d\n", errno);
            } else {
                printf("WriteFile ERROR: returned errno:%d\n", errno);
            }
            myExit(1);
        }
        Sleep(SLEEP);
    }

    // close the file
    CloseHandle(hFile);


    // Create a file using FILE_APPEND_DATA

    memset(&sa, 0, sizeof(sa));
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = FALSE;
    printf("CreateFile: %ws\n", filename_append);
    hFile = CreateFileW(
        filename_append,                    // lpFileName
        GENERIC_READ | FILE_APPEND_DATA,    // dwDesiredAccess
        FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
        &sa,                                // lpSecurityAttributes
        OPEN_ALWAYS,                        // dwCreationDisposition
        FILE_ATTRIBUTE_NORMAL,              // dwFlagsAndAttributes
        NULL);                              // hTemplateFile
    if (hFile == INVALID_HANDLE_VALUE) {
        printf("CreateFile returned INVALID_HANDLE_VALUE errno:%d\n", GetLastError());
        myExit(1);
    }

    // write COUNT records to the file that was created using FILE_APPEND_DATA
    rval = 0;
    for (ii = 0; ii < COUNT; ii++) {
        sprintf_s(buf, "TEST-%d\n", pid);
        printf("WriteFile: %s", buf);
        if (!WriteFile(hFile, buf, strlen(buf), &rval, NULL)) {
            errno = GetLastError();
            if (errno == ERROR_INVALID_PARAMETER) {
                printf("WriteFile returned ERROR_INVALID_PARAMETER errno:%d\n", errno);
            }
            else {
                printf("WriteFile ERROR: returned errno:%d\n", errno);
            }
            myExit(1);
        }
        Sleep(SLEEP);
    }

    // close the file
    CloseHandle(hFile);

    myExit(0);

} // main

void *myExit(int exitVal)
{
    printf("Press return to exit...\n");
    int rval = getchar();
    exit(exitVal);
} // myExit
Windows 远程桌面 writefile createfile 终端 服务

评论

0赞 user207421 11/14/2023
GENERIC_WRITE 和 FILE_APPEND_DATA 不是替代品,一个可以被另一个取代。你两者都需要。您正在写入文件:您需要GENERIC_WRITE。你在附加:你需要FILE_APPEND_DATA。你正在分享写作:你需要FILE_SHARE_WRITE。
0赞 Gary 11/15/2023
@user207421 感谢您的快速回复!当我将 GENERIC_WRITE 和 FILE_APPEND_DATA 与 FILE_SHARE_WRITE 一起使用时,我不再从 WriteFile() 返回ERROR_INVALID_PARAMETER但两个进程都不会附加该文件。文件中仅显示第二个进程的记录。您知道如何让追加在 Windows Server 上运行时工作吗?
0赞 user207421 11/15/2023
嗯。Microsoft 文档还远不清楚。尝试。但这似乎只与权限有关。我能找到的唯一样本是在每次写入之前完成的。也许这就是你需要的,或者你可以使用 C 库函数 、 和 .他们当然可以附加。FILE_APPEND_DATA | FILE_GENERIC_READSetFilePointer(hAppend, 0, NULL, FILE_END)open()write()close()
0赞 user207421 11/15/2023
另请参阅有关使用 OVERLAPPED 结构的答案。我认为这是真正的解决方案。寻找自己很容易受到时机窗口问题的影响。
0赞 user207421 11/17/2023
这回答了你的问题吗?如何在 win32 中的文件上追加数据

答: 暂无答案