如何使用C ++迭代器调用Win32 API函数`WriteFile()`?

时间:2013-05-17 03:31:39

标签: c++ winapi iterator

我有一个包装Win32 API函数WriteFile()的类方法。此API函数对要写入的数据采用LPCVOID参数。但相反,我想将C ++迭代器传递给它。我该怎么做?


WriteFile()功能:

BOOL WINAPI WriteFile(
  _In_         HANDLE hFile,
  _In_         LPCVOID lpBuffer,
  _In_         DWORD nNumberOfBytesToWrite,
  _Out_opt_    LPDWORD lpNumberOfBytesWritten,
  _Inout_opt_  LPOVERLAPPED lpOverlapped
);

我的实施:

template <class Iter>
BinaryFile::RETURN_VALUES BinaryFile::Write(
                        Iter Begin,
                        Iter End,
                        DWORD & dwNumberOfBytesWritten /*= DUMMY_DWORD_REFERENCE*/)
{
    if (m_nFileState != STATE_OPEN) return WRITE_FILE_NOT_OPEN;
    BOOL bResult = WriteFile((HANDLE)       m_hFile,
                            (LPCVOID)       Begin,
                            (DWORD)         sizeof(*Begin) * (End - Begin),
                            (LPDWORD)       &dwNumberOfBytesWritten,
                            (LPOVERLAPPED)  NULL);
    m_dwLastError = ::GetLastError();
    m_FilePointer += dwNumberOfBytesWritten;
    if (bResult)
        return WRITE_SUCCESSFUL;
    else
        return WRITE_FAILURE;
}

尝试调用它:

TextFile::RETURN_VALUES TextFile::Write(std::vector<uint8_t> & String)
{
    DWORD dwNumberOfBytesWritten;
    BinaryFile::RETURN_VALUES WriteReturn = m_File.Write(
                            String.begin(),
                            String.end(),
                            dwNumberOfBytesWritten);
    if (WriteReturn == BinaryFile::RETURN_VALUES::WRITE_SUCCESSFUL)
        return WRITE_SUCCESSFUL;
    else if (dwNumberOfBytesWritten < String.end() - String.begin())
        return WRITE_NOT_ALL_WRITTEN;
    else
        return WRITE_FAILURE;
}

我得到的编译器(VS2012)错误:

  

BinaryFile.h
  错误C2440
  'type cast':无法转换为'std :: _ Vector_iterator&lt; _Myvec&gt;' 'LPCVOID'

2 个答案:

答案 0 :(得分:3)

对于std:::vector<some POD type>std::string这样的简单容器,您可以这样做:

template <class Iter>
BinaryFile::RETURN_VALUES BinaryFile::Write(
                        Iter Begin,
                        Iter End,
                        DWORD & dwNumberOfBytesWritten /*= DUMMY_DWORD_REFERENCE*/)
{
    if (m_nFileState != STATE_OPEN)
        return WRITE_FILE_NOT_OPEN;

    BOOL bResult = WriteFile((HANDLE)       m_hFile,
                            (LPCVOID)       &*Begin,
                            (DWORD)         sizeof(*Begin) * (End - Begin),
                            (LPDWORD)       &dwNumberOfBytesWritten,
                            (LPOVERLAPPED)  NULL);

    m_dwLastError = ::GetLastError();
    if (!bResult)
        return WRITE_FAILURE;

    m_FilePointer += dwNumberOfBytesWritten;
    return WRITE_SUCCESSFUL;
}

但是对于更复杂的容器,例如std::list,你必须这样做(这将适用于所有容器,但只要它们持有POD类型):

template <class Iter>
BinaryFile::RETURN_VALUES BinaryFile::Write(
                        Iter Begin,
                        Iter End,
                        DWORD & dwNumberOfBytesWritten /*= DUMMY_DWORD_REFERENCE*/)
{
    dwNumberOfBytesWritten = 0;

    if (m_nFileState != STATE_OPEN)
        return WRITE_FILE_NOT_OPEN;

    DWORD dwWritten;
    while (Begin != End)
    {
        BOOL bResult = WriteFile((HANDLE)       m_hFile,
                                (LPCVOID)       &*Begin,
                                (DWORD)         sizeof(*Begin),
                                (LPDWORD)       &dwWritten,
                                (LPOVERLAPPED)  NULL);
        m_dwLastError = ::GetLastError();
        if (!bResult)
            return WRITE_FAILURE;

        m_FilePointer += dwWritten;
        dwNumberOfBytesWritten += dwWritten;

        ++Begin;
    }

    return WRITE_SUCCESSFUL;
}

在这种情况下,dwNumberOfBytesWritten并没有那么有意义。将其更改为dwNumberOfItemsWritten会更有意义,例如:

template <class Iter>
BinaryFile::RETURN_VALUES BinaryFile::Write(
                        Iter Begin,
                        Iter End,
                        DWORD & dwNumberOfItemsWritten /*= DUMMY_DWORD_REFERENCE*/)
{
    dwNumberOfItemsWritten = 0;

    if (m_nFileState != STATE_OPEN)
        return WRITE_FILE_NOT_OPEN;

    DWORD dwWritten;
    while (Begin != End)
    {
        BOOL bResult = WriteFile((HANDLE)       m_hFile,
                                (LPCVOID)       &*Begin,
                                (DWORD)         sizeof(*Begin),
                                (LPDWORD)       &dwWritten,
                                (LPOVERLAPPED)  NULL);
        m_dwLastError = ::GetLastError();
        if (!bResult)
            return WRITE_FAILURE;

        m_FilePointer += dwWritten;
        ++dwNumberOfItemsWritten;

        ++Begin;
    }

    return WRITE_SUCCESSFUL;
}

TextFile::RETURN_VALUES TextFile::Write(std::vector<uint8_t> & String)
{
    DWORD dwNumberOfItemsWritten;
    BinaryFile::RETURN_VALUES WriteReturn = m_File.Write(
                            String.begin(),
                            String.end(),
                            dwNumberOfItemsWritten);
    if (WriteReturn == BinaryFile::RETURN_VALUES::WRITE_SUCCESSFUL)
        return WRITE_SUCCESSFUL;
    else if (dwNumberOfItemsWritten < String.size())
        return WRITE_NOT_ALL_WRITTEN;
    else
        return WRITE_FAILURE;
}

最后,在任何一种情况下,都不要忘记WriteFile()不能保证写入你请求的字节数,所以你真的应该在循环中调用它,直到所有预期的数据都被写入完全或直到发生错误,例如:

template <class Iter>
BinaryFile::RETURN_VALUES BinaryFile::Write(
                        Iter Begin,
                        Iter End,
                        DWORD & dwNumberOfItemsWritten /*= DUMMY_DWORD_REFERENCE*/)
{
    dwNumberOfItemsWritten = 0;

    if (m_nFileState != STATE_OPEN)
        return WRITE_FILE_NOT_OPEN;

    DWORD dwWritten;
    while (Begin != End)
    {
        LPBYTE pData = (LPBYTE) &*Begin;
        DWORD dwSize = sizeof(*Begin);

        do
        {
            BOOL bResult = WriteFile((HANDLE)       m_hFile,
                                     (LPCVOID)      pData,
                                     (DWORD)        dwSize,
                                     (LPDWORD)      &dwWritten,
                                     (LPOVERLAPPED) NULL);
            m_dwLastError = ::GetLastError();
            if (!bResult)
                return WRITE_FAILURE;

            m_FilePointer += dwWritten;

            pData += dwWritten;
            dwSize -= dwWritten;
        }
        while (dwSize > 0);

        ++dwNumberOfItemsWritten;
        ++Begin;
    }

    return WRITE_SUCCESSFUL;
}

答案 1 :(得分:0)

你可以(甚至应该)将你的函数专门用于向量的迭代器和原始指针,并拒绝所有其他函数。如果是vector的迭代器,你可以传递给指针式函数&*Begin,就像@chris所说的那样。我不确定,你能够为operator*迭代器调用End,但你可以尝试这个技巧:

auto e = End;
e--;
auto pe = &*e;
e++;

最后:你应该在功能开始时检查Begin != End