1. पहले ये बातें समझ लें
पुराने Windows desktop applications maintain करते हुए ये नाम अक्सर सामने आते हैं।
CWinApp
CWnd
CDialog
CDialogEx
CFrameWnd
CDocument
CView
CString
CFile
CArchive
BEGIN_MESSAGE_MAP
ON_COMMAND
ON_BN_CLICKED
DoDataExchange
UpdateData
ये नाम MFC में बार-बार दिखते हैं — C++ के लिए एक Windows application framework। MFC Microsoft Foundation Classes का short form है, एक library जो Win32 API को C++ classes के रूप में इस्तेमाल करना आसान बनाती है।
आज के Windows app development में WinUI, WPF, Windows Forms, Electron, Qt, web technologies जैसे कई विकल्प हैं, इसलिए नई development की पहली पसंद के रूप में MFC कम ही आता है। फिर भी यह मरी हुई technology नहीं है। Business applications, measurement instruments, control software, CAD/CAM, internal tools, और लंबे समय से चल रहे packaged software में आज भी MFC codebases maintain करनी पड़ती हैं।
MFC समझने के लिए ये नज़रिए पहले रख लें।
MFC पुराने Windows desktop apps पढ़ने का एक ज़रूरी map है
MFC Win32 API को छुपाता नहीं, उसे C++-friendly तरीके से wrap करता है
MFC की conventions न पता हों तो code के appearance से ज़्यादा behavior गलत पढ़ेंगे
नई adoption से ज़्यादा value existing assets के maintenance, life-extension और incremental migration में है
यह लेख MFC का overview, application structure, message map, Document/View, dialogs, DDX/DDV, resources, build, और maintenance के दौरान ध्यान रखने वाली बातें समेटता है।
यह लेख उस reader के लिए है जो C++ लिख सकता है, लेकिन Win32 API या MFC में नया है। Prerequisites का अंदाज़ा इतना काफी है।
| क्षेत्र | अपेक्षित स्तर |
|---|---|
| C++ | Classes, inheritance, virtual functions, pointers और references पढ़ सकें |
| Win32 API | Experience नहीं चाहिए। Window और message शब्द सुने हों, इतना काफी |
| Visual Studio | Solution खोलकर build किया हो |
| COM / OLE | Experience नहीं चाहिए। Chapter 27 में ज़रूरत पड़े तब देख लेना काफी |
Chapter 2 के अंत में “MFC पढ़ने के लिए ज़रूरी knowledge” दी गई है, लेकिन उसे पहले से पूरा जमा करने की ज़रूरत नहीं है। पढ़ते हुए, जब ज़रूरत पड़े तब लौट आना काफी है।
पढ़ने का क्रम भी chapter 1 से 41 तक सीधा नहीं चलाना पड़ता। उद्देश्य के हिसाब से सबसे छोटा रास्ता यह है।
| उद्देश्य | पढ़ने वाले chapters |
|---|---|
| सिर्फ़ यह जानना है कि MFC क्या है और आज उसकी जगह क्या है | Chapters 2–4, 36 |
| Existing MFC code पढ़ना सीखना है | Chapter 6 → 9 → 10 → 14 → 12 और 13 → 38 |
| Build fail हो रहा है, ठीक करना है | Chapters 5, 25, 32, 33 |
| Bug investigate करना है | Chapter 34 → 35 → 8 और 22 |
| Maintenance या migration की नीति तय करनी है | Chapters 30, 31, 37, 39 |
सबसे पहले दो चीज़ें पकड़नी हैं: message map (chapter 9) और Document/View (chapter 14)। ये दो समझ आ जाएँ तो “caller न दिखने वाला function event पर क्यों चलता है” और “data और screen कैसे जुड़े हैं” पढ़ने लगते हैं। इन्हें छोड़ दें तो बाकी chapters हवा में लटक जाते हैं।
इस लेख के code fragments chapter-wise files में बाँटकर GitHub पर reference collection के रूप में उपलब्ध हैं।
windows-mfc-overview - komurasoft-blog-samples (GitHub)
इस लेख का knowledge map
MFC Win32 API को C++ classes के रूप में इस्तेमाल करना आसान बनाने वाला framework है; CWinApp पूरे app की initialization संभालता है, message map Windows messages को handler functions से bind करता है, Document/View architecture data और UI display को separate करता है, और DDX/DDV dialog के controls को member variables से जोड़कर validate करता है। MFC इस्तेमाल करने के लिए Visual Studio Installer से MFC component अलग से install करना पड़ता है, और shared DLL या static linking भी configure किया जा सकता है। लेख यह positioning दिखाता है कि brand-new general GUI applications में MFC adoption सावधानी से decide करना चाहिए, जबकि existing MFC apps के maintenance, feature addition, और incremental migration में realistically अक्सर value होती है।
flowchart LR
accTitle: MFC से Windows desktop apps maintain करने का knowledge map
accDescr: MFC Win32 API को C++ में wrap करता है और message map, Document/View जैसे mechanisms implement करता है; existing assets के maintenance के लिए उपयुक्त है पर brand-new GUI development में सावधानी से decide करना चाहिए — यह positioning; तथा build environment और COM integration में ध्यान रखने वाली बातों का relation दिखाने वाला diagram
mfc["MFC (Microsoft Foundation Classes)"]
win32_api["Win32 API"]
cwinapp["CWinApp"]
message_map["message map"]
document_view_architecture["Document/View architecture"]
mfc_ddx_ddv["DDX/DDV"]
resource_script["resource file (.rc / resource.h)"]
cstring_class["CString"]
vs_mfc_component["Visual Studio Installer का MFC component"]
mfc_shared_dll_linking["MFC का linking mode (Use of MFC)"]
mfc_module_state["MFC module state"]
activex["ActiveX"]
bitness_match_requirement["bitness मिलान की requirement"]
high_dpi_support["high DPI support"]
new_gui_application_development["brand-new general GUI app development"]
legacy_app_maintenance_and_migration["existing MFC apps का maintenance और incremental migration"]
mfc -->|"use करता है"| win32_api
mfc -->|"use करता है"| cwinapp
cwinapp -->|"automate करता है"| win32_api
mfc -->|"implement करता है"| message_map
message_map -->|"require करता है"| win32_api
mfc -->|"implement करता है"| document_view_architecture
document_view_architecture -->|"require करता है"| cwinapp
message_map -.->|"use करता है"| document_view_architecture
mfc -->|"implement करता है"| mfc_ddx_ddv
mfc_ddx_ddv -->|"require करता है"| resource_script
mfc -->|"use करता है"| cstring_class
mfc -->|"require करता है"| vs_mfc_component
mfc -->|"से configure"| mfc_shared_dll_linking
mfc -.->|"require करता है"| mfc_module_state
mfc -.->|"use करता है"| activex
mfc -.->|"require करता है"| bitness_match_requirement
mfc -.->|"require करता है"| high_dpi_support
mfc -->|"recommended नहीं"| new_gui_application_development
mfc -->|"recommended उपाय"| legacy_app_maintenance_and_migration
mfc_module_state -.->|"require करता है"| resource_script
Diagram में solid line हमेशा लागू रहने वाला relation दिखाती है और dashed line conditional relation दिखाती है (शर्तें detail page पर हर relation के explanation में दी गई हैं)। Relations की पूरी list (कुल 20, evidence और certainty सहित) तथा मुख्य concepts की definitions knowledge map की detail page पर संकलित हैं (जापानी में)। Data: JSON-LD / Turtle
2. MFC क्या है
MFC native Windows desktop applications C++ में बनाने की class library है।
Win32 API सीधे use करते समय आमतौर पर ऐसा code लिखते हैं।
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
// drawing
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Win32 API बहुत powerful है, लेकिन C functions, handles, messages और callbacks के इर्द-गिर्द बनता है, इसलिए बड़े applications में नज़र रखना मुश्किल हो जाता है। MFC इसे C++ classes के रूप में इस्तेमाल करने लायक बनाता है: window CWnd है, dialog CDialog, पूरा application CWinApp, frame window CFrameWnd, view CView।
class CMainFrame : public CFrameWnd
{
public:
CMainFrame();
protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
DECLARE_MESSAGE_MAP()
};
MFC Win32 API को पूरी तरह किसी और चीज़ से replace नहीं करता। Win32 के ideas पर टिका एक पतला, लेकिन wide-ranging, C++ framework है। इसलिए MFC पढ़ने के लिए सिर्फ़ MFC classes नहीं, ये knowledge भी चाहिए।
Windows messages
HWND जैसे handles
GDI/GDI+
Resource files
COM/OLE
DLLs और runtime
Character encoding
Threads और message loop
“Windows जाने बिना लिखने वाली magic library” नहीं — असल रूप यह है: “Windows के mechanisms को C++ types और framework से organize किया गया है।”
3. क्या MFC आज भी use किया जा सकता है
MFC आज भी Visual Studio में available है। लेकिन उसकी जगह को गलत न समझें। Support जारी है, हाँ — लेकिन यह वह latest UI framework नहीं है जिसमें नई features लगातार जुड़ रही हों। Microsoft की MFC documentation में यह note दिखता है कि MFC support जारी रहेगा, जबकि नई features या documentation updates नहीं आएँगे।
इसलिए MFC की जगह लगभग ऐसी है।
Existing MFC apps का maintenance -> realistically आम
Existing MFC apps में feature जोड़ना -> हो सकता है
MFC app का build environment update -> ज़रूरी
MFC से दूसरे UI पर incremental migration -> हो सकता है
Brand-new general GUI app में adopt करना -> सावधानी से decide करें
खासकर लंबे समय से चल रहे business applications में UI, printing, file I/O, device control, custom protocols, COM integration अक्सर MFC के अंदर ही बैठे होते हैं।
ऐसे codebase में “MFC छोड़ दो” से पहले “MFC पढ़ सको” ज़रूरी है।
4. MFC जिन क्षेत्रों में मजबूत रहा
MFC मुख्य रूप से Windows native desktop applications में इस्तेमाल हुआ।
ठोस उदाहरण ये applications हैं।
Dialog-centric business tools
फ़ाइल खोलकर edit करने वाले SDI apps
कई documents संभालने वाले MDI apps
Measurement instruments या manufacturing equipment के control screens
CAD/CAM जैसे native apps
Printing और preview बहुत इस्तेमाल करने वाले apps
ActiveX या OLE integration वाले apps
पुराने Windows APIs या COM assets से tightly जुड़े apps
MFC की ताकत यह है कि वह Windows native components के बहुत पास चलता है। window, menus, toolbars, status bars, dialogs, common controls, printing, file dialogs, Registry, GDI drawing — इन्हें C++ classes के रूप में इस्तेमाल कर सकते हैं।
कमज़ोरी यह है कि modern UI construction, data binding, testability, async processing, modern layout, high DPI, localization, accessibility हाल के frameworks जितने naturally नहीं लिखे जाते।
खास बातें list करें तो ऐसा दिखता है।
Windows native के करीब
C++ से सीधा control
Existing assets बहुत हैं
Win32 knowledge चाहिए
पुरानी conventions ज़्यादा हैं
Testable structure खुद बनानी पड़ती है
5. Visual Studio में MFC के लिए तैयारी
Visual Studio में C++ install होने का मतलब यह नहीं कि MFC भी ज़रूर बैठा है। MFC Visual Studio Installer का individual component है। आमतौर पर ये components चेक करें।
Desktop development with C++
MSVC v143 - VS 2022 C++ x64/x86 build tools
Windows SDK
C++ MFC for latest v143 build tools
C++ ATL for latest v143 build tools
Spectre Mitigations वाला MFC चाहिए या नहीं
Build के समय MFC-related files न मिलें, तो सिर्फ़ project settings नहीं — Visual Studio में MFC component बैठा है या नहीं, वह भी देखें।
Installer में चुनने का तरीका यह है।
1. Start menu से Visual Studio Installer खोलें
2. जिस Visual Studio installation पर काम करना है, वहाँ Modify दबाएँ
3. Workloads tab में Desktop development with C++ चेक करें
4. उसी screen के दाईं तरफ़ Installation details में
C++ MFC for latest v143 build tools चेक करें
5. न दिखे तो Individual components tab पर जाएँ,
search box में MFC टाइप करके ढूँढें
6. Modify दबाकर install करें
Desktop development with C++ workload चुनने भर से MFC हमेशा नहीं आता, इसलिए step 4 या step 5 में component स्वयं चेक है, यह ज़रूर देखें।
Scripts या CI से install करना हो तो component ID दें।
| Display name | Component ID |
|---|---|
| C++ MFC for latest v143 build tools | Microsoft.VisualStudio.Component.VC.ATLMFC |
| C++ ATL for latest v143 build tools | Microsoft.VisualStudio.Component.VC.ATL |
| Desktop development with C++ (Build Tools workload) | Microsoft.VisualStudio.Workload.VCTools |
बैठा है या नहीं, यह MFC headers वाले atlmfc folder की मौजूदगी से पता चलता है। MFC headers और libraries MSVC toolset के नीचे लगते हैं।
<Visual Studio install location>\VC\Tools\MSVC\<toolset version>\atlmfc\include\afxwin.h
PowerShell से ढूँढना हो तो ऐसा करें।
Get-ChildItem -Path "$env:ProgramFiles\Microsoft Visual Studio\2022" -Recurse -Filter afxwin.h -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty FullName
कुछ न दिखे तो MFC component install नहीं है।
इसी हालत में build करेंगे तो afxwin.h include करते ही रुक जाएगा। आमतौर पर यह compile error आता है।
fatal error C1083: Cannot open include file: 'afxwin.h': No such file or directory
इस error को “include path गलत है” पढ़कर project properties में भटकना एक आम लंबा चक्कर है। afxwin.h या afxdialogex.h न मिलें, तो पहले Visual Studio Installer पर शक करें।
CI environment या build server पर भी वही बात है। Local Visual Studio पर build चलता हो और CI पर fail हो, तो कारण अक्सर MFC component की कमी या target toolset version का फ़र्क होता है।
6. MFC application की basic structure
MFC application आमतौर पर ऐसी structure रखता है।
CWinApp-derived class
पूरे application का initialization और shutdown
CFrameWnd / CMDIFrameWnd / CDialog-derived class
Main window या dialog
CView-derived class
Display और user interaction
CDocument-derived class
Data और file save
Resource files
Menus, dialogs, icons, strings वगैरह रखते हैं
Message map
Windows messages और commands को handler functions से bind करता है
उदाहरण के लिए एक साधारण MFC app में ऐसा CWinApp-derived class दिखता है।
class CMyApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
CMyApp theApp;
BOOL CMyApp::InitInstance()
{
CWinApp::InitInstance();
CMainFrame* pFrame = new CMainFrame;
m_pMainWnd = pFrame;
pFrame->Create(nullptr, _T("My MFC Application"));
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CWinApp पूरे application को represent करने वाला class है।
MFC application में आमतौर पर CWinApp से derived एक ही object होता है।
theApp जैसा global object पहले अजीब लग सकता है, लेकिन MFC में यही standard structure है।
7. CWinApp क्या करता है
CWinApp MFC application का entry point है, इसलिए महत्वपूर्ण है। साधारण Win32 application में WinMain, window class registration, message loop खुद लिखते हैं; MFC में उनमें से ज़्यादातर framework ले लेता है। Developer मुख्य रूप से InitInstance override करके application-specific initialization लिखता है।
BOOL CMyApp::InitInstance()
{
CWinApp::InitInstance();
// load settings
// COM initialization
// create main window
// register document template
return TRUE;
}
InitInstance में अक्सर ये काम लिखे जाते हैं।
Common controls का initialization
Registry key सेट करना
Recent file list पढ़ना
Document template register करना
Main frame बनाना
Command-line arguments handle करना
COM/OLE initialization
Maintenance के समय पहले CWinApp-derived class देखें — पूरे application का startup order साफ़ दिखने लगता है।
8. CWnd MFC का central class है
MFC के ज़्यादातर UI classes Windows window को represent करने वाले CWnd से derive होते हैं। लेकिन CWnd object और HWND एक ही चीज़ नहीं हैं।
HWND
Windows OS द्वारा manage किया जाने वाला window handle
CWnd
HWND को आसानी से इस्तेमाल करने वाला C++ wrapper object
MFC में CWnd अपने अंदर HWND रखता है।
HWND hWnd = m_hWnd;
या ऐसे लेते हैं।
HWND hWnd = GetSafeHwnd();
Maintenance में ज़रूरी बात: CWnd* मौजूद होने का मतलब यह नहीं कि corresponding HWND अभी live है — वह पहले ही destroy हो चुका हो सकता है।
इसलिए window valid है या नहीं, ऐसा चेक करते हैं।
if (pWnd != nullptr && ::IsWindow(pWnd->GetSafeHwnd()))
{
pWnd->ShowWindow(SW_SHOW);
}
MFC bug investigation में देखें कि CWnd के C++ object की lifetime और असल Windows window handle की lifetime अलग तो नहीं हो गई।
9. Message map क्या है
MFC का flavour सबसे ज़्यादा message map में दिखता है।
Windows application mouse click, key input, repaint, window resize, menu selection को Windows messages के रूप में लेता है।
Win32 API में आमतौर पर WndProc के switch में messages handle करते हैं।
MFC में उसी को message map के ज़रिए handler functions से bind करते हैं।
BEGIN_MESSAGE_MAP(CMyDialog, CDialogEx)
ON_BN_CLICKED(IDC_BUTTON_OK, &CMyDialog::OnClickedButtonOk)
ON_WM_CLOSE()
END_MESSAGE_MAP()
void CMyDialog::OnClickedButtonOk()
{
AfxMessageBox(_T("Clicked"));
}
इस code का मतलब यह है।
IDC_BUTTON_OK वाला button click हो
तो CMyDialog::OnClickedButtonOk call हो
Message आने से handler call तक का flow diagram में ऐसा है।
flowchart TB
accTitle: Message से handler तक का flow
accDescr: Windows message MFC के message loop और CWnd::WindowProc से गुज़रकर class के message map में match ढूँढता है, नहीं मिला तो base class तक जाता है, और अंत में DefWindowProc पर जाता है।
MSG["Windows message<br/>WM_COMMAND / WM_PAINT आदि"] --> LOOP["Message loop<br/>MFC framework चलाता है"]
LOOP --> PROC["CWnd::WindowProc<br/>MFC का common entry point"]
PROC --> MAP{"इस class के message map में<br/>matching entry है?"}
MAP -->|हाँ| HANDLER["ON_BN_CLICKED आदि वाला<br/>handler function call होता है"]
MAP -->|नहीं| BASE["Base class का message map खोजें<br/>CDialogEx से CDialog, CWnd तक क्रम से"]
BASE --> FOUND{"कहीं मिला?"}
FOUND -->|मिला| HANDLER
FOUND -->|नहीं मिला| DEF["DefWindowProc<br/>Windows default processing"]
switch इसलिए नहीं दिखता क्योंकि “इस class से base class तक message map walk करना” framework अपने ऊपर ले लेता है। DECLARE_MESSAGE_MAP और BEGIN_MESSAGE_MAP को इसी search के लिए per-class lookup table बनाने वाले macros समझें, तो बात बैठती है।
MFC में नए हो तो function कहाँ से call हो रहा है, समझना मुश्किल लगता है। Search करने पर direct call न मिले, तो message map देखें।
Function कहीं directly call नहीं हो रहा
फिर भी event पर चल रहा है
-> BEGIN_MESSAGE_MAP / ON_... macros चेक करें
MFC code review में handler functions अकेले नहीं — message map के साथ सेट में देखना ज़रूरी है।
10. Command routing
MFC में menus और toolbars भी commands के रूप में चलते हैं।
सबसे आम ON_COMMAND है।
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_COMMAND(ID_FILE_OPEN, &CMainFrame::OnFileOpen)
END_MESSAGE_MAP()
void CMainFrame::OnFileOpen()
{
// file open करना
}
MFC के पास command को सही object तक पहुँचाने का mechanism है।
उदाहरण: वही ID_EDIT_COPY कभी active view handle करे, कभी document, कभी frame, कभी application।
Active view
Document
Frame window
Application
इसी क्रम में जो object handle कर सके, उस तक command जाता है।
इसलिए MFC में “menu दबाया तो कौन-सा function चला” सिर्फ़ string search से पकड़ना मुश्किल हो सकता है।
Maintenance में ये बिंदु देखें।
Command ID क्या है
ON_COMMAND किस class में है
ON_UPDATE_COMMAND_UI कहाँ है
अभी active view कौन-सा है
Document/View structure इस्तेमाल हो रही है या नहीं
11. ON_UPDATE_COMMAND_UI क्या है
MFC में menu items या toolbar buttons को enable/disable करने, check state बदलने, display text update करने के लिए ON_UPDATE_COMMAND_UI इस्तेमाल होता है।
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_COMMAND(ID_EDIT_DELETE, &CMainFrame::OnEditDelete)
ON_UPDATE_COMMAND_UI(ID_EDIT_DELETE, &CMainFrame::OnUpdateEditDelete)
END_MESSAGE_MAP()
void CMainFrame::OnUpdateEditDelete(CCmdUI* pCmdUI)
{
pCmdUI->Enable(CanDeleteCurrentItem());
}
इससे menu या button तभी enable रहता है जब delete संभव हो।
MFC app चलाते हुए button बिना वजह greyed out हो, menu न दबे, check state बदल जाए — ऐसे व्यवहार में ON_UPDATE_COMMAND_UI ढूँढने से कारण अक्सर निकल आता है।
12. Dialog-based MFC apps
MFC के सबसे समझने में आसान रूपों में से एक dialog-based application है।
Settings screens, छोटे business tools, device operation screens अक्सर dialog के इर्द-गिर्द बने होते हैं।
आमतौर पर CDialog या CDialogEx inherit करते हैं।
class CSettingsDialog : public CDialogEx
{
public:
CSettingsDialog(CWnd* pParent = nullptr);
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_SETTINGS_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX);
virtual BOOL OnInitDialog();
afx_msg void OnBnClickedOk();
DECLARE_MESSAGE_MAP()
private:
CString m_name;
int m_interval;
};
Dialog-based code में ये तत्व बार-बार आते हैं।
IDD_... Dialog resource ID
IDC_... Control ID
OnInitDialog Initialization
DoDataExchange Controls और member variables का association
UpdateData Screen और variables का sync
ON_BN_CLICKED Button click handling
Dialog सिर्फ़ दिखने वाली चीज़ नहीं है। Resource, member variables, message map, initialization मिलकर चलते हैं।
13. DDX और DDV
MFC dialogs में अक्सर DDX और DDV दिखते हैं।
DDX = Dialog Data Exchange
DDV = Dialog Data Validation
DDX dialog के controls को C++ member variables से जोड़ता है, DDV उस input को validate करता है।
void CSettingsDialog::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_NAME, m_name);
DDX_Text(pDX, IDC_EDIT_INTERVAL, m_interval);
DDV_MinMaxInt(pDX, m_interval, 1, 3600);
}
UpdateData(TRUE) बुलाने पर screen पर भरी values member variables में आ जाती हैं।
void CSettingsDialog::OnBnClickedOk()
{
if (!UpdateData(TRUE))
{
return;
}
// यहाँ m_name और m_interval में screen की input values हैं
SaveSettings(m_name, m_interval);
CDialogEx::OnOK();
}
उलटा, UpdateData(FALSE) member variables की values screen पर लिख देता है।
BOOL CSettingsDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
m_name = _T("default");
m_interval = 60;
UpdateData(FALSE);
return TRUE;
}
MFC dialog में input अजीब लगे, तो ये चेक करें।
DoDataExchange में DDX defined है या नहीं
UpdateData(TRUE) call हो रहा है या नहीं
UpdateData(FALSE) का timing सही है या नहीं
DDV input अस्वीकार तो नहीं कर रहा
Control IDs resources से match करते हैं या नहीं
14. Document/View architecture
MFC की बड़ी पहचान Document/View architecture है।
यह application के data और उसके display को अलग रखने की structure है।
CDocument
Data रखता है
File read/write संभालता है
कई views को update notify करता है
CView
Data दिखाता है
User interaction संभालता है
Drawing और selection state manage करता है
Frame, view और document का संबंध diagram में ऐसा है।
flowchart TB
accTitle: Frame, view और document का संबंध
accDescr: CWinApp document template register करता है जो frame, document और view को जोड़ता है; view GetDocument से document लेता है और document UpdateAllViews से views को notify करता है।
APP["CWinApp-derived<br/>पूरे app का start और exit"] --> TPL["Document template<br/>CSingleDocTemplate / CMultiDocTemplate"]
TPL --> FRAME["Frame window<br/>CFrameWnd / CMDIChildWnd"]
TPL --> DOC["CDocument-derived<br/>Data और file I/O"]
TPL --> VIEW["CView-derived<br/>Drawing और user interaction"]
FRAME --> VIEW
VIEW -->|GetDocument से मिलता है| DOC
DOC -->|UpdateAllViews से notify| VIEW
मुख्य बात: frame, document और view — तीनों को जोड़ने वाला document template है। InitInstance में यही template register होता है, इसलिए “कौन-सा view किस document को देखता है” जानना हो तो पहले InitInstance पढ़ें।
View से document देखने के लिए GetDocument, document की change सभी views तक पहुँचाने के लिए UpdateAllViews — यह दिशा का फ़र्क याद रहे तो screen update न होने वाले bugs आसानी से पकड़ते हैं।
Text editor, drawing editor, settings-file editor, CAD जैसे apps में data और display अलग रखना मतलब रखता है।
class CMyDocument : public CDocument
{
public:
std::vector<Item> m_items;
virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);
virtual BOOL OnSaveDocument(LPCTSTR lpszPathName);
};
class CMyView : public CView
{
protected:
virtual void OnDraw(CDC* pDC);
CMyDocument* GetDocument() const;
};
View document लेकर draw करता है।
void CMyView::OnDraw(CDC* pDC)
{
CMyDocument* pDoc = GetDocument();
if (pDoc == nullptr)
{
return;
}
for (const auto& item : pDoc->m_items)
{
// pDC से draw करें
}
}
Document/View का फ़ायदा: वही data कई views पर दिखाना आसान होता है।
उदाहरण के लिए वही data ऐसे दिखा सकते हैं।
Tabular view
Graph view
Detail view
Preview
Print view
लेकिन साधारण settings screen या छोटे tool पर Document/View लगाने से structure उल्टा भारी पड़ सकती है।
Maintenance में पहले यह तय करें कि app Document/View इस्तेमाल कर रहा है या dialog-centric है — उसके बाद code follow करना आसान होता है।
15. SDI और MDI
MFC में Document/View के साथ SDI और MDI अक्सर आते हैं।
SDI = Single Document Interface
MDI = Multiple Document Interface
SDI मूल रूप से एक frame में एक document संभालता है।
Main window
एक document
एक या कई views
MDI एक parent window के अंदर कई child windows रखता है, और हर child अपना document संभालता है।
MDI parent frame
MDI child frame 1 -> document 1
MDI child frame 2 -> document 2
MDI child frame 3 -> document 3
पुराने Windows applications में MDI आम था।
Maintenance में class names देखकर structure का अंदाज़ा लग जाता है।
CFrameWnd SDI-style frame
CMDIFrameWnd MDI parent frame
CMDIChildWnd MDI child frame
CSingleDocTemplate SDI document template
CMultiDocTemplate MDI document template
MFC wizard से बने apps में InitInstance के अंदर CSingleDocTemplate या CMultiDocTemplate का registration अक्सर होता है।
16. Resource files को समझना
MFC apps में .rc file बहुत महत्वपूर्ण है।
.rc Windows का resource file है।
यहाँ ये चीज़ें defined होती हैं।
Dialog templates
Menus
Accelerator keys
Icons
Bitmaps
String tables
Version information
Toolbars
resource.h में resource IDs defined होते हैं।
#define IDD_SETTINGS_DIALOG 101
#define IDC_EDIT_NAME 1001
#define IDC_EDIT_INTERVAL 1002
#define ID_FILE_OPEN 32771
MFC code इन्हीं IDs से resources को C++ code से जोड़ता है।
DDX_Text(pDX, IDC_EDIT_NAME, m_name);
ON_COMMAND(ID_FILE_OPEN, &CMainFrame::OnFileOpen)
Maintenance में आम समस्या resource ID mismatch है।
resource.h का ID बदल गया
दूसरी branch merge पर IDs collide हो गए
Dialog के control ID और DDX का ID match नहीं करते
हटाया हुआ menu ID अभी भी पड़ा है
String table के IDs duplicate हैं
MFC app का behavior देखते समय सिर्फ़ C++ code नहीं — .rc और resource.h साथ देखें।
17. Class Wizard और handwritten code
MFC का इतिहास Visual Studio के Class Wizard से गहरा जुड़ा है।
Class Wizard message handlers, DDX variables, virtual function overrides अपने आप generate कर सकता है।
इसलिए MFC code में tool-generated आकार बहुत बचा रहता है।
//{{AFX_DATA(CSettingsDialog)
//}}AFX_DATA
//{{AFX_MSG(CSettingsDialog)
//}}AFX_MSG
नए Visual Studio में दिखने और generate होने का रूप बदल चुका हो सकता है, लेकिन पुराने codebases में ऐसे comment markers अभी भी मिलते हैं।
Maintenance में ज़रूरी है कि generated code और handwritten code की सीमा लापरवाही से न तोड़ें।
Message map मत हटाएँ
DDX mapping मत तोड़ें
Resource IDs बेवजह मत बदलें
पुराने Class Wizard वाले comments बिना सोचे मत मिटाएँ
MFC में सिर्फ़ “C++ के रूप में compile हो गया” काफी नहीं है। Visual Studio के resource editor और Class Wizard जो आकार expect करते हैं, वह भी कुछ हद तक रखना पड़ता है।
18. CString और strings
MFC में सबसे ज़्यादा दिखने वाला string class CString है।
CString name = _T("Komura");
CString message;
message.Format(_T("Hello, %s"), name.GetString());
CString MFC/ATL code में आम variable-length string class है। Modern C++ में std::string या std::wstring ज़्यादा इस्तेमाल होते हैं, लेकिन MFC में APIs और controls के साथ compatibility की वजह से CString बहुत चलता है।
Maintenance में character encoding का ध्यान रखना पड़ता है।
CString Project settings के हिसाब से CStringA या CStringW जैसा
CStringA ANSI / MBCS
CStringW Unicode / UTF-16
LPCTSTR TCHAR-based string pointer
LPCSTR char-based
LPCWSTR wchar_t-based
std::string आमतौर पर char-based
std::wstring wchar_t-based
आज के Windows apps में Unicode मानकर चलना सुरक्षित है, लेकिन पुराने MFC apps में MBCS वाला code बचा हो सकता है।
CString text = _T("日本語");
std::wstring ws(text.GetString());
String conversion bugs MFC maintenance में बार-बार आते हैं।
खासकर ये मामले देखें।
Shift_JIS मानकर फ़ाइल पढ़ना
Unicode build पर स्विच करना
External DLL char* माँगती है
COM BSTR माँगता है
std::string में लापरवाही से convert करके garbled text
CString देखकर सिर्फ़ “पुराना string class” मत सोचें। Project का character-set setting, external APIs, और file format के साथ सेट में चेक करें।
19. CFile और CArchive
MFC में file I/O और serialization के classes भी हैं। सबसे आम CFile और CArchive हैं।
CFile file;
if (file.Open(path, CFile::modeRead))
{
CArchive ar(&file, CArchive::load);
// ar से पढ़ें
}
CArchive MFC के serialization mechanism में अक्सर इस्तेमाल होता है।
CDocument-derived class में Serialize override करके load और save एक ही function में लिखे जाते हैं।
void CMyDocument::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_title;
ar << static_cast<int>(m_items.size());
for (const auto& item : m_items)
{
ar << item.Name;
ar << item.Value;
}
}
else
{
int count = 0;
ar >> m_title;
ar >> count;
m_items.clear();
for (int i = 0; i < count; ++i)
{
Item item;
ar >> item.Name;
ar >> item.Value;
m_items.push_back(item);
}
}
}
MFC serialization सुविधाजनक है, लेकिन लंबे समय तक चलाने पर सावधानी चाहिए।
पुराने file format के साथ compatibility
Version numbers का management
Read fail होने पर recovery
Exception handling
Character encoding
Endianness
Struct को ज्यों का त्यों तो save नहीं कर रहे
Custom binary format लंबे समय से इस्तेमाल करने वाले MFC apps में Serialize practically file spec बन जाता है।
ऐसे में code बदलने से पहले existing files पढ़ने वाला test data ज़रूर तैयार रखें।
20. GDI drawing और CDC
MFC की screen drawing में Windows Device Context संभालने वाला CDC class आम है। CView::OnDraw को argument के रूप में CDC* मिलता है।
void CMyView::OnDraw(CDC* pDC)
{
pDC->TextOut(10, 10, _T("Hello MFC"));
pDC->Rectangle(10, 40, 200, 120);
}
Pen या brush इस्तेमाल करें तो select और restore पर ध्यान दें।
void CMyView::OnDraw(CDC* pDC)
{
CPen pen(PS_SOLID, 1, RGB(0, 0, 0));
CPen* pOldPen = pDC->SelectObject(&pen);
pDC->MoveTo(10, 10);
pDC->LineTo(100, 100);
pDC->SelectObject(pOldPen);
}
GDI objects के आसपास ये mistakes समस्या बनती हैं।
SelectObject के बाद पुराना object वापस नहीं लगाया
GDI objects ढेर सारे बनाए और destroy नहीं किए
OnPaint और OnDraw की भूमिका मिला दी
Double buffering नहीं है, इसलिए flicker
High DPI पर fixed-pixel drawing टूट जाती है
MFC drawing bugs में सिर्फ़ C++ logic नहीं — Windows के GDI resources, repaint timing, DPI, font size भी देखें।
21. Modal dialog और modeless dialog
MFC में dialog कैसे दिखाते हैं, वह भी महत्वपूर्ण है।
Modal dialog DoModal से दिखता है।
CSettingsDialog dlg(this);
if (dlg.DoModal() == IDOK)
{
// OK पर processing
}
इसमें dialog बंद होने तक caller रुकता है।
Modeless dialog बनाने के बाद caller की processing लौट आती है।
m_pToolDialog = new CToolDialog(this);
m_pToolDialog->Create(IDD_TOOL_DIALOG, this);
m_pToolDialog->ShowWindow(SW_SHOW);
Modeless dialog में lifetime management ज़रूरी है।
new किया dialog कब delete होगा
Parent window पहले destroy तो नहीं हो रहा
Dialog तरफ़ PostNcDestroy इस्तेमाल हो रहा है या नहीं
Double-create तो नहीं हो रहा
बंद होने के बाद pointer पड़ा तो नहीं रह गया
MFC crash investigation में modeless dialog की lifetime अक्सर कारण बनती है।
22. C++ object और Windows handle की lifetime
MFC में बहुत महत्वपूर्ण फ़र्क: C++ object की lifetime और Windows handle की lifetime एक नहीं हैं। उदाहरण: CWnd C++ object है, लेकिन असल window को Windows OS HWND के रूप में manage करता है, और ये दोनों हमेशा एक साथ बनकर एक साथ गायब नहीं होते।
CWnd object है, HWND अभी नहीं बना
HWND destroy हो चुका, CWnd object बचा है
Temporary CWnd wrapper बना है
Attach/Detach से handle बदला जा रहा है
उदाहरण के लिए ऐसा code सावधानी का है।
CWnd* pWnd = GetDlgItem(IDC_SOME_CONTROL);
// pWnd को member में रख कर बाद में use करना
GetDlgItem से मिला pointer लंबे समय तक रखेंगे तो window destroy होने के बाद dereference का खतरा है।
ज़रूरत हो तो हर बार GetDlgItem करें, या control के लिए member variable DDX से manage करें — वह अक्सर सुरक्षित है।
DDX_Control(pDX, IDC_LIST_ITEMS, m_listItems);
MFC में pointer non-null होने का मतलब safe नहीं है।
if (m_pDialog != nullptr && ::IsWindow(m_pDialog->GetSafeHwnd()))
{
m_pDialog->SetWindowText(_T("Running"));
}
यह intuition MFC maintenance में बहुत काम आता है।
23. Threads और UI update
Windows UI मूल रूप से उसी UI thread से operate करनी होती है जिसने उसे बनाया, और MFC apps में भी वही नियम है। Worker thread से UI controls सीधे छूने पर unstable behavior या crash आता है।
इस पैटर्न से बचें।
UINT WorkerThreadProc(LPVOID pParam)
{
CMyDialog* pDlg = static_cast<CMyDialog*>(pParam);
// Worker thread से UI सीधे मत छुएँ
pDlg->SetDlgItemText(IDC_STATUS, _T("Done"));
return 0;
}
आम तरीका: PostMessage आदि से UI thread को notify करें।
constexpr UINT WM_APP_WORK_DONE = WM_APP + 1;
UINT WorkerThreadProc(LPVOID pParam)
{
HWND hWnd = static_cast<HWND>(pParam);
// भारी processing
::PostMessage(hWnd, WM_APP_WORK_DONE, 0, 0);
return 0;
}
UI तरफ़ message map से receive करें।
BEGIN_MESSAGE_MAP(CMyDialog, CDialogEx)
ON_MESSAGE(WM_APP_WORK_DONE, &CMyDialog::OnWorkDone)
END_MESSAGE_MAP()
LRESULT CMyDialog::OnWorkDone(WPARAM, LPARAM)
{
SetDlgItemText(IDC_STATUS, _T("Done"));
return 0;
}
MFC threads के आसपास ये चेक करें।
Worker thread से UI सीधे तो नहीं छू रहे
Window destroy होने के बाद PostMessage तो नहीं भेज रहे
Thread के खत्म होने का wait UI thread को रोक तो नहीं रहा
Shared data का lock सही है या नहीं
AfxBeginThread की return value और lifetime गलत तो नहीं समझ रहे
24. MFC DLL और module state
MFC में DLL बनाते समय module state आता है।
MFC DLL से resource load करना, dialog दिखाना, extension DLL बनाना — ऐसे जगहों पर सवाल यह होता है कि कौन-से module के resources देखे जाएँगे।
MFC DLL के function entry पर ऐसा macro दिखता है।
AFX_MANAGE_STATE(AfxGetStaticModuleState());
यह MFC को सही module state इस्तेमाल करने देता है।
यह macro भूल गए तो ये defects आते हैं।
DLL के अंदर का dialog resource नहीं मिलता
String resource दूसरे module से पढ़ा जाता है
Icons या menus नहीं मिलते
Debug में चलता है, Release में टूटता है
MFC DLL maintain करते समय EXE, regular DLL, extension DLL, resource DLL के संबंध साफ़ करें।
खासकर जब non-MFC app MFC DLL को call कर रहा हो, या plugin architecture हो, तब सावधानी चाहिए।
25. MFC static link करें या shared DLL
MFC apps के project settings में “Use of MFC” होता है।
दो आम विकल्प ये हैं।
Use MFC in a Shared DLL
Use MFC in a Static Library
Shared DLL पर runtime में matching MFC runtime और Visual C++ runtime चाहिए।
Static link पर distributable सरल लग सकता है, लेकिन executable size, updates, security fixes लेना, license और redistribution conditions सोचनी पड़ती हैं।
कोई एक हमेशा सही नहीं है।
निर्णय के लिए ये बिंदु देखें।
Target machines पर Visual C++ Redistributable डाल सकते हैं या नहीं
App को single exe के करीब रखना है या नहीं
Security updates कैसे apply होंगे
कई apps एक ही runtime share करेंगे या नहीं
Installer बना सकते हैं या नहीं
Target Windows version क्या है
Maintenance में पहले मौजूदा setting देखें।
Configuration Properties
General
Use of MFC
साथ में Runtime Library setting भी देखें।
/MD Multi-threaded DLL
/MDd Multi-threaded Debug DLL
/MT Multi-threaded
/MTd Multi-threaded Debug
MFC और CRT की link settings मिश्रित हों तो library boundary पर allocate/free की समस्या आ सकती है।
26. Unicode, MBCS, TCHAR
पुराने MFC code में TCHAR, LPCTSTR, _T() macros आम हैं।
CString title = _T("Settings");
SetWindowText(title);
यह Unicode build और MBCS build दोनों संभालने का लिखने का तरीका है।
Unicode build
TCHAR -> wchar_t
LPCTSTR -> const wchar_t*
_T("...") -> L"..."
MBCS build
TCHAR -> char
LPCTSTR -> const char*
_T("...") -> "..."
आज Unicode build आम है, लेकिन पुराने apps में MBCS वाली processing बची हो सकती है।
खासकर external files, communication protocols, पुरानी DLLs, database connections, serial communication में character encoding की धारणा चेक करें।
Unicode migration को साधारण find-and-replace मत समझें।
char array का size bytes है या characters
strlen तो नहीं इस्तेमाल हो रहा
sizeof(buffer) को character count तो नहीं मान रहे
External API UTF-16 लेती है या Shift_JIS
File save format बदल सकता है या नहीं
MFC strings ठीक करते समय सिर्फ़ screen display नहीं — file compatibility और external integration तक देखें।
27. MFC और COM/OLE/ActiveX
MFC उन applications में भी इस्तेमाल हुआ जो COM, OLE, ActiveX से जुड़े थे।
पुराने business apps में ये तत्व बचे हो सकते हैं।
OLE Automation
ActiveX Control
COM server
COM client
IDispatch
BSTR
VARIANT
COleDispatchDriver
COleVariant
MFC app के startup में ऐसा code दिख सकता है।
if (!AfxOleInit())
{
AfxMessageBox(_T("OLE initialization failed"));
return FALSE;
}
COM/OLE इस्तेमाल हो रहा हो तो जो MFC की समस्या लगे, असल में COM initialization, threading model, reference counting, registration, 32-bit/64-bit फ़र्क कारण हो सकता है।
खासकर 32-bit ActiveX और COM components पर ध्यान दें।
32-bit MFC app से 32-bit COM इस्तेमाल होता है
64-bit MFC app से 64-bit COM इस्तेमाल होता है
32-bit/64-bit COM registration अलग है
पुराना ActiveX 64-bit support नहीं करता हो सकता है
MFC app को x64 करते समय सिर्फ़ UI code नहीं — COM/OLE dependencies भी ज़रूर चेक करें।
28. High DPI support और आज का Windows
पुराने MFC apps आज के Windows पर चलाएँ तो high DPI पर display टूट सकता है।
उदाहरण ये समस्याएँ।
Text कट जाता है
Buttons बहुत छोटे लगते हैं
Fixed-pixel drawing शिफ्ट हो जाता है
कई monitors पर अलग scaling से layout टूटता है
पुराने bitmaps धुँधले दिखते हैं
Dialog layout cramped हो जाता है
Windows desktop apps को DPI-aware mode explicitly बताना पड़ता है।
MFC apps में भी manifest, resources, drawing code, fonts, layout चेक करें।
खासकर fixed coordinates सीधे लिखे हुए ऐसे code high DPI पर जल्दी टूटते हैं।
pDC->TextOut(10, 10, _T("Status"));
pDC->Rectangle(10, 40, 200, 80);
Fixed-pixel coordinates DPI बदलते ही दिखने में बिगड़ते हैं।
Maintenance में ये बिंदु देखें।
Application manifest की DPI setting
Dialog resource का font
Fixed-pixel drawing
Image resources का resolution
कई monitors पर व्यवहार
Windows 10 / Windows 11 पर display
MFC का high DPI support सिर्फ़ project setting बदल देने से पूरा नहीं होता। पुराने UI में असल screen पर देखना और layout ठीक करना पड़ता है।
29. Exception handling और error handling
MFC के अपने exception classes और error-handling conventions हैं।
पुराने code में ऐसे macros दिखते हैं।
TRY
{
// processing
}
CATCH(CFileException, e)
{
e->ReportError();
}
END_CATCH
Modern C++ के try / catch के साथ मिला-जुला code भी होता है।
try
{
DoSomething();
}
catch (const std::exception& ex)
{
// log लिखना
}
MFC maintenance में ये बिंदु देखें।
MFC exceptions और C++ standard exceptions मिश्रित तो नहीं
Exception object की lifetime गलत तो नहीं समझ रहे
पुराने THROW/CATCH macros समझ रहे हो या नहीं
Return-value errors और exceptions मिश्रित तो नहीं
AfxMessageBox भर से log बचता ही नहीं, ऐसा तो नहीं
Business apps में screen पर error message भर काफी नहीं — log, operation history, input values, external connection state भी रखना ज़रूरी है।
पुराने MFC apps में error AfxMessageBox पर खत्म हो जाता है।
AfxMessageBox(_T("Save failed"));
Maintainability बढ़ानी हो तो UI display और log recording अलग रखें।
LogError(_T("Save failed"), path);
AfxMessageBox(_T("Save failed. Check the log."));
30. MFC और modern C++ को साथ कैसे चलाएँ
MFC app maintain कर रहे हो, इसका मतलब यह नहीं कि सब कुछ पुरानी C++ style में लिखना है।
UI layer MFC की conventions का सम्मान करे, domain logic और calculation modern C++ में साफ़ रख सकते हैं।
उदाहरण के लिए ऐसा बाँटें।
MFC layer
CDialog
CView
CDocument
CString
Message map
Resource operations
Non-MFC layer
std::string / std::wstring
std::vector
std::optional
std::variant
std::filesystem
Unit-testable classes
Business logic
खराब रूप यह है कि सारी processing dialog class में ठूँस दी गई हो।
void CMainDialog::OnBnClickedExecute()
{
// input लेना
// file पढ़ना
// communication
// calculation
// DB update
// screen update
// log लिखना
// exception handling
}
ऐसा code बदलना मुश्किल, test करना मुश्किल, bug investigation भी मुश्किल हो जाता है।
सुधार यह है कि logic MFC classes से बाहर निकालें।
void CMainDialog::OnBnClickedExecute()
{
if (!UpdateData(TRUE))
{
return;
}
ExecuteRequest request;
request.Name = ToStdWString(m_name);
request.Interval = m_interval;
ExecuteResult result = m_service.Execute(request);
m_status = ToCString(result.Message);
UpdateData(FALSE);
}
इस तरह m_service.Execute MFC के बिना test हो सकता है।
Existing MFC assets maintain करते समय सबसे असरदार सुधार यही है: UI classes से logic थोड़ा-थोड़ा काटना।
31. MFC code को testable बनाना
MFC apps ज्यों के त्यों unit-test करना अक्सर मुश्किल होता है।
कारण: UI, Win32, files, communication, database, global state आसानी से tightly coupled हो जाते हैं।
Testable बनाने का सोच यह है।
CDialog या CView को सीधे test करने की कोशिश मत करें
पहले non-UI logic काटें
MFC types को boundary पर convert करें
Files और communication को interface बनाएँ
Screen event handlers पतले रखें
उदाहरण: शुद्ध C++ class में processing ले जाएँ।
class PriceCalculator
{
public:
int CalculateTotal(const std::vector<int>& prices) const
{
int total = 0;
for (int price : prices)
{
total += price;
}
return total;
}
};
MFC तरफ़ सिर्फ़ input और output संभालती है।
void CPriceDialog::OnBnClickedCalculate()
{
if (!UpdateData(TRUE))
{
return;
}
std::vector<int> prices = ParsePrices(ToStdWString(m_input));
int total = m_calculator.CalculateTotal(prices);
m_result.Format(_T("%d"), total);
UpdateData(FALSE);
}
इस structure में PriceCalculator और ParsePrices साधारण C++ test framework से test हो सकते हैं।
पूरे MFC app को एक बार में rewrite करने की ज़रूरत नहीं। Event handlers के अंदर से testable processing बाहर निकालना भर से फ़ायदा होता है।
32. Build environment को freeze करना
MFC app maintenance में build environment freeze करना ज़रूरी है।
पुराने codebases में ये फ़र्क build result बदल देते हैं।
Visual Studio version
MSVC toolset version
Windows SDK version
MFC/ATL component है या नहीं
x86 / x64 / ARM64
Debug / Release
Unicode / MBCS
MFC static link / shared DLL
Runtime library setting
Precompiled headers
MFC apps में stdafx.h या pch.h पर बहुत सारी dependencies इकट्ठा हो जाती हैं।
#include "framework.h"
#include "MyApp.h"
किसी एक file की compile settings अलग हों, precompiled header setting टेढ़ी हो — ऐसे कारणों से build टूटता है।
Maintenance project में यह जानकारी README में लिख दें, बाद में काम आसान रहता है।
ज़रूरी Visual Studio version
ज़रूरी workloads और individual components
ज़रूरी Windows SDK
Target platform
MFC की linking style
Build steps
CI कैसे चलाएँ
Distributable कैसे बनाएँ
“मेरी PC पर build हो जाता है” से आगे बढ़ना MFC maintenance का पहला कदम है।
33. CI पर MFC build करना
MFC apps भी CI पर build हो सकते हैं।
लेकिन CI environment में MFC component बैठा होना ज़रूरी है।
Visual Studio Build Tools इस्तेमाल करें तो MFC/ATL के component IDs देकर install करना पड़ता है। IDs chapter 5 की table जैसी ही हैं।
ये बिंदु चेक करें।
Build Tools में MFC बैठा है या नहीं
Target toolset project से match करता है या नहीं
Windows SDK बैठा है या नहीं
x86 build और x64 build दोनों चेक हो रहे हैं या नहीं
Resource compiler चलता है या नहीं
Signing step है या नहीं
Installer generation भी CI का हिस्सा है या नहीं
MFC apps में UI tests तक automate करना आसान नहीं, लेकिन कम से कम ये automation काम की है।
Debug / Release builds
x86 / x64 builds
Static analysis
Unit tests
Installer बनाना
Artifacts का hash रखना
Dependent DLLs चेक करना
लंबे maintenance में “build होता रहे” भर भी बड़ी value है।
34. MFC app debug करते समय कहाँ देखें
MFC app में bug chase करते समय यह क्रम efficient है।
1. कौन-सा screen है
2. Dialog है, View है, या Frame
3. Operation का resource ID क्या है
4. Message map किस function पर ले जाता है
5. UpdateData की दिशा सही है या नहीं
6. Document/View हो तो Document की state क्या है
7. Command routing किसी और class पर तो नहीं चला गया
8. Worker thread से UI तो नहीं छू रहे
9. Exception या error AfxMessageBox पर दब तो नहीं गई
10. Release build वाली uninitialized या lifetime समस्या तो नहीं
उदाहरण: “button दबाया, कुछ नहीं हुआ” तो ये देखें।
Button का IDC सही है या नहीं
ON_BN_CLICKED मौजूद है या नहीं
Handler का signature सही है या नहीं
Dialog resource कोई और तो नहीं लग रहा
Button disable तो नहीं है
बीच में UpdateData fail तो नहीं हो रहा
Exception दब तो नहीं गई
“Menu नहीं दबता” तो ये।
ON_UPDATE_COMMAND_UI ने disable तो नहीं कर दिया
Command IDs duplicate तो नहीं
Active view expected वाला है या नहीं
Handler Frame/View/Document/App में कहाँ है
MFC में सतह का event और असल processing macros और routing से जुड़े होते हैं, इसलिए आदत पड़ने तक call path का diagram बनाना समझने में मदद करता है। Chapter 9 का diagram उसी call path का basic रूप है।
लक्षण से अंदाज़ा लगाना हो तो पहले chapter 35 की table देखें। आम pitfalls और उन्हें कहाँ चेक करना है, वहाँ मैप किया गया है।
35. आम pitfalls
MFC maintenance की आम pitfalls यह हैं।
Message map देखे बिना सिर्फ़ function calls search करना
CWnd* non-null है तो valid मान लेना
HWND की lifetime और C++ object की lifetime मिला देना
UpdateData(TRUE/FALSE) की दिशा उलटी कर देना
ON_UPDATE_COMMAND_UI ने disable कर दिया, वह न दिखना
resource.h में ID collision न दिखना
Worker thread से UI सीधे छूना
CString और std::string conversion से garbled text
MBCS वाला code Unicode migration पर तोड़ना
MFC DLL में AFX_MANAGE_STATE भूल जाना
x86 वाला COM/ActiveX x64 migration पर तोड़ना
GDI object select/release गलत करना
High DPI पर fixed-coordinate layout टूटना
हर एक के लिए “क्या symptom दिखता है” और “कहाँ चेक करें” मैप कर देता हूँ। Debug की entry chapter 34 के steps से मेल खाती है।
| Pitfall | आम symptom | कहाँ चेक करें |
|---|---|---|
| Message map देखे बिना सिर्फ़ function calls search करना | Caller न मिले, फिर भी function चल रहा हो | BEGIN_MESSAGE_MAP search करें। Chapter 9, chapter 34 step 4 |
CWnd* non-null है तो valid मान लेना |
कभी-कभी crash, बंद screen operate करने पर crash | ::IsWindow(pWnd->GetSafeHwnd()) लगाएँ। Chapter 8 |
HWND की lifetime और C++ object की lifetime मिला देना |
Dialog बंद करने के बाद access violation | GetDlgItem की return value तो नहीं रखी। Chapter 22 |
UpdateData की दिशा उलटी |
Input values sync नहीं होते, initial values screen पर नहीं आते | UpdateData(TRUE) और UpdateData(FALSE) कहाँ call हैं। Chapter 13, chapter 34 step 5 |
ON_UPDATE_COMMAND_UI ने disable कर दिया, वह न दिखना |
Button या menu greyed out, दब नहीं रहा | ON_UPDATE_COMMAND_UI handler। Chapter 11, chapter 34 का “menu नहीं दबता” |
resource.h में ID collision न दिखना |
कोई और dialog या menu item प्रतिक्रिया दे | resource.h और .rc को ID से मिलाएँ। Chapter 16 |
| Worker thread से UI सीधे छूना | Reproduce मुश्किल unstable crash, कभी hang | AfxBeginThread वाले function में UI तो नहीं छू रहे। Chapter 23 |
CString और std::string conversion से garbled text |
सिर्फ़ Japanese text टूटे, अंत कट जाए | Project का character-set setting और conversion sites। Chapter 18 |
| MBCS वाला code Unicode migration पर तोड़ना | Buffer length mismatch, existing files न पढ़ें | sizeof को character count तो नहीं माना। Chapter 26 |
MFC DLL में AFX_MANAGE_STATE भूल जाना |
DLL के dialog या string resources न मिलें | DLL के exported functions की शुरुआत। Chapter 24 |
| x86 वाला COM/ActiveX x64 migration पर तोड़ना | सिर्फ़ 64-bit build startup या screen display पर fail | COM registration सिर्फ़ 32-bit तरफ़ तो नहीं। Chapter 27 |
| GDI object select/release गलत | लंबे समय चलाने पर drawing बिगड़ जाए | Task Manager की “GDI objects” column बढ़ती ही तो नहीं जा रही। Chapter 20 |
| High DPI पर fixed-coordinate layout टूटना | सिर्फ़ 150% scaling पर text कट जाए | Manifest की DPI setting और fixed-coordinate drawing। Chapter 28 |
MFC defects C++ syntax अकेले देखने से अक्सर नहीं मिलते। Windows messages, resources, handles, modules, runtime settings तक देखना पड़ता है।
36. New development में MFC चुनें या नहीं
पूरी तरह नई development में MFC चुनना हो तो सावधानी से decide करें।
MFC चुनने की वजह अगर हो, तो ऐसे मामले।
Existing MFC code से tight integration ज़रूरी है
Existing MFC components या screens reuse करने हैं
Win32/GDI/COM के बहुत पास वाला control चाहिए
टीम में MFC maintenance skill पर्याप्त है
Target सिर्फ़ Windows desktop है
लंबी migration plan में पहले MFC पर ही बढ़ाना ज़रूरी है
उलटा, इन मामलों में दूसरा विकल्प सोचें।
Modern UI बनानी है
Flexible layout या animation चाहिए
Web integration या cloud integration केंद्र में है
Testability प्राथमिकता है
Junior developers आसानी से जुड़ सकें, ऐसी technology चुननी है
Cross-platform support चाहिए
Accessibility और high DPI शुरू से महत्वपूर्ण हैं
MFC न तो “अब सीखने लायक नहीं” है, न “नया है इसलिए चुनें” — यह existing Windows native assets से निपटने की technology है।
37. MFC से migrate करते समय कैसे सोचें
MFC app दूसरी technology पर ले जाना हो तो एकदम पूरा rewrite लक्ष्य बनाना fail होने का आसान रास्ता है।
पहले app को ऐसे तोड़कर सोचें।
UI
Business logic
File formats
Communication
Database processing
Device control
Printing
COM/OLE integration
Settings management
Logging
इनमें MFC पर सबसे ज़्यादा निर्भर UI है।
Business logic या file processing काटे जा सकते हैं।
Migration का realistic क्रम यह है।
1. Build environment reproduce करें
2. Existing behavior को test data से freeze करें
3. UI event handlers से logic काटें
4. Non-MFC C++ library की तरफ़ ले जाएँ
5. Automated tests जोड़ें
6. External spec document करें
7. ज़रूरी screens से चरणबद्ध replacement करें
“MFC छोड़ना” स्वयं goal बनाने से बेहतर है “MFC में बंद पड़ा important logic बाहर निकालना” — उसी से success ज़्यादा मिलती है।
38. MFC code पढ़ने की entry points
Existing MFC project पहली बार पढ़ें तो इन files से शुरू करें।
*.vcxproj
Toolset, MFC setting, character set, runtime setting देखें
resource.h
Resource IDs देखें
*.rc
Dialogs, menus, strings, icons देखें
*App.cpp / *App.h
CWinApp-derived class और InitInstance देखें
MainFrm.cpp / MainFrm.h
Main frame और menus/toolbars देखें
*Doc.cpp / *Doc.h
Document/View हो तो data structure और save processing देखें
*View.cpp / *View.h
Drawing और user interaction देखें
*Dlg.cpp / *Dlg.h
Dialogs, DDX, button handling देखें
फिर ये search keywords आम हैं।
BEGIN_MESSAGE_MAP
ON_COMMAND
ON_UPDATE_COMMAND_UI
ON_BN_CLICKED
DoDataExchange
UpdateData
OnInitDialog
OnDraw
Serialize
AfxMessageBox
AfxBeginThread
AFX_MANAGE_STATE
इन्हें search करें तो application का व्यवहार दिखने लगता है।
39. MFC maintain करते समय design approach
Existing MFC assets लंबे समय maintain करने हों तो यह approach काम आता है।
UI event handlers पतले रखें
CString और CWnd non-UI layer में ज़्यादा मत लीक करें
Business logic साधारण C++ classes में ले जाएँ
File format compatibility tests बनाएँ
x86/x64 का फ़र्क साफ़ करें
Resource ID changes review करें
MFC DLL का module state चेक करें
Logging व्यवस्थित करें
CI पर build freeze करें
High DPI और Windows 11 पर screen checks नियमित करें
खासकर CDialog या CView में processing ज़्यादा मत ठूसें।
MFC की screen classes input, display, event routing पर केंद्रित रखें।
Screen से values लें
Service को दें
Result screen पर दिखाएँ
इतना रख पाएँ तो MFC होने पर भी maintenance काफ़ी आसान हो जाता है।
40. Practical checklist
MFC app संभालते समय यह checklist।
Visual Studio version साफ़ है या नहीं
MFC/ATL components install हैं या नहीं
x86/x64 target साफ़ है या नहीं
Unicode/MBCS setting पता है या नहीं
MFC static link है या shared DLL
ज़रूरी Visual C++ Redistributable क्या है
resource.h और .rc review के दायरे में हैं या नहीं
Message map से event path follow हो रहा है या नहीं
UpdateData की दिशा सही है या नहीं
Document/View structure इस्तेमाल हो रही है या नहीं
Modeless dialog की lifetime safe है या नहीं
Worker thread से UI सीधे तो नहीं छू रहे
MFC DLL में AFX_MANAGE_STATE ज़रूरी जगहें तो नहीं छूटी
High DPI पर screen चेक हो रहा है या नहीं
COM/ActiveX dependencies 32-bit/64-bit संभालती हैं या नहीं
Log बचता है या नहीं
Non-UI logic test हो सकता है या नहीं
MFC आदत पड़ने तक अजीब लगता है, लेकिन देखने की जगह पता चल जाए तो काफ़ी regular पढ़ा जाता है।
41. सारांश
MFC native Windows desktop applications C++ में बनाने का एक पुराना, established framework है। नई development की मुख्यधारा नहीं रहा, लेकिन existing assets का maintenance, build environment update, feature addition, incremental migration में आज भी महत्वपूर्ण technology है।
MFC समझने में ये बिंदु खासकर ज़रूरी हैं।
MFC Win32 API को C++ में इस्तेमाल करना आसान बनाता है
CWinApp पूरे app को manage करता है
CWnd और HWND की lifetime एक नहीं है
Message map events को functions से bind करता है
Document/View data और display अलग करता है
DDX/DDV dialog values sync और validate करते हैं
Resource files और resource.h बहुत महत्वपूर्ण हैं
CString और TCHAR character-set settings के साथ सेट में समझें
MFC DLL में module state पर ध्यान दें
पुराने MFC apps को high DPI, x64, CI, testing की नज़र से फिर देखना value रखता है
MFC संभालते समय “पुराना है इसलिए खराब” मत तय करें — पहले structure समझें। Existing MFC apps में सालों का business knowledge, customer-specific specs, device integration, file compatibility बैठा हो सकता है। उस value को रखते हुए धीरे-धीरे maintainable बनाने का realistic रास्ता यही है: MFC की conventions समझें, non-UI logic काटें, build और tests व्यवस्थित करें।
एक वाक्य में कहें तो यह है।
Windows native apps के mechanisms को C++ classes और framework से संभालने की नींव।
यह नज़रिया हो तो MFC सिर्फ़ पुरानी technology नहीं, existing Windows assets को सुरक्षित पढ़ने का map बन जाता है।
संदर्भ
- इस लेख के code fragments का chapter-wise reference collection - komurasoft-blog-samples (GitHub)
- MFC Desktop Applications - Microsoft Learn
- MFC and ATL - Microsoft Learn
- Creating an MFC Application - Microsoft Learn
- CWinApp Class - Microsoft Learn
- CWinApp: The Application Class - Microsoft Learn
- Mapping Messages - Microsoft Learn
- Document-View Architecture - Microsoft Learn
- Dialog Data Exchange and Validation - Microsoft Learn
- MFC Library Versions - Microsoft Learn
- Redistribute the MFC Library - Microsoft Learn
- Visual Studio Build Tools workload and component IDs - Microsoft Learn
- High DPI Desktop Application Development on Windows - Microsoft Learn
संबंधित लेख
निकटवर्ती विषयों में गहराई से जाने के लिए समान टैग वाले नवीनतम लेख।
Win32 Thread Pool API — CreateThreadpoolWork से thread बनाए बिना concurrency
क्या आपके native code में CreateThread calls बिखरी पड़ी हैं? यह लेख Vista में redesign की गई Win32 thread pool API — work, timer, wait और...
Named Pipes व्यवहार में — design से security तक, Windows की standard IPC
Named pipes — Windows की standard inter-process communication — की practical guide। यह लेख primary sources से byte और message mode का चुन...
DllMain और Loader Lock — DLL initialization में "कुछ मत करो" कहा जाने का असली कारण
DllMain से LoadLibrary क्यों न call करें और दूसरे thread से synchronize न करें। Primary sources से यह लेख बताता है कि loader lock हर DLL ...
Spurious wakeup — condition variable "बिना notification के" क्यों जागती है और Windows पर सही wait कैसे करें
Condition variable की wait notification आए बिना भी लौट सकती है (spurious wakeup)। यह लेख Windows implementation से समझाता है कि spec इसे ...
Practical multithreading best practices: C++ संस्करण — RAII और jthread से structure द्वारा accidents मिटाना
C++ में multithreading वह संसार है जहाँ data race undefined behavior बन जाता है। यह लेख std::thread के destructor का pitfall, jthread और ...
संबंधित विषय
ये पृष्ठ विषय को सेवाओं और निर्णयों के व्यापक संदर्भ में रखते हैं।
Windows के तकनीकी विषय
Windows विकास, बग जाँच और मौजूदा संपत्तियों के उपयोग का प्रवेश-द्वार।
इस विषय से जुड़ी सेवाएँ
यह लेख निम्नलिखित सेवाओं से सीधे जुड़ा है।
Windows ऐप विकास
व्यावसायिक ऐप, डिवाइस एकीकरण और संचार उपकरण, आवश्यकताओं से विकास तक।
अक्सर पूछे जाने वाले प्रश्न
इस लेख के विषय पर परामर्श में अक्सर पूछे जाने वाले प्रश्न।
- MFC क्या है?
- MFC Microsoft Foundation Classes का short form है — Win32 API को C++ classes के रूप में इस्तेमाल करना आसान बनाने वाला Windows application framework। Window को CWnd, dialog को CDialog, पूरे app को CWinApp जैसे classes represent करते हैं। यह Windows जाने बिना लिखने वाली magic library नहीं है; Windows के mechanisms को C++ types और framework से organize किया गया है, इसलिए Windows messages और handles जैसे Win32 knowledge भी चाहिए।
- क्या MFC आज भी use हो सकता है? Support जारी है?
- MFC आज भी Visual Studio में available है और support जारी है। Microsoft documentation में यह note दिखता है कि नई features या documentation updates नहीं आएँगे। Positioning यह है कि existing MFC apps का maintenance, feature addition, build environment update, और दूसरे UI पर incremental migration realistically आम है; brand-new general GUI apps के लिए adoption सावधानी से decide करें। Visual Studio Installer का individual component (C++ MFC for latest build tools) install करना ज़रूरी है।
- MFC का message map क्या है?
- Windows messages और commands को handler functions से bind करने वाला MFC mechanism। BEGIN_MESSAGE_MAP से END_MESSAGE_MAP के बीच ON_BN_CLICKED या ON_COMMAND जैसे macros से लिखा जाता है कि यह button click हो तो यह function call हो। Function search करने पर direct call न दिखे, फिर भी event पर run हो रहा हो, तो message map देखें। MFC code review में handler functions के साथ-साथ message map भी साथ में check करना ज़रूरी है।
- MFC से दूसरी technology पर कैसे migrate करें?
- एकदम पूरा rewrite लक्ष्य बनाना fail होने का आसान रास्ता है। Realistic sequence यह है: build environment reproduce करें, existing behavior को test data से freeze करें, UI event handlers से logic निकालकर non-MFC C++ library की तरफ़ ले जाएँ, automated tests जोड़ें, external spec document करें, फिर ज़रूरी screens से चरणबद्ध replacement करें। MFC छोड़ना स्वयं goal बनाने से बेहतर है MFC में बंद पड़ा important logic बाहर निकालना — उसी से success ज़्यादा मिलती है।