Get file size using GetFileSize reports a segv on a valid file

KGC*_*beX 4 c++ file-io winapi qt filesize

I have an application that scans file and collects meta data about a file. One function is to get the file size of a file. To do so, I am using the winapi function GetFileSizeEx(Handle, PLARGE_INTEGER). The parameters require a file HANDLE and a reference to a PLARGE_INTEGER aka (*LARGE_INTEGER).

To get a file HANDLE in Qt, it is suggested here to get the file handle using QFile::handle() and pass the result into _get_osfhandle(int) and cast it as a HANDLE.

HANDLE handle = (HANDLE) _get_osfhandle(file.handle()).
Run Code Online (Sandbox Code Playgroud)

Using this handle, pass it with a PLARGE_INTEGER variable into the [GetFileSizeEx(Handle, PLARGE_INTEGER)] which returns 0 if the operation failed or != 0 if the operation succeeded.

GetFileSize(HANDLE, PLARGE_INTEGER) returns with:

  • 0(或失败),可以根据此错误代码列表(作为开始,还有更多)使用GetLastError来帮助。

  • 任何表示成功的非零值

问题:

使用这种方法,我尝试对有效文件进行相同的操作,但是在调用GetFileSizeEx(Handle, PLARGE_INTEGER). 我在QFile::open(QIODevice::ReadOnly)作为测试调用之前和之后都尝试过这个,但是它仍然失败了。

 int localHandle = file.handle(); // handle returns -1 as expected
 bool localOpen = file.open(QIODevice::ReadOnly);
 if (localOpen) {
      int localFileHandle = file.handle(); // returns a valid >0 handle value
      HANDLE handle = (HANDLE) _get_osfhandle(localFileHandle); // returns a valid > 0 handle value
      PLARGE_INTEGER l = PLARGE_INTEGER(); // representation value of 0
      BOOL b = GetFileSizeEx(handle, l); // segv
      if (!b) {
           qDebug() << getLastErrorMsg();
           return QFileInfo(filepath).size();
      }

      return l->QuadPart;
 }
Run Code Online (Sandbox Code Playgroud)

我做错什么了吗?


见附件截图

在此处输入图片说明

MVCE

#include <QCoreApplication>
#include "windows.h"
#include <comdef.h>
#include <QFile>
#include <QDebug>
#include <QString>
#include <QFileInfo>

#include <windows.h>
#include <fileapi.h>
#include <io.h>

static QString toString(HRESULT hr)
{
     _com_error err{hr};
     const TCHAR* lastError = err.ErrorMessage();
     return QStringLiteral("Error 0x%1: %2").arg((quint32)hr, 8, 16, QLatin1Char('0'))
            .arg(lastError);
}

static QString getLastErrorMsg()
{
     DWORD lastError = GetLastError();
     QString s = toString(HRESULT_FROM_WIN32(lastError));
     return s;
}

static qint64 getWinAPIFileSize(QString filepath)
{
     QFile file(filepath);
     if (!file.exists()) {
          return 0;
     }

     int localHandle = file.handle(); // handle returns -1 as expected
     bool localOpen = file.open(QIODevice::ReadOnly);
     if (localOpen) {
          int localFileHandle = file.handle(); // returns a valid >0 handle value
          HANDLE handle = (HANDLE) _get_osfhandle(localFileHandle); // returns a valid > 0 handle value
          PLARGE_INTEGER l = PLARGE_INTEGER(); // representation value of 0
          BOOL b = GetFileSizeEx(handle, l); // segv
          if (!b) {
               qDebug() << getLastErrorMsg();
               return QFileInfo(filepath).size();
          }

          return l->QuadPart;
     }

     return QFileInfo(filepath).size();
}

int main(int argc, char* argv[])
{
     QCoreApplication a(argc, argv);

     QString src = QString("C:/Users/CybeX/.bash_history"); // change path to a valid file on your PC

     qint64 size = getWinAPIFileSize(src);
     qDebug() << size;

     return a.exec();
}
Run Code Online (Sandbox Code Playgroud)

Som*_*ude 9

该类型PLARGE_INTEGER是“指向LARGE_INTEGER”的别名。并且PLARGE_INTEGER()是类型“指向LARGE_INTEGER”的默认值初始化。对于所有指针,这样的初始化是一个空指针。

这意味着定义

PLARGE_INTEGER l = PLARGE_INTEGER();
Run Code Online (Sandbox Code Playgroud)

相当于

LARGE_INTEGER* l = nullptr;
Run Code Online (Sandbox Code Playgroud)

这意味着您将空指针传递给GetFileSizeEx.

您需要创建一个实际LARGE_INTEGER对象,并使用 address-of 运算符传递指向该对象的指针&

LARGE_INTEGER l;
GetFileSizeEx(handle, &l);  // Pass pointer to the variable l
Run Code Online (Sandbox Code Playgroud)