I am new to MFC programming. I have a very simple MFC application that shows a plain dialog. I want to make a DLL that do the same as this piece of code.
The working dialog code looks like this:
class MyForm : public CDialog
{
public:
MyForm(CWnd* pParent = NULL) : CDialog(MyForm::IDD, pParent) {};
enum { IDD = DIALOG1 };
protected:
virtual void DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); };
virtual BOOL OnInitDialog()
{
CDialog::OnInitDialog();
return true;
}
public:
DECLARE_MESSAGE_MAP()
};
//Actural App
class MyApp: public CWinApp
{
public:
MyApp() {};
virtual BOOL InitInstance()
{
CWinApp::InitInstance();
MyForm dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
return false;
}
};
BEGIN_MESSAGE_MAP(MyForm, CDialog)
END_MESSAGE_MAP()
//start the app
MyApp theApp;
I use visual studio MFC DLL project to make a new DLL project. I make a separate *.h file to declare the dll class, and a *.cpp file to define the class.
This is the *.h file looks like:
//header file for dll project
#include "stdafx.h"
#include <afxwin.h>
#include "resource.h"
class CMyDllApp : public CDialog
{
public:
__declspec(dllexport) CMyDllApp();
enum { IDD = DLL_Dialog };
protected:
__declspec(dllexport) virtual void DoDataExchange(CDataExchange* pDX);
__declspec(dllexport) virtual BOOL OnInitDialog();
public:
__declspec(dllexport) afx_msg void myFunction();
DECLARE_MESSAGE_MAP()
};
//Actural App
class MyDllMain : public CWinApp
{
public:
__declspec(dllexport) MyDllMain() {};
__declspec(dllexport) virtual BOOL InitInstance();
};
Now I include the *.h file in my client application, but I don't know how to call the dll class correctly.
Even if I only include the *.h file and do not add any other code, the dialog of dll class just replace my client dialog, if have MyDllMain theApp; in the cpp file of dll project.
//in *.cpp of the dll project
...
MyDllMain theApp;
If I put this line in my client application, I just get a "Assertion Failed" error when running.
But if I don't put the line MyDllMain theApp; in dll project, how can I call my dll class when I want?
I am trying to create CWnd derived class at runtime but CWnd::Create fails. I have no idea why. Here is minimal code that show the problem:
MFCTestApplicationDlg.h
#pragma once
class c_CustomButton : public CButton
{
protected:
DECLARE_MESSAGE_MAP()
virtual void PreSubclassWindow();
public:
c_CustomButton();
virtual ~c_CustomButton();
};
class TestWindow : public CWnd
{
public:
TestWindow();
virtual ~TestWindow();
protected:
DECLARE_MESSAGE_MAP()
DECLARE_DYNCREATE(TestWindow)
};
// CMFCTestApplicationDlg dialog
class CMFCTestApplicationDlg : public CDialogEx
{
...
}
MFCTestApplicationDlg.cpp
//
#include "stdafx.h"
#include "MFCTestApplication.h"
#include "MFCTestApplicationDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
/*==========================================================================*/
c_CustomButton::c_CustomButton()
{
}
/*==========================================================================*/
c_CustomButton::~c_CustomButton()
{
}
BEGIN_MESSAGE_MAP(c_CustomButton, CButton)
END_MESSAGE_MAP()
/*==========================================================================*/
void c_CustomButton::PreSubclassWindow()
{
CButton::PreSubclassWindow();
ModifyStyle(0, BS_OWNERDRAW);
}
IMPLEMENT_DYNAMIC(TestWindow, CWnd)
TestWindow::TestWindow()
{
}
TestWindow::~TestWindow()
{
}
BEGIN_MESSAGE_MAP(TestWindow, CWnd)
END_MESSAGE_MAP()
void CMFCTestApplicationDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
c_CustomButton* pColoredButton = new c_CustomButton;
pColoredButton->Create((LPCTSTR)"", 0, CRect(), this, 0);// successeded
pColoredButton->SetWindowTextW((LPCTSTR)"test");
TestWindow* pTestWindow = new TestWindow;
pTestWindow->Create((LPCTSTR)"TestWindow", (LPCTSTR)"TestWindowName", 0, CRect(), this, 0);// failed
pTestWindow->SetWindowText((LPCTSTR)"test");
}
In void CMFCTestApplicationDlg::DoDataExchange(CDataExchange* pDX) I tried to create a CButton derived class object and CWnd derived class object. The first one created successfully but CWnd derived class object fails to create. Whats wrong with this code?
I have a simple MFC dialog.
class CMessageBoxWithCustomTextDlg : public CDialogEx
{
// Construction
public:
CMessageBoxWithCustomTextDlg(CWnd* pParent = NULL); // standard constructor
__declspec(dllexport) void SetData(std::string& data);
// Dialog Data
enum { IDD = IDD_MESSAGEBOXWITHCUSTOMTEXT_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 OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedShowMessagebox();
};
I would like to export it as dll and call it from a simple console application. Is it possible?
It is possible; here is how I did it:
For your console application have it be simply this:
#include <Windows.h>
typedef void (*EntryFunc)();
int main()
{
HMODULE hMod = LoadLibrary(L"MFCDll.dll");
EntryFunc func = (EntryFunc)GetProcAddress(hMod, "entrypoint");
func();
}
The name of the DLL is MFCDll.dll and there is an exported function called entrypoint in that DLL.
For the DLL I created a New MFC DLL project. And other than the dialog code and the dialog in the resources add this code:
extern "C" __declspec(dllexport) void entrypoint()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CMessageBoxWithCustomTextDlg dlg;
dlg.DoModal();
}
And the console program will load the DLL, call into the DLL and the dialog shows.
I have a problem about save Edit text to registy.
I did in main class save to registy text data and i did another registry class that call
CRegSettings so this class doing enum each time when i clicked button like
MyItem\0, MyItem\1.
my problem is i cant get that CString text into this CRegSettings class, this class doesnt have DoDataExchange so when i did it somehow its turn to error "CMySettingsItem::DoDataExchange' : recursive on all control paths" so it's doesnt work and i cant get CString from main class to this class, does anyone know how to do it ? Thanks.
Here is my codes.
Main.cpp
// CNewConnectionDlg dialog
IMPLEMENT_DYNAMIC(CNewConnectionDlg, CDialog)
CNewConnectionDlg::CNewConnectionDlg(CWnd* pParent /*=NULL*/)
: CDialog(CNewConnectionDlg::IDD, pParent)
, m_csIp(_T("localhost"))
, m_csPort(_T("22"))
, m_csUsername(_T("Username"))
, m_csPassword(_T("Password"))
{
}
class CMySettingsItem : public CRegSettings
{
public:
DWORD Id;
CString m_Password;
CString Password;
BEGIN_REG_MAP(CMySettingsItem)
REG_ITEM(Id, 1)
REG_ITEM(Password, m_Password)
END_REG_MAP()
protected:
virtual void DoDataExchange(CDataExchange* pDX);
};
// Sample application configuration
class CMySettings : public CRegSettings
{
public:
DWORD RootId; // DWORD option
CString RootName; // String option
std::string FullName;
// list of options (CMySettingsItem)
CSimpleArray<CMySettingsItem> Profile; // ATL CSimpleArray
//std::list<CMySettingsItem> ProfileList; // STL list
CMySettingsItem SubItem; // Subitem test
BEGIN_REG_MAP(CMySettings)
REG_ITEM(RootId, 1)
REG_ITEM(RootName, "Profile")
REG_ITEM_STL(FullName, "Profile")
REG_ITEM_SIMPLE_ARRAY(Profile)
//REG_ITEM_LIST(ProfileList)
END_REG_MAP()
};
void CMySettingsItem::DoDataExchange(CDataExchange* pDX)
{
CMySettingsItem::DoDataExchange(pDX);
DDX_Text(pDX, IDC_PASSWORD, m_Password);
}
CNewConnectionDlg::~CNewConnectionDlg()
{
AfxGetApp()->WriteProfileString("Settings", "UserName", m_csUsername);
AfxGetApp()->WriteProfileString("Settings", "IP", m_csIp);
AfxGetApp()->WriteProfileString("Settings", "Port", m_csPort);
AfxGetApp()->WriteProfileString("Settings", "Password", m_csPassword);
CMySettings configuration(HKEY_CURRENT_USER, "Software\\MyItem\\Item");
// Load configuration
if(configuration.Load() != ERROR_SUCCESS)
printf("failed to load\n");
// Use loaded configuration
configuration.RootId++;
CMySettingsItem item;
item.Id = configuration.RootId;
configuration.Profile.Add(item); // CSimpleArray
//configuration.ProfileList.push_back(item); // list
// Save new configuration
if(configuration.Save() != ERROR_SUCCESS)
printf("failed to save\n");
}
void CNewConnectionDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_IP, m_csIp);
DDV_MaxChars(pDX, m_csIp, 255);
DDX_Text(pDX, IDC_PORT, m_csPort);
DDV_MaxChars(pDX, m_csPort, 6);
DDX_Text(pDX, IDC_USERNAME, m_csUsername);
DDV_MaxChars(pDX, m_csUsername, 20);
DDX_Text(pDX, IDC_PASSWORD, m_csPassword);
DDV_MaxChars(pDX, m_csPassword, 255);
}
BEGIN_MESSAGE_MAP(CNewConnectionDlg, CDialog)
ON_EN_CHANGE(IDC_PASSWORD, &CNewConnectionDlg::OnEnChangePassword)
ON_EN_CHANGE(IDC_USERNAME, &CNewConnectionDlg::OnEnChangeUsername)
END_MESSAGE_MAP()
void CNewConnectionDlg::OnEnChangePassword()
{
}
void CNewConnectionDlg::OnEnChangeUsername()
{
}
And Header
Main.h
#pragma once
#include "InnerDlg.h"
#include <afxtempl.h>
class CNewConnectionDlg : public CDialog
{
DECLARE_DYNAMIC(CNewConnectionDlg)
public:
CNewConnectionDlg(CWnd* pParent = NULL); // standard constructor
virtual ~CNewConnectionDlg();
CNewConnectionDlg(const CString sSection, const CString sArrayName);
// Dialog Data
enum { IDD = IDD_NEWCONNECTION };
public:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
protected:
DECLARE_MESSAGE_MAP()
public:
// The server ip or name
CString m_csIp;
// The negotiating port on the server
CString m_csPort;
// Username for the server
CString m_csUsername;
// Password for the server
CString m_csPassword;
afx_msg void OnEnChangePassword();
afx_msg void OnEnChangeUsername();
};
DoDataExchange is only intended for user interface classes, such as your CDialog-based class. It is used to connect the user interface elements on screen with the member variables of that object. So your data is sitting in the m_csIp, m_csPort, m_csUsername, and m_csPassword members. You just need to assign it to the relevant member of your CMySettingsItem instance.
For example:
item.m_Password = m_csPassword;
I am using two classes in one project. First class is CClientSocketDlg and other one is CUserSpecificationDlg.
Here is the some part of the code.
class CClientSocketDlg : public CDialog
{
public:
bool StartClient();
CClientSocketDlg(CWnd* pParent = NULL);
void AppendMessage(LPCTSTR strText );
enum { IDD = IDD_CLIENTSOCKET_DIALOG };
CEdit m_ctlMsgList;
CIPAddressCtrl m_ctlIPAddress;
};
class CuserspecificationDlg : public CDialogEx
{
public:
CuserspecificationDlg(CWnd* pParent = NULL);
// Dialog Data
enum { IDD = IDD_USERSPECIFICATION_DIALOG };
CListCtrl m_List;
CString out; // For Edit control in list box having IDC_EDIT2
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
};
Can I declare them in one project ? Is it allowed? Can I use m_ctlIPAddress
in CUserspecification class ?