I have created MFC dialog form resource. After I ask Form Wizard to create class for this resource it generates header and cpp file correctly except one thing - my class does not recognize control ID that appears in class code like ID_BLABLABLA. After including resource.h - everything goes fine. But why wizard doesn't do it automatically?
This is dialog header:
#pragma once
// dlg4 dialog
class dlg4 : public CDialogEx
{
DECLARE_DYNAMIC(dlg4)
public:
dlg4(CWnd* pParent = NULL); // standard constructor
virtual ~dlg4();
// Dialog Data
enum { IDD = IDD_DIALOG2 };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
};
dialog cpp:
// dlg4.cpp : implementation file
//
#include "stdafx.h"
#include "dlg4.h"
#include "afxdialogex.h"
// dlg4 dialog
IMPLEMENT_DYNAMIC(dlg4, CDialogEx)
dlg4::dlg4(CWnd* pParent /*=NULL*/)
: CDialogEx(dlg4::IDD, pParent)
{
}
dlg4::~dlg4()
{
}
void dlg4::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(dlg4, CDialogEx)
END_MESSAGE_MAP()
// dlg4 message handlers
The wizard includes the app class h file. The app class h file includes resource.h
It is quite reasonable for you to remove the include of app.h and replace it with resource.h
Related
I implemented a general object factory following the guidelines of Andrei Alexandrescu's book Modern C++ Design, so I can define a class hierarchy like this (I will write the code in the most simplified way, avoiding implementation details or memory allocation/deallocation issues; I'm aware of these things and I would like to focus the discussion on the main issue):
// File "base.h"
#include <string>
#include "singleton.h"
#include "object_factory.h"
class Base;
using SingletonBaseFactory = Singleton
<
ObjectFactory
<
Base, // Abstract product type
std::string, // Identifier type
Base* (*)() // Concrete product creator type
>
>;
class Base {
// Define the interface (virtual functions, virtual dtor)
public:
// Wrap the Factory method
static Base* Factory(const std::string& ID) {
return SingletonBaseFactory::Instance().Factory(ID);
}
};
// File "derived_1.h"
#include "base.h"
class Derived_1 : public Base { /* ... */ };
// File "derived_2.h"
#include "base.h"
class Derived_2 : public Base { /* ... */ };
and register each derived class within an anonymous namespace in the corresponding implementation file:
// File "derived_1.cpp"
#include "derived_1.h"
namespace {
Base* CreateDerived_1() {
return new Derived_1;
}
const bool registered = SingletonBaseFactory::Instance().Register("Derived_1", CreateDerived_1);
}
// Same for Derived_2 in file "derived_2.cpp"
Therefore, an user that wants to use this hierarchy in his code has just to invoke the Base::Factory method with a proper identifier:
// File main.cpp
#include"base.h"
int main(){
Base* pb = Base::Factory("Derived_1");
// Do stuff with pb
return 0;
}
Now, suppose I have a template class hierarchy, say:
// File "baset.h"
#include <string>
#include "singleton.h"
#include "object_factory.h"
template<class T>
class BaseT;
template<class T>
using SingletonBaseTFactory = Singleton
<
ObjectFactory
<
BaseT<T>, // Abstract product type
std::string, // Identifier type
BaseT<T>* (*)() // Concrete product creator type
>
>;
template<class T>
class BaseT {
/*Define the interface*/
public:
BaseT Factory(const std::string& ID) {
return SingletonBaseTFactory<T>::Instance().Factory(ID);
}
};
// File "derivedt_1.h"
#include "baset.h"
template<class T>
class DerivedT_1 : public BaseT<T> { /* ... */ };
In this case the registration is an user responsibility for each type T he wants to use, before using the class hierarchy:
// File main.cpp
#include "baset.h"
#include "derivedt_1.h"
bool register_derived_1_int = SingletonBaseTFactory<int>::Instance().Register("Derived_1", [](){ return new DerivedT_1<int>; });
int main() {
BaseT<int>* pb = BaseT<int>::Factory("Derived_1");
return 0;
}
Keeping in mind that the ID of each derived template class is the same for every type T, would it make sense to delegate the registration responsibility to the developer of each derived class (rather than the user) even in the templated case?
If so, is there a workaround to achieve it?
EDIT:
I found this work https://www.artima.com/cppsource/subscription_problem.html which addresses the object factory registration problem in the templated case.
However, the registration of the derived classes is still a responsibility of whoever knows the type(s) the derived class can be instantiated with.
Typically, the class developer does not have such a knowledge - the user does have it.
So, again, is there any method to dismiss the user from the responsibility of registering the derived class?
I have implemented this MFC class.(Note that what is written here is just a part of my class)
here is the file FilesWorkFlow.h
#pragma once
// FilesWorkFlow
class FilesWorkFlow : public CWnd
{
DECLARE_DYNAMIC(FilesWorkFlow)
public:
FilesWorkFlow();
virtual ~FilesWorkFlow();
CString GetPath();
protected:
DECLARE_MESSAGE_MAP()
private:
wchar_t* lpszFilter;
};
and here is the file FilesWorkFlow.cpp
// FilesWorkFlow.cpp : implementation file
//
#include "stdafx.h"
#include "InitialJobProject2.h"
#include "FilesWorkFlow.h"
// FilesWorkFlow
IMPLEMENT_DYNAMIC(FilesWorkFlow, CWnd)
FilesWorkFlow::FilesWorkFlow()
{
lpszFilter = _T("JPEG Files (*.jpg)|*.jpg|")
_T("TIFF Files (*.tif)|*.tif|")_T("PNG Files (*.png)|*.png|")_T("Bitmap Files (*.bmp)|*.bmp|");
}
FilesWorkFlow::~FilesWorkFlow()
{
}
CString FilesWorkFlow::GetPath()
{
CFileDialog dlgFile = CFileDialog(true,0,0,OFN_ENABLESIZING | OFN_HIDEREADONLY,lpszFilter,0,0,true);
if (dlgFile.DoModal() == IDOK)
{
CString pathname = dlgFile.GetPathName();
return pathname;
}
}
BEGIN_MESSAGE_MAP(FilesWorkFlow, CWnd)
END_MESSAGE_MAP()
// FilesWorkFlow message handlers
and in the file InitialJobProject2Dlg.h that is the header of the class related to my Dialog window and is derived from the class CDialogEx, I have this code:
#include "FilesWorkFlow.h"
......
private:
CWndResizer m_resizer;
FilesWorkFlow m_filesWorkFlow;
and finally this is what is in file FilesWorkFlow.cpp
void CInitialJobProject2Dlg::OnBnClickedBtnbrowse()
{
// TODO: Add your control notification handler code here
m_filesWorkFlow = FilesWorkFlow();
CString filepath = m_filesWorkFlow.GetPath();
}
I can't find the reason for the error specified?
You are trying to assign a CFileDialog to a CFileDialog, which is not a supported operation. Initialize dlgFile this way:
CFileDialog dlgFile(...);
I am desparately in search of MFC dll sample that updates an edit field on a dialog derived from CDialog with a string using only the callback function. I realize static functions are the ones that are used in the calback.
I guess you realise that the dll should have something (like a separate thread, or a certain third-party message handler for this model. So, this is out of scope for this question.
Back to the question:
In order to create a callback function you need to "typedef" its prototype and pass the address of this function from your calling app to the dll. In your dll "h" file specify this:
// This is the Mfcdll1.h header file
// You should have some code created by the wizard, similar to the following:
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
// This is the typedef for your callback function type:
typedef void (CALLBACK* MY_DLL_CALLBACK)
(
LPVOID lpParam,
LPCTSTR lpszMessage
);
class CMyDllApp : public CWinApp
{
public:
CMyDllApp();
// etc.
void SetCallBack(MY_DLL_CALLBACK pCallback, LPVOID pCallbackParm){m_pCallback = pCallback; m_pCallbackParm = pCallbackParm;}
private:
MY_DLL_CALLBACK m_pCallback;
LPVOID m_pCallbackParm;
};
MYDLL_API void SetCallBack(MY_DLL_CALLBACK pCallback, LPVOID pCallbackParm);
In your dll's cpp file specify this:
CMyDllApp::CMyDllApp()
{
m_pCallback = NULL;
m_pCallbackParm = NULL;
}
MYDLL_API void SetCallBack(MY_DLL_CALLBACK pCallback, LPVOID pCallbackParm)
{
theApp.SetCallBack(pCallback, pCallbackParm);
}
Now, if your dll wants to call the callback function, all you need to do is:
CMyDllApp::SendCallbackToTheCaller(LPCTSTR lpszMessage)
{
if(m_pCallback) (*(m_pCallback))(m_pCallbackParm, lpszMessage);
}
At this stage you have done coding in the dll. Now, all you need to do is specify the static callback function in your dialog that will update you Edit control, similar to this:
In the h file:
// TestDlg.h - My Test dialog with the Edit Control
CTestDlg: public CDialog
{
public:
static void CALLBACK StatusCallback(LPVOID lpParam, LPCTSTR lpszMessage);
};
In the cpp file:
BOOL CTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Insert this line along your stuff
::SetCallback((MY_DLL_CALLBACK)StatusCallback, (LPVOID)this);
}
void CALLBACK CTestDlg::StatusCallback(LPVOID lpParam, LPCTSTR lpszMessage)
{
CTestDlg* pTestDlg = reinterpret_cast<CTestDlg*>(lpParam);
ASSERT(pTestDlg!=NULL);
pTestDlg->m_edStatus.SetWindowText(lpszMessage);
}
I make a interface class in C++ for voice recognition, i´m using the Julius API. http://julius.sourceforge.jp/en_index.php?q=index-en.html.
Well, my class has some events, these events will be triggered by the Julius API.
The Julius API has the function call callback_add with this signature:
int callback_add (Recog *recog, int code, void(*func)(Recog *recog, void *data), void data)
I using some 'proxy' functions to Invoke the events and passing this functions to callback_add.
If the property event is static, it works fine, but if is a non static, inside the proxy function the property not be recognized.
The difficult is because I have to use the callback_add function and can't modify this.
Here is a summary of the class with 2 events (static and non-static)
Header
#ifndef FALAENGINE_H_
#define FALAENGINE_H_
#pragma once
extern "C"{
#include <julius/julius.h>
}
namespace FalaAPI {
public ref class FalaEngine
{
public:
FalaEngine();
~FalaEngine();
// Events
delegate void OnRecognizedDele(FalaAPI::RecoResult^ result);
static property OnRecognizedDele^ OnRecognized;
delegate void OnEngineStartDele();
property OnEngineStartDele^ OnEngineStart;
private:
Recog *recog;
Jconf *jconf;
};
}
#endif /* FALAENGINE_H_*/
Source
#include "stdafx.h"
using System::String;
using System::Console;
#include "FalaEngine.h"
#include <windows.h>
namespace FalaAPI{
void StartOnEngineStart()(Recog *recog, void * dummy){
if(FalaEngine::OnEngineStart->GetInvocationList()->Length > 0)
FalaEngine::OnEngineStart->Invoke();
}
void StartOnRecognized()(Recog *recog, void * dummy){
if(FalaEngine::OnRecognized->GetInvocationList()->Length > 0)
FalaEngine::OnRecognized->Invoke();
}
FalaEngine::FalaEngine(){
recog = j_recog_new();
jconf = j_jconf_new();
//Julius callback Functions
callback_add(recog, CALLBACK_EVENT_PROCESS_ONLINE, StartOnEngineStart, NULL);
callback_add(recog, CALLBACK_RESULT, StartOnRecognized, NULL);
}
}
The problem occurs inside StartOnEngineStart function:
error C2227: left of '->GetInvocationList' must point to class/struct/union/generic type
A non-static member exists separately in each instance. You haven't specified which instance contains the delegate you want to inspect, you've only specified a class (and there may be many instances).
Try using the dummy parameter to pass your instance. But be careful, because the garbage collector will move objects around unless you have pinned them, so simply passing the address will not work. You need to create and pass a GCHandle instead. (Be careful not to leak the GCHandle, or your object will never be released)
Something like this should be effective:
ref class FalaEngine;
struct EngineHandle
{
gcroot<FalaEngine^> handle;
EngineHandle(FalaEngine^ engine) : handle(engine) {}
};
public ref class FalaEngine
{
clr_scoped_ptr<EngineHandle> callback_ptr;
public:
FalaEngine();
~FalaEngine();
// Events
delegate void OnRecognizedDele(FalaAPI::RecoResult^ result);
property OnRecognizedDele^ OnRecognized;
delegate void OnEngineStartDele();
property OnEngineStartDele^ OnEngineStart;
private:
Recog *recog;
Jconf *jconf;
};
void StartOnEngineStart(Recog *recog, void * dummy)
{
FalaEngine^ that = static_cast<EngineHandle*>(dummy)->handle;
that->OnEngineStart(); // C++/CLI already checks if the invocation list is empty
}
void StartOnRecognized(Recog *recog, void * dummy)
{
FalaEngine^ that = static_cast<EngineHandle*>(dummy)->handle;
that->OnRecognized(recog->get_result());
}
FalaEngine::FalaEngine()
: callback_ptr(new EngineHandle(this))
{
recog = j_recog_new();
jconf = j_jconf_new();
//Julius callback Functions
callback_add(recog, CALLBACK_EVENT_PROCESS_ONLINE, StartOnEngineStart, callback_ptr.get());
callback_add(recog, CALLBACK_RESULT, StartOnRecognized, callback_ptr.get());
}
The clr_scoped_ptr class is here. There are not many license requirements, make sure you follow them though if you use it.
In my MFC application I used CSplitterWnd to create two panes and each pane is a CFormView dialog box. When run this GUI application the splitter is working and both panes are showing but all controls (button, edit box, combo box...) are disabled. Both dialog boxes have property of 'child' and 'no border'.
Did I miss something to enable all those conntrols on the pane view?
Thanks a lot for help.
CK
/////////// Header file
class CParentSelectionDlg : public CFormView
{
protected:
CParentSelectionDlg(); // protected constructor used by dynamic creation
DECLARE_DYNCREATE(CParentSelectionDlg)
// Form Data
public:
//{{AFX_DATA(CParentSelectionDlg)
enum { IDD = IDD_PARENT_SELECTION };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CParentSelectionDlg)
public:
virtual void OnInitialUpdate();
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
virtual ~CParentSelectionDlg();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
// Generated message map functions
//{{AFX_MSG(CParentSelectionDlg)
afx_msg void OnButtonSave();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////// CPP
IMPLEMENT_DYNCREATE(CParentSelectionDlg, CFormView)
CParentSelectionDlg::CParentSelectionDlg()
: CFormView(CParentSelectionDlg::IDD)
{
//{{AFX_DATA_INIT(CParentSelectionDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
CParentSelectionDlg::~CParentSelectionDlg()
{
}
void CParentSelectionDlg::DoDataExchange(CDataExchange* pDX)
{
CFormView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CParentSelectionDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CParentSelectionDlg, CFormView)
//{{AFX_MSG_MAP(CParentSelectionDlg)
ON_BN_CLICKED(IDC_BUTTON_SAVE, OnButtonSave)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CParentSelectionDlg diagnostics
#ifdef _DEBUG
void CParentSelectionDlg::AssertValid() const
{
CFormView::AssertValid();
}
void CParentSelectionDlg::Dump(CDumpContext& dc) const
{
CFormView::Dump(dc);
}
#endif //_DEBUG
void CParentSelectionDlg::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
}
/////////////////////////////////////////////////////////////////////////////
// CParentSelectionDlg message handlers
void CParentSelectionDlg::OnButtonSave()
{
// TODO: Add your control notification handler code here
}
/// Thanks a lot
I bet your message map isn't set up correctly.
Can you post your code?