In Qt Creator, I could view the qDebug(), qWarning() etc. output directly in the IDE. How could I do this in Visual Studio?
There is an easier way:
Go to Project Properties > Linker > System : set SubSystem to "SUBSYSTEM:CONSOLE"
You will now get a console when you run your program and qDebug() will be redirected to it. (You can also use std::cout)
When you run the program with an attached debugger, it will show in the Output Window of Visual Studio, but for Debug purposes i often redirect the debug output to some kind of nice log window, which you can do by using the function qInstallMsgHandler:
the code that i use:
#include <qapplication.h>
#include <qwidget.h>
#include <qplaintextedit.h>
#include <qmetaobject.h>
#include <qthread.h>
#include <qboxlayout.h>
#include <qdatetime.h>
#include <qdebug.h>
#include <cstdio>
#include <cassert>
QWidget *DEBUG_MESSAGE_DISPLAY_WIDGET = NULL;
QPlainTextEdit *DEBUG_MESSAGE_DISPLAY_TEXTEDIT = NULL;
void setupDebugDisplay();
void debugMessageDisplayFunc(QtMsgType type, const char *msg);
int main( int argc, char* argv[] )
{
QApplication a( argc, argv );
a.setQuitOnLastWindowClosed( true );
setupDebugDisplay();
// your code here.... e.g:
// YourMainWindow mainWindow;
int ret = a.exec();
delete DEBUG_MESSAGE_DISPLAY_WIDGET;
return ret;
}
void setupDebugDisplay()
{
QWidget *widget = new QWidget();
widget->setWindowTitle( "Debug Log" );
widget->setAttribute( Qt::WA_QuitOnClose, false ); //quit only when mainwindow is closed
QBoxLayout* layout = new QVBoxLayout();
widget->setLayout( layout );
QPlainTextEdit *textEdit = new QPlainTextEdit( widget );
QFont font = QFont( "Monospace" );
font.setStyleHint(QFont::TypeWriter);
textEdit->setFont( font );
textEdit->setReadOnly(true);
layout->addWidget( textEdit );
widget->show();
DEBUG_MESSAGE_DISPLAY_WIDGET = widget;
DEBUG_MESSAGE_DISPLAY_TEXTEDIT = textEdit;
qInstallMsgHandler(debugMessageDisplayFunc);
}
void debugMessageDisplayFunc(QtMsgType type, const char *msg)
{
bool do_abort = false;
const char* msgTypeStr = NULL;
switch (type) {
case QtDebugMsg:
msgTypeStr = "Debug";
break;
case QtWarningMsg:
msgTypeStr = "Warning";
break;
case QtCriticalMsg:
msgTypeStr = "Critical";
break;
case QtFatalMsg:
msgTypeStr = "Fatal";
do_abort = true;
default:
assert(0);
return;
}
QTime now = QTime::currentTime();
QString formattedMessage =
QString::fromLatin1("%1 %2 %3")
.arg(now.toString("hh:mm:ss:zzz"))
.arg(msgTypeStr).arg(msg);
// print on console:
fprintf( stderr, "%s\n", formattedMessage.toLocal8Bit().constData() );
// print in debug log window
{
bool isMainThread = QThread::currentThread() == QApplication::instance()->thread();
if(DEBUG_MESSAGE_DISPLAY_TEXTEDIT)
{
if( isMainThread )
DEBUG_MESSAGE_DISPLAY_TEXTEDIT->appendPlainText( formattedMessage );
else // additional code, so that qDebug calls in threads will work aswell
QMetaObject::invokeMethod( DEBUG_MESSAGE_DISPLAY_TEXTEDIT, "appendPlainText", Qt::QueuedConnection, Q_ARG( QString, formattedMessage ) );
}
}
}
It redirect to Output windows of visual studio.
You may as well use DebugView++ for QDebug it still works with it
https://github.com/CobaltFusion/DebugViewPP
OutputDebugString is key to do that.
How I do with Qt 5.15:
#if defined(Q_OS_WIN) && defined(QT_DEBUG)
qInstallMessageHandler([](QtMsgType type, const QMessageLogContext &ctx, const QString &message) {
const QString msg = qFormatLogMessage(type, ctx, message);
// write logs to Output window of Visual Studio
{
QString prefix;
switch (type) {
case QtWarningMsg:
prefix = "[WARNING] ";
break;
case QtCriticalMsg:
prefix = "[CRITICAL ERROR] ";
break;
case QtFatalMsg:
prefix = "[FATAL ERROR] ";
break;
}
auto msgW = QString(prefix + message).toStdWString();
msgW.append(L"\n");
OutputDebugString(msgW.c_str());
}
});
#endif
Related
I have a small example .ui where the user can drag and drop from a QListWidget to a QGraphicsView using QGraphicsProxyWidget a specific widget (in my case is a QTableWidget) as shown below.
Basically the behavior I have been looking for is:
If I drag and drop "Imgaes" than the QTableWidget on the QGraphicsView will have 2 columns and 2 rows; (which is correct)
If I drag and drop "Path" than the QTableWidget on the QGraphicsView will have 3 columns and 3 rows; (which is wrong)
[1] : https://imgur.com/NQ1DZpx
Below the selection of "Path", which still give 2 rows and 2 columns instead of 3 rows and 3 columns
[2] : https://imgur.com/d4YcOiL
Below the code:
scene.h
class Scene : public QGraphicsScene {
enum LaserTableWidget {
Images,
Path
};
Q_ENUM(LaserTableWidget)
public:
Scene(QObject *parent = nullptr);
void compare(const QString& comp);
template<typename QEnum>
std::string QtEnumToString (const QEnum value)
{
return std::string(QMetaEnum::fromType<QEnum>().valueToKey(value));
}
protected:
void dropEvent(QGraphicsSceneDragDropEvent *event);
scene.cpp
Scene::Scene(QObject *parent) : QGraphicsScene(parent) {
setBackgroundBrush(Qt::lightGray);
}
void Scene::compare(const QString &comp)
{
// get information about the enum named "LaserTableWidget"
QMetaObject MetaObject = this->staticMetaObject;
QMetaEnum MetaEnum = MetaObject.enumerator(MetaObject.indexOfEnumerator("LaserTableWidget"));
QStringList tabs;
switch (MetaEnum.keyToValue(comp.toUpper().toLatin1()))
// or simply switch (MetaEnum.keyToValue(word)) if no string modification is needed
{
case Images:
for (const QString &color : tabs) {
QPoint initPos(0,0);
QTableWidget *wgt = new QTableWidget;
QGraphicsRectItem *proxyControl = addRect(initPos.x(), initPos.y(), wgt->width(), 20, QPen(Qt::black), QBrush(Qt::darkGreen)); // widget->width() works properly here because of the resize(layout->sizeHint()) that we have used inside it
proxyControl->setFlag(QGraphicsItem::ItemIsMovable, true);
proxyControl->setFlag(QGraphicsItem::ItemIsSelectable, true);
wgt->setColumnCount(2);
wgt->setRowCount(2);
for (int ridx = 0 ; ridx < wgt->rowCount() ; ridx++ )
{
for (int cidx = 0 ; cidx < wgt->columnCount() ; cidx++)
{
QTableWidgetItem* item = new QTableWidgetItem();
item->setText(QString("%1").arg(ridx));
wgt->setItem(ridx,cidx,item);
}
}
QGraphicsProxyWidget * const proxy = addWidget(wgt);
// In my case the rectangular graphics item is supposed to be above my widget so the position of the widget is shifted along the Y axis based on the height of the rectangle of that graphics item
proxy->setPos(initPos.x(), initPos.y()+proxyControl->rect().height());
proxy->setParentItem(proxyControl);
}
break;
case Path:
for (const QString &color : tabs) {
QPoint initPos(0,0);
QTableWidget *wgt = new QTableWidget;
QGraphicsRectItem *proxyControl = addRect(initPos.x(), initPos.y(), wgt->width(), 20, QPen(Qt::black), QBrush(Qt::darkGreen)); // widget->width() works properly here because of the resize(layout->sizeHint()) that we have used inside it
proxyControl->setFlag(QGraphicsItem::ItemIsMovable, true);
proxyControl->setFlag(QGraphicsItem::ItemIsSelectable, true);
wgt->setColumnCount(3);
wgt->setRowCount(3);
for (int ridx = 0 ; ridx < wgt->rowCount() ; ridx++ )
{
for (int cidx = 0 ; cidx < wgt->columnCount() ; cidx++)
{
QTableWidgetItem* item = new QTableWidgetItem();
item->setText(QString("%1").arg(ridx));
wgt->setItem(ridx,cidx,item);
}
}
QGraphicsProxyWidget * const proxy = addWidget(wgt);
// In my case the rectangular graphics item is supposed to be above my widget so the position of the widget is shifted along the Y axis based on the height of the rectangle of that graphics item
proxy->setPos(initPos.x(), initPos.y()+proxyControl->rect().height());
proxy->setParentItem(proxyControl);
}
break;
default:
break;
}
}
void Scene::dropEvent(QGraphicsSceneDragDropEvent *event) {
QByteArray encoded =
event->mimeData()->data("application/x-qabstractitemmodeldatalist");
QDataStream stream(&encoded, QIODevice::ReadOnly);
QStringList rosTables;
while (!stream.atEnd()) {
int row, col;
QMap<int, QVariant> roleDataMap;
stream >> row >> col >> roleDataMap;
rosTables << roleDataMap[Qt::DisplayRole].toString();
}
compare(const QString &comp)
}
I tried to use the template function declared on the header file that for completeness I am also attaching below:
template<typename QEnum>
std::string QtEnumToString (const QEnum value)
{
return std::string(QMetaEnum::fromType<QEnum>().valueToKey(value));
}
Maybe I the template function is the wrong choice? I was trying to find a way to use it if possible.
That is the reason why I switched to a void compare(const QString& comp); function and tried to delegate the job to a switch - case statement but that also is not working as I expect and I still see the same exact QtableWidget dropped onto the QGraphicsView.
Of course I did more research and came across this source and above all this post which was useful to understand the basic comparison and following this post I decided to go ahead and try to apply the Q_ENUM - QString or even the QStringList as a valuable tool. But I could not figure out what I was doing wrong.
Can anyone please shed light on which approach could be better? (or maybe they are both correct) and try to explain what I am missing to solve this problem.
There are two problems I see in your code:
Wrong parameter passed to keyToValue(). Since you have Image and Path in your enum, the valid values to pass to keyToValue() are "Image" (returns 0), and "Path" (return 1), other values will returns -1.
In the function Scene::compare(), tabs is just created as an empty QStringList, so the code inside the loops for (const QString &color : tabs) are never executed
Below is a test program to show you what I mean:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMetaEnum>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
enum LaserTableWidget
{
Images,
Path
};
Q_ENUM(LaserTableWidget)
template<typename enum_type>
QString QtEnumToString (const enum_type value)
{
return QMetaEnum::fromType<enum_type>().valueToKey(value);
}
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QDebug>
#include <QStringList>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// First problem: wrong parameter passed to keyToValue()
qDebug() << 1 << QtEnumToString<LaserTableWidget>(Images);
qDebug() << 2 << QtEnumToString<LaserTableWidget>(Path);
QMetaObject MetaObject = this->staticMetaObject;
QMetaEnum MetaEnum = MetaObject.enumerator(MetaObject.indexOfEnumerator("LaserTableWidget"));
qDebug() << 3 << MetaEnum.keyToValue(QtEnumToString<LaserTableWidget>(Path).toUpper().toLatin1());
qDebug() << 4 << MetaEnum.keyToValue(QtEnumToString<LaserTableWidget>(Path).toStdString().c_str());
switch (MetaEnum.keyToValue(QtEnumToString<LaserTableWidget>(Path).toUpper().toLatin1()))
{
case Images:
qDebug() << "switch Images";
break;
case Path:
qDebug() << "switch Path";
break;
default:
qDebug() << "switch default";
break;
}
// Second problem: tabs is empty
QStringList tabs;
for (const QString &color : tabs)
qDebug() << color; // this line is never executed
}
MainWindow::~MainWindow()
{
}
Output:
1 "Images"
2 "Path"
3 -1
4 1
switch default
I have been attempting to deploy my app to windows (a laptop without QT installed) and I am assuming I have a dependency issue, but I am getting no error messages.
Currently using: C:\Qt\5.12.6\mingw73_64
My app runs fine in QtCreator, and I have used windeployqt (with adding the qmldir as well), which works fine initially. However, I change my C:\Qt folder to C:\QtHidden (I read somewhere that this imitates not having QT installed) and my .exe file does not load. I can click on it, but no error message comes up, my mouse cursor changes to a loading cursor for a few moments, and then nothing happens. Does anyone know of a way I can log what is happening so I can try to fix it?
I also tried following https://wiki.qt.io/Deploy_an_Application_on_Windows 'initial deployment' instructions where I put every .dll file from /bin, and every folder from plugins and qml. The same no error and no opening problem occurs and I'm not sure what else I can do.
Any ideas?
Thanks
Implement custom message logger. I used this code once (this one is in my actuall app and pretty generic). It can log QML errors too:
#include <QDateTime>
#include <QStandardPaths>
#include <QMessageBox>
#include <QDir>
#include <QDebug>
#include <QThread>
#include <QTextStream>
#include <iostream>
QUrl logFileUrl;
bool logToFile=true;
int appLogLevel=3;
void logger(QtMsgType type, const QMessageLogContext &context, const QString &msg){
bool writeLogLine = false;
QString line;
QString msgType;
QString time = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");
switch (type) {
case QtInfoMsg:{
msgType = "Info";
break;
}
case QtDebugMsg:{
msgType = "Debug";
break;
}
case QtWarningMsg:{
msgType = "Warning";
break;
}
case QtCriticalMsg:{
msgType = "Critical";
break;
}
case QtFatalMsg:{
msgType = "Fatal";
abort();
}
}
line = QString("[%1] <%2> %3 (%4) | %5:%6 (%7) '%8'")
.arg(time)
.arg(static_cast<int>(reinterpret_cast<intptr_t>(QThread::currentThreadId())))
.arg(msgType)
.arg(context.category)
.arg(context.file)
.arg(context.line)
.arg(context.function)
.arg(msg);
if (!logToFile){
writeLogLine = false;
std::cout << line.toStdString() << std::endl;
} else {
switch (appLogLevel){
case 0:{
writeLogLine = false;
break;
}
case 1:{
if (type == QtFatalMsg)
writeLogLine = true;
break;
}
case 2:{
if (type == QtCriticalMsg || type == QtFatalMsg)
writeLogLine = true;
break;
}
case 3:{
if (type != QtInfoMsg && type != QtDebugMsg)
writeLogLine = true;
break;
}
case 4:{
if (type != QtDebugMsg)
writeLogLine = true;
break;
}
case 5:{
writeLogLine = true;
break;
}
}
}
if (writeLogLine){
QFile logFile(logFileUrl.toLocalFile());
if (logFile.open(QIODevice::WriteOnly | QIODevice::Append)) {
QTextStream ts(&logFile);
ts << line << endl;
logFile.close();
} else {
QMessageBox msgBox;
msgBox.setWindowTitle("WARNING");
msgBox.setIcon(QMessageBox::Warning);
msgBox.setText(logFile.errorString());
msgBox.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
msgBox.exec();
}
}
}
And the installer it using qInstallMessageHandler:
qInstallMessageHandler(logger);
Check documentation here https://doc.qt.io/qt-5/qtglobal.html#qInstallMessageHandler
P.S. - this code also displays all message in your QtCreator instance when running from there.
As title says, I am trying to create MFC dialog-based app to let the user select the file destination folder.
I am doing this by using CMFCShellTreeCtrl. However, somehow there is only one root item which is Desktop. I would like to see all items like My Computer, C drive etc.
Could you please tell me what's wrong and how do I fix it. Thanks.
Edit: Sorry I forgot to post my code. (Very simple dialog for browsing)
// BrowseDlg.cpp : implementation file
//
#include "stdafx.h"
#include "MFC Grab to FTP.h"
#include "BrowseDlg.h"
#include "afxdialogex.h"
// CBrowseDlg dialog
IMPLEMENT_DYNAMIC(CBrowseDlg, CDialog)
CBrowseDlg::CBrowseDlg(CWnd* pParent /*=NULL*/)
: CDialog(CBrowseDlg::IDD, pParent)
{
}
CBrowseDlg::~CBrowseDlg()
{
}
void CBrowseDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_PATH, m_PathTree);
}
BEGIN_MESSAGE_MAP(CBrowseDlg, CDialog)
ON_NOTIFY(TVN_SELCHANGED, IDC_PATH, &CBrowseDlg::OnTvnSelchangedMfcshelltree1)
ON_BN_CLICKED(IDOK, &CBrowseDlg::OnBnClickedOk)
END_MESSAGE_MAP()
// CBrowseDlg message handlers
BOOL CBrowseDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
m_PathTree.Expand(m_PathTree.GetRootItem(),TVE_EXPAND);
return TRUE; // return TRUE unless you set the focus to a control
}
void CBrowseDlg::OnTvnSelchangedMfcshelltree1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
}
void CBrowseDlg::OnBnClickedOk()
{
m_PathTree.GetItemPath(path,m_PathTree.GetSelectedItem());
// TODO: Add your control notification handler code here
CDialog::OnOK();
}
//
#pragma once
#include "afxshelltreectrl.h"
// CBrowseDlg dialog
// header file
class CBrowseDlg : public CDialog
{
DECLARE_DYNAMIC(CBrowseDlg)
public:
CBrowseDlg(CWnd* pParent = NULL); // standard constructor
virtual ~CBrowseDlg();
// Dialog Data
enum { IDD = IDD_BROWSER };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnTvnSelchangedMfcshelltree1(NMHDR *pNMHDR, LRESULT *pResult);
CString path;
CMFCShellTreeCtrl m_PathTree;
afx_msg void OnBnClickedOk();
virtual BOOL OnInitDialog();
};
The problem is that CShellManager in not initialized. You have to do it manually. To initialize it you need to call CWinAppEx::InitShellManager() in OnInitInstance() of your CWinApp-derived class.
There is an alternative to using CMFCShellTreeCtrl, if you just want to pick a folder: IFileDialog.
This is my code for a select folder dialog (rather complicated, because I still want to support Windows XP using XFolderDialog):
HINSTANCE hEasyCTXP_DLL = NULL;
// Select Folder Dialog -- uses either CXFolderDialog or IFileDialog
// to open a folder picker dialog depending on OS version
// returns "" if Cancel was pressed or something else went wrong
// Note: This is just multi-byte code and not yet unicode compatible!
BOOL SelectFolder(LPSTR sFolder, LPCTSTR sTitle = "Choose Folder")
{
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (GetVersionEx((OSVERSIONINFO *)&osvi) && osvi.dwMajorVersion >= 6) // Vista or higher?
{
if (!(hEasyCTXP_DLL = LoadLibrary("XPHelper.dll")))
{
AfxMessageBox("Error opening Select Folder dialog. XPHelper.dll may not be installed properly.");
return FALSE;
}
else
{
BOOL (__cdecl *pSelectFolder)(LPSTR, LPCTSTR);
pSelectFolder = (BOOL (__cdecl *)(LPSTR, LPCTSTR))GetProcAddress(hEasyCTXP_DLL, "SelectFolder");
if (pSelectFolder)
{
return (*pSelectFolder)(sFolder, sTitle);
}
else
{
AfxMessageBox("Error opening Select Folder dialog. (SelectFolder() function entry point not found.)");
return FALSE;
}
}
}
else // XP
{
CXFolderDialog dlg(sFolder);
dlg.SetTitle(sTitle);
if (dlg.DoModal() == IDOK)
{
CString csPath = dlg.GetPath();
strcpy(sFolder, (LPCTSTR)csPath);
return TRUE;
}
else
return FALSE;
}
}
Here comes the function I provide in XPHelper.dll. This dll is delay loaded only, if Vista or later OS is used, so the main program won't fail because of missing dependencies in Windows XP:
// sFolder should be at least MAX_FILE in size!
extern "C" BOOL SelectFolder(LPSTR sFolder, LPCTSTR sTitle)
{
BOOL bRet = TRUE;
IFileDialog *pfd;
LPWSTR pwstrPath;
HRESULT hr;
if (SUCCEEDED(hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd))))
{
DWORD dwOptions;
hr = pfd->GetOptions(&dwOptions);
if (SUCCEEDED(hr))
hr = pfd->SetOptions(dwOptions | FOS_PICKFOLDERS); // put IFileDialog in folder mode
if (SUCCEEDED(hr))
{
WCHAR wcTitle[MAX_PATH+1];
if (MultiByteToWideChar(CP_ACP, 0, sTitle, (int)min(strlen(sTitle), MAX_PATH), wcTitle, sizeof(MAX_PATH + 1)))
{
wcTitle[min(strlen(sTitle), MAX_PATH)] = '\0';
pfd->SetTitle(wcTitle); // Set dialog title
}
char *cp = sFolder;
WCHAR wcDefaultPath[MAX_PATH+1];
IShellItem *psi;
if (MultiByteToWideChar(CP_ACP, 0, cp, (int)strlen(cp), wcDefaultPath, MAX_PATH + 1))
{
wcDefaultPath[strlen(cp)] = '\0';
if (SUCCEEDED(::SHCreateItemFromParsingName(wcDefaultPath, NULL, IID_PPV_ARGS(&psi))))
{
hr = pfd->SetFileName(wcDefaultPath);
hr = pfd->SetFolder(psi);
psi->Release();
}
}
}
if (SUCCEEDED(hr))
hr = pfd->Show(AfxGetMainWnd()->GetSafeHwnd());
if (SUCCEEDED(hr))
{
IShellItem *psi;
if (SUCCEEDED(pfd->GetResult(&psi)))
{
if(SUCCEEDED(psi->GetDisplayName(SIGDN_FILESYSPATH, &pwstrPath)))
{
int nSize = (int)wcslen(pwstrPath);
WideCharToMultiByte(CP_ACP, 0, pwstrPath, nSize, sFolder, MAX_PATH+1, NULL, NULL);
sFolder[nSize] = '\0';
::CoTaskMemFree(pwstrPath);
}
else
{
AfxMessageBox("IShellItem::GetDisplayName() failed.");
bRet = FALSE;
}
psi->Release();
}
else
{
AfxMessageBox("IFileDialog failed.");
bRet = FALSE;
}
}
pfd->Release();
}
if(!SUCCEEDED(hr))
bRet = FALSE;
return bRet;
}
I spent much time to capture unhandled exceptions in my process (win32) using API so called setunhandledexceptionfilter().
But I haven't captured exception when WER(Windows Error Report - which is well know for DR.watson) is showed.
Is impossible to catch all of exceptions without third-party in my APP?
I think that there is method for handling, but I don't get it.
I am not accustomed to Windows DEV environment. that's why I lost my mental in googling.
Below is my test-case in vc110(Visual Studio 2012).
chat test[65];
int main() {
// after attaching unhandled exception call-back using setunhandledexceptionfilter()
// die point (ACCESS_VIOLATION c0000005)
for (int k=0; k<1000000; k++)
test[k]=65;
My callback isn't called after WER(windows Error Report) occurs. It doesn't work as my intend.
*But strcpy(NULL, "TEST") which is okay (SUCCESS)*
Below is my source code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/stat.h>
#include <assert.h>
#include <process.h>
#include <direct.h>
#include <conio.h>
#include <time.h>
#include <Windows.h>
#include <tchar.h>
#include <dbghelp.h>
#include <stdio.h>
#include <crtdbg.h>
#include <WinBase.h>
#pragma comment ( lib, "dbghelp.lib" )
void CreateMiniDump( EXCEPTION_POINTERS* pep );
BOOL CALLBACK MyMiniDumpCallback(
PVOID pParam,
const PMINIDUMP_CALLBACK_INPUT pInput,
PMINIDUMP_CALLBACK_OUTPUT pOutput
);
///////////////////////////////////////////////////////////////////////////////
// Minidump creation function
//
#if 0
LONG WINAPI lpTopLevelExceptionFilter(EXCEPTION_POINTERS* ExceptionInfo);
#endif
void CreateMiniDump( EXCEPTION_POINTERS* pep )
{
time_t t;
struct tm *tinfo;
wchar_t dump_name[128];
HANDLE hFile;
time(&t);
tinfo = localtime(&t);
wcsftime(dump_name, 128, L"MiniDump[%Y%m%d][%H_%M_%S].dmp", tinfo);
// file format MiniDump[YYYYMMDD][HH_MM_SEC]
hFile = CreateFile(dump_name, GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) )
{
// Create the minidump
MINIDUMP_EXCEPTION_INFORMATION mdei;
MINIDUMP_CALLBACK_INFORMATION mci;
MINIDUMP_TYPE mdt;
BOOL rv;
mdei.ThreadId = GetCurrentThreadId();
mdei.ExceptionPointers = pep;
mdei.ClientPointers = FALSE;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback;
mci.CallbackParam = 0;
mdt = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory| MiniDumpWithThreadInfo);
rv = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci );
if( !rv )
_tprintf( _T("MiniDumpWriteDump failed. Error: %u \n"), GetLastError() );
else
_tprintf( _T("Minidump created.\n") );
// Close the file
CloseHandle( hFile );
}
else
{
_tprintf( _T("CreateFile failed. Error: %u \n"), GetLastError() );
}
}
///////////////////////////////////////////////////////////////////////////////
// Custom minidump callback
//
BOOL CALLBACK MyMiniDumpCallback(
PVOID pParam,
const PMINIDUMP_CALLBACK_INPUT pInput,
PMINIDUMP_CALLBACK_OUTPUT pOutput
)
{
BOOL bRet = FALSE;
// Check parameters
if( pInput == 0 )
return FALSE;
if( pOutput == 0 )
return FALSE;
// Process the callbacks
switch( pInput->CallbackType )
{
case IncludeModuleCallback:
{
// Include the module into the dump
bRet = TRUE;
}
break;
case IncludeThreadCallback:
{
// Include the thread into the dump
bRet = TRUE;
}
break;
case ModuleCallback:
{
// Does the module have ModuleReferencedByMemory flag set ?
if( !(pOutput->ModuleWriteFlags & ModuleReferencedByMemory) )
{
// No, it does not - exclude it
wprintf( L"Excluding module: %s \n", pInput->Module.FullPath );
pOutput->ModuleWriteFlags &= (~ModuleWriteModule);
}
bRet = TRUE;
}
break;
case ThreadCallback:
{
// Include all thread information into the minidump
bRet = TRUE;
}
break;
case ThreadExCallback:
{
// Include this information
bRet = TRUE;
}
break;
case MemoryCallback:
{
// We do not include any information here -> return FALSE
bRet = FALSE;
}
break;
case CancelCallback:
break;
}
return bRet;
}
LONG WINAPI exception_filter_func(EXCEPTION_POINTERS* pep)
{
if (pep == NULL) {
return EXCEPTION_EXECUTE_HANDLER;
}
if (pep->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CreateMiniDump, pep, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
} else {
CreateMiniDump(pep);
}
return EXCEPTION_EXECUTE_HANDLER;
}
char test[65];
int main(int argc, char **argv)
{
int k;
SetUnhandledExceptionFilter(exception_filter_func);
// exception occured (ACCESS_VIOLATION)
for (k=0; k<1000000; k++)
test[k]=65;
}
I am using the GLFW and only want to open a empty windows.
I downloaded the GLFW for Windows 32.
Created an empty console project and wrote this code:
#include "main.h"
#pragma comment (lib, "glfw3dll")
#pragma comment (lib, "OpenGL32")
#define GLFW_DLL
#include <glfw3.h>
#include <chrono>
#include <iostream>
using namespace std::chrono;
GLFWwindow* window;
bool running = true;
bool initialise(){
return true;
}
void update(double deltaTime){
}
void render(){
}
int main(int argc, char **argv) {
if (!glfwInit)
return -1;
window = (glfwCreateWindow(800, 600, "Hello World", nullptr, nullptr));
if (window == nullptr){
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!initialise()){
glfwTerminate();
return -1;
}
auto currentTimeStamp = system_clock::now();
auto prevTimeStamp = system_clock::now();
while (running)
{
currentTimeStamp = system_clock::now();
auto elapsed = duration_cast<milliseconds>(currentTimeStamp - prevTimeStamp);
auto seconds = double(elapsed.count()) / 1000.0;
update(seconds);
render();
glfwPollEvents();
prevTimeStamp = currentTimeStamp;
}
glfwTerminate();
return -1;
}
And I think I added the library and the header correctly.
But everytime the programm exits with -1 after the glfwCreateWindow(..) function, because this functions return null.
Can somebody help me?
if (!glfwInit)
return -1;
I'm not sure why glfwInit would be NULL unless something truly terrible happened during DLL load.
Try calling glfwInit() instead:
if( !glfwInit() )
return -1;