Problem Dsecription: Application to show an editable table in new window. e.g.: In the following table, I want to be able to edit the register values. I tried to write the application using MFC on Visual Studio 2015 in C++
===========================================================================
I'm working on a MFC application using Visual Studio 2015 in C++
I've created a Dialog Editor In which I want to show a list of registers (type list control) with two columns, one that specifies the registers numbers and a second column to show their values. I've started with the simplest case, and created such list with only one register successfully with the following code:
.cpp file:
#include "stdafx.h"
#include "MFCApplication4.h"
#include "MFCApplication4Dlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
CMFCApplication4Dlg::CMFCApplication4Dlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_MFCAPPLICATION4_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMFCApplication4Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST1, listCtrl);
}
BEGIN_MESSAGE_MAP(CMFCApplication4Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, &CMFCApplication4Dlg::OnLvnItemchangedList1)
END_MESSAGE_MAP()
BOOL CMFCApplication4Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
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);
}
}
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
listCtrl.InsertColumn(0, _T("Register Number"));
listCtrl.InsertColumn(1, _T("Register Value"));
listCtrl.SetColumnWidth(0, 200);
listCtrl.SetColumnWidth(1, 400);
int nItem = listCtrl.InsertItem(0, L"0x00");
listCtrl.SetItemText(nItem, 1, L"01000001");
return TRUE; // return TRUE unless you set the focus to a control
}
void CMFCApplication4Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
void CMFCApplication4Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
HCURSOR CMFCApplication4Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CMFCApplication4Dlg::OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
}
.h file:
#pragma once
#include "afxcmn.h"
#include "afxwin.h"
class CMFCApplication4Dlg : public CDialogEx
{
public:
CMFCApplication4Dlg(CWnd* pParent = NULL); // standard constructor
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_MFCAPPLICATION4_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
protected:
HICON m_hIcon;
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult);
CListCtrl listCtrl;
};
I would like to be able to edit the value of the register by clicking on it once or twice and typing the new value. I tried adding the following function to the header beneath the last line of CListCtrl listCtrl:
afx_msg void RightButtonClick(WPARAM wParam, LPARAM lParam, CPoint point);
the implementation of the function in .cpp file:
afx_msg void CMFCApplication4Dlg::RightButtonClick(WPARAM wParam, LPARAM lParam, CPoint point)
{
//listCtrl.SetFocus();
//CEdit* itemToEdit = listCtrl.EditLabel(1);
// The string replacing the text in the edit control.
LPCTSTR lpszmyString = _T("custom label!");
// If possible, replace the text in the label edit control.
CEdit* pEdit = listCtrl.GetEditControl();
if (pEdit != NULL)
{
pEdit->SetWindowText(lpszmyString);
}
}
and I added the following message to the message map in the .cpp file (last line in the block BEGIN_MESSAGE_MAP):
ON_WM_RBUTTONDBLCLK(LVN_ENDLABELEDIT, IDC_LIST1, &CMFCApplication4Dlg::RightButtonClick)
but unfortunately that's what I'm getting no results.
I've tried reading some more, and I've spent few hours trying to fix it, but haven't succeeded. I've tried to follow the answers to similar posts which are listed below:
Make single items editable in a list control (C++, MFC)
and
How to edit cell in listcontrol mfc?
but I wasn't able to implement the suggestions that were written there, I didn't understand how to connect all the parts of the answers. Additionally, I tried using this guide:
https://www.tutorialspoint.com/mfc/mfc_messages_events.htm
Unfortunately, nothing helped. I have a feeling that I'm missing something fundamental, perhaps I'm not handling the messages as I should. I'd appreciate it if anyone could explain to me what I'm missing and how to fix it.
Please let me know if my question isn't clear enough or if there's any other problem with it, so I'll edit it and get better.
Thank you very much for your time and attention.
I used this guide which solved my problem
Related
I want to create an ActiveX control supporting modal and modeless dialogs, which can be used in multiple IE9~IE11 tab pages at the same time. It means a pop-up of dialog box by the ActiveX control within current IE tab page won't prevent us from switching to other IE tab pages and these dialogs only appear in current IE tab page. First I created an ATL Dynamic-link library (DLL) application named as AtlActiveX using ATL/C++ by Visual Studio 2010. Then add an ActiveX control named as AtlActiveXCtl, specifying Allow merging of proxy/stub code and IObjectWithSite (IE object support) options. And then add a dialog resource named as IDD_DIALOG1. If not mentioned here, other options are left as default. Since windows/dialogs need to be supported, the member variable m_bWindowOnly has to be assigned in CAtlActiveXCtl constructor. After that add a message handler for WM_CREATE message, displaying dialog boxes in OnCreate function. The full code of AtlActiveXCtl.h is attached below.
I referred to another question Display Modal Dialog Box with ActiveX on StackOverflow. Three pop-up dialogs are tested in OnCreate() function.
#pragma once
#include "resource.h"
#include <atlctl.h>
#include "AtlActiveX_i.h"
using namespace ATL;
// Modeless dialog
class CModelessDialog : public CDialogImpl<CModelessDialog>
{
public:
enum { IDD = IDD_DIALOG1 };
BEGIN_MSG_MAP(CModelessDialog)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
END_MSG_MAP()
LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL &)
{
return 0;
}
LRESULT OnClose(UINT, WPARAM, LPARAM, BOOL &)
{
DestroyWindow();
return 0;
}
};
// CAtlActiveXCtl
class ATL_NO_VTABLE CAtlActiveXCtl :
public CComObjectRootEx<CComSingleThreadModel>,
public IDispatchImpl<IAtlActiveXCtl, &IID_IAtlActiveXCtl, &LIBID_AtlActiveXLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IOleControlImpl<CAtlActiveXCtl>,
public IOleObjectImpl<CAtlActiveXCtl>,
public IOleInPlaceActiveObjectImpl<CAtlActiveXCtl>,
public IViewObjectExImpl<CAtlActiveXCtl>,
public IOleInPlaceObjectWindowlessImpl<CAtlActiveXCtl>,
public ISupportErrorInfo,
public IObjectWithSiteImpl<CAtlActiveXCtl>,
public IQuickActivateImpl<CAtlActiveXCtl>,
public IDataObjectImpl<CAtlActiveXCtl>,
public IProvideClassInfo2Impl<&CLSID_AtlActiveXCtl, NULL, &LIBID_AtlActiveXLib>,
public CComCoClass<CAtlActiveXCtl, &CLSID_AtlActiveXCtl>,
public CComControl<CAtlActiveXCtl>
{
public:
CAtlActiveXCtl()
{
m_bWindowOnly = 1;
}
DECLARE_OLEMISC_STATUS(OLEMISC_RECOMPOSEONRESIZE |
OLEMISC_CANTLINKINSIDE |
OLEMISC_INSIDEOUT |
OLEMISC_ACTIVATEWHENVISIBLE |
OLEMISC_SETCLIENTSITEFIRST
)
DECLARE_REGISTRY_RESOURCEID(IDR_ATLACTIVEXCTL)
BEGIN_COM_MAP(CAtlActiveXCtl)
COM_INTERFACE_ENTRY(IAtlActiveXCtl)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IViewObjectEx)
COM_INTERFACE_ENTRY(IViewObject2)
COM_INTERFACE_ENTRY(IViewObject)
COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY(IOleInPlaceObject)
COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
COM_INTERFACE_ENTRY(IOleControl)
COM_INTERFACE_ENTRY(IOleObject)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
COM_INTERFACE_ENTRY(IQuickActivate)
COM_INTERFACE_ENTRY(IDataObject)
COM_INTERFACE_ENTRY(IProvideClassInfo)
COM_INTERFACE_ENTRY(IProvideClassInfo2)
COM_INTERFACE_ENTRY(IObjectWithSite)
END_COM_MAP()
BEGIN_PROP_MAP(CAtlActiveXCtl)
PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
// Example entries
// PROP_ENTRY_TYPE("Property Name", dispid, clsid, vtType)
// PROP_PAGE(CLSID_StockColorPage)
END_PROP_MAP()
BEGIN_MSG_MAP(CAtlActiveXCtl)
CHAIN_MSG_MAP(CComControl<CAtlActiveXCtl>)
DEFAULT_REFLECTION_HANDLER()
MESSAGE_HANDLER(WM_CREATE, OnCreate)
END_MSG_MAP()
// Handler prototypes:
// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
// ISupportsErrorInfo
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)
{
static const IID* const arr[] =
{
&IID_IAtlActiveXCtl,
};
for (int i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
{
if (InlineIsEqualGUID(*arr[i], riid))
return S_OK;
}
return S_FALSE;
}
// IViewObjectEx
DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE)
// IAtlActiveXCtl
public:
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
IOleInPlaceFrame *pOleInPlaceFrame = NULL;
IOleInPlaceUIWindow *pOleInPlaceUIwindow = NULL;
IOleInPlaceSite *pOleInPlaceSite = NULL;
OLEINPLACEFRAMEINFO oleInPlaceFrameInfo;
oleInPlaceFrameInfo.cb = sizeof(oleInPlaceFrameInfo);
HRESULT hr = m_spClientSite->QueryInterface(IID_IOleInPlaceSite, (LPVOID *)&pOleInPlaceSite);
if (hr != S_OK)
return S_OK;
RECT rc1, rc2;
hr = pOleInPlaceSite->GetWindowContext(&pOleInPlaceFrame, &pOleInPlaceUIwindow, &rc1, &rc2, &oleInPlaceFrameInfo);
{
HWND hWndTop = NULL;
pOleInPlaceSite->GetWindow(&hWndTop);
pOleInPlaceFrame->EnableModeless(TRUE);
::EnableWindow(hWndTop, FALSE);
//[1] Message box, cannot switch tab page
MessageBox(L"Hello, world!", L"MSG", MB_OK);
//[2] Modal dialog, cannot switch tab page
CSimpleDialog<IDD_DIALOG1> dlg;
dlg.DoModal(hWndTop);
//[3] Modeless dialog, can switch tab page, but always stays on top of IE browser
CModelessDialog *pDlg = new CModelessDialog;
pDlg->Create(hWndTop);
pDlg->ShowWindow(SW_SHOWNORMAL);
pOleInPlaceFrame->EnableModeless(FALSE);
::EnableWindow(hWndTop, TRUE);
}
return 0;
}
HRESULT OnDraw(ATL_DRAWINFO& di)
{
RECT& rc = *(RECT*)di.prcBounds;
// Set Clip region to the rectangle specified by di.prcBounds
HRGN hRgnOld = NULL;
if (GetClipRgn(di.hdcDraw, hRgnOld) != 1)
hRgnOld = NULL;
bool bSelectOldRgn = false;
HRGN hRgnNew = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
if (hRgnNew != NULL)
bSelectOldRgn = (SelectClipRgn(di.hdcDraw, hRgnNew) != ERROR);
Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
LPCTSTR pszText = _T("AtlActiveXCtl");
TextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
pszText,
lstrlen(pszText));
if (bSelectOldRgn)
SelectClipRgn(di.hdcDraw, hRgnOld);
return S_OK;
}
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
};
OBJECT_ENTRY_AUTO(__uuidof(AtlActiveXCtl), CAtlActiveXCtl)
Modal and modeless dialogs need to be supported in ActiveX controls within IE11 tab pages just like in plain Win32 GUI applications. Can anyone kindly help me to solve this problem?
I'm having trouble in fixing the errors in this MFC uArt code. Three intellisense is undefined even though I included some header files to the program.
This is the error code when I build and run the program.
ERROR
PROGRAM
// MFCApplication2Dlg.cpp : implementation file
//
#include "stdafx.h"
#include "MFCApplication2.h"
#include "MFCApplication2Dlg.h"
#include "afxdialogex.h"
#include "afxwin.h"
#include "CyAPI.h"
#include "Periph.h"
#define UART_H
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
bool IsConnect = false;
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// Dialog Data
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CMFCApplication2Dlg dialog
CMFCApplication2Dlg::CMFCApplication2Dlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CMFCApplication2Dlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMFCApplication2Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CMFCApplication2Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &CMFCApplication2Dlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &CMFCApplication2Dlg::OnBnClickedButton2)
ON_BN_CLICKED(IDC_BUTTON3, &CMFCApplication2Dlg::OnBnClickedButton3)
END_MESSAGE_MAP()
// CMFCApplication2Dlg message handlers
BOOL CMFCApplication2Dlg::OnInitDialog()
{
CDialogEx::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
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
void CMFCApplication2Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CMFCApplication2Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMFCApplication2Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CMFCApplication2Dlg::OnBnClickedButton1()
{
USBDevice->Open(0);
if (USBDevice->IsOpen() != TRUE)
{
AfxMessageBox(_T("Failed to Open Device"));
}
else
{
IsConnect = true;
}
}
void CMFCApplication2Dlg::OnBnClickedButton3()
{
USBDevice->Close();
IsConnect = false;
}
void CMFCApplication2Dlg::OnBnClickedButton2()
{
char tmpUart[60];
long OutPacketSize;
OutPacketSize = sizeof(sUart);
LPTSTR pBuffer;
CString sBuffer;
int i;
if (IsConnect == false)
{
AfxMessageBox(_T("USB Connect Fail"));
return;
}
CEdit *OutValue = (CEdit*)GetDlgItem(IDC_OUT_VALUE);
pBuffer = sBuffer.GetBuffer(60);
OutValue->GetWindowText(pBuffer, 60);
strcpy(tmpUart, pBuffer);
OutPacketSize = strlen(tmpUart);
for (i = 0; i<OutPacketSize; i++) sUart[i] = tmpUart[i];
sUart[OutPacketSize + 1] = 0;
OutPacketSize = OutPacketSize + 1;
//Perform the BULK OUT
if (USBDevice->BulkOutEndPt)
{
USBDevice->BulkOutEndPt->XferData(sUart, OutPacketSize);
}
}
Does anyone have any idea what header files I've been missing to include with? cause when i declare char sUart[60] in the code there's an error and also on the strcpy method there seems to be an error in the pBuffer LPTSTR. Please help.
This is usually a sign that you're doing a Unicode build, where LPTSTR expands out to wchar_t *, and you're trying to mix it with non-Unicode strings (in your case a char array.
Instead define tmpUart as:
TCHAR tmpUart[60];
and use _tcscpy to copy the string. This way your code will compile in Unicode and non-Unicode builds.
i'm working on a mfc application for embedded compact. At the moment i try to add a dialog which offers to close the programm. My problem is that i get an access violation at the destructor call from my CMainFrame.
To make it more clear first a piece of code.
This is the startpoint of my application:
SWinApp.h
class SWinApp : public CWinApp
{
public:
SWinApp();
~SWinApp(){};
public:
virtual BOOL InitInstance();
protected:
DECLARE_MESSAGE_MAP()
};
SWinApp.cpp
SWinApp::SWinApp():CWinApp()
{
}
BOOL SWinApp::InitInstance()
{
CRuntimeClass* pRuntimeClass = RUNTIME_CLASS( SMainFrame );
CObject* pObject = pRuntimeClass->CreateObject();
ASSERT( pObject->IsKindOf( RUNTIME_CLASS( SMainFrame ) ) );
m_pMainWnd = (SMainFrame*)pObject;
m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
return FALSE; // this is the next executed line after the access violation
}
BEGIN_MESSAGE_MAP(SWinApp, CWinApp)
END_MESSAGE_MAP()
SMainFrame.h
class SMainFrame : public CFrameWnd
{
DECLARE_DYNCREATE(SMainFrame)
protected:
SMainFrame();
~SMainFrame();
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
afx_msg LRESULT OnDialogReady(WPARAM wParam, LPARAM lParam);
afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
CurrentData* GetCurrentData(){return this->currentData;};
Configuration* GetConfiguration(){return this->configuration;};
private:
BOOL m_shown;
CurrentData* currentData;
Configuration* configuration;
std::map<UINT, CDialog*> views;
UINT currentID;
};
SMainFrame.cpp
IMPLEMENT_DYNCREATE(SMainFrame, CFrameWnd)
SMainFrame::SMainFrame()
{
CString appName;
appName.LoadStringW(IDS_APP_NAME);
Create(NULL, appName);
m_shown = FALSE;
this->configuration = new Configuration();
this->currentData = new CurrentData();
this->currentID = IDD_MAIN_MENU_DIALOG;
views.insert(std::make_pair(IDD_MAIN_MENU_DIALOG, new MainMenuDialog(this->configuration, this->currentData)));
// There are more dialogs but for tests one is enough
}
SMainFrame::~SMainFrame()
{
for(auto iterator:views)
{
delete iterator.second;
}
delete this->configuration;
delete this->currentData; //Is executed properly
} // After this line an access violation occurres...
BEGIN_MESSAGE_MAP(SMainFrame, CFrameWnd)
ON_MESSAGE(WM_USER_DIALOG_READY, &SMainFrame::OnDialogReady)
ON_WM_CREATE()
ON_WM_ACTIVATE()
END_MESSAGE_MAP()
// SMainFrame message handlers
int SMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
ModifyStyle(WS_CAPTION, 0, SWP_DRAWFRAME | SWP_NOZORDER );
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
return 0;
}
afx_msg LRESULT SMainFrame::OnDialogReady(WPARAM wParam, LPARAM lParam)
{
DialogThreadParams* params = (DialogThreadParams*)lParam;
this->currentID = params->nextDialogID;
m_shown = FALSE;
this->ActivateFrame();
return 0;
}
BOOL SMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
cs.dwExStyle &= ~WS_EX_CLIENTEDGE | SWP_DRAWFRAME;
cs.style = WS_EX_CLIENTEDGE;
return TRUE;
}
void SMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
if(m_shown == FALSE)
{
m_shown = TRUE;
if(IsWindow(views[currentID]->m_hWnd))
{
views[currentID]->SetFocus();
}
else
{
views[currentID]->DoModal();
}
}
CFrameWnd::OnActivate(nState, pWndOther, bMinimized);
}
The MainMenuDialog is an inherited class from StandardDialog, which is inherited from CDialog. I will post only pieces of the code now, since this post is already too long(If you need more tell me which part can be interesting)...
The dialog which offers the possibility to close the app ist called ShutdownDialog(only inherited from CDialog) and is stored as a private variable of MainMenuDialog:
ShutdownDialog* shutdownDialog;
Created in constructor of MainMenuDialog:
this->shutdownDialog = new ShutdownDialog();
I show the dialog on a button click:
void MainMenuDialog::OnClickedShutdownButton()
{
shutdownDialog->DoModal();
}
And is deleted in destructor of MainMenuDialog:
MainMenuDialog::~MainMenuDialog()
{
delete shutdownDialog;
}
In ShutdowDialog i close the app with this piece of code:
AfxGetMainWnd()->PostMessage(WM_CLOSE);
EndDialog( 0 );
Until this everything is working fine. The application starts to destroy the objects. But after finishing the call to SMainFrame destructor i get an access violation. The program doesnt stops, just a line in Output window. It continues with statement "return FALSE;" in SWinApp InitInstance().
I know that access violation occurres when deleting an object twice or using a pointer where the depending object was already destroyed, but i cannot figure out whats going wrong here. Additional i have to say that SWinApp and SMainFrame was created by a colleague and i modified the parts with the dialogs in SMainFrame.
I thought that the m_pMainWnd could be the problem since after the destructor call to SMainFrame it must be an invalid pointer. So i tried:
SMainFrame::~SMainFrame()
{
for(auto iterator:views)
{
delete iterator.second;
}
delete this->configuration;
delete this->currentData;
AfxGetApp()->m_pMainWnd = NULL;
}
But the violation still occurres...
I searched for the Callstack Window but could not find it under the view tab...
Sry for this long post!
And sry if this is too specific...But i am struggling since severals hours and have no idea what i can try...Any help is welcome!
Change AfxGetMainWnd()->PostMessage(WM_CLOSE); to ::PostQuitMessage( 0 );
I am using owner drawn dialog. I like to give the shadow for my sub-dialog. Is it possible?
Thank in advance.
Sure, it's possible. You could tweak your dialog background using OnEraseBkgnd().
As an example, I have put shadows on the OK and Cancel buttons of a dialog (CDialogControlShadowDlg) ...
First, some declarations in the header file of your dialog class:
// Implementation
protected:
HICON m_hIcon;
CRect ComputeDrawingRect(int control_id); // <-- !!!
void DrawShadow(CDC* pDC, CRect &r); // <-- !!!
// Generated message map functions
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg BOOL OnEraseBkgnd(CDC* pDC); // <-- !!!
DECLARE_MESSAGE_MAP()
};
Then add OnEraseBkgnd to your message map in the .cpp file:
BEGIN_MESSAGE_MAP(CDialogControlShadowDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_ERASEBKGND() // <-- !!!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
Last, but not least, the member function definitions:
// gets the actual drawing location of a control relative to the dialog frame
CRect CDialogControlShadowDlg::ComputeDrawingRect(int control_id)
{
CRect r;
GetDlgItem(control_id)->GetWindowRect(&r);
ScreenToClient(&r);
return r;
}
#define SHADOW_WIDTH 6
// draws the actual shadow
void CDialogControlShadowDlg::DrawShadow(CDC* pDC, CRect &r)
{
DWORD dwBackgroundColor = GetSysColor(COLOR_BTNFACE);
DWORD dwDarkestColor = RGB(GetRValue(dwBackgroundColor)/2,
GetGValue(dwBackgroundColor)/2,
GetBValue(dwBackgroundColor)/2); // dialog background halftone as base color for shadow
int nOffset;
for (nOffset = SHADOW_WIDTH; nOffset > 0; nOffset--)
{
DWORD dwCurrentColorR = (GetRValue(dwDarkestColor)*(SHADOW_WIDTH-nOffset)
+ GetRValue(dwBackgroundColor)*nOffset) / SHADOW_WIDTH;
DWORD dwCurrentColorG = (GetGValue(dwDarkestColor)*(SHADOW_WIDTH-nOffset)
+ GetGValue(dwBackgroundColor)*nOffset) / SHADOW_WIDTH;
DWORD dwCurrentColorB = (GetBValue(dwDarkestColor)*(SHADOW_WIDTH-nOffset)
+ GetBValue(dwBackgroundColor)*nOffset) / SHADOW_WIDTH;
pDC->FillSolidRect(r + CPoint(nOffset, nOffset), RGB(dwCurrentColorR, dwCurrentColorG, dwCurrentColorB));
}
}
BOOL CDialogControlShadowDlg::OnEraseBkgnd( CDC* pDC )
{
// draw dialog background
CRect rdlg;
GetClientRect(&rdlg);
DWORD dwBackgroundColor = GetSysColor(COLOR_BTNFACE);
pDC->FillSolidRect(rdlg, dwBackgroundColor);
// draw shadows
CRect r1, r2;
r1 = ComputeDrawingRect(IDOK);
r2 = ComputeDrawingRect(IDCANCEL);
DrawShadow(pDC, r1);
DrawShadow(pDC, r2);
return TRUE;
}
After applying these modifications, the dialog should look like this:
(source: easyct.de)
I created a simple tab control that has 2 tabs (each tab is a different dialog). The thing is that i don't have any idea how to switch between tabs (when the user presses Titlu Tab1 to show the dialog i made for the first tab, and when it presses Titlu Tab2 to show my other dialog). I added a handler for changing items, but i don't know how should i acces some kind of index or child for tabs.
Tab1.h and Tab2.h are headers for dialogs that show only static texts with the name of the each tab.
There may be an obvious answer to my question, but i am a real newbie in c++ and MFC.
This is my header:
// CTabControlDlg.h : header file
//
#pragma once
#include "afxcmn.h"
#include "Tab1.h"
#include "Tab2.h"
// CCTabControlDlg dialog
class CCTabControlDlg : public CDialog
{
// Construction
public:
CCTabControlDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
enum { IDD = IDD_CTABCONTROL_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CTabCtrl m_tabcontrol1;
CTab1 m_tab1;
CTab2 m_tab2;
afx_msg void OnTcnSelchangeTabcontrol(NMHDR *pNMHDR, LRESULT *pResult);
};
And this is the .cpp:
// CTabControlDlg.cpp : implementation file
//
#include "stdafx.h"
#include "CTabControl.h"
#include "CTabControlDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
// CCTabControlDlg dialog
CCTabControlDlg::CCTabControlDlg(CWnd* pParent /*=NULL*/)
: CDialog(CCTabControlDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CCTabControlDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_TABCONTROL, m_tabcontrol1);
}
BEGIN_MESSAGE_MAP(CCTabControlDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_NOTIFY(TCN_SELCHANGE, IDC_TABCONTROL, &CCTabControlDlg::OnTcnSelchangeTabcontrol)
END_MESSAGE_MAP()
// CCTabControlDlg message handlers
BOOL CCTabControlDlg::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)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
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
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
CTabCtrl* pTabCtrl = (CTabCtrl*)GetDlgItem(IDC_TABCONTROL);
m_tab1.Create(IDD_TAB1, pTabCtrl);
TCITEM item1;
item1.mask = TCIF_TEXT | TCIF_PARAM;
item1.lParam = (LPARAM)& m_tab1;
item1.pszText = _T("Titlu Tab1");
pTabCtrl->InsertItem(0, &item1);
//Pozitionarea dialogului
CRect rcItem;
pTabCtrl->GetItemRect(0, &rcItem);
m_tab1.SetWindowPos(NULL, rcItem.left, rcItem.bottom + 1, 0, 0, SWP_NOSIZE | SWP_NOZORDER );
m_tab1.ShowWindow(SW_SHOW);
// al doilea tab
m_tab2.Create(IDD_TAB2, pTabCtrl);
TCITEM item2;
item2.mask = TCIF_TEXT | TCIF_PARAM;
item2.lParam = (LPARAM)& m_tab1;
item2.pszText = _T("Titlu Tab2");
pTabCtrl->InsertItem(0, &item2);
//Pozitionarea dialogului
//CRect rcItem;
pTabCtrl->GetItemRect(0, &rcItem);
m_tab2.SetWindowPos(NULL, rcItem.left, rcItem.bottom + 1, 0, 0, SWP_NOSIZE | SWP_NOZORDER );
m_tab2.ShowWindow(SW_SHOW);
return TRUE; // return TRUE unless you set the focus to a control
}
void CCTabControlDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CCTabControlDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CCTabControlDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CCTabControlDlg::OnTcnSelchangeTabcontrol(NMHDR *pNMHDR, LRESULT *pResult)
{
// TODO: Add your control notification handler code here
*pResult = 0;
}
You can do this automatically in MFC by making the parent dialog a CPropertySheet and the contained dialogs CPropertyPage.
With the way you have it structured currently, you should do a ShowWindow for each of the dialogs with one set to SW_SHOW and the other to SW_HIDE in your OnTcnSelchangeTabcontrol function.
You should add your Tabcontrol click event and do the following codes. Dialog pointers pTab1 and pTab2 for each dialog/tab.
void CYourClass::OnNMClickTab1(NMHDR *pNMHDR, LRESULT *pResult)
{
pTab1->ShowWindow(SW_HIDE);
pTab2->ShowWindow(SW_HIDE);
for(int i=0;i<2;i++)
{
m_tbCtrl.HighlightItem(i,FALSE);
}
switch(m_tbCtrl.GetCurSel())
{
case 0: pTab1->ShowWindow(SW_SHOW);break;
case 1: pTab2->ShowWindow(SW_SHOW);break;
}
m_tbCtrl.HighlightItem(m_tbCtrl.GetCurSel(),TRUE);
*pResult = 0;
}