Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 大于2**32字节的文件上的shCreateStreamonFilex_C++_Winapi_Com - Fatal编程技术网

C++ 大于2**32字节的文件上的shCreateStreamonFilex

C++ 大于2**32字节的文件上的shCreateStreamonFilex,c++,winapi,com,C++,Winapi,Com,对于使用的文件,我得到了一个IStream,但是当seek指针的新位置为2**32字节或更大时,它的Read()方法在非常大的文件上出现错误 : 此方法根据实际读取的字节数调整搜索指针 这与我所知道的所有平台上的read(2)和fread(3)的行为相同 但对于这些流,我在某些情况下看到的实际行为并非如此: Seek(2**32-2,Seek\u SET,&pos),Read(buf,1,&bytesRead),Seek(0,MOVE\u CUR,&pos)→ 字节读取==1和位置==2**3

对于使用的文件,我得到了一个
IStream
,但是当seek指针的新位置为2**32字节或更大时,它的
Read()
方法在非常大的文件上出现错误

:

此方法根据实际读取的字节数调整搜索指针

这与我所知道的所有平台上的
read(2)
fread(3)
的行为相同

但对于这些流,我在某些情况下看到的实际行为并非如此:

  • Seek(2**32-2,Seek\u SET,&pos)
    Read(buf,1,&bytesRead)
    Seek(0,MOVE\u CUR,&pos)
    → <代码>字节读取==1和
    位置==2**32-1
    ,如预期
  • Seek(2**32-1,Seek\u SET,&pos)
    Read(buf,1,&bytesRead)
    Seek(0,MOVE\u CUR,&pos)
    bytesRead==1
    ,但是
    pos==(2**32-1)+4096
    ,这是不正确的。这意味着任何后续读取(没有另一个
    Seek
    来固定光标位置)都读取了错误的数据,我的应用程序无法工作
我是不是“拿错了”?是否需要设置一些标志以使该类正常运行?或者这是
Shlwapi.dll
中的错误

下面的代码为我重现了这个问题。(设置
OFFSET=WORKS
以查看成功案例。)

#包括“stdafx.h”
静态常数int64_t TWO_three_TWO=4294967296LL;
静态常数int64_t WORKS=2_三十二-2LL;
静态常数int64\u t FAILS=TWO\u three\u TWO-1LL;
静态常量int64\u t OFFSET=失败;
静态无效检查位置(CComPtrfileStream,ULONGLONG预期位置)
{
大整数移动;
ULARGE_整数新位置;
move.QuadPart=0;
HRESULT hr=fileStream->Seek(移动、搜索当前和新位置);
断言(成功(hr));
ULONGLONG error=newPosition.QuadPart-expectedPosition;
断言(错误==0);
}
int main()
{
const wchar_t*path=/*大于2**32字节的文件路径*/L“C:\\users\\wjt\\Desktop\\eos-eos3.1-amd64-amd64.170216-122002.base.img”;
CComPtrfileStream;
HRESULT-hr;
hr=shcreatestreamonfilex(路径、STGM\u读取、文件属性\u正常、FALSE、NULL和fileStream);
断言(成功(hr));
大整数移动;
ULARGE_整数新位置;
//前进
move.QuadPart=偏移量;
hr=fileStream->Seek(移动、搜索集和新位置);
断言(成功(hr));
断言(newPosition.QuadPart==偏移量);
//检查位置
检查位置(文件流、偏移量);
//阅读
char-buf[1];
ULONG字节读取=0;
hr=fileStream->Read(buf、1和bytesRead);
断言(成功(hr));
断言(bytesRead==1);
//检查位置:如果Read()调用移动光标,此断言将失败
//跨越2**32字节边界
检查位置(文件流,偏移量+1);
返回0;
}

这确实是windows的错误。在多个windows版本上测试,包括最新的
SHCore.DLL
version
10.0.14393.0
x64。复制的简单方法:

void BugDemo(PCWSTR path)
{
    // FILE_FLAG_DELETE_ON_CLOSE !
    HANDLE hFile = CreateFile(path, FILE_GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_DELETE, 0, 
        CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, 0);

    if (hFile != INVALID_HANDLE_VALUE)
    {
        ULONG dwBytesRet;
        // i not want really take disk space
        if (DeviceIoControl(hFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwBytesRet, NULL))
        {
            static FILE_END_OF_FILE_INFO eof = { 0, 2 };// 8GB
            if (SetFileInformationByHandle(hFile, FileEndOfFileInfo, &eof, sizeof(eof)))
            {
                IStream* pstm;
                if (!SHCreateStreamOnFileEx(path, STGM_READ|STGM_SHARE_DENY_NONE, 0,FALSE, NULL, &pstm))
                {
                    LARGE_INTEGER pos = { 0xffffffff };
                    ULARGE_INTEGER newpos;
                    if (!pstm->Seek(pos, STREAM_SEEK_SET, &newpos) && !pstm->Read(&newpos, 1, &dwBytesRet))
                    {
                        pos.QuadPart = 0;
                        if (!pstm->Seek(pos, STREAM_SEEK_CUR, &newpos))
                        {
                            DbgPrint("newpos={%I64x}\n", newpos.QuadPart);//newpos={100000fff}
                        }
                    }
                    pstm->Release();
                }
            }
        }

        // close and delete
        CloseHandle(hFile);
    }
}

void BugDemo()
{
    WCHAR path[MAX_PATH];
    if (ULONG len = GetTempPath(RTL_NUMBER_OF(path), path))
    {
        if (len + 16 < MAX_PATH)
        {
            FILETIME ft;
            GetSystemTimeAsFileTime(&ft);
            swprintf(path + len, L"%08x%08x", ~ft.dwLowDateTime, ft.dwHighDateTime);
            BugDemo(path);
        }
    }
}
void BugDemo(PCWSTR路径)
{
//文件\u标志\u删除\u关闭!
HANDLE hFile=CreateFile(路径,文件\通用\写入,文件\共享\读取,文件\共享\删除,0,
创建_新建,文件_属性_临时|文件_标志_删除_关闭,0);
if(hFile!=无效的句柄值)
{
乌隆·德比特斯特雷特;
//我不想真的占用磁盘空间
if(设备控制(hFile、FSCTL\u SET\u SPARSE、NULL、0、NULL、0和dwBytesRet、NULL))
{
静态文件\u END\u OF_FILE\u INFO eof={0,2};//8GB
if(SetFileInformationByHandle(hFile、fileendofileinfo、&eof、sizeof(eof)))
{
IStream*pstm;
如果(!shCreateStreamonFilex(路径、STGM_读取、STGM_共享、拒绝、无、0、FALSE、NULL和pstm))
{
大整数pos={0xffffffffff};
ULARGE_整数newpos;
如果(!pstm->Seek(pos、STREAM_Seek_SET和newpos)和&!pstm->Read(&newpos、1和dwBytesRet))
{
四分位=0;
如果(!pstm->Seek(pos、STREAM\u Seek\u CUR和newpos))
{
DbgPrint(“newpos={%I64x}\n”,newpos.QuadPart);//newpos={100000fff}
}
}
pstm->Release();
}
}
}
//关闭并删除
闭合手柄(hFile);
}
}
void BugDemo()
{
WCHAR路径[最大路径];
if(ULONG len=GetTempPath(路径的RTL_编号,路径))
{
if(长度+16<最大路径)
{
文件时间ft;
GetSystemTimeAsFileTime(&ft);
swprintf(path+len,L“%08x%08x”,~ft.dwLowDateTime,ft.dwHighDateTime);
BugDemo(路径);
}
}
}
I trace
virtual long CFileStream::Seek(大整数、ULONG、ULARGE整数*)在调试器下,可以确认此函数的设计不适用于大于4GB大小的文件


更确切地说,为什么
100000FFF
offset-
CFileStream
使用内部缓冲区读取
1000
字节大小。当您要求从
FFFFFFFF
offset读取1字节时,它实际上将
1000
字节读取到缓冲区,文件偏移量变为
10000fff
。然后调用
Seek(0,STREAM\u Seek\u CUR,&newpos)
-
CFileStream
调用
SetFilePointer(hFile,1-1000,0/*lpDistanceToMoveHigh*/,FILE\u CURRENT)

(1这是缓冲区中的内部位置,因为我们读取1字节减去缓冲区大小1000)。如果不考虑溢出,则溢出可以
(1000000FFF+(1-1000))==100000000

了解

如果lpDistanceToMoveHigh为NULL且新文件位置不适合 在32位值中,函数失败并返回
void BugDemo(PCWSTR path)
{
    // FILE_FLAG_DELETE_ON_CLOSE !
    HANDLE hFile = CreateFile(path, FILE_GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_DELETE, 0, 
        CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, 0);

    if (hFile != INVALID_HANDLE_VALUE)
    {
        ULONG dwBytesRet;
        // i not want really take disk space
        if (DeviceIoControl(hFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwBytesRet, NULL))
        {
            static FILE_END_OF_FILE_INFO eof = { 0, 2 };// 8GB
            if (SetFileInformationByHandle(hFile, FileEndOfFileInfo, &eof, sizeof(eof)))
            {
                IStream* pstm;
                if (!SHCreateStreamOnFileEx(path, STGM_READ|STGM_SHARE_DENY_NONE, 0,FALSE, NULL, &pstm))
                {
                    LARGE_INTEGER pos = { 0xffffffff };
                    ULARGE_INTEGER newpos;
                    if (!pstm->Seek(pos, STREAM_SEEK_SET, &newpos) && !pstm->Read(&newpos, 1, &dwBytesRet))
                    {
                        pos.QuadPart = 0;
                        if (!pstm->Seek(pos, STREAM_SEEK_CUR, &newpos))
                        {
                            DbgPrint("newpos={%I64x}\n", newpos.QuadPart);//newpos={100000fff}
                        }
                    }
                    pstm->Release();
                }
            }
        }

        // close and delete
        CloseHandle(hFile);
    }
}

void BugDemo()
{
    WCHAR path[MAX_PATH];
    if (ULONG len = GetTempPath(RTL_NUMBER_OF(path), path))
    {
        if (len + 16 < MAX_PATH)
        {
            FILETIME ft;
            GetSystemTimeAsFileTime(&ft);
            swprintf(path + len, L"%08x%08x", ~ft.dwLowDateTime, ft.dwHighDateTime);
            BugDemo(path);
        }
    }
}