Класс CSysError:
// error.h
#pragma once
#include <Windows.h>
#include <memory>
class CError
{
public:
CError();
virtual ~CError();
virtual const TCHAR* description() const = 0;
unsigned long code() const;
protected:
unsigned long m_errCode;
};
class CSysError : public CError
{
public:
CSysError();
virtual ~CSysError();
virtual const TCHAR* description() const override;
DWORD bytesInMsg() const;
protected:
std::shared_ptr<TCHAR> m_errMsg;
};
// error.cpp
#include "error.h"
CError::CError()
: m_errCode( 0UL )
{}
CError::~CError()
{}
unsigned long CError::code() const
{
return m_errCode;
}
CSysError::CSysError()
: CError()
, m_errMsg( nullptr )
{
DWORD dwErrCode = GetLastError();
HLOCAL pMsgBuf = NULL;
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
, NULL
, dwErrCode
, MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US )
, (PTSTR) &pMsgBuf
, 0
, NULL );
if( pMsgBuf != NULL )
{
m_errMsg.reset( (TCHAR*) pMsgBuf );
m_errCode = dwErrCode;
}
else
{
// LocalFree( pMsgBuf );
}
}
CSysError::~CSysError()
{}
const TCHAR* CSysError::description() const
{
return ( m_errMsg ) ? m_errMsg.get() : __TEXT( "" );
}
DWORD CSysError::bytesInMsg() const
{
if( m_errMsg )
return HeapSize( GetProcessHeap(), HEAP_NO_SERIALIZE, m_errMsg.get() );
return 0UL;
}
Проблемное место:
HANDLE hFile = CreateFile( __TEXT( "C:/Users/isnullxbh/Documents/Visual Studio 2015/Projects/winapi/example2.txt" )
, GENERIC_READ | GENERIC_WRITE
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, NULL
, NULL );
if( (unsigned) hFile == 0xffffffff )
{
CSysError sysError;
const TCHAR* pErrMsg = sysError.description();
DWORD dwBufSizeInBytes = sysError.bytesInMsg();
DWORD dwNumCharsForWrite = dwBufSizeInBytes / sizeof( TCHAR );
DWORD dwWrittenChars = 0;
WriteConsole( hSTDErr, (LPCVOID) pErrMsg, dwNumCharsForWrite, &dwWrittenChars, NULL );
if( dwNumCharsForWrite != dwWrittenChars )
{
// TODO
}
}
Когда вызывается деструктор у объекта sysError
( класс CSysError
) наблюдается неопределенное поведение (если так можно выразится): при release-конфигурации все проходит без ошибок, при debug-конфигурации - наблюдаются проблемы с разрушением std::shared_ptr
- жалуется на неполный тип TCHAR
. Что подскажите ?
Call-стек:
Я думаю, проблема в том, что Вы неправильно работаете с памятью.
Читаем документацию к функции FormatMessage
:
lpBuffer [out]
A pointer to a buffer that receives the null-terminated string that specifies the formatted message. If dwFlags
includes FORMAT_MESSAGE_ALLOCATE_BUFFER
, the function allocates a buffer using the LocalAlloc
function, and places the pointer to the buffer at the address specified in lpBuffer
.
Перевод:
Указатель на буфер, который примет строку, завершающуюся нулём, содержащую форматированное сообщение. Если dwFlags
содержит FORMAT_MESSAGE_ALLOCATE_BUFFER
, функция размещает буфер, используя функцию LocalAlloc
, и помещает указатель на буфер по адресу, указанному в lpBuffer
.
Иными словами, память для строки выделяется функцией LocalAlloc
, а Вы пихаете указатель на эту память в std::shared_ptr
, который при разрушении пытается освободить память совершенно другим методом (подозреваю, что это delete[]
). Естественно, получается неопределённое поведение. Для очистки такой памяти нужно использовать LocalFree
.
Я бы скопировал полученную строку в std::string
, которую и передал бы в std::shared_ptr
, а память немедленно очистил бы посредством LocalFree
. Или же можно создать свой маленький класс-обёртку, автоматически разрушающую такую строку и передавал бы в std::shared_ptr
его экземпляр. Например, этот класс может выглядеть так:
template<class T> class LocalAllocWrapper {
private :
T* p;
public :
LocalAllocWrapper(T* _p) : p(_p) {}
~LocalAllocWrapper() {
LocalFree(p);
}
T* data() {
return p;
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
При компиляции MinGW ругается, что в dshowh присутствуют не разрешённые заголовки
Нужно изменить не имя проекта, не имя (apk) установочного файла, а когда файл уже установился и в меню телефона появляется иконка для запуска...
Есть класс, наследованный от QAbstractItemModel и QTreeView на основе этой моделиМодель строится на основе таблицы вида id/name/parent_id взятой из базы данных...