Vista上的随机MoveFileEx失败

时间:2008-09-30 14:22:22

标签: c++ windows winapi windows-vista

我注意到写入文件,关闭它并将其移动到目标位置随机失败。具体来说,MoveFileEx()将返回ERROR_ACCESS_DENIED没有明显的原因。这至少发生在Vista SP1上(32位)。在XP SP3上不会发生。

在互联网上找到关于完全相同问题的this thread,没有真正的解决方案。到目前为止,看起来错误是由Vista的搜索索引器引起的,见下文。

这里给出的代码示例足以重现问题。我也在这里粘贴它:

#include <windows.h>
#include <stdlib.h> 
#include <stdio.h> 

bool test() {
    unsigned char buf[] = {
        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 
        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 
    }; 
    HANDLE h; 
    DWORD nbytes; 
    LPCTSTR fn_tmp = "aaa"; 
    LPCTSTR fn = "bbb"; 
    h = CreateFile(fn_tmp, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, 0, 0); 
    if (h == INVALID_HANDLE_VALUE) return 0; 
    if (!WriteFile(h, buf, sizeof buf, &nbytes, 0)) goto error; 
    if (!FlushFileBuffers(h)) goto error; 
    if (!CloseHandle(h)) goto error; 
    if (!MoveFileEx(fn_tmp, fn, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH)) { 
        printf("error=%d\n", GetLastError()); 
        return 0; 
    } 
    return 1; 
error: 
    CloseHandle(h); 
    return 0; 
} 

int main(int argc, char** argv) { 
    unsigned int i; 
    for (i = 0;; ++i) { 
        printf("*%u\n", i); 
        if (!test()) return 1; 
    } 
    return 0; 
}

使用Visual Studio将其构建为控制台应用程序。正确的行为将是打印测试数字的无限循环。在Vista SP1上,程序在随机迭代次数之后退出(通常在进行100次迭代之前)。

在Windows XP SP2上不会发生这种情况。根本没有防病毒运行;并没有其他奇怪的后台进程(机器几乎是vanilla OS install + Visual Studio)。

编辑:通过Process Monitor进一步挖掘(感谢@sixlettervariables),我看不出任何特别糟糕的东西。每次测试迭代都会产生176个磁盘操作,其中大部分来自SearchProtocolHost.exe(搜索索引器)。如果停止搜索索引服务,则不会发生错误,因此看起来它是罪魁祸首。

在失败时(当应用程序获得ERROR_ACCESS_DENIED时),SearchProtocolHost.exe有两个CreateFile(s)到detination文件(bbb)打开,具有读/写/删除共享模式,所以它应该是好。其中一个开放之后是机会锁定(FSCTL_REQUEST_FILTER_OPLOCK),也许这就是原因?

无论如何,我发现我可以通过在文件上设置FILE_ATTRIBUTE_TEMPORARYFILE_ATTRIBUTE_NOT_CONTENT_INDEXED标志来避免此问题。看起来FILE_ATTRIBUTE_NOT_CONTENT_INDEXED本身就足够了,但将文件标记为临时文件也会大大减少搜索索引器导致的磁盘操作。

但这不是真正的解决方案。我的意思是,如果一个应用程序不能期望能够创建一个文件并重命名它,因为一些Vista的搜索索引器正在搞乱它,它是完全疯狂的!它应该继续重试吗?对用户大喊大叫(非常不受欢迎)?做点什么吗?

4 个答案:

答案 0 :(得分:4)

我建议您使用Process Monitor (编辑:以前称为FileMon的艺术家)来观看并查看哪个应用程序正在阻碍。它可以显示在您的计算机上进行的整个文件系统调用跟踪。

(编辑:感谢@moocha申请中的更改)

答案 1 :(得分:1)

我会说这是你的反病毒或Windows Indexing在同一时间弄乱文件。你可以在没有防病毒的情况下运行相同的测试。然后再次运行它确保临时文件是在Windows Search没有编入索引的地方创建的?

答案 2 :(得分:0)

这通常意味着其他东西在有问题的文件上有一个打开的句柄,可能是一个活动的病毒扫描程序正在运行?您是否尝试过从Sysinternals站点运行Process Monitor之类的东西?你应该过滤所有的文件操作,并更好地了解幕后发生的事情。

答案 3 :(得分:0)

Windows有一个用于存储应用程序文件的特殊位置,我不认为它已编入索引(至少在默认情况下不是这样)。在Vista中,路径是:

C:\ Users \ 用户名 \ AppData

我建议您将文件放在那里,如果它适合您的应用程序。