1. আগে যা ধরে রাখা দরকার
পুরোনো Windows ডেস্কটপ অ্যাপ রক্ষণাবেক্ষণ করতে গেলে এই নামগুলোর মুখোমুখি হওয়া যায়।
CWinApp
CWnd
CDialog
CDialogEx
CFrameWnd
CDocument
CView
CString
CFile
CArchive
BEGIN_MESSAGE_MAP
ON_COMMAND
ON_BN_CLICKED
DoDataExchange
UpdateData
এগুলো MFC নামের C++-এর Windows অ্যাপ্লিকেশন framework-এ বারবার আসে। MFC মানে Microsoft Foundation Classes — Win32 API-কে C++ ক্লাস হিসেবে সহজে ব্যবহার করার লাইব্রেরি।
আজকের Windows অ্যাপ ডেভেলপমেন্টে WinUI, WPF, Windows Forms, Electron, Qt, Web প্রযুক্তি — বিকল্প অনেক, তাই নতুন কাজের প্রথম পছন্দ হিসেবে MFC কমই আসে। তা বলে হারিয়ে যাওয়া প্রযুক্তিও নয়। ব্যবসায়িক অ্যাপ, পরিমাপ যন্ত্র, কন্ট্রোল সফটওয়্যার, CAD/CAM, অফিসের টুল, পুরোনো প্যাকেজ সফটওয়্যারে আজও MFC কোডবেস রক্ষণাবেক্ষণ করতে হয়।
MFC বুঝতে এই দৃষ্টিগুলো আগে ধরে রাখা ভালো।
MFC পুরোনো Windows ডেস্কটপ অ্যাপ পড়ার গুরুত্বপূর্ণ মানচিত্র
MFC Win32 API লুকোয় না; C++-এর মতো মুড়ে দেয়
MFC-এর রীতি না জানলে কোডের চেহারার চেয়ে আচরণ ভুল পড়া যায়
নতুন করে বেছে নেওয়ার চেয়ে বিদ্যমান অ্যাসেট রক্ষণাবেক্ষণ, আয়ু বাড়ানো ও ধাপে ধাপে মাইগ্রেশনে মূল্য বেরোয়
এই নিবন্ধে MFC-এর সারসংক্ষেপ, অ্যাপ্লিকেশনের কাঠামো, message map, Document/View, ডায়ালগ, DDX/DDV, রিসোর্স, বিল্ড এবং রক্ষণাবেক্ষণে খেয়াল রাখার বিষয় সাজানো হয়েছে।
যাদের কথা ভেবে লেখা: C++ লিখতে পারেন, কিন্তু Win32 API বা MFC করেননি। পূর্বজ্ঞান এই মাত্রাই যথেষ্ট।
| ক্ষেত্র | প্রত্যাশিত স্তর |
|---|---|
| C++ | ক্লাস, ইনহেরিটেন্স, ভার্চুয়াল ফাংশন, পয়েন্টার ও রেফারেন্স পড়া যায় |
| Win32 API | অভিজ্ঞতা না থাকলেও চলে। উইন্ডো ও message শব্দ শুনেছেন এমন হলেই যথেষ্ট |
| Visual Studio | সলিউশন খুলে বিল্ড করেছেন |
| COM / OLE | অভিজ্ঞতা না থাকলেও চলে। 27 অধ্যায়ে দরকার হলে খুঁজলেই হয় |
2 অধ্যায়ের শেষে «MFC পড়তে যে জ্ঞান লাগে» তালিকা আছে, সব আগে জোগাড় করতে হয় না। পড়তে পড়তে দরকার হলে ফিরে এলেই চলে।
পড়াও 1 থেকে 41 অধ্যায় একনাগাড়ে শেষ করতে হয় না। উদ্দেশ্য অনুযায়ী ছোট পথ এই।
| উদ্দেশ্য | যে অধ্যায় পড়বেন |
|---|---|
| MFC কী, এখন অবস্থান কী — শুধু তা জানতে চান | 2–4 অধ্যায়, 36 অধ্যায় |
| বিদ্যমান MFC কোড পড়তে চান | 6 অধ্যায় → 9 অধ্যায় → 10 অধ্যায় → 14 অধ্যায় → 12 ও 13 অধ্যায় → 38 অধ্যায় |
| বিল্ড আটকে গেছে, সারাতে চান | 5 অধ্যায়, 25 অধ্যায়, 32 অধ্যায়, 33 অধ্যায় |
| বাগ তদন্ত করতে চান | 34 অধ্যায় → 35 অধ্যায় → 8 ও 22 অধ্যায় |
| রক্ষণাবেক্ষণ বা মাইগ্রেশনের নীতি ঠিক করতে চান | 30 অধ্যায়, 31 অধ্যায়, 37 অধ্যায়, 39 অধ্যায় |
আগে ধরে রাখুন দুটো: message map (9 অধ্যায়) ও Document/View (14 অধ্যায়)। এই দুটো বুঝলে «caller খুঁজে পাওয়া যায় না, তবু ফাংশন চলে কেন» এবং «ডেটা ও স্ক্রিন কীভাবে যুক্ত» পড়া যায়। এ দুটো বাদ দিলে অন্য অধ্যায়ের ব্যাখ্যা ঝুলে থাকে।
এই নিবন্ধের কোড খণ্ড অধ্যায় অনুযায়ী ফাইলে সাজানো রেফারেন্স সংগ্রহ হিসেবে GitHub-এ আছে।
windows-mfc-overview - komurasoft-blog-samples (GitHub)
এই নিবন্ধের জ্ঞান মানচিত্র
MFC Win32 API-কে C++ ক্লাস হিসেবে সহজে ব্যবহার করার framework; CWinApp পুরো অ্যাপের initialize সামলায়, message map Windows message-কে handler ফাংশনের সঙ্গে বাঁধে, Document/View আর্কিটেকচার ডেটা ও UI-এর প্রদর্শন আলাদা করে, আর DDX/DDV ডায়ালগের কন্ট্রোল ও মেম্বার ভেরিয়েবল মিলিয়ে যাচাই করে। MFC ব্যবহার করতে Visual Studio Installer-এ MFC কম্পোনেন্ট আলাদা করে ইনস্টল করতে হয়, shared DLL না স্ট্যাটিক লিঙ্ক সেটাও কনফিগার করা যায়। নিবন্ধ দেখায়, পুরোপুরি নতুন সাধারণ GUI অ্যাপে MFC বেছে নেওয়া সতর্কতার সঙ্গে ভাবা উচিত; অন্যদিকে বিদ্যমান MFC অ্যাপের রক্ষণাবেক্ষণ, ফিচার যোগ ও ধাপে ধাপে মাইগ্রেশনে বাস্তবে প্রায়ই মূল্য থাকে।
flowchart LR
accTitle: MFC দিয়ে Windows ডেস্কটপ অ্যাপ রক্ষণাবেক্ষণের জ্ঞান মানচিত্র
accDescr: MFC যেভাবে Win32 API-কে C++-এ মুড়ে message map ও Document/View-এর মতো ব্যবস্থা বাস্তবায়ন করে, বিদ্যমান অ্যাসেটের রক্ষণাবেক্ষণে মানায় কিন্তু নতুন GUI ডেভেলপমেন্টে সতর্ক থাকা উচিত—এই অবস্থান, এবং বিল্ড এনভায়রনমেন্ট ও COM ইন্টিগ্রেশনে খেয়াল রাখার বিষয়গুলোর সম্পর্ক দেখানো চিত্র
mfc["MFC (Microsoft Foundation Classes)"]
win32_api["Win32 API"]
cwinapp["CWinApp"]
message_map["মেসেজ ম্যাপ"]
document_view_architecture["Document/View আর্কিটেকচার"]
mfc_ddx_ddv["DDX/DDV"]
resource_script["রিসোর্স ফাইল (.rc/resource.h)"]
cstring_class["CString"]
vs_mfc_component["Visual Studio Installer-এর MFC কম্পোনেন্ট"]
mfc_shared_dll_linking["MFC লিংক পদ্ধতি (Use of MFC)"]
mfc_module_state["MFC মডিউল অবস্থা"]
activex["ActiveX"]
bitness_match_requirement["bitness মিলের শর্ত"]
high_dpi_support["উচ্চ DPI সাপোর্ট"]
new_gui_application_development["সম্পূর্ণ নতুন সাধারণ GUI অ্যাপ ডেভেলপমেন্ট"]
legacy_app_maintenance_and_migration["বিদ্যমান MFC অ্যাপের রক্ষণাবেক্ষণ ও ধাপে ধাপে মাইগ্রেশন"]
mfc -->|"ব্যবহার করে"| win32_api
mfc -->|"ব্যবহার করে"| cwinapp
cwinapp -->|"স্বয়ংক্রিয় করে"| win32_api
mfc -->|"বাস্তবায়ন করে"| message_map
message_map -->|"পূর্বশর্ত"| win32_api
mfc -->|"বাস্তবায়ন করে"| document_view_architecture
document_view_architecture -->|"পূর্বশর্ত"| cwinapp
message_map -.->|"ব্যবহার করে"| document_view_architecture
mfc -->|"বাস্তবায়ন করে"| mfc_ddx_ddv
mfc_ddx_ddv -->|"পূর্বশর্ত"| resource_script
mfc -->|"ব্যবহার করে"| cstring_class
mfc -->|"পূর্বশর্ত"| vs_mfc_component
mfc -->|"দিয়ে কনফিগার"| mfc_shared_dll_linking
mfc -.->|"পূর্বশর্ত"| mfc_module_state
mfc -.->|"ব্যবহার করে"| activex
mfc -.->|"পূর্বশর্ত"| bitness_match_requirement
mfc -.->|"পূর্বশর্ত"| high_dpi_support
mfc -->|"ব্যবহার নিরুৎসাহিত"| new_gui_application_development
mfc -->|"প্রস্তাবিত সমাধান"| legacy_app_maintenance_and_migration
mfc_module_state -.->|"পূর্বশর্ত"| resource_script
চিত্রে, টানা রেখা সবসময় সত্য এমন সম্পর্ককে এবং ভাঙা রেখা শর্তসাপেক্ষ সম্পর্ককে নির্দেশ করে (শর্তগুলো বিস্তারিত পাতায় প্রতিটি সম্পর্কের ব্যাখ্যায় আছে)। সম্পর্কের সম্পূর্ণ তালিকা (মোট 20, প্রমাণ ও নিশ্চয়তার মাত্রাসহ) এবং প্রধান ধারণাগুলোর সংজ্ঞা জ্ঞান মানচিত্রের বিস্তারিত পাতায় সংগ্রহ করা আছে (জাপানি ভাষায়)। তথ্য: JSON-LD / Turtle
2. MFC কী
MFC Windows-এর native ডেস্কটপ অ্যাপ্লিকেশন C++-এ বানানোর ক্লাস লাইব্রেরি।
Win32 API সরাসরি ব্যবহার করলে সাধারণত এমন কোড লেখা হয়।
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
// আঁকার কাজ
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Win32 API খুবই শক্তিশালী, কিন্তু C ফাংশন, handle, message ও callback ঘিরে গড়া বলে বড় অ্যাপে পথ খুঁজে পাওয়া কঠিন হয়ে যায়। MFC এগুলোকে C++ ক্লাস করে: উইন্ডো CWnd, ডায়ালগ CDialog, পুরো অ্যাপ্লিকেশন 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-কে অন্য কিছু দিয়ে পুরোপুরি সরিয়ে দেয় না। Win32-এর চিন্তাধারার ওপর দাঁড়ানো পাতলা কিন্তু বিস্তৃত C++ framework। তাই MFC পড়তে শুধু MFC ক্লাস নয়, এই জ্ঞানও লাগে।
Windows message
HWND-এর মতো handle
GDI/GDI+
রিসোর্স ফাইল
COM/OLE
DLL ও রানটাইম
ক্যারেক্টার এনকোডিং
থ্রেড ও message loop
«Windows না জেনেই লেখা যায় এমন জাদু লাইব্রেরি» নয়; «Windows-এর mechanism C++ টাইপ ও framework দিয়ে সাজানো» — এটাই MFC-এর আসল রূপ।
3. MFC এখনও ব্যবহার করা যায় কি
MFC এখনও Visual Studio-তে পাওয়া যায়। তবে অবস্থান ভুল বোঝা চলবে না। সাপোর্ট চলছে, কিন্তু নতুন ফিচার সক্রিয়ভাবে যোগ হওয়া আধুনিক UI framework নয়। Microsoft-এর MFC ডকুমেন্টেও সাপোর্ট চলবে, কিন্তু নতুন ফিচার বা ডকুমেন্ট আপডেট হবে না — এমন নোট আছে।
তাই MFC-এর অবস্থান মোটামুটি এমন।
বিদ্যমান MFC অ্যাপের রক্ষণাবেক্ষণ -> বাস্তবে সাধারণ
বিদ্যমান MFC অ্যাপে ফিচার যোগ -> হতে পারে
MFC অ্যাপের বিল্ড এনভায়রনমেন্ট আপডেট -> গুরুত্বপূর্ণ
MFC থেকে অন্য UI-তে ধাপে ধাপে মাইগ্রেশন -> হতে পারে
পুরোপুরি নতুন সাধারণ GUI অ্যাপে বেছে নেওয়া -> সতর্কতার সঙ্গে সিদ্ধান্ত
বিশেষ করে দীর্ঘদিন চলা ব্যবসায়িক অ্যাপে UI, প্রিন্ট, ফাইল I/O, ডিভাইস কন্ট্রোল, নিজস্ব প্রোটোকল, COM ইন্টিগ্রেশন MFC-এর ভিতরে গুচ্ছ হয়ে থাকে।
এমন কোডবেসে «MFC ফেলে দেব»-এর আগে «MFC পড়া যায় এমন অবস্থা» দরকার।
4. MFC যেখানে শক্তিশালী ছিল
MFC যেখানে বেশি ব্যবহৃত হয়েছে, সেটা Windows-এর native ডেস্কটপ অ্যাপ্লিকেশন।
নির্দিষ্ট করে এমন অ্যাপ।
ডায়ালগ-কেন্দ্রিক ব্যবসায়িক টুল
ফাইল খুলে এডিট করা SDI অ্যাপ
একাধিক ডকুমেন্ট সামলানো MDI অ্যাপ
পরিমাপ যন্ত্র বা ম্যানুফ্যাকচারিং ডিভাইসের কন্ট্রোল স্ক্রিন
CAD/CAM জাতীয় native অ্যাপ
প্রিন্ট ও প্রিভিউ বেশি ব্যবহার করা অ্যাপ
ActiveX বা OLE ইন্টিগ্রেশন থাকা অ্যাপ
পুরোনো Windows API বা COM অ্যাসেটের সঙ্গে ঘনিষ্ঠ অ্যাপ
MFC-এর শক্তি Windows native উপাদানের কাছাকাছি চলা। উইন্ডো, মেনু, টুলবার, স্ট্যাটাসবার, ডায়ালগ, common control, প্রিন্ট, ফাইল ডায়ালগ, Registry, GDI আঁকা — এগুলো C++ ক্লাস হিসেবে ব্যবহার করা যায়।
দুর্বলতা অন্যদিকে: আধুনিক UI গড়া, data binding, টেস্ট সহজ করা, অ্যাসিঙ্ক্রোনাস প্রক্রিয়া, আধুনিক লেআউট, উচ্চ DPI, বহুভাষা, অ্যাক্সেসিবিলিটি — সাম্প্রতিক framework-এর মতো স্বাভাবিকভাবে লেখা যায় না।
বৈশিষ্ট্য সাজালে এমন।
Windows native-এর কাছাকাছি
C++ থেকে সরাসরি নিয়ন্ত্রণ যায়
বিদ্যমান অ্যাসেট অনেক
Win32 জ্ঞান লাগে
পুরোনো রীতি অনেক
টেস্টযোগ্য কাঠামো নিজে গুছিয়ে নিতে হয়
5. Visual Studio-তে MFC ব্যবহারের প্রস্তুতি
Visual Studio-তে C++ ইনস্টল থাকলেও MFC যে থাকবেই তা নয়। MFC Visual Studio Installer-এর individual component। সাধারণত এই উপাদানগুলো দেখুন।
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 লাগবে কি না
বিল্ডে MFC-সম্পর্কিত ফাইল না পাওয়া গেলে শুধু প্রজেক্ট সেটিং নয়, Visual Studio-তে MFC component আছে কি না দেখুন।
Installer-এ বেছে নেওয়ার ধাপ এই।
1. Start মেনু থেকে Visual Studio Installer চালু করুন
2. টার্গেট ইনস্টল করা Visual Studio-তে Modify চাপুন
3. Workloads ট্যাবে Desktop development with C++ টিক দিন
4. একই স্ক্রিনের ডানদিকে Installation details-এ
C++ MFC for latest v143 build tools টিক দিন
5. না পেলে Individual components ট্যাবে গিয়ে
সার্চ বক্সে MFC লিখে খুঁজুন
6. Modify চেপে ইনস্টল করুন
শুধু Desktop development with C++ workload নিলেই MFC নাও আসতে পারে, তাই ধাপ 4 বা ধাপ 5-এ component-এ টিক আছে কি না নিশ্চিত করুন।
স্ক্রিপ্ট বা CI থেকে দিলে component ID নির্দিষ্ট করুন।
| প্রদর্শিত নাম | 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 হেডার যে atlmfc ফোল্ডারে থাকে, সেটা আছে কি না দেখে। MFC-এর হেডার ও লাইব্রেরি MSVC টুলসেটের নিচে বসে।
<Visual Studio ইনস্টল পাথ>\VC\Tools\MSVC\<টুলসেটের ভার্সন>\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 নেই।
এই অবস্থায় বিল্ড করলে afxwin.h ইনক্লুড করতে গিয়ে থেমে যায়। সাধারণত এই কম্পাইল এরর আসে।
fatal error C1083: Cannot open include file: 'afxwin.h': No such file or directory
এটাকে «ইনক্লুড পাথ ভুল» ভেবে প্রজেক্ট প্রপার্টি ঘোরানো সাধারণ ঘুরপথ। afxwin.h বা afxdialogex.h না পাওয়া গেলে আগে Visual Studio Installer সন্দেহ করুন।
CI এনভায়রনমেন্ট বা বিল্ড সার্ভারেও একই। লোকাল Visual Studio-তে বিল্ড হয়, CI-তে ফেল হলে কারণ হতে পারে MFC component-এর অভাব, বা টার্গেট টুলসেটের ভার্সন ফারাক।
6. MFC অ্যাপ্লিকেশনের মৌলিক কাঠামো
MFC অ্যাপ্লিকেশনের কাঠামো মোটামুটি এমন।
CWinApp-derived ক্লাস
পুরো অ্যাপ্লিকেশনের initialize ও শেষ সামলায়
CFrameWnd / CMDIFrameWnd / CDialog-derived ক্লাস
মেইন উইন্ডো বা ডায়ালগ সামলায়
CView-derived ক্লাস
স্ক্রিন দেখানো ও ইউজার ইন্টারঅ্যাকশন সামলায়
CDocument-derived ক্লাস
ডেটা ও ফাইল সেভ সামলায়
রিসোর্স ফাইল
মেনু, ডায়ালগ, আইকন, স্ট্রিং ইত্যাদি রাখে
Message map
Windows message ও command-কে handler ফাংশনের সঙ্গে বাঁধে
উদাহরণ: সাধারণ MFC অ্যাপে এমন CWinApp-derived ক্লাস আসে।
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 পুরো অ্যাপ্লিকেশনকে represent করা ক্লাস।
MFC অ্যাপে সাধারণত CWinApp থেকে derived একটি অবজেক্ট থাকে।
theApp-এর মতো গ্লোবাল অবজেক্ট প্রথমে অস্বস্তিকর লাগতে পারে, কিন্তু MFC-তে এটাই স্ট্যান্ডার্ড কাঠামো।
7. CWinApp কী করে
CWinApp MFC অ্যাপ্লিকেশনের প্রবেশপথ হিসেবে গুরুত্বপূর্ণ। সাধারণ Win32 অ্যাপে WinMain, উইন্ডো ক্লাস রেজিস্ট্রেশন, message loop নিজে লিখতে হয়; MFC-তে তার অনেকটা framework সামলে নেয়। ডেভেলপার মূলত InitInstance ওভাররাইড করে অ্যাপ-নির্দিষ্ট initialize লেখেন।
BOOL CMyApp::InitInstance()
{
CWinApp::InitInstance();
// সেটিং পড়া
// COM initialize
// মেইন উইন্ডো তৈরি
// document template রেজিস্টার
return TRUE;
}
InitInstance-এ সাধারণত এমন কাজ লেখা হয়।
Common control initialize
Registry কী সেট করা
সম্প্রতি ব্যবহৃত ফাইল তালিকা পড়া
Document template রেজিস্টার
মেইন ফ্রেম তৈরি
Command-line argument প্রক্রিয়া
COM/OLE initialize
রক্ষণাবেক্ষণে আগে CWinApp-derived ক্লাস দেখলে পুরো অ্যাপের চালু হওয়ার ক্রম সহজে দেখা যায়।
8. CWnd MFC-এর কেন্দ্রের ক্লাস
MFC-এর UI ক্লাসের অনেকগুলোর বেস হল Windows উইন্ডোকে represent করা CWnd। তবে CWnd অবজেক্ট আর HWND এক জিনিস নয়।
HWND
Windows OS যে উইন্ডো handle সামলায়
CWnd
HWND সহজে ব্যবহারের C++ wrapper অবজেক্ট
MFC-তে CWnd-এর ভিতরে HWND থাকে।
HWND hWnd = m_hWnd;
অথবা এভাবে পাওয়া যায়।
HWND hWnd = GetSafeHwnd();
রক্ষণাবেক্ষণে গুরুত্বপূর্ণ: CWnd* থাকলেও সংশ্লিষ্ট HWND ইতিমধ্যে ধ্বংস হয়ে থাকতে পারে।
তাই উইন্ডো বৈধ কি না এভাবে দেখুন।
if (pWnd != nullptr && ::IsWindow(pWnd->GetSafeHwnd()))
{
pWnd->ShowWindow(SW_SHOW);
}
MFC বাগ তদন্তে CWnd-এর C++ অবজেক্টের lifetime আর আসল Windows উইন্ডো handle-এর lifetime সরে গেছে কি না দেখা জরুরি।
9. Message map কী
MFC-এর চরিত্র সবচেয়ে স্পষ্ট হয় যে ব্যবস্থাগুলোর একটা message map।
Windows অ্যাপ্লিকেশন মাউস ক্লিক, কী ইনপুট, পুনরায় আঁকা, উইন্ডোর সাইজ বদল, মেনু সিলেক্ট — এসব Windows message হিসেবে পায়।
Win32 API-তে সাধারণত WndProc-এর switch দিয়ে message সামলানো হয়।
MFC-তে তা message map দিয়ে handler ফাংশনের সঙ্গে বাঁধা হয়।
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"));
}
এই কোডের অর্থ এমন।
IDC_BUTTON_OK নামের বাটনে ক্লিক হলে
CMyDialog::OnClickedButtonOk ডাকে
Message এসে handler ডাকার আগের প্রবাহ ছবিতে এমন।
flowchart TB
accTitle: MFC-এ message map-এর প্রক্রিয়াকরণ প্রবাহ
accDescr: Windows message MFC-এর message loop ও CWnd::WindowProc দিয়ে যায়, নিজের ক্লাসের message map খোঁজা হয়, না মিললে বেস ক্লাসে যায়, শেষে 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{"নিজের ক্লাসের message map-এ<br/>মিল entry আছে কি?"}
MAP -->|আছে| HANDLER["ON_BN_CLICKED ইত্যাদি যে handler<br/>ফাংশন নির্দেশ করে, সেটা ডাকে"]
MAP -->|নেই| BASE["বেস ক্লাসের message map খোঁজে<br/>CDialogEx থেকে CDialog, CWnd পর্যন্ত ক্রমানুসারে যায়"]
BASE --> FOUND{"কোথাও পাওয়া গেল কি?"}
FOUND -->|পাওয়া গেল| HANDLER
FOUND -->|শেষ পর্যন্ত নেই| DEF["DefWindowProc<br/>Windows-এর ডিফল্ট প্রক্রিয়ায় ছেড়ে দেয়"]
switch দেখা যায় না কারণ «নিজের ক্লাস থেকে বেস ক্লাসে message map অনুসরণ করা» অংশটা framework নিজে সামলায়। DECLARE_MESSAGE_MAP ও BEGIN_MESSAGE_MAP-কে এই খোঁজার জন্য ক্লাসপ্রতি মিলের টেবিল তৈরির ম্যাক্রো ভাবা সহজ।
MFC পড়তে অভ্যস্ত না হলে ফাংশন কোথা থেকে ডাকা হচ্ছে বোঝা কঠিন লাগে। সার্চে সরাসরি কল না পেলে message map দেখুন।
ফাংশন সরাসরি ডাকা হয়নি
তবু ইভেন্টে চলে
-> BEGIN_MESSAGE_MAP / ON_... ম্যাক্রো দেখুন
MFC কোড রিভিউতে শুধু handler ফাংশন নয়, message map-এর সঙ্গে একসেট করে দেখা জরুরি।
10. Command routing
MFC-তে মেনু বা টুলবারের কাজও command হিসেবে সামলানো হয়।
প্রতিনিধি ON_COMMAND।
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_COMMAND(ID_FILE_OPEN, &CMainFrame::OnFileOpen)
END_MESSAGE_MAP()
void CMainFrame::OnFileOpen()
{
// ফাইল খোলার কাজ
}
MFC-তে command উপযুক্ত অবজেক্টে পাঠানোর ব্যবস্থা আছে।
উদাহরণ: একই ID_EDIT_COPY-ও এখন অ্যাকটিভ view, document, frame, অ্যাপ্লিকেশন — কে সামলাবে তা বদলাতে পারে।
অ্যাকটিভ view
Document
Frame window
অ্যাপ্লিকেশন
এই ক্রমে যে অবজেক্ট সামলাতে পারে, সেখানে command যায়।
তাই MFC-তে «মেনু চাপলে কোন ফাংশন ডাকে» সাধারণ স্ট্রিং সার্চ দিয়ে ধরা কঠিন হতে পারে।
রক্ষণাবেক্ষণে এই দিকগুলো দেখুন।
Command ID কী
ON_COMMAND কোন ক্লাসে আছে
ON_UPDATE_COMMAND_UI কোথায় আছে
এখন অ্যাকটিভ view কোনটা
Document/View কাঠামো ব্যবহার হচ্ছে কি
11. ON_UPDATE_COMMAND_UI কী
MFC-তে মেনু আইটেম বা টুলবার বাটনের সক্রিয়/নিষ্ক্রিয়, চেক অবস্থা, দেখানো টেক্সট আপডেট করতে 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());
}
এতে মুছে ফেলা যায় এমন অবস্থায়ই মেনু বা বাটন সক্রিয় থাকে।
MFC অ্যাপ ব্যবহার করতে গিয়ে বাটন কেন grey out, মেনু ক্লিক করা যায় না, চেক অবস্থা বদলায় — এমন আচরণ খুঁজতে ON_UPDATE_COMMAND_UI দেখলে কারণ পাওয়া যায়।
12. Dialog-based MFC অ্যাপ
MFC-এর সবচেয়ে সহজবোধ্য রূপগুলোর একটা dialog-based অ্যাপ্লিকেশন।
সেটিং স্ক্রিন, ছোট ব্যবসায়িক টুল, ডিভাইস অপারেশন স্ক্রিনে ডায়ালগকে কেন্দ্র করে গড়া থাকে।
সাধারণত CDialog বা CDialogEx ইনহেরিট করা হয়।
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 কোডে এই উপাদানগুলো বেশি আসে।
IDD_... ডায়ালগ রিসোর্স ID
IDC_... কন্ট্রোল ID
OnInitDialog initialize
DoDataExchange কন্ট্রোল ও মেম্বার ভেরিয়েবলের মিল
UpdateData স্ক্রিন ও ভেরিয়েবলের সিঙ্ক
ON_BN_CLICKED বাটন ক্লিক হ্যান্ডলিং
ডায়ালগ শুধু চেহারা নয়; রিসোর্স, মেম্বার ভেরিয়েবল, message map, initialize মিলে চলে।
13. DDX ও DDV
MFC ডায়ালগে বেশি আসে DDX ও DDV।
DDX = Dialog Data Exchange
DDV = Dialog Data Validation
DDX ডায়ালগের কন্ট্রোল ও C++ মেম্বার ভেরিয়েবল মিলিয়ে দেয়, DDV সেই ইনপুট যাচাই করে।
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) ডাকলে স্ক্রিনের ইনপুট মেম্বার ভেরিয়েবলে যায়।
void CSettingsDialog::OnBnClickedOk()
{
if (!UpdateData(TRUE))
{
return;
}
// এখানে m_name ও m_interval-এ স্ক্রিনের ইনপুট আছে
SaveSettings(m_name, m_interval);
CDialogEx::OnOK();
}
উল্টোদিকে UpdateData(FALSE) ডাকলে মেম্বার ভেরিয়েবলের মান স্ক্রিনে যায়।
BOOL CSettingsDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
m_name = _T("default");
m_interval = 60;
UpdateData(FALSE);
return TRUE;
}
MFC ডায়ালগে ইনপুট অদ্ভুত লাগলে এই দিকগুলো দেখুন।
DoDataExchange-এ DDX আছে কি
UpdateData(TRUE) ডাকা হয়েছে কি
UpdateData(FALSE) ডাকার সময় ঠিক কি
DDV ইনপুট ফিরিয়ে দিচ্ছে কি
কন্ট্রোল ID রিসোর্সের সঙ্গে মিলছে কি
14. Document/View আর্কিটেকচার
MFC-এর বড় বৈশিষ্ট্যগুলোর একটা Document/View আর্কিটেকচার।
অ্যাপ্লিকেশন যে ডেটা সামলায়, আর তার প্রদর্শন — দুটো আলাদা করার কাঠামো।
CDocument
ডেটা রাখে
ফাইল পড়া-লেখা সামলায়
একাধিক view-কে আপডেট জানায়
CView
ডেটা দেখায়
ইউজার ইন্টারঅ্যাকশন সামলায়
আঁকা ও সিলেকশন অবস্থা সামলায়
Frame, view ও document-এর সম্পর্ক ছবিতে এমন।
flowchart TB
accTitle: Frame, view ও document-এর সম্পর্ক
accDescr: CWinApp-derived অ্যাপ document template দিয়ে frame window, document ও view বেঁধে রাখে; view GetDocument দিয়ে document পায়, document UpdateAllViews দিয়ে view-গুলোকে জানায়।
APP["CWinApp-derived<br/>পুরো অ্যাপের চালু ও বন্ধ"] --> TPL["Document template<br/>CSingleDocTemplate / CMultiDocTemplate"]
TPL --> FRAME["Frame window<br/>CFrameWnd / CMDIChildWnd"]
TPL --> DOC["CDocument-derived<br/>ডেটা ও ফাইল I/O"]
TPL --> VIEW["CView-derived<br/>আঁকা ও ইউজার ইন্টারঅ্যাকশন"]
FRAME --> VIEW
VIEW -->|GetDocument দিয়ে পাওয়া| DOC
DOC -->|UpdateAllViews দিয়ে জানানো| VIEW
পয়েন্ট: frame, document ও view — তিনটেকে বাঁধে document template। InitInstance-এ এই template রেজিস্টার হয়, তাই «কোন view কোন document দেখে» জানতে আগে InitInstance পড়ুন।
View থেকে document দেখতে GetDocument, document-এর বদল সব view-কে জানাতে UpdateAllViews — এই দিকের ফারাক ধরে রাখলে স্ক্রিন আপডেট না হওয়ার বাগ ধরা সহজ।
উদাহরণ: টেক্সট এডিটর, আকৃতি এডিটর, কনফিগ ফাইল এডিট টুল, CAD জাতীয় অ্যাপে ডেটা ও প্রদর্শন আলাদা করার মানে আছে।
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 নিয়ে আঁকা হয়।
void CMyView::OnDraw(CDC* pDC)
{
CMyDocument* pDoc = GetDocument();
if (pDoc == nullptr)
{
return;
}
for (const auto& item : pDoc->m_items)
{
// pDC দিয়ে আঁকা
}
}
Document/View-এর সুবিধা: একই ডেটা একাধিক view-তে দেখানো সহজ।
উদাহরণ: একই ডেটা এভাবে দেখানো যায়।
টেবিল view
গ্রাফ view
বিস্তারিত view
প্রিভিউ
প্রিন্ট view
তবে সাধারণ সেটিং স্ক্রিন বা ছোট টুলে Document/View দিলে কাঠামো ভারী লাগতে পারে।
রক্ষণাবেক্ষণে আগে বুঝুন অ্যাপ Document/View ব্যবহার করে, না ডায়ালগ-কেন্দ্রিক — তাহলে কোড ধরা সহজ।
15. SDI ও MDI
MFC-তে Document/View-এর সঙ্গে SDI বা MDI কাঠামো বেশি আসে।
SDI = Single Document Interface
MDI = Multiple Document Interface
SDI মূলত এক frame-এ এক document সামলায়।
মেইন উইন্ডো
একটি document
একটি বা একাধিক view
MDI এক প্যারেন্ট উইন্ডোর ভিতরে একাধিক চাইল্ড উইন্ডো রাখে, প্রত্যেকে document সামলায়।
MDI প্যারেন্ট ফ্রেম
MDI চাইল্ড ফ্রেম 1 -> document 1
MDI চাইল্ড ফ্রেম 2 -> document 2
MDI চাইল্ড ফ্রেম 3 -> document 3
পুরোনো Windows অ্যাপে MDI বেশি ব্যবহৃত হত।
রক্ষণাবেক্ষণে ক্লাসের নাম দেখলে কাঠামোর আন্দাজ পাওয়া যায়।
CFrameWnd SDI জাতীয় ফ্রেম
CMDIFrameWnd MDI প্যারেন্ট ফ্রেম
CMDIChildWnd MDI চাইল্ড ফ্রেম
CSingleDocTemplate SDI-এর document template
CMultiDocTemplate MDI-এর document template
MFC wizard-এ তৈরি অ্যাপে InitInstance-এ CSingleDocTemplate বা CMultiDocTemplate রেজিস্টার থাকা সাধারণ।
16. রিসোর্স ফাইল বোঝা
MFC অ্যাপে .rc ফাইল খুবই গুরুত্বপূর্ণ।
.rc Windows-এর রিসোর্স ফাইল।
এখানে এমন জিনিস থাকে।
ডায়ালগ টেমপ্লেট
মেনু
অ্যাকসিলারেটর কী
আইকন
বিটম্যাপ
স্ট্রিং টেবিল
ভার্সন তথ্য
টুলবার
আর resource.h-এ রিসোর্স ID থাকে।
#define IDD_SETTINGS_DIALOG 101
#define IDC_EDIT_NAME 1001
#define IDC_EDIT_INTERVAL 1002
#define ID_FILE_OPEN 32771
MFC কোডে এই ID দিয়ে রিসোর্স ও C++ কোড বাঁধা হয়।
DDX_Text(pDX, IDC_EDIT_NAME, m_name);
ON_COMMAND(ID_FILE_OPEN, &CMainFrame::OnFileOpen)
রক্ষণাবেক্ষণে সাধারণ সমস্যা: রিসোর্স ID-এর অমিল।
resource.h-এর ID বদলেছে
অন্য ব্রাঞ্চ মার্জে ID সংঘর্ষ
ডায়ালগের কন্ট্রোল ID ও DDX-এর ID মিলছে না
মুছে ফেলা মেনু ID থেকে গেছে
স্ট্রিং টেবিলের ID ডুপ্লিকেট
MFC অ্যাপের আচরণ খুঁজতে শুধু C++ কোড নয়, .rc ও resource.h একসাথে দেখতে হয়।
17. Class Wizard ও হাতে লেখা কোড
MFC-এর ইতিহাস Visual Studio-এর Class Wizard-এর সঙ্গে ঘনিষ্ঠ।
Class Wizard দিয়ে message handler, DDX ভেরিয়েবল, ভার্চুয়াল ফাংশন ওভাররাইড অটো-জেনারেট হয়।
তাই MFC কোডে টুল-জেনারেটেড আকার অনেক থাকে।
//{{AFX_DATA(CSettingsDialog)
//}}AFX_DATA
//{{AFX_MSG(CSettingsDialog)
//}}AFX_MSG
নতুন Visual Studio-তে চেহারা বা জেনারেটেড আকার বদলেছে, তবু পুরোনো কোডবেসে এমন কমেন্ট মার্কার থেকে যায়।
রক্ষণাবেক্ষণে গুরুত্বপূর্ণ: জেনারেটেড কোড ও হাতে লেখা কোডের সীমানা এলোমেলো ভাঙবেন না।
Message map মুছবেন না
DDX-এর মিল ভাঙবেন না
রিসোর্স ID বেপরোয়া বদলাবেন না
পুরোনো Class Wizard-এর কমেন্ট অকারণে ঘষবেন না
MFC-তে শুধু C++ হিসেবে কম্পাইল হলেই চলে না। Visual Studio-এর রিসোর্স এডিটর বা Class Wizard যে আকার আশা করে, সেটাও কিছুটা রাখতে হয়।
18. CString ও স্ট্রিং
MFC-তে ঘন ঘন আসা স্ট্রিং ক্লাস CString।
CString name = _T("Komura");
CString message;
message.Format(_T("Hello, %s"), name.GetString());
CString MFC/ATL জাতীয় কোডে ব্যবহৃত পরিবর্তনশীল দৈর্ঘ্যের স্ট্রিং ক্লাস। আধুনিক C++-এ std::string বা std::wstring বেশি, কিন্তু MFC-তে API ও কন্ট্রোলের সঙ্গে মিলের জন্য CString বেশি ব্যবহার হয়।
রক্ষণাবেক্ষণে ক্যারেক্টার এনকোডিং খেয়াল রাখতে হয়।
CString প্রজেক্ট সেটিং অনুসারে CStringA বা CStringW-এর সমতুল্য
CStringA ANSI / MBCS জাতীয়
CStringW Unicode / UTF-16 জাতীয়
LPCTSTR TCHAR-ভিত্তিক স্ট্রিং পয়েন্টার
LPCSTR char জাতীয়
LPCWSTR wchar_t জাতীয়
std::string সাধারণত char জাতীয়
std::wstring wchar_t জাতীয়
আজকের Windows অ্যাপে মূলত Unicode ধরে চলা নিরাপদ, কিন্তু পুরোনো MFC অ্যাপে MBCS-ধরে লেখা কোড থেকে যায়।
CString text = _T("日本語");
std::wstring ws(text.GetString());
স্ট্রিং রূপান্তরের বাগ MFC অ্যাপ রক্ষণাবেক্ষণে সাধারণ।
বিশেষ করে এই কেসগুলো দেখুন।
Shift_JIS ধরে ফাইল পড়া
Unicode বিল্ডে স্যুইচ
বাইরের DLL char* চায়
COM BSTR চায়
std::string-এ সহজে রূপান্তর করে টেক্সট নষ্ট হয়
CString দেখে শুধু «পুরোনো স্ট্রিং ক্লাস» ভাবা নয়; প্রজেক্টের ক্যারেক্টার সেট সেটিং, বাইরের API, ফাইল ফরম্যাট — একসেট করে দেখা জরুরি।
19. CFile ও CArchive
MFC-তে ফাইল অপারেশন ও serialize-এর ক্লাসও আছে। প্রতিনিধি CFile ও CArchive।
CFile file;
if (file.Open(path, CFile::modeRead))
{
CArchive ar(&file, CArchive::load);
// ar থেকে পড়া
}
CArchive MFC-এর serialize ব্যবস্থায় বেশি ব্যবহৃত হয়।
CDocument-derived ক্লাসে Serialize ওভাররাইড করে পড়া ও সেভ একই ফাংশনে লেখা যায়।
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 serialize সুবিধাজনক, কিন্তু দীর্ঘ পরিচালনায় সতর্কতা লাগে।
পুরোনো ফাইল ফরম্যাটের সামঞ্জস্য
ভার্সন নম্বর সামলানো
পড়া ব্যর্থ হলে পুনরুদ্ধার
Exception হ্যান্ডলিং
ক্যারেক্টার এনকোডিং
Endian
স্ট্রাকচার সরাসরি সেভ হচ্ছে কি না
নিজস্ব বাইনারি ফরম্যাট দীর্ঘদিন ব্যবহার করা MFC অ্যাপে Serialize কার্যত ফাইল স্পেসিফিকেশন হয়ে যায়।
এ ক্ষেত্রে কোড বদলানোর আগে বিদ্যমান ফাইল পড়ার টেস্ট ডেটা অবশ্যই রাখুন।
20. GDI আঁকা ও CDC
MFC স্ক্রিন আঁকায় Windows Device Context সামলানোর CDC ক্লাস বেশি ব্যবহৃত হয়। CView::OnDraw-এ আর্গুমেন্ট হিসেবে CDC* আসে।
void CMyView::OnDraw(CDC* pDC)
{
pDC->TextOut(10, 10, _T("Hello MFC"));
pDC->Rectangle(10, 40, 200, 120);
}
পেন বা ব্রাশ ব্যবহার করলে সিলেক্ট ও পুনরুদ্ধার খেয়াল রাখুন।
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 অবজেক্ট ঘিরে এমন ভুল সমস্যা হয়।
SelectObject-এর পর আগেরটা ফেরত দেননি
GDI অবজেক্ট অনেক বানিয়ে ধ্বংস করেননি
OnPaint ও OnDraw-এর ভূমিকা মিশিয়ে ফেলেছেন
ডাবল বাফারিং নেই, তাই flicker
উচ্চ DPI-তে ফিক্সড পিক্সেল ধরে আঁকা ভেঙে যায়
MFC আঁকার বাগে শুধু C++ লজিক নয়; Windows-এর GDI রিসোর্স, পুনরায় আঁকার সময়, DPI, ফন্ট সাইজ দেখতে হয়।
21. Modal dialog ও modeless dialog
MFC-তে ডায়ালগ দেখানোর ধরনও খেয়াল রাখতে হয়।
Modal dialog DoModal দিয়ে দেখানো হয়।
CSettingsDialog dlg(this);
if (dlg.DoModal() == IDOK)
{
// OK-এর সময়ের কাজ
}
এ ক্ষেত্রে ডায়ালগ বন্ধ না হওয়া পর্যন্ত caller অপেক্ষা করে।
অন্যদিকে modeless dialog তৈরির পরও caller-এর প্রক্রিয়া ফিরে আসে।
m_pToolDialog = new CToolDialog(this);
m_pToolDialog->Create(IDD_TOOL_DIALOG, this);
m_pToolDialog->ShowWindow(SW_SHOW);
modeless dialog-এ lifetime সামলানো জরুরি।
new করা ডায়ালগ কখন delete করবেন
প্যারেন্ট উইন্ডো আগে ধ্বংস হচ্ছে কি না
ডায়ালগ পাশে PostNcDestroy ব্যবহার হচ্ছে কি
দুবার তৈরি হচ্ছে কি না
বন্ধ হওয়ার পর পয়েন্টার থেকে গেছে কি না
MFC ক্র্যাশ তদন্তে modeless dialog-এর lifetime সমস্যা কারণ হতে পারে।
22. C++ অবজেক্ট ও Windows handle-এর lifetime
MFC-তে খুবই গুরুত্বপূর্ণ: C++ অবজেক্ট ও Windows handle-এর lifetime আলাদা। উদাহরণ: CWnd C++ অবজেক্ট, কিন্তু আসল উইন্ডো Windows HWND হিসেবে সামলায়; দুটো সবসময় একসঙ্গে তৈরি হয়ে একসঙ্গে মরে না।
CWnd অবজেক্ট আছে, HWND এখনও নেই
HWND ধ্বংস হয়েছে, CWnd অবজেক্ট থেকে গেছে
অস্থায়ী CWnd wrapper তৈরি হয়েছে
Attach/Detach দিয়ে handle বদলানো হয়েছে
উদাহরণ: এমন কোডে সতর্ক থাকুন।
CWnd* pWnd = GetDlgItem(IDC_SOME_CONTROL);
// pWnd সদস্য হিসেবে রেখে পরে ব্যবহার
GetDlgItem-এ পাওয়া পয়েন্টার দীর্ঘদিন ধরে রাখলে উইন্ডো ধ্বংসের পর রেফারেন্স করার ঝুঁকি থাকে।
দরকার হলে প্রতিবার GetDlgItem করুন, অথবা কন্ট্রোলের মেম্বার ভেরিয়েবল DDX দিয়ে সামলান — সেটা নিরাপদ হতে পারে।
DDX_Control(pDX, IDC_LIST_ITEMS, m_listItems);
MFC-তে পয়েন্টার non-null হলেই নিরাপদ নয়।
if (m_pDialog != nullptr && ::IsWindow(m_pDialog->GetSafeHwnd()))
{
m_pDialog->SetWindowText(_T("Running"));
}
এই বোধ MFC রক্ষণাবেক্ষণে খুবই গুরুত্বপূর্ণ।
23. থ্রেড ও UI আপডেট
Windows UI মূলত যে UI থ্রেডে তৈরি, সেখানেই স্পর্শ করতে হয়; MFC অ্যাপেও একই। Worker thread থেকে সরাসরি UI কন্ট্রোল ছুঁলে অস্থির আচরণ বা ক্র্যাশ হয়।
এড়ানো উচিত এমন উদাহরণ।
UINT WorkerThreadProc(LPVOID pParam)
{
CMyDialog* pDlg = static_cast<CMyDialog*>(pParam);
// worker thread থেকে সরাসরি UI ছোঁয়া এড়িয়ে চলুন
pDlg->SetDlgItemText(IDC_STATUS, _T("Done"));
return 0;
}
সাধারণত PostMessage ইত্যাদি দিয়ে UI থ্রেডকে জানানো হয়।
constexpr UINT WM_APP_WORK_DONE = WM_APP + 1;
UINT WorkerThreadProc(LPVOID pParam)
{
HWND hWnd = static_cast<HWND>(pParam);
// ভারী কাজ
::PostMessage(hWnd, WM_APP_WORK_DONE, 0, 0);
return 0;
}
UI পাশে message map দিয়ে নেওয়া হয়।
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-এর থ্রেড ঘিরে এগুলো দেখুন।
Worker thread থেকে সরাসরি UI ছোঁয়া হচ্ছে কি না
উইন্ডো ধ্বংসের পর PostMessage হচ্ছে কি না
থ্রেড শেষের অপেক্ষায় UI থ্রেড আটকে রাখা হচ্ছে কি না
শেয়ারড ডেটার লক ঠিক আছে কি
AfxBeginThread-এর রিটার্ন ও lifetime ভুল বোঝা হচ্ছে কি না
24. MFC DLL ও মডিউল স্টেট
MFC দিয়ে DLL বানালে মডিউল স্টেট আসে।
MFC DLL থেকে রিসোর্স পড়া, ডায়ালগ দেখানো, extension DLL বানানো — এমন জায়গায় কোন মডিউলের রিসোর্স দেখা হবে সেটা সমস্যা হয়।
MFC DLL-এর ফাংশন প্রবেশে এমন ম্যাক্রো দেখা যায়।
AFX_MANAGE_STATE(AfxGetStaticModuleState());
এটা MFC-কে সঠিক মডিউল স্টেট ব্যবহার করতে দেয়।
ম্যাক্রো ভুললে এমন বাগ হয়।
DLL-এর ভিতরের ডায়ালগ রিসোর্স পাওয়া যায় না
স্ট্রিং রিসোর্স অন্য মডিউল থেকে পড়া হয়
আইকন বা মেনু পাওয়া যায় না
ডিবাগে চলে, রিলিজে ভাঙে
MFC DLL রক্ষণাবেক্ষণে EXE, সাধারণ DLL, extension DLL, রিসোর্স DLL-এর সম্পর্ক গোছানো জরুরি।
বিশেষ করে non-MFC অ্যাপ থেকে MFC DLL ডাকা হলে, বা প্লাগইন কাঠামো থাকলে সতর্কতা লাগে।
25. MFC স্ট্যাটিক লিঙ্ক করবেন, না shared DLL ব্যবহার করবেনন
MFC অ্যাপে প্রজেক্ট সেটিংয়ে «Use of MFC» থাকে।
প্রতিনিধি দুটো পছন্দ এই।
Use MFC in a Shared DLL
Use MFC in a Static Library
Shared DLL ব্যবহার করলে রানটাইম এনভায়রনমেন্টে সংগত MFC রানটাইম বা Visual C++ রানটাইম লাগে।
স্ট্যাটিক লিঙ্কে ডিস্ট্রিবিউশন সরল দেখাতে পারে, কিন্তু এক্সিকিউটেবল সাইজ, আপডেট, সিকিউরিটি ফিক্স নেওয়া, লাইসেন্স ও redistribute শর্ত ভাবা লাগে।
কোনোটাই সবসময় সঠিক নয়।
সিদ্ধান্তের উপকরণ এই দিকগুলো।
ডিপ্লয় টার্গেটে Visual C++ Redistributable দেওয়া যায় কি
অ্যাপকে একক exe-এর কাছাকাছি রাখতে চান কি
সিকিউরিটি আপডেট কীভাবে আনবেন
একাধিক অ্যাপ একই রানটাইম শেয়ার করবে কি
Installer তৈরি করা যায় কি
টার্গেট Windows ভার্সন কী
রক্ষণাবেক্ষণে আগে বর্তমান সেটিং দেখা জরুরি।
Configuration Properties
General
Use of MFC
এর সঙ্গে Runtime Library সেটিংও দেখুন।
/MD Multi-threaded DLL
/MDd Multi-threaded Debug DLL
/MT Multi-threaded
/MTd Multi-threaded Debug
MFC ও CRT-এর লিঙ্ক সেটিং মিশলে লাইব্রেরি সীমানায় মেমরি allocate/free সমস্যা হতে পারে।
26. Unicode, MBCS, TCHAR
পুরোনো MFC কোডে TCHAR, LPCTSTR, _T() ম্যাক্রো বেশি আসে।
CString title = _T("設定");
SetWindowText(title);
এটা Unicode বিল্ড ও MBCS বিল্ড দুই দিকেই চলার লেখার ধরন।
Unicode বিল্ড
TCHAR -> wchar_t
LPCTSTR -> const wchar_t*
_T("...") -> L"..."
MBCS বিল্ড
TCHAR -> char
LPCTSTR -> const char*
_T("...") -> "..."
এখন Unicode বিল্ড সাধারণ, কিন্তু পুরোনো অ্যাপে MBCS ধরে প্রক্রিয়া থেকে যায়।
বিশেষ করে বাইরের ফাইল, কমিউনিকেশন প্রোটোকল, পুরোনো DLL, ডেটাবেস কানেকশন, সিরিয়াল কমিউনিকেশনে ক্যারেক্টার এনকোডিংয়ের ধারণা যাচাই করতে হয়।
খেয়াল রাখুন: Unicode করাটা সাধারণ রিপ্লেসমেন্ট কাজ নয়।
char অ্যারের সাইজ বাইট সংখ্যা, না ক্যারেক্টার সংখ্যা
strlen ব্যবহার হচ্ছে কি না
sizeof(buffer)-কে ক্যারেক্টার সংখ্যা ধরা হচ্ছে কি না
বাইরের API UTF-16 নেয়, না Shift_JIS নেয়
ফাইল সেভ ফরম্যাট বদলানো চলে কি না
MFC স্ট্রিং ঠিক করতে শুধু স্ক্রিন নয়; ফাইল সামঞ্জস্য ও বাইরের ইন্টিগ্রেশন পর্যন্ত দেখুন।
27. MFC ও COM/OLE/ActiveX
MFC COM, OLE, ActiveX-এর সঙ্গে ঘনিষ্ঠ অ্যাপেও ব্যবহৃত হয়েছে।
পুরোনো ব্যবসায়িক অ্যাপে এমন উপাদান থেকে যায়।
OLE Automation
ActiveX Control
COM সার্ভার
COM ক্লায়েন্ট
IDispatch
BSTR
VARIANT
COleDispatchDriver
COleVariant
MFC অ্যাপের স্টার্টআপে এমন কোড আসতে পারে।
if (!AfxOleInit())
{
AfxMessageBox(_T("OLE initialization failed"));
return FALSE;
}
COM/OLE ব্যবহার হলে MFC সমস্যা মনে হলেও আসলে COM initialize, থ্রেড মডেল, রেফারেন্স কাউন্ট, রেজিস্ট্রেশন তথ্য, 32bit/64bit ফারাক কারণ হতে পারে।
বিশেষ করে 32bit ActiveX বা COM কম্পোনেন্ট দেখুন।
32bit MFC অ্যাপ থেকে 32bit COM ব্যবহার হয়
64bit MFC অ্যাপ থেকে 64bit COM ব্যবহার হয়
32bit/64bit COM রেজিস্ট্রেশন আলাদা
পুরোনো ActiveX 64bit সাপোর্ট করে না, এমন হতে পারে
MFC অ্যাপ x64 করতে শুধু UI কোড নয়, COM/OLE নির্ভরতাও অবশ্যই দেখুন।
28. উচ্চ DPI সাপোর্ট ও আজকের Windows
পুরোনো MFC অ্যাপ আজকের Windows-এ চালালে উচ্চ DPI এনভায়রনমেন্টে প্রদর্শন ভেঙে যেতে পারে।
উদাহরণ: এমন সমস্যা।
অক্ষর কাটা যায়
বাটন খুব ছোট
ফিক্সড পিক্সেল আঁকা সরে যায়
একাধিক মনিটরে স্কেল আলাদা হলে ভেঙে যায়
পুরোনো বিটম্যাপ ঝাপসা হয়
ডায়ালগ লেআউট জমে যায়
Windows ডেস্কটপ অ্যাপে অ্যাপ্লিকেশনকে DPI মোড স্পষ্ট করতে হয়।
MFC অ্যাপেও ম্যানিফেস্ট, রিসোর্স, আঁকার কোড, ফন্ট, লেআউট দেখতে হয়।
বিশেষ করে ফিক্সড কোঅর্ডিনেট সরাসরি লেখা এমন কোড উচ্চ DPI-তে সমস্যা করে।
pDC->TextOut(10, 10, _T("Status"));
pDC->Rectangle(10, 40, 200, 80);
ফিক্সড পিক্সেল ধরে কোঅর্ডিনেট DPI বদলালে চেহারা ভাঙে।
রক্ষণাবেক্ষণে যাচাইয়ের দৃষ্টি এমন।
অ্যাপ্লিকেশন ম্যানিফেস্টের DPI সেটিং
ডায়ালগ রিসোর্সের ফন্ট
ফিক্সড পিক্সেল আঁকা
ইমেজ রিসোর্সের রেজোলিউশন
একাধিক মনিটরে আচরণ
Windows 10 / Windows 11-এ প্রদর্শন
MFC-এর উচ্চ DPI সাপোর্ট শুধু প্রজেক্ট সেটিং বদলালেই শেষ হয় না। পুরোনো UI-তে আসল স্ক্রিন দেখে লেআউট ঠিক করতে হয়।
29. Exception হ্যান্ডলিং ও এরর হ্যান্ডলিং
MFC-তে নিজস্ব exception ক্লাস ও এরর হ্যান্ডলিংয়ের রীতি আছে।
পুরোনো কোডে এমন ম্যাক্রো দেখা যায়।
TRY
{
// কাজ
}
CATCH(CFileException, e)
{
e->ReportError();
}
END_CATCH
আধুনিক C++-এর try / catch-এর সঙ্গে মেশানো কোডও আছে।
try
{
DoSomething();
}
catch (const std::exception& ex)
{
// লগ লেখা
}
MFC রক্ষণাবেক্ষণে এই দিকগুলো দেখুন।
MFC exception ও C++ স্ট্যান্ডার্ড exception মেশানো আছে কি না
Exception অবজেক্টের lifetime ভুল বোঝা হচ্ছে কি না
পুরোনো THROW/CATCH ম্যাক্রো বোঝা আছে কি না
রিটার্ন ভ্যালু এরর ও exception মেশানো আছে কি না
শুধু AfxMessageBox-এ শেষ, লগ নেই — এমন অবস্থা কি না
ব্যবসায়িক অ্যাপে স্ক্রিনে এরর মেসেজ দেখানোই যথেষ্ট নয়; লগ, অপারেশন ইতিহাস, ইনপুট, বাইরের কানেকশন অবস্থা রাখা জরুরি।
পুরোনো MFC অ্যাপে এরর শুধু AfxMessageBox-এ শেষ হতে পারে।
AfxMessageBox(_T("সেভ ব্যর্থ হয়েছে"));
রক্ষণাবেক্ষণ সহজ করতে UI প্রদর্শন ও লগ আলাদা রাখা ভালো।
LogError(_T("Save failed"), path);
AfxMessageBox(_T("সেভ ব্যর্থ হয়েছে। লগ দেখুন।"));
30. MFC ও আধুনিক C++ কীভাবে সহাবস্থান করবে
MFC অ্যাপ রক্ষণাবেক্ষণ করছেন বলে সব পুরোনো C++ লেখার সঙ্গে মেলাতে হয় না।
UI স্তর MFC-এর রীতি মানুক, ডোমেইন লজিক বা হিসাব আধুনিক C++-এ গোছানো যায়।
উদাহরণ: এভাবে ভাগ করুন।
MFC স্তর
CDialog
CView
CDocument
CString
Message map
রিসোর্স অপারেশন
Non-MFC স্তর
std::string / std::wstring
std::vector
std::optional
std::variant
std::filesystem
ইউনিট টেস্টযোগ্য ক্লাস
বিজনেস লজিক
খারাপ রূপ: সব কাজ ডায়ালগ ক্লাসে ঠাসা।
void CMainDialog::OnBnClickedExecute()
{
// ইনপুট নেওয়া
// ফাইল পড়া
// কমিউনিকেশন
// হিসাব
// DB আপডেট
// স্ক্রিন আপডেট
// লগ লেখা
// exception হ্যান্ডলিং
}
এমন কোড বদলানো কঠিন, টেস্ট কঠিন, বাগ তদন্তও কঠিন।
উন্নতি করতে MFC ক্লাস থেকে লজিক বাইরে নিন।
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 ছাড়াই টেস্ট করা যায়।
বিদ্যমান MFC অ্যাসেট রক্ষণাবেক্ষণে সবচেয়ে কাজে লাগে UI ক্লাস থেকে লজিক একটু একটু আলাদা করা।
31. টেস্ট করা যায় এমন MFC কোড
MFC অ্যাপ সরাসরি ইউনিট টেস্ট করা প্রায়ই কঠিন।
কারণ UI, Win32, ফাইল, কমিউনিকেশন, ডেটাবেস, গ্লোবাল স্টেট ঘনিষ্ঠভাবে জড়িয়ে যায়।
টেস্ট সহজ করার চিন্তা এমন।
CDialog বা CView সরাসরি টেস্ট করতে যাবেন না
আগে non-UI লজিক আলাদা করুন
MFC টাইপ সীমানায় রূপান্তর করুন
ফাইল বা কমিউনিকেশন ইন্টারফেস করুন
স্ক্রিন ইভেন্ট handler পাতলা রাখুন
উদাহরণ: বিশুদ্ধ C++ ক্লাসে কাজ সরান।
class PriceCalculator
{
public:
int CalculateTotal(const std::vector<int>& prices) const
{
int total = 0;
for (int price : prices)
{
total += price;
}
return total;
}
};
MFC পাশ শুধু ইনপুট ও আউটপুট সামলায়।
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);
}
এই কাঠামোয় PriceCalculator বা ParsePrices সাধারণ C++ টেস্ট framework দিয়ে টেস্ট করা যায়।
পুরো MFC অ্যাপ একবারে নতুন করে বানাতে হয় না; আগে ইভেন্ট handler-এর ভিতর থেকে টেস্টযোগ্য কাজ বাইরে নিলেই কাজ হয়।
32. বিল্ড এনভায়রনমেন্ট স্থির করা
MFC অ্যাপ রক্ষণাবেক্ষণে বিল্ড এনভায়রনমেন্ট স্থির করা জরুরি।
পুরোনো কোডবেসে এই ফারাকে বিল্ড ফল বদলায়।
Visual Studio ভার্সন
MSVC টুলসেট ভার্সন
Windows SDK ভার্সন
MFC/ATL component আছে কি না
x86 / x64 / ARM64
Debug / Release
Unicode / MBCS
MFC স্ট্যাটিক লিঙ্ক / shared DLL
রানটাইম লাইব্রেরি সেটিং
প্রিকম্পাইলড হেডার
MFC অ্যাপে stdafx.h বা pch.h-এ অনেক নির্ভরতা জমে থাকতে পারে।
#include "framework.h"
#include "MyApp.h"
একটা ফাইলের কম্পাইল সেটিং আলাদা, প্রিকম্পাইলড হেডার সেটিং সরে গেছে — এমন কারণে বিল্ড ভাঙতে পারে।
রক্ষণাবেক্ষণ প্রজেক্টে এই তথ্য README-তে লিখে রাখলে পরে সহজ।
দরকারি Visual Studio ভার্সন
দরকারি workload ও individual component
দরকারি Windows SDK
টার্গেট প্ল্যাটফর্ম
MFC লিঙ্কের ধরন
বিল্ড ধাপ
CI চালানোর পদ্ধতি
ডিস্ট্রিবিউশন বানানোর পদ্ধতি
«আমার পিসিতে বিল্ড হয়» থেকে বেরোনোই MFC রক্ষণাবেক্ষণের প্রথম ধাপ।
33. CI-তে MFC বিল্ড
MFC অ্যাপও CI-তে বিল্ড করা যায়।
তবে CI এনভায়রনমেন্টে MFC component থাকতে হয়।
Visual Studio Build Tools ব্যবহার করলে MFC/ATL-এর component ID দিয়ে ইনস্টল করতে হয়। ID 5 অধ্যায়ের টেবিলের মতোই।
যাচাইয়ের পয়েন্ট এই।
Build Tools-এ MFC আছে কি
টার্গেট টুলসেট প্রজেক্টের সঙ্গে মিলছে কি
Windows SDK আছে কি
x86 বিল্ড ও x64 বিল্ড দুটোই দেখা হয়েছে কি
রিসোর্স কম্পাইলার চলে কি
সাইন প্রক্রিয়া আছে কি
Installer তৈরিও CI-এর আওতায় কি
MFC অ্যাপে UI টেস্ট পর্যন্ত অটোমেট করা সহজ নয়, কিন্তু অন্তত এই অটোমেশন কাজে লাগে।
Debug / Release বিল্ড
x86 / x64 বিল্ড
স্ট্যাটিক অ্যানালিসিস
ইউনিট টেস্ট
Installer তৈরি
আর্টিফ্যাক্টের হ্যাশ রাখা
নির্ভরশীল DLL যাচাই
দীর্ঘ রক্ষণাবেক্ষণে বিল্ড চলার অবস্থা রাখাই বড় মূল্য।
34. MFC অ্যাপ ডিবাগে যেখানে দেখবেন
MFC অ্যাপে বাগ ধরতে এই ক্রমে দেখলে কাজ হয়।
1. কোন স্ক্রিন
2. ডায়ালগ, View, না Frame
3. অপারেশনের সংশ্লিষ্ট রিসোর্স ID কী
4. Message map কোন ফাংশনে যায়
5. UpdateData-এর দিক ঠিক কি
6. Document/View হলে Document-এর অবস্থা কী
7. Command routing অন্য ক্লাসে যাচ্ছে কি না
8. Worker thread থেকে UI ছোঁয়া হচ্ছে কি না
9. Exception বা এরর শুধু AfxMessageBox-এ গিলে ফেলা হচ্ছে কি না
10. রিলিজ বিল্ড-নির্দিষ্ট uninitialized বা lifetime সমস্যা আছে কি না
উদাহরণ: «বাটন চাপলে কিছু হয় না» হলে এখানে দেখুন।
বাটনের IDC ঠিক কি
ON_BN_CLICKED আছে কি
Handler-এর সিগনেচার ঠিক কি
ডায়ালগ রিসোর্স অন্য কিছু কি না
বাটন নিষ্ক্রিয় কি না
মাঝপথে UpdateData ব্যর্থ কি না
Exception গিলে ফেলা হচ্ছে কি না
«মেনু ক্লিক করা যায় না» হলে এদিকে।
ON_UPDATE_COMMAND_UI নিষ্ক্রিয় করছে কি না
Command ID ডুপ্লিকেট কি না
অ্যাকটিভ view ধারণা অনুযায়ী কি
Frame/View/Document/App — handler কোথায়
MFC-তে উপরের ইভেন্ট ও আসল প্রক্রিয়া ম্যাক্রো ও routing দিয়ে যুক্ত, তাই অভ্যস্ত না হওয়া পর্যন্ত কল পাথ ছবিতে আঁকলে বোঝা সহজ। 9 অধ্যায়ের ছবি সেই কল পাথের মৌলিক রূপ।
লক্ষণ থেকে আন্দাজ করতে চাইলে আগে 35 অধ্যায়ের টেবিল দেখুন। সাধারণ ফাঁদ ও কোথায় যাচাই করবেন — মিলিয়ে রাখা আছে।
35. সাধারণ ফাঁদ
MFC রক্ষণাবেক্ষণে সাধারণ ফাঁদ সাজানো এই।
Message map না দেখে শুধু ফাংশন কল সার্চ করা
CWnd* non-null হলেই বৈধ ভাবা
HWND-এর lifetime ও C++ অবজেক্টের lifetime মেশানো
UpdateData(TRUE/FALSE)-এর দিক ভুল করা
ON_UPDATE_COMMAND_UI নিষ্ক্রিয় করেছে, খেয়াল নেই
resource.h-এ ID সংঘর্ষ খেয়াল নেই
Worker thread থেকে সরাসরি UI ছোঁয়া
CString ও std::string রূপান্তরে টেক্সট নষ্ট হওয়া
MBCS-ধরে কোড Unicode করে ভাঙা
MFC DLL-এ AFX_MANAGE_STATE ভুলে যাওয়া
x86-ধরে COM/ActiveX x64 করে ভাঙা
GDI অবজেক্ট সিলেক্ট/মুক্ত করা ভুল
উচ্চ DPI-তে ফিক্সড কোঅর্ডিনেট লেআউট ভাঙা
প্রত্যেকের জন্য «কী লক্ষণে বেরোয়» ও «কোথায় দেখে নিশ্চিত করবেন» মিলিয়ে রাখা হল। ডিবাগের প্রবেশ 34 অধ্যায়ের ধাপের সঙ্গে মিলে।
| ফাঁদ | যে লক্ষণে বেশি দেখা যায় | যেখানে যাচাই করবেন |
|---|---|---|
| Message map না দেখে শুধু ফাংশন কল সার্চ করা | caller পাওয়া যায় না, তবু চলে | BEGIN_MESSAGE_MAP সার্চ করুন। 9 অধ্যায়, 34 অধ্যায়ের ধাপ 4 |
CWnd* non-null হলেই বৈধ ভাবা |
মাঝে মাঝে ক্র্যাশ হয়, বন্ধ স্ক্রিন ছুঁলে ক্র্যাশ হয় | ::IsWindow(pWnd->GetSafeHwnd()) দিয়ে যাচাই করুন। 8 অধ্যায় |
HWND-এর lifetime ও C++ অবজেক্টের lifetime মেশানো |
ডায়ালগ বন্ধের পর access violation | GetDlgItem-এর রিটার্ন ধরে রাখা হচ্ছে কি না। 22 অধ্যায় |
UpdateData-এর দিক ভুল |
ইনপুট যায় না, প্রাথমিক মান স্ক্রিনে আসে না | UpdateData(TRUE) ও UpdateData(FALSE)-এর কল পজিশন। 13 অধ্যায়, 34 অধ্যায়ের ধাপ 5 |
ON_UPDATE_COMMAND_UI নিষ্ক্রিয় করেছে, খেয়াল নেই |
বাটন বা মেনু grey out, ক্লিক করা যায় না | ON_UPDATE_COMMAND_UI handler। 11 অধ্যায়, 34 অধ্যায়ের «মেনু ক্লিক করা যায় না» |
resource.h-এ ID সংঘর্ষ খেয়াল নেই |
অন্য ডায়ালগ বা মেনু আইটেম সাড়া দেয় | resource.h ও .rc ID দিয়ে মিলান। 16 অধ্যায় |
| Worker thread থেকে সরাসরি UI ছোঁয়া | পুনরুৎপাদন করা কঠিন অস্থির ক্র্যাশ, মাঝে মাঝে hang | AfxBeginThread-এ দেওয়া ফাংশনের ভিতরে UI ছোঁয়া হচ্ছে কি না। 23 অধ্যায় |
CString ও std::string রূপান্তরে টেক্সট নষ্ট হওয়া |
শুধু জাপানি ভাঙে, শেষ কাটা যায় | প্রজেক্টের ক্যারেক্টার সেট সেটিং ও রূপান্তরের জায়গা। 18 অধ্যায় |
| MBCS-ধরে কোড Unicode করে ভাঙা | বাফার দৈর্ঘ্য সরে যায়, বিদ্যমান ফাইল পড়া যায় না | sizeof-কে ক্যারেক্টার সংখ্যা ধরা হচ্ছে কি না। 26 অধ্যায় |
MFC DLL-এ AFX_MANAGE_STATE ভুলে যাওয়া |
DLL-এর ভিতরের ডায়ালগ বা স্ট্রিং রিসোর্স পাওয়া যায় না | DLL-এর পাবলিক ফাংশনের শুরু। 24 অধ্যায় |
| x86-ধরে COM/ActiveX x64 করে ভাঙা | শুধু 64bit বিল্ডে স্টার্টআপ বা স্ক্রিন দেখাতে ব্যর্থ | COM রেজিস্ট্রেশন শুধু 32bit পাশে কি না। 27 অধ্যায় |
| GDI অবজেক্ট সিলেক্ট ও মুক্ত করা ভুল | দীর্ঘক্ষণ চালালে আঁকা ভাঙে | টাস্ক ম্যানেজারের «GDI objects» কলাম বাড়তেই থাকে কি না। 20 অধ্যায় |
| উচ্চ DPI-তে ফিক্সড কোঅর্ডিনেট লেআউট ভাঙা | শুধু 150% স্কেলে অক্ষর কাটা যায় | ম্যানিফেস্টের DPI সেটিং ও ফিক্সড কোঅর্ডিনেট আঁকা। 28 অধ্যায় |
MFC-এর সমস্যা শুধু C++ সিনট্যাক্স দেখে বোঝা যায় না; Windows message, রিসোর্স, handle, মডিউল, রানটাইম সেটিং পর্যন্ত দেখতে হয়।
36. নতুন ডেভেলপমেন্টে MFC বেছে নেবেন কি
পুরোপুরি নতুন কাজে MFC বেছে নেওয়া সতর্কতার সঙ্গে ভাবা উচিত।
MFC বেছে নেওয়ার কারণ থাকলে এমন ক্ষেত্র।
বিদ্যমান MFC কোডের সঙ্গে ঘনিষ্ঠ ইন্টিগ্রেশন লাগে
বিদ্যমান MFC উপাদান বা স্ক্রিন পুনর্ব্যবহার করতে চান
Win32/GDI/COM-এর খুব কাছাকাছি নিয়ন্ত্রণ লাগে
অফিসে MFC রক্ষণাবেক্ষণ স্কিল যথেষ্ট আছে
টার্গেট শুধু Windows ডেস্কটপ
দীর্ঘমেয়াদি মাইগ্রেশন প্ল্যানে আগে MFC-তে বাড়াতে হয়
উল্টোদিকে এ ক্ষেত্রে অন্য বিকল্প ভাবা ভালো।
আধুনিক UI চান
নমনীয় লেআউট বা অ্যানিমেশন লাগে
Web বা ক্লাউড ইন্টিগ্রেশন কেন্দ্রে
টেস্ট সহজতাকে গুরুত্ব দিতে চান
নতুন ডেভেলপার সহজে যোগ দিতে পারে এমন প্রযুক্তি চান
ক্রস-প্ল্যাটফর্ম লাগে
অ্যাক্সেসিবিলিটি বা উচ্চ DPI শুরু থেকেই গুরুত্ব দিতে চান
MFC «এখন শেখার মূল্য নেই» প্রযুক্তিও নয়, «নতুন বলে বেছে নেওয়া» প্রযুক্তিও নয়; বিদ্যমান Windows native অ্যাসেটের মুখোমুখি হওয়ার প্রযুক্তি।
37. MFC থেকে মাইগ্রেট করার চিন্তা
MFC অ্যাপ অন্য প্রযুক্তিতে নিয়ে যেতে চাইলে একবারে পুরো বদলের লক্ষ্য নিলে ব্যর্থ হওয়া সহজ।
আগে অ্যাপকে এভাবে ভাঙুন।
UI
বিজনেস লজিক
ফাইল ফরম্যাট
কমিউনিকেশন
ডেটাবেস প্রক্রিয়া
ডিভাইস কন্ট্রোল
প্রিন্ট
COM/OLE ইন্টিগ্রেশন
সেটিং ব্যবস্থাপনা
লগ
এর মধ্যে MFC-এর ওপর সবচেয়ে নির্ভরশীল UI।
অন্যদিকে বিজনেস লজিক বা ফাইল প্রক্রিয়া আলাদা করা যেতে পারে।
মাইগ্রেশনের বাস্তব ক্রম এমন।
1. বিল্ড এনভায়রনমেন্ট পুনরায় তৈরি করুন
2. বিদ্যমান আচরণ টেস্ট ডেটায় স্থির করুন
3. UI ইভেন্ট handler থেকে লজিক আলাদা করুন
4. Non-MFC C++ লাইব্রেরির দিকে সরান
5. অটোমেটেড টেস্ট যোগ করুন
6. বাইরের স্পেসিফিকেশন ডকুমেন্ট করুন
7. দরকারি স্ক্রিন থেকে ধাপে ধাপে বদলান
উদ্দেশ্য «MFC ছাড়ব» না করে «MFC-এর ভিতরে আটকে থাকা গুরুত্বপূর্ণ লজিক বাইরে বের করা» হলে সফল হওয়া সহজ।
38. MFC কোড পড়ার প্রবেশ
বিদ্যমান MFC প্রজেক্ট প্রথমবার পড়তে এই ফাইলগুলো থেকে শুরু করুন।
*.vcxproj
টুলসেট, MFC সেটিং, ক্যারেক্টার সেট, রানটাইম সেটিং দেখুন
resource.h
রিসোর্স ID দেখুন
*.rc
ডায়ালগ, মেনু, স্ট্রিং, আইকন দেখুন
*App.cpp / *App.h
CWinApp-derived ক্লাস ও InitInstance দেখুন
MainFrm.cpp / MainFrm.h
মেইন ফ্রেম ও মেনু/টুলবার দেখুন
*Doc.cpp / *Doc.h
Document/View হলে ডেটা স্ট্রাকচার ও সেভ দেখুন
*View.cpp / *View.h
আঁকা ও ইউজার ইন্টারঅ্যাকশন দেখুন
*Dlg.cpp / *Dlg.h
ডায়ালগ, DDX, বাটন হ্যান্ডলিং দেখুন
এর পর সাধারণ সার্চ কিওয়ার্ড।
BEGIN_MESSAGE_MAP
ON_COMMAND
ON_UPDATE_COMMAND_UI
ON_BN_CLICKED
DoDataExchange
UpdateData
OnInitDialog
OnDraw
Serialize
AfxMessageBox
AfxBeginThread
AFX_MANAGE_STATE
এগুলো সার্চ করলে অ্যাপ্লিকেশনের চলাচল দেখা সহজ হয়।
39. MFC রক্ষণাবেক্ষণের ডিজাইন নীতি
বিদ্যমান MFC অ্যাসেট দীর্ঘদিন রক্ষণাবেক্ষণ করতে এমন নীতি কাজে লাগে।
UI ইভেন্ট handler পাতলা রাখুন
CString বা CWnd non-UI স্তরে বেশি leak করবেন না
বিজনেস লজিক সাধারণ C++ ক্লাসে সরান
ফাইল ফরম্যাটের সামঞ্জস্য টেস্ট বানান
x86/x64 ফারাক স্পষ্ট করুন
রিসোর্স ID বদল রিভিউ করুন
MFC DLL-এর মডিউল স্টেট যাচাই করুন
লগ গুছিয়ে রাখুন
CI-তে বিল্ড স্থির করুন
উচ্চ DPI ও Windows 11-এ স্ক্রিন নিয়মিত দেখুন
বিশেষ করে CDialog বা CView-এ কাজ বেশি ঠাসাবেন না।
MFC স্ক্রিন ক্লাস ইনপুট, প্রদর্শন, ইভেন্ট পাঠানোতে মন দিক।
স্ক্রিন থেকে মান নিন
সার্ভিসে দিন
ফল স্ক্রিনে দেখান
এই মাত্রায় রাখতে পারলে MFC হলেও রক্ষণাবেক্ষণ অনেক সহজ হয়।
40. বাস্তব চেকলিস্ট
MFC অ্যাপ সামলানোর চেকলিস্ট।
Visual Studio ভার্সন স্পষ্ট কি
MFC/ATL component ইনস্টল আছে কি
x86/x64 টার্গেট স্পষ্ট কি
Unicode/MBCS সেটিং ধরা আছে কি
MFC স্ট্যাটিক লিঙ্ক, না shared DLL
দরকারি Visual C++ Redistributable কী
resource.h ও .rc রিভিউয়ের আওতায় কি
Message map দিয়ে ইভেন্ট পাথ ধরা হচ্ছে কি
UpdateData-এর দিক ঠিক কি
Document/View কাঠামো ব্যবহার হচ্ছে কি
modeless dialog-এর lifetime নিরাপদ কি
Worker thread থেকে সরাসরি UI ছোঁয়া হচ্ছে কি না
MFC DLL-এ AFX_MANAGE_STATE দরকার এমন জায়গা আছে কি
উচ্চ DPI এনভায়রনমেন্টে স্ক্রিন দেখা হয়েছে কি
COM/ActiveX নির্ভরতা 32bit/64bit সামলানো কি
লগ থাকে কি
Non-UI লজিক টেস্ট করা যায় কি
MFC অভ্যস্ত না হওয়া পর্যন্ত আলাদা লাগে, কিন্তু দেখার জায়গা জানলে বেশ নিয়মমাফিক পড়া যায়।
41. সারসংক্ষেপ
MFC Windows-এর native ডেস্কটপ অ্যাপ্লিকেশন C++-এ গড়ার ইতিহাসসমৃদ্ধ framework। নতুন ডেভেলপমেন্টের মূলধারা নয়, তবু বিদ্যমান অ্যাসেট রক্ষণাবেক্ষণ, বিল্ড এনভায়রনমেন্ট আপডেট, ফিচার যোগ, ধাপে ধাপে মাইগ্রেশনে আজও গুরুত্বপূর্ণ প্রযুক্তি।
MFC বুঝতে বিশেষ করে এই দিকগুলো জরুরি।
MFC Win32 API-কে C++-এ সহজে ব্যবহার করায়
CWinApp পুরো অ্যাপ সামলায়
CWnd ও HWND-এর lifetime এক নয়
Message map ইভেন্ট ও ফাংশন বাঁধে
Document/View ডেটা ও প্রদর্শন আলাদা করে
DDX/DDV ডায়ালগের মান সিঙ্ক ও যাচাইয়ে ব্যবহার হয়
রিসোর্স ফাইল ও resource.h খুবই গুরুত্বপূর্ণ
CString ও TCHAR ক্যারেক্টার এনকোডিং সেটিংয়ের সঙ্গে একসেট করে বোঝা
MFC DLL-এ মডিউল স্টেট খেয়াল রাখা
পুরোনো MFC অ্যাপ উচ্চ DPI, x64, CI, টেস্টের দৃষ্টিতে নতুন করে দেখার মূল্য আছে
MFC সামলাতে «পুরোনো বলে খারাপ» বলে সিদ্ধান্ত না নিয়ে আগে কাঠামো বোঝা জরুরি। বিদ্যমান MFC অ্যাপে বছরের ব্যবসায়িক জ্ঞান, কাস্টমার-নির্দিষ্ট স্পেসিফিকেশন, ডিভাইস ইন্টিগ্রেশন, ফাইল সামঞ্জস্য জমে থাকতে পারে। সেই মূল্য রেখে একটু একটু রক্ষণাবেক্ষণ সহজ করতে MFC-এর রীতি বুঝে non-UI লজিক আলাদা করা, বিল্ড ও টেস্ট গোছানোই বাস্তব পথ।
এক বাক্যে বললে এমন।
Windows native অ্যাপের mechanism C++ ক্লাস ও framework দিয়ে সামলানোর ভিত্তি।
এই দৃষ্টি থাকলে MFC শুধু পুরোনো প্রযুক্তি নয়, বিদ্যমান Windows অ্যাসেট নিরাপদে পড়ার সূত্র হয়ে ওঠে।
তথ্যসূত্র
- এই নিবন্ধের কোড খণ্ড অধ্যায় অনুযায়ী সাজানো রেফারেন্স সংগ্রহ - komurasoft-blog-samples (GitHub)
- Microsoft Learn, 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
সম্পর্কিত নিবন্ধ
কাছাকাছি বিষয়ে গভীরে যেতে একই ট্যাগযুক্ত সাম্প্রতিক নিবন্ধ।
Win32 থ্রেড পুল API — CreateThreadpoolWork দিয়ে থ্রেড তৈরি না করে কনকারেন্সি
নেটিভ কোডে চারদিকে CreateThread ডাকছেন? এই নিবন্ধ Vista-তে নতুন করে সাজানো Win32 থ্রেড পুল API ব্যাখ্যা করে — work, timer, wait ও io চারট...
নেমড পাইপ ব্যবহারিকভাবে — ডিজাইন থেকে নিরাপত্তা পর্যন্ত Windows-এর মানক IPC
Windows-এর মানক আন্তঃপ্রক্রিয়া যোগাযোগ নেমড পাইপের ব্যবহারিক গাইড। প্রাথমিক উৎস থেকে এই নিবন্ধ বাইট ও মেসেজ মোডের পছন্দ, একাধিক ক্লায়েন...
DllMain ও লোডার লক — DLL ইনিশিয়ালাইজেশনে "কিছুই করবেন না" বলা হয় তার আসল কারণ
DllMain থেকে LoadLibrary ডাকা বা অন্য থ্রেডের সাথে সিঙ্ক্রোনাইজ করা যায় না কেন। প্রাথমিক উৎস থেকে এই নিবন্ধ ব্যাখ্যা করে লোডার লক প্রতিট...
Spurious Wakeup — কন্ডিশন ভেরিয়েবল কেন "নোটিফাই না হয়েও" জাগে এবং Windows-এ সঠিকভাবে কীভাবে অপেক্ষা করবেন
কন্ডিশন ভেরিয়েবলের ওয়েট নোটিফিকেশন না এলেও ফিরতে পারে (spurious wakeup)। এই নিবন্ধ Windows বাস্তবায়ন থেকে ব্যাখ্যা করে স্পেসিফিকেশন কে...
ব্যবহারিক মাল্টিথ্রেডিং সেরা অনুশীলন: C++ সংস্করণ — RAII ও jthread দিয়ে কাঠামো থেকে দুর্ঘটনা মুছে ফেলা
C++-এ মাল্টিথ্রেডিং এমন জগৎ যেখানে ডেটা রেসই অনির্ধারিত আচরণ। এই নিবন্ধ std::thread-এর ডেস্ট্রাক্টরের ফাঁদ, jthread ও stop_token দিয়ে থা...
সম্পর্কিত বিষয়
এই পৃষ্ঠাগুলো বিষয়টিকে সেবা ও সিদ্ধান্তের বৃহত্তর প্রেক্ষাপটে স্থাপন করে।
Windows-এর প্রযুক্তিগত বিষয়
Windows ডেভেলপমেন্ট, বাগ তদন্ত ও বিদ্যমান সম্পদ ব্যবহারের প্রবেশদ্বার।
এই বিষয়ের সাথে সম্পর্কিত সেবা
নিবন্ধটি নিচের সেবাগুলোর সাথে সরাসরি সম্পর্কিত।
Windows অ্যাপ ডেভেলপমেন্ট
ব্যবসায়িক অ্যাপ, ডিভাইস ইন্টিগ্রেশন ও যোগাযোগ টুল, চাহিদা থেকে ডেভেলপমেন্ট পর্যন্ত।
প্রায়শ জিজ্ঞাসিত প্রশ্ন
এই নিবন্ধের বিষয়ে পরামর্শে প্রায়ই আসা প্রশ্ন।
- MFC কী?
- MFC মানে Microsoft Foundation Classes। Win32 API-কে C++ ক্লাস হিসেবে সহজে ব্যবহার করার Windows অ্যাপ্লিকেশন framework। উইন্ডো হয় CWnd, ডায়ালগ হয় CDialog, পুরো অ্যাপ্লিকেশন হয় CWinApp—এই ধরনের ক্লাসে represent হয়। এটা «Windows না জেনেই লেখা যায় এমন জাদু লাইব্রেরি» নয়; Windows-এর mechanism C++ টাইপ ও framework দিয়ে সাজানো, তাই Windows message ও handle-এর মতো Win32 জ্ঞানও লাগে।
- MFC এখনও ব্যবহার করা যায়? সাপোর্ট চলছে?
- MFC এখনও Visual Studio-তে পাওয়া যায়, সাপোর্টও চলছে। তবে Microsoft-এর ডকুমেন্টে নতুন ফিচার যোগ বা ডকুমেন্ট আপডেট হবে না বলে নোট আছে। অবস্থানটা এমন: বিদ্যমান MFC অ্যাপের রক্ষণাবেক্ষণ, ফিচার যোগ, বিল্ড এনভায়রনমেন্ট আপডেট, অন্য UI-তে ধাপে ধাপে মাইগ্রেশন বাস্তবে সাধারণ; পুরোপুরি নতুন সাধারণ GUI অ্যাপে বেছে নেওয়া সতর্কতার সঙ্গে ভাবা উচিত। Visual Studio Installer-এর individual component (C++ MFC for latest build tools) ইনস্টল করতে হয়।
- MFC-এর message map কী?
- Windows message ও command-কে handler ফাংশনের সঙ্গে বাঁধার MFC ব্যবস্থা। BEGIN_MESSAGE_MAP থেকে END_MESSAGE_MAP-এর মধ্যে ON_BN_CLICKED বা ON_COMMAND-এর মতো ম্যাক্রো দিয়ে «এই বাটনে ক্লিক হলে এই ফাংশন ডাকো» লেখা হয়। ফাংশন খুঁজে সরাসরি কল না পেয়েও ইভেন্টে চললে message map দেখুন। MFC কোড রিভিউতে handler ফাংশনের সঙ্গে message map একসাথে দেখা জরুরি।
- MFC থেকে অন্য প্রযুক্তিতে কীভাবে মাইগ্রেট করবেন?
- একবারে পুরো বদলের লক্ষ্য নিলে ব্যর্থ হওয়া সহজ। বাস্তব ক্রম: বিল্ড এনভায়রনমেন্ট পুনরায় তৈরি করুন, বিদ্যমান আচরণ টেস্ট ডেটায় স্থির করুন, UI ইভেন্ট handler থেকে লজিক আলাদা করে non-MFC C++ লাইব্রেরিতে নিয়ে যান, অটোমেটেড টেস্ট যোগ করুন, বাইরের স্পেসিফিকেশন ডকুমেন্ট করুন, তারপর দরকারি স্ক্রিন থেকে ধাপে ধাপে বদলান। উদ্দেশ্য «MFC ছাড়ব» না করে «MFC-এর ভিতরে আটকে থাকা গুরুত্বপূর্ণ লজিক বাইরে বের করা» হলে সফল হওয়া সহজ।