অ্যাপের চোখে Windows শাটডাউন — প্রস্থান নোটিফিকেশন, রিস্টার্ট ও বিদ্যুৎ বিচ্ছিন্নতা সঠিকভাবে সহ্য করা
· Go Komura · Windows, শাটডাউন, Windows ডেভেলপমেন্ট, Windows সার্ভিস, ডিভাইস PC, ডেটা অখণ্ডতা, দীর্ঘসময় চলা কাজ, UPS
“Windows Update-এর রাতের রিস্টার্টের পর ডিভাইস PC-র মাপ অ্যাপ লিখতে লিখতে পড়ে গেল, আর সকালে মাপের ফাইল নষ্ট।” “কেউ শেয়ার করা PC থেকে সাইন-আউট করে অভিযোগ করল অসংরক্ষিত সম্পাদনা উধাও।” — দীর্ঘসময় চলা Windows অ্যাপের জন্য এই দুই পরামর্শ ক্লাসিক।
দুই সাইটের মিল শাটডাউনকে “এমন অস্বাভাবিক ঘটনা যা হওয়াই উচিত নয়” ধরা। বাস্তবে Windows Update স্বয়ংক্রিয় রিস্টার্ট, ব্যবহারকারী সাইন-আউট, আর UPS-সূচিত শাটডাউন থেকে শুরু করে ঘোষণাহীন বিদ্যুৎ বিচ্ছিন্নতা পর্যন্ত, অ্যাপের বাইরে থেকে চালনা কাটা ইভেন্ট আসবে, দেরিতে হোক তাড়াতাড়ি হোক। আসা আটকানো যায় না। যা আটকানো যায় তা “এলে ডেটা হারানো”।
সৌভাগ্যক্রমে Windows-এ শাটডাউনের আগে অ্যাপকে জানানোর কৌশল আছে — GUI অ্যাপ, কনসোল অ্যাপ ও সার্ভিস তিনটিতেই। ক্ষুদ্র-মাঝারি ব্যবসার IT স্টাফ ও Windows অ্যাপ ডেভেলপারদের (বিশেষত ডিভাইস-PC ও দীর্ঘসময় চলা অ্যাপ) লক্ষ্য করে এই নিবন্ধ সেই নোটিফিকেশন কীভাবে নেবেন, “কয়েক সেকেন্ডে শেষ” ক্লিনআপ কীভাবে ডিজাইন করবেন, রিস্টার্টের পর স্বয়ংক্রিয় পুনরুদ্ধার, আর নোটিফিকেশনহীন বিদ্যুৎ বিচ্ছিন্নতার প্রস্তুতি — সব আগস্ট ২০২৬ পর্যন্ত Microsoft Learn প্রাথমিক উৎসে ভিত্তি করে — সাজায়।
১. আগে উপসংহার
- শাটডাউনকে “স্বাভাবিক ইভেন্ট যা দেরিতে হোক তাড়াতাড়ি আসবে” ধরে ডিজাইন করুন। নোটিফিকেশন পাওয়ার পর ব্যবহারযোগ্য সময় নীতিগতভাবে প্রায় ৫ সেকেন্ডই, তাই সেখানে সব হুড়োহুড়ি সেভ করার ডিজাইন ভেঙে পড়বে। পূর্বশর্ত ঘন ঘন অটোসেভ যাতে “শাটডাউনে সেভ করতে হয় এমন ডেল্টা” ছোট থাকে।1
- Windows 8 থেকে পরের ক্লায়েন্ট OS-এ, fast startup চালু থাকলে (হাইবারনেশন-সমর্থিত বেশিরভাগ PC-তে ডিফল্ট) “Shut down” hybrid shutdown, আর কার্নেল শুধু হাইবারনেট করছে। পুরোপুরি রিসেট শুধু “Restart”। এটাই আসল কারণ “শাটডাউন করলাম, ভালো হয়নি, তারপর রিস্টার্ট করলে হল”।2
- GUI অ্যাপের WM_QUERYENDSESSION-এ সঙ্গে সঙ্গে TRUE ফেরানো উচিত, আর ক্লিনআপ WM_ENDSESSION-এ করা উচিত। নীতিগতভাবে FALSE (প্রত্যাখ্যান) ফেরাবেন না।1
- শুধু সত্যিই মাঝপথে কাটা যায় না এমন কাজ থাকলে ShutdownBlockReasonCreate দিয়ে কারণ দেখান। তবু ব্যবহারকারী ও OS জোর করে চালিয়ে যেতে পারে, তাই “আমরা ব্লক করতে পারি” ধরা ডিজাইন দাঁড়ায় না।34
- কনসোল অ্যাপ নোটিফিকেশন পায় SetConsoleCtrlHandler দিয়ে। ছাড় আরও ছোট — কনসোল বন্ধে ডিফল্ট ৫ সেকেন্ড। একটি ফাঁদও আছে: যে প্রক্রিয়া gdi32.dll বা user32.dll লোড করেছে, এসব ইভেন্টের কিছু আসে না।56
- .NET-এর AppDomain.ProcessExit-এর উপর নির্ভর ক্লিনআপ .NET 10 থেকে সেই পথে চলে না যেখানে প্রক্রিয়া “বাইরে থেকে শেষ” হয়। Main থেকে ফেরার মতো সাধারণ প্রস্থানে আগের মতোই চলে, কিন্তু রানটাইম কনসোল বন্ধ ও শাটডাউনের মতো সমাপ্তি সিগন্যালের ডিফল্ট হ্যান্ডলিং আর দেয় না বলে সেই পথের ক্লিনআপ অ্যাপ মডেলের সাথে মিলে এমন নোটিফিকেশনে যেতে হয়।7
- Windows সার্ভিস SERVICE_ACCEPT_PRESHUTDOWN SERVICE_ACCEPT_SHUTDOWN-এর (প্রায় ২০ সেকেন্ড ছাড়) আগে, আর কনফিগারযোগ্য ছাড়সহ, পেতে পারে। তবে ডিফল্ট PRESHUTDOWN টাইমআউট Windows 10 Creators Update থেকে ১০ সেকেন্ডে ছোট হয়েছে, তাই যেভাবেই হোক ছাড়ের উপর বেশি হেলান দেওয়া ডিজাইন লাগে না।89
- রিস্টার্টের পর স্বয়ংক্রিয় পুনরুদ্ধার RegisterApplicationRestart-কে ARSO-র (স্বয়ংক্রিয় সাইন-অন) সাথে জুড়ে হয়। ক্র্যাশ, সাড়া না দেওয়া, আর আপডেট-চালিত রিস্টার্টের পথ আছে।1011
- বিদ্যুৎ বিচ্ছিন্নতা কোনো নোটিফিকেশন আনে না। মানক আকৃতি অস্থায়ী ফাইলে পুরো লেখা, ফ্লাশ, আর ReplaceFile দিয়ে অদলবদল, কিন্তু বিদ্যুৎ কাটার উপর ReplaceFileও পরমাণবিকতা গ্যারান্টি দেয় না বলে ব্যাকআপ (.bak) প্লাস লোড-সময় যাচাই পুনরুদ্ধার পথ সেটের অংশ। পরে আলাদা করা যায় ইভেন্ট লগ থেকে (১০৭৪/৪১/৬০০৮)।121314
এক বাক্যে এই নিবন্ধের উপসংহার: “নোটিফিকেশন এলে কয়েক সেকেন্ডে দোকান বন্ধ করতে পারা স্টেট সবসময় রাখুন, আর এমনভাবে লিখুন যা নোটিফিকেশনহীন বিদ্যুৎ বিচ্ছিন্নতায়ও না ভাঙে”।
২. শাটডাউনে কী হয় — শেষ হওয়ার চার পথ
২.১. সাইন-আউট, শাটডাউন, রিস্টার্ট ও বিদ্যুৎ বিচ্ছিন্নতা
অ্যাপের চোখে দুটি অক্ষ জরুরি: “ব্যবহারকারী সেশন কীভাবে শেষ হয়” আর “কার্নেলের কী হয়”।
| কাজ | ব্যবহারকারী সেশন | কার্নেল ও ড্রাইভার | অ্যাপে নোটিফিকেশন |
|---|---|---|---|
| সাইন-আউট | শেষ | চলতে থাকে | WM_QUERYENDSESSION (ENDSESSION_LOGOFF) → WM_ENDSESSION |
| শাটডাউন (fast startup চালু) | শেষ | হাইবারনেট (hiberfil.sys-এ সেভ) | WM_QUERYENDSESSION → WM_ENDSESSION, সার্ভিসে (PRE)SHUTDOWN |
| রিস্টার্ট | শেষ | পুরোপুরি শেষ; পরের বুট পূর্ণ বুট | উপরের মতো |
| বিদ্যুৎ বিচ্ছিন্নতা | সঙ্গে সঙ্গে উধাও | সঙ্গে সঙ্গে উধাও | নেই |
অ্যাপের চোখে সাইন-আউট ও শাটডাউন প্রায় একই ইভেন্ট। WM_QUERYENDSESSION-এর lParam-এ ENDSESSION_LOGOFF বিট সেট থাকলে সাইন-আউট; ০ হলে শাটডাউন বা রিস্টার্ট (দুটো আলাদা করা যায় না)।1 অর্থাৎ “শুধু সাইন-আউট, চলবে” ঢিলেমি দাঁড়ায় না, আর সঠিক ডিজাইন একই ক্লিনআপ কোড চালানো।
flowchart TB
accTitle: শেষ হওয়ার চার পথ, আর অ্যাপে নোটিফিকেশন
accDescr: সাইন-আউট, শাটডাউন ও রিস্টার্ট WM_QUERYENDSESSION থেকে WM_ENDSESSION নোটিফিকেশন দেয়, আর ক্লিনআপ কয়েক সেকেন্ডে শেষ হয়। শুধু বিদ্যুৎ বিচ্ছিন্নতায় কোনো নোটিফিকেশন নেই, তাই অধ্যায় ৮-এর লেখার ডিজাইন ও UPS দিয়ে প্রস্তুতি নিন
signout["সাইন-আউট"] --> notified["QUERY → ENDSESSION"]
shutdown["শাটডাউন"] --> notified
reboot["রিস্টার্ট"] --> notified
poweroff["বিদ্যুৎ বিচ্ছিন্নতা"] --> none["নোটিফিকেশন নেই: লেখা + UPS"]
notified --> cleanup["সেকেন্ডে ক্লিনআপ"]
চিত্র 1: সাইন-আউট, শাটডাউন ও রিস্টার্ট WM_QUERYENDSESSION থেকে WM_ENDSESSION নোটিফিকেশন দেয়, আর ক্লিনআপ কয়েক সেকেন্ডে শেষ হয়। শুধু বিদ্যুৎ বিচ্ছিন্নতায় কোনো নোটিফিকেশন নেই, তাই অধ্যায় ৮-এর লেখার ডিজাইন ও UPS দিয়ে প্রস্তুতি নিন।
২.২. “শাটডাউন করলাম তবু ভালো হয়নি”-এর আসল কারণ — hybrid shutdown
টেবিলের সহজে ছুটে যাওয়া সারি দ্বিতীয়টি। Windows 8 থেকে পরের ক্লায়েন্ট OS-এ fast startup (hybrid shutdown) হাইবারনেশন-সমর্থিত PC-তে ডিফল্টে চালু, আর “Shut down”-এর আচরণ বদলেছে। ব্যবহারকারী সেশনের সাইন-আউট আগের মতোই হয়, কিন্তু কার্নেল সেশন বন্ধ হয় না; ডিভাইস ড্রাইভারসহ হাইবারনেশন ফাইলে (hiberfil.sys) সেভ হয়ে পরের বুটে যেমন ছিল তেমন ফেরে। এতে স্টার্টআপ দ্রুত হয়, কিন্তু কার্নেল ও ড্রাইভার স্টেট বিদ্যুৎ কাটলেও বেঁচে থাকে।2 তবে এটি শর্তসাপেক্ষ আচরণ। যে পরিবেশে হাইবারনেশন নিজেই বন্ধ (powercfg /hibernate off), যেখানে নীতি বা Power Options fast startup বন্ধ করেছে, আর Windows Server-এ, শাটডাউন পুরনো পূর্ণ শাটডাউন। কোন PC কোন পথে চলছে Power Options-এর “Turn on fast startup” চেক বক্স থেকে, অথবা powercfg /a (উপলব্ধ ঘুম অবস্থা) “Fast Startup” তালিকা করে কি না তা থেকে বোঝা যায়।
flowchart TB
accTitle: Shut down কাজে কার্নেলের কী হয়
accDescr: Shut down কাজ fast startup চালু থাকলে পূর্ণ শাটডাউন বা কার্নেল হাইবারনেশনে ভাগ হয়, আর Restart সবসময় পূর্ণ বুট করে
op["Shut down"]
restart["Restart"]
op -->|"Fast startup চালু"| hybrid["সেশন শেষ + কার্নেল হাইবারনেট"]
op -->|"হাইবারনেট বন্ধ / Server"| full["পূর্ণ শাটডাউন"]
hybrid --> resume["পরের: কার্নেল ফেরানো"]
full --> boot["পরের: পূর্ণ বুট"]
restart --> boot
চিত্র 2: Shut down কাজ fast startup চালু থাকলে পূর্ণ শাটডাউন বা কার্নেল হাইবারনেশনে ভাগ হয়, আর Restart সবসময় পূর্ণ বুট করে।
অন্যদিকে “Restart” সবসময় পূর্ণ বুট চক্র চালায়। ড্রাইভার আপডেটের পর, উদাহরণস্বরূপ, পুরোপুরি নতুন স্টেট লাগে।2 তা থেকে মাঠে শোনা কয়েকটি ঘটনা জায়গায় বসে।
- “শাটডাউন করে আবার চালু করলাম, ডিভাইস সমস্যা যায়নি” — কার্নেল ও ড্রাইভার শুধু হাইবারনেশন থেকে ফিরেছে; রিসেট হয়নি
- “রিস্টার্টের পর ভালো হয়েছে” — কারণ পূর্ণ বুট সেগুলো শুরু করেছে
- ডিভাইস-PC ঘটনা পদ্ধতিতে বলা উচিত “Restart”, “বন্ধ করে চালু করুন” নয়
কমান্ড লাইন থেকে পূর্ণ শাটডাউন স্পষ্ট করতে চাইলে shutdown /s (Shutdown.exe-এর ডিফল্ট পূর্ণ শাটডাউন); ডিফল্ট হাইব্রিড আচরণ চাইলে shutdown /s /hybrid।2 fast startup বন্ধ করা সুপারিশ নয়। অ্যাপ পাশ ধরে নেবে “শাটডাউনে কার্নেল শুধু হাইবারনেট হতে পারে” — উদাহরণস্বরূপ OS বুট সময় থেকে “সঞ্চিত আপটাইম” অনুমান করবেন না — আর এমন ডিজাইন করুন যা যে পথেই হোক না ভাঙে (fast startup চালু বা বন্ধ পরিবেশভেদে আলাদা)।
৩. GUI অ্যাপের কেমন আচরণ করা উচিত — WM_QUERYENDSESSION ও WM_ENDSESSION
৩.১. দুই মেসেজ কাজ কীভাবে ভাগে
যে অ্যাপে উইন্ডো ও মেসেজ কিউ আছে তাকে সেশন শেষ দুই ধাপে জানানো হয়।1
- WM_QUERYENDSESSION — প্রশ্ন: “শেষ করা ঠিক?” অ্যাপের সঙ্গে সঙ্গে TRUE ফেরানো উচিত; DefWindowProc-এর ডিফল্ট উত্তরও TRUE। এখানে ক্লিনআপ শুরু করবেন না।
- WM_ENDSESSION (wParam=TRUE) — নিশ্চিত নোটিফিকেশন: “সেশন সত্যিই শেষ হচ্ছে”। ক্লিনআপ এখানে হয়।
WM_QUERYENDSESSION-এ FALSE ফেরালে শাটডাউন থামতে পারে, কিন্তু ডকুমেন্ট স্পষ্ট যে “TRUE ফেরিয়ে ব্যবহারকারীর ইচ্ছা সম্মান করা উচিত”, আর FALSE ফেরানো অ্যাপ তবু পূর্ণ-স্ক্রিন UI-তে “শাটডাউন আটকানো অ্যাপ” হিসেবে দেখা যায়। কনসোল অ্যাপ ও দৃশ্যমান উইন্ডোহীন অ্যাপ শাটডাউন আটকাতেই পারে না, আর ৫ সেকেন্ডে সাড়া না দিলে স্বয়ংক্রিয় শেষ হয়।14
flowchart TB
accTitle: দুই-ধাপ সেশন-শেষ নোটিফিকেশনের প্রবাহ
accDescr: WM_QUERYENDSESSION প্রশ্নে TRUE ফেরালে WM_ENDSESSION নিশ্চিত হয় আর ক্লিনআপ চলে। FALSE দিয়ে প্রত্যাখ্যান অ্যাপকে শাটডাউন আটকানো দেখায়, আর প্রায় ৫ সেকেন্ড সাড়া না দিলে জোর করে চালিয়ে যেতে পারে
q["WM_QUERYENDSESSION"]
q -->|"TRUE(নিয়ম)"| e["WM_ENDSESSION(নিশ্চিত)"]
q -->|"FALSE(প্রত্যাখ্যান)"| blocked["শাটডাউন আটকানো দেখানো"]
q -->|"সাড়া নেই ~৫ সেকেন্ড"| hung["হ্যাং ধরা"]
e --> cleanup["ক্লিনআপ এখানে"]
cleanup --> term["প্রক্রিয়া প্রস্থান"]
hung --> term
blocked -->|"জোর করে চালাও"| term
blocked -->|"বাতিল"| cont["শাটডাউন বাতিল"]
চিত্র 3: WM_QUERYENDSESSION প্রশ্নে TRUE ফেরালে WM_ENDSESSION নিশ্চিত হয় আর ক্লিনআপ চলে। FALSE দিয়ে প্রত্যাখ্যান অ্যাপকে শাটডাউন আটকানো দেখায়, আর প্রায় ৫ সেকেন্ড সাড়া না দিলে জোর করে চালিয়ে যেতে পারে।
৩.২. সাড়া না দিলে কী হয় — ৫-সেকেন্ডের দেয়াল
WM_QUERYENDSESSION ও WM_ENDSESSION দুটোতেই উত্তর প্রায় ৫ সেকেন্ড দেরি করা যায়। তার বেশি হলে সিস্টেম “এই অ্যাপ শাটডাউন আটকাচ্ছে” স্ক্রিন দেখায়, আর ব্যবহারকারী জোর করে চালিয়ে যেতে (= অ্যাপ জোর করে শেষ) বেছে নিতে পারেন।4 জোর-শেষ প্রক্রিয়াকে সেভ শেষ করার আর সুযোগ দেওয়া হয় না।
ডিজাইন বিন্দু তাই এই দুটি।
- ক্লিনআপ সেই পরিমাণে রাখুন যা ৫ সেকেন্ডে শেষ হয়। Microsoft নিজেই সাধারণ কাজে ঘন ঘন ডেটা সেভ করার পরামর্শ দেয় যাতে শাটডাউনে কম সেভ করতে হয়, আর অসংরক্ষিত ডেটা অস্থায়ী জায়গায় সেভ করে পরের লঞ্চে ফেরান।1
- শাটডাউনের সময় নিশ্চিতকরণ ডায়ালগ দেখাবেন না। “সেভ করবেন?”-এ বসে থাকতে ৫ সেকেন্ড চলে যায়। চুপচাপ নিরাপদ পাশে পড়ুন (অটোসেভ)।
৩.৩. WinForms ও WPF-এ বাস্তবায়ন
.NET ডেস্কটপ অ্যাপে এই মেসেজ ফ্রেমওয়ার্ক ইভেন্টে অনুবাদ হয়। WinForms-এ FormClosing ওঠে, আর CloseReason বলে শাটডাউন কারণ কি না।
// WinForms: FormClosing is also raised on shutdown / sign-out
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.WindowsShutDown)
{
// Do only an idempotent snapshot save. Do not show a dialog.
// Do not set e.Cancel = true (refuse) either.
SaveWorkingStateToTempFile();
return;
}
// For ordinary closes such as the user clicking the × button, you may confirm here
}
WPF-এ Application.SessionEnding ইভেন্ট (XAML SessionEnding অ্যাট্রিবিউট, অথবা OnSessionEnding ওভাররাইড) মিলে।
flowchart TB
accTitle: WinForms/WPF ইভেন্ট মেসেজের সাথে কীভাবে ম্যাপ হয়
accDescr: WM_QUERYENDSESSION-এর কুয়েরি পর্যায় WinForms FormClosing ও WPF SessionEnding-এ ম্যাপ হয়, আর সেখানে সর্বোচ্চ idempotent স্ন্যাপশট সেভ। নিশ্চিত WM_ENDSESSION-এর মিল ইভেন্ট নেই, তাই WndProc বা হুকে নিয়ে শুধু নিশ্চিত হওয়ার পরে চলতে পারে এমন ক্লিনআপ করুন
q["WM_QUERYENDSESSION"] --> fc["WinForms: FormClosing"]
q --> se["WPF: SessionEnding"]
fc -.-> idem["শুধু idempotent স্ন্যাপশট"]
se -.-> idem
e["WM_ENDSESSION"] --> hook["ইভেন্ট নেই: WndProc হুক"]
hook -.-> final["নিশ্চিত হওয়ার পর ক্লিনআপ"]
চিত্র 4: WM_QUERYENDSESSION-এর কুয়েরি পর্যায় WinForms FormClosing ও WPF SessionEnding-এ ম্যাপ হয়, আর সেখানে সর্বোচ্চ idempotent স্ন্যাপশট সেভ। নিশ্চিত WM_ENDSESSION-এর মিল ইভেন্ট নেই, তাই WndProc বা হুকে নিয়ে শুধু নিশ্চিত হওয়ার পরে চলতে পারে এমন ক্লিনআপ করুন।
// WPF: App.xaml.cs
protected override void OnSessionEnding(SessionEndingCancelEventArgs e)
{
base.OnSessionEnding(e);
// You can distinguish ReasonSessionEnding.Logoff / Shutdown,
// but the baseline is to run the same snapshot save in either case
SaveWorkingStateToTempFile();
// Do not set e.Cancel = true unless you have an exceptional reason
}
এখানে একটি সতর্কতা আছে। FormClosing (CloseReason.WindowsShutDown) ও WPF-এর SessionEnding দুটোই কুয়েরি পর্যায় (WM_QUERYENDSESSION)-এর সাথে মিলে। অন্য অ্যাপ প্রত্যাখ্যান করলে শাটডাউন বাতিল হয় আর আপনার অ্যাপ চলতে থাকে। তাই এই ইভেন্টে যা করা যায় তা idempotent স্ন্যাপশট সেভ যা শাটডাউন বাতিল হলে ক্ষতি করে না আর যতবার চলুক একই ফল দেয়। “শুধু সত্যিই শেষ হলেই করতে হয় এমন ক্লিনআপ” (সংযোগ ছাড়া, সম্পদ ফেরানো ইত্যাদি) লাগলে নিশ্চিত WM_ENDSESSION (wParam=TRUE) সরাসরি WndProc-এ হুক করে সেখানে করুন।
যে পথেই হোক শরীর সাধারণ “স্ন্যাপশট সেভ” ফাংশনে ভাঁজ করুন আর সাধারণ প্রস্থান, শাটডাউন, আর (সম্ভব হলে) ক্র্যাশের জন্য ফেরানো ডেটা একই ফরম্যাটে লিখুন, যাতে পরের লঞ্চে ফেরানো লজিক এক পথ হয়। ক্র্যাশেও তথ্য রেখে যাওয়ার ডিজাইন “ক্র্যাশ হলে লগ ও ডাম্প রেখে যাওয়া Windows অ্যাপ ডিজাইন“-এ আছে।
৪. সত্যিই ব্লক করতে হলে — ShutdownBlockReasonCreate
মাঝপথে কাটলে শারীরিকভাবে ভাঙে এমন কাজ, যেমন CD বা ফার্মওয়্যার লেখা, ব্যতিক্রম। এখানে সঠিক চর্চা অবিচ্ছিন্ন কাজ শুরু হলে ShutdownBlockReasonCreate দিয়ে কারণ স্ট্রিং নিবন্ধ করা, আর শেষ হলেই ShutdownBlockReasonDestroy কল করা। শাটডাউন অনুরোধে সেই কারণ “এই অ্যাপ শাটডাউন আটকাচ্ছে” স্ক্রিনে দেখা যায়, আর ব্যবহারকারী চালিয়ে যাবেন না বাতিল করবেন সিদ্ধান্ত নিতে পারেন।3
flowchart TB
accTitle: ShutdownBlockReasonCreate দিয়ে সুরক্ষার প্রবাহ
accDescr: অবিচ্ছিন্ন কাজ শুরু হলে কারণ নিবন্ধ করুন; সুরক্ষাকালে শাটডাউন অনুরোধ এলে কারণ পূর্ণ স্ক্রিনে দেখা যায় আর WM_QUERYENDSESSION FALSE দিয়ে প্রত্যাখ্যাত হয়। ব্যবহারকারী বাতিল বা জোর করে চালাতে পারেন, আর কাজ শেষে কারণ খালি হয়
begin["অবিচ্ছিন্ন কাজ শুরু"] --> reg["ShutdownBlockReasonCreate"]
reg --> work["ওয়ার্কার থ্রেডে চালান"]
work --> done["শেষ: Destroy"]
req["এই সময়ে শাটডাউন"] --> show["কারণ দেখান + FALSE"]
show -->|"বাতিল"| work
show -->|"জোর করে চালাও"| kill["প্রক্রিয়া প্রস্থান"]
চিত্র 5: অবিচ্ছিন্ন কাজ শুরু হলে কারণ নিবন্ধ করুন; সুরক্ষাকালে শাটডাউন অনুরোধ এলে কারণ পূর্ণ স্ক্রিনে দেখা যায় আর WM_QUERYENDSESSION FALSE দিয়ে প্রত্যাখ্যাত হয়। ব্যবহারকারী বাতিল বা জোর করে চালাতে পারেন, আর কাজ শেষে কারণ খালি হয়।
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool ShutdownBlockReasonCreate(IntPtr hWnd, string pwszReason);
[DllImport("user32.dll", SetLastError = true)]
static extern bool ShutdownBlockReasonDestroy(IntPtr hWnd);
// Call from the thread that created the main window (it fails from other threads)
_criticalOperationInProgress = true;
ShutdownBlockReasonCreate(this.Handle, "Writing measurement data to a file");
try
{
// Run the uninterruptible operation on a worker thread. If you run it
// synchronously on the UI thread the message pump stops, and the process
// is force-continued as "Not Responding" before the WM_QUERYENDSESSION
// refusal code below can run
await Task.Run(() => WriteMeasurementData());
}
finally
{
ShutdownBlockReasonDestroy(this.Handle);
_criticalOperationInProgress = false;
}
// Also, refuse WM_QUERYENDSESSION with FALSE only while protected
protected override void WndProc(ref Message m)
{
const int WM_QUERYENDSESSION = 0x0011;
if (m.Msg == WM_QUERYENDSESSION && _criticalOperationInProgress)
{
m.Result = IntPtr.Zero; // Refuse. The registered reason string is shown in the full-screen UI
return;
}
base.WndProc(ref m);
}
এখানে সহজ ভুল বোঝাবুঝি ভূমিকার ভাগ। ShutdownBlockReasonCreate শুধু কারণ স্ট্রিং নিবন্ধ করে; নিজে শাটডাউন থামায় না। যা সত্যি শাটডাউন আটকায় তা আপনার নিজের হ্যান্ডলিং যা সুরক্ষা পতাকা সেট থাকাকালীন WM_QUERYENDSESSION-এ FALSE ফেরায়, উপরের মতো। দুটোকে সেট হিসেবে ব্যবহার করুন, আর কাজ শেষেই দুটো সঙ্গে সঙ্গে খালি করুন। এছাড়া সুরক্ষিত কাজ নিজে ওয়ার্কার থ্রেডে চালান আর UI থ্রেডকে মেসেজ প্রক্রিয়া করতে দিন — প্রত্যাখ্যান কৌশল তখনই কাজ করে যখন মেসেজ আসে (আর তবু ব্যবহারকারী ও OS জোর করে চালিয়ে যেতে পারে, তাই “না থামলেও” না ভাঙা লেখার ডিজাইন — অধ্যায় ৮ — এখনও দরকার)।
পরিচালনার তিনটি সতর্কতা আছে।
- কারণ স্ট্রিং ছোট ও নির্দিষ্ট রাখুন। ব্যবহারকারী তাড়াহুড়োয় আর কয়েক সেকেন্ডই পড়বেন। ডকুমেন্ট নিজেই “Burning a CD” উপযুক্ত উদাহরণ দেয়।3
- অ্যাপের পুরো জীবন নিবন্ধ রেখে দেবেন না। “শুধু অবিচ্ছিন্ন কাজ চলাকালীন” এটাই API ধরে।
- ব্লক করতে পারি এই ধারণায় ডিজাইন করবেন না। ব্যবহারকারী জোর করে চালাতে পারেন, আর জোর শাটডাউন (ENDSESSION_CRITICAL) আগে থেকেই অপেক্ষা করবে না। ডকুমেন্ট স্পষ্ট: “Applications should not depend on being able to block shutdown”।4
৫. কনসোল অ্যাপ ও ব্যাকগ্রাউন্ড প্রক্রিয়ার কেমন আচরণ করা উচিত
৫.১. SetConsoleCtrlHandler ও ছোট ছাড়
কনসোল অ্যাপ উইন্ডো মেসেজ পায় না, তাই নিয়ন্ত্রণ সিগন্যাল SetConsoleCtrlHandler দিয়ে নিবন্ধ হ্যান্ডলার ফাংশনে আসে। সিগন্যালপ্রতি ডিফল্ট ছাড় নিম্নরূপ।5
| সিগন্যাল | কখন হয় | ডিফল্ট ছাড় |
|---|---|---|
| CTRL_C_EVENT / CTRL_BREAK_EVENT | Ctrl+C / Ctrl+Break | টাইমআউট নেই |
| CTRL_CLOSE_EVENT | কনসোল বন্ধ, Task Manager “End task” (“Details” ট্যাব থেকে জোর করে প্রক্রিয়া মারা নোটিফিকেশনহীন সঙ্গে সঙ্গে প্রস্থান, আর এই টেবিলের বাইরে) | প্রায় ৫ সেকেন্ড |
| CTRL_SHUTDOWN_EVENT | সিস্টেম শাটডাউন (সার্ভিস প্রক্রিয়া) | প্রায় ২০ সেকেন্ড |
দেখার দুটি বিষয় আছে। প্রথম, মূলে শুধু সার্ভিস হিসেবে চলা প্রক্রিয়া CTRL_LOGOFF_EVENT ও CTRL_SHUTDOWN_EVENT পেতে পারে। ইন্টারঅ্যাকটিভ সেশনের অ্যাপ সাইন-আউটে শেষ হয়, তাই এই সিগন্যালের অপেক্ষা করা ডিজাইন দাঁড়ায় না।5 দ্বিতীয়, যে প্রক্রিয়া gdi32.dll বা user32.dll লোড করেছে তাকে কনসোল অ্যাপ ভাবলেও Windows অ্যাপ ধরা হয়, আর LOGOFF/SHUTDOWN হ্যান্ডলার ডাকা হয় না। সরকারি সমাধান লুকানো উইন্ডো বানিয়ে WM_QUERYENDSESSION/WM_ENDSESSION নেওয়া।6
flowchart TB
accTitle: কনসোল সিগন্যালপ্রতি ছাড়
accDescr: Ctrl+C ও Ctrl+Break-এর স্পষ্ট টাইমআউট নেই; কনসোল বন্ধে প্রায় ৫ সেকেন্ড আর সার্ভিস প্রক্রিয়ায় শাটডাউন সিগন্যালে প্রায় ২০ সেকেন্ড; অতিক্রম করলে প্রক্রিয়া জোর করে শেষ
ctrlc["CTRL_C / BREAK"] -->|"টাইমআউট নেই"| handler["HandlerRoutine ক্লিনআপ"]
closeev["CTRL_CLOSE"] -->|"প্রায় ৫ সেকেন্ড"| handler
shutev["CTRL_SHUTDOWN"] -->|"প্রায় ২০ সেকেন্ড"| handler
handler --> timeout["ছাড় শেষে জোর মারা"]
চিত্র 6: Ctrl+C ও Ctrl+Break-এর স্পষ্ট টাইমআউট নেই; কনসোল বন্ধে প্রায় ৫ সেকেন্ড আর সার্ভিস প্রক্রিয়ায় শাটডাউন সিগন্যালে প্রায় ২০ সেকেন্ড; অতিক্রম করলে প্রক্রিয়া জোর করে শেষ।
// Console app: clean up on Ctrl+C and console close
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetConsoleCtrlHandler(HandlerRoutine handler, bool add);
delegate bool HandlerRoutine(int ctrlType); // 2 = CTRL_CLOSE_EVENT
static readonly HandlerRoutine s_handler = OnCtrlEvent; // Keep a reference so GC does not collect it
static bool OnCtrlEvent(int ctrlType)
{
// Do only cleanup that finishes within 5 seconds
FlushAndCloseDataFile();
return false; // Proceed to the default handler; the process exits
}
static void Main()
{
SetConsoleCtrlHandler(s_handler, add: true);
// ...
}
৫.২. .NET-এর ফাঁদ — ProcessExit-এর উপর নির্ভর করবেন না
.NET-এ দীর্ঘদিন “AppDomain.ProcessExit-এ শুধু ক্লিনআপ করে দিন” স্টক আকৃতি ছিল, কিন্তু .NET 10 থেকে রানটাইম ডিফল্ট সমাপ্তি-সিগন্যাল হ্যান্ডলার দেয় না, আর CTRL_CLOSE_EVENT/CTRL_SHUTDOWN_EVENT-এ ProcessExit বা AssemblyLoadContext.Unloading কেউ চলে না। OS ডিফল্ট হ্যান্ডলার প্রক্রিয়া সঙ্গে সঙ্গে শেষ করে।7
flowchart TB
accTitle: .NET 10-এ ProcessExit কীভাবে বদলেছে
accDescr: .NET 9 পর্যন্ত রানটাইমের ডিফল্ট সিগন্যাল হ্যান্ডলার সমাপ্তি সিগন্যাল নিত, ProcessExit তুলত, তারপর প্রস্থান। .NET 10 থেকে রানটাইম ডিফল্ট হ্যান্ডলার দেয় না, OS ডিফল্ট হ্যান্ডলিং প্রক্রিয়া সঙ্গে সঙ্গে শেষ করে, আর হ্যান্ডলার আপনি নিজে নিবন্ধ করেন
sig["CTRL_CLOSE / SHUTDOWN"] --> old9[".NET 9 পর্যন্ত: ProcessExit"]
sig --> new10[".NET 10 থেকে: সঙ্গে সঙ্গে প্রস্থান"]
new10 -.-> alt["হ্যান্ডলার নিজে নিবন্ধ করুন"]
চিত্র 7: .NET 9 পর্যন্ত রানটাইমের ডিফল্ট সিগন্যাল হ্যান্ডলার সমাপ্তি সিগন্যাল নিত, ProcessExit তুলত, তারপর প্রস্থান। .NET 10 থেকে রানটাইম ডিফল্ট হ্যান্ডলার দেয় না, OS ডিফল্ট হ্যান্ডলিং প্রক্রিয়া সঙ্গে সঙ্গে শেষ করে, আর হ্যান্ডলার আপনি নিজে নিবন্ধ করেন।
বরং প্রতিটি অ্যাপ মডেলের মানক পথে যান।
- GUI অ্যাপ: আগের অধ্যায়ের FormClosing / SessionEnding
- Generic Host (Worker Serviceসহ): IHostApplicationLifetime ও BackgroundService.StopAsync। HostOptions.ShutdownTimeout দিয়ে থামার ছাড় স্পষ্ট করুন
- সাদা কনসোল অ্যাপ: SetConsoleCtrlHandler (অথবা PosixSignalRegistration দিয়ে SIGINT/SIGTERM সমতুল্য সাবস্ক্রাইব)
flowchart TB
accTitle: প্রতিটি অ্যাপ মডেল প্রস্থান নোটিফিকেশন কোথায় পায়
accDescr: GUI অ্যাপ FormClosing ও SessionEnding প্লাস নিশ্চিত কাজের জন্য WM_ENDSESSION হুক ব্যবহার করে; Generic Host IHostApplicationLifetime ও StopAsync; সাদা কনসোল অ্যাপ SetConsoleCtrlHandler বা PosixSignalRegistration। ProcessExit-এর উপর নির্ভরতা বাইরের-সিগন্যাল পথে চলে না
model{"কোন অ্যাপ মডেল?"}
model -->|"GUI"| gui["FormClosing / SessionEnding"]
model -->|"GUI নয়"| other{"Host না কনসোল?"}
gui -.-> guihook["ENDSESSION হুক"]
other -->|"Host"| host["Lifetime + StopAsync"]
other -->|"কনসোল"| con["SetConsoleCtrlHandler"]
host -.-> hostto["ShutdownTimeout সেট করুন"]
con -.-> ngx["ProcessExit-এ নির্ভর করবেন না"]
চিত্র 8: GUI অ্যাপ FormClosing ও SessionEnding প্লাস নিশ্চিত কাজের জন্য WM_ENDSESSION হুক ব্যবহার করে; Generic Host IHostApplicationLifetime ও StopAsync; সাদা কনসোল অ্যাপ SetConsoleCtrlHandler বা PosixSignalRegistration। ProcessExit-এর উপর নির্ভরতা বাইরের-সিগন্যাল পথে চলে না।
ছাড় পথভেদে আলাদা — GUI ও কনসোল বন্ধে প্রায় ৫ সেকেন্ড, সার্ভিসের জন্য অধ্যায় ৬-এর SCM ছাড় (প্রায় ২০ সেকেন্ড, অথবা PRESHUTDOWN-এর কনফিগার মান), আর Ctrl+C-তে স্পষ্ট টাইমআউট নেই। প্রতিটি পথেই তবে ছাড় সীমিত ও নির্ভরযোগ্য নয়, তাই ডিজাইন অক্ষ স্বাভাবিক ক্ষেত্র “প্রতিটি প্রক্রিয়া চেকপয়েন্টে আগেই সেভ”, “প্রস্থান ইভেন্টে কঠোর পরিশ্রম” নয়।
৬. Windows সার্ভিসের কেমন আচরণ করা উচিত — SHUTDOWN ও PRESHUTDOWN
৬.১. শাটডাউন নোটিফিকেশনের দুই ধরন
সার্ভিস সাইন-আউটে প্রভাবিত হয় না, কিন্তু শাটডাউন ও রিস্টার্টে থামে। নোটিফিকেশন Service Control Manager (SCM) থেকে কন্ট্রোল কোড হিসেবে আসে, আর পেতে গ্রহণ পতাকা ঘোষণা করতে হয়।8
| ঘোষণা | যে নোটিফিকেশন আসে | সময় ও ছাড় |
|---|---|---|
| SERVICE_ACCEPT_SHUTDOWN | SERVICE_CONTROL_SHUTDOWN | শাটডাউন প্রক্রিয়ার সময় জানানো। ডিফল্ট প্রায় ২০ সেকেন্ড, উপরের সীমা WaitToKillServiceTimeout |
| SERVICE_ACCEPT_PRESHUTDOWN | SERVICE_CONTROL_PRESHUTDOWN | SHUTDOWN-এর আগে জানানো। SCM সার্ভিস থামা বা টাইমআউট পর্যন্ত অপেক্ষা করে |
flowchart TB
accTitle: সার্ভিসে শাটডাউন নোটিফিকেশনের ক্রম
accDescr: শাটডাউন শুরু হলে PRESHUTDOWN ঘোষিত সার্ভিস আগে কনফিগার ছাড়সহ জানানো হয়, তারপর SHUTDOWN নোটিফিকেশন প্রায় ২০ সেকেন্ড ডিফল্টসহ পাঠানো হয়, আর ছাড় শেষে প্রক্রিয়া শেষ
start["শাটডাউন শুরু"] --> pre["PRESHUTDOWN(ঘোষিত হলে)"]
pre --> shut["SHUTDOWN(প্রায় ২০ সেকেন্ড)"]
shut --> kill["ছাড় শেষ → প্রস্থান"]
চিত্র 9: শাটডাউন শুরু হলে PRESHUTDOWN ঘোষিত সার্ভিস আগে কনফিগার ছাড়সহ জানানো হয়, তারপর SHUTDOWN নোটিফিকেশন প্রায় ২০ সেকেন্ড ডিফল্টসহ পাঠানো হয়, আর ছাড় শেষে প্রক্রিয়া শেষ।
PRESHUTDOWN টাইমআউট ChangeServiceConfig2 (SERVICE_CONFIG_PRESHUTDOWN_INFO) দিয়ে কনফিগার করা যায়; ডিফল্ট Windows 10 Creators Update (build 15063) থেকে ১০ সেকেন্ড, তার আগে ৩ মিনিট।9 যদি এখনও পুরনো জ্ঞানে কাজ করেন যে “PRESHUTDOWN ৩ মিনিট দেয়”, বর্তমান OS-এ প্রত্যাশিত ছাড়ের মাত্র ১/১৮। এছাড়া PRESHUTDOWN সেই অংশে পুরো সিস্টেমের শাটডাউন আটকে রাখে, তাই ডকুমেন্টও বলে এটি “শুধু বিশেষ পরিস্থিতিতে ব্যবহার করা উচিত”।8
হ্যান্ডলার-পাশের চর্চাও জরুরি। কন্ট্রোল হ্যান্ডলার ৩০ সেকেন্ডের মধ্যে ফিরতে হবে; সময়সাপেক্ষ থামার কাজ অন্য থ্রেডে রাখুন, SERVICE_STOP_PENDING রিপোর্ট করুন, আর সঙ্গে সঙ্গে ফিরুন।8
// Win32 service: accept PRESHUTDOWN and leave stop work to a worker
g_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN;
DWORD WINAPI ServiceHandlerEx(DWORD control, DWORD, LPVOID, LPVOID)
{
switch (control)
{
case SERVICE_CONTROL_PRESHUTDOWN:
case SERVICE_CONTROL_STOP:
ReportStatus(SERVICE_STOP_PENDING, /*waitHintMs*/ 3000);
SetEvent(g_stopEvent); // Tell the worker to stop and return immediately
return NO_ERROR;
}
return ERROR_CALL_NOT_IMPLEMENTED;
}
// Worker side: if cleanup runs longer than waitHint, keep reporting
// SERVICE_STOP_PENDING periodically while incrementing dwCheckPoint.
// The SCM judges "still alive and making progress" from waitHint and
// checkpoint advance. If reporting stops it can be treated as hung and
// shutdown can proceed. Always report SERVICE_STOPPED when finished
৬.২. ছাড়ের উপর নির্ভর করে না এমন ডিজাইন
ছাড়ের ছাদ WaitToKillServiceTimeout সার্ভিস পাশ থেকে লিখে বাড়ানো স্পষ্টভাবে সুপারিশ নয়। ডকুমেন্ট উল্টো চায় — সার্ভিসের ক্লিনআপ যত তাড়াতাড়ি সম্ভব শেষ করা উচিত যাতে UPS-চালিত মেশিন ব্যাটারি শেষ হওয়ার আগে শাটডাউন সম্পূর্ণ করতে পারে। পরামর্শ সাধারণ কাজে ঘন ঘন সেভ করা যাতে অসংরক্ষিত ডেটা ন্যূনতম থাকে, শাটডাউনে মেমরি খালি করতে সময় না খরচ করা, আর নেটওয়ার্ক পক্ষকে জানাতে খুব দীর্ঘ অপেক্ষা না করা। এছাড়া SCM শাটডাউনে ডিফল্টে নির্ভরতা দেখে না, তাই থামার প্রক্রিয়া “যে সার্ভিসের উপর নির্ভর করি সে আগে পড়ে গেলেও” কাজ করতে হবে।8
flowchart TB
accTitle: ছাড়ের উপর নির্ভর করে না এমন থামার প্রক্রিয়া ডিজাইন
accDescr: প্রতিটি প্রক্রিয়া চেকপয়েন্টে সেভ করলে অসংরক্ষিত ডেটা সবসময় ন্যূনতম থাকে, থামার নোটিফিকেশন এলে ক্লিনআপ কয়েক সেকেন্ডে শেষ হয়। প্রস্থানে সব সেভ করা ডিজাইন ছাড়ে মাপবে না, আর জোর-শেষ ডেটা হারায়
good["প্রতিটি চেকপয়েন্টে সেভ"] --> gstop["থামুন → ছোট সেভ → শেষ"]
bad["প্রস্থানে সব সেভ"] --> bstop["থামুন → সেভ ছাড় মিস করে"]
bstop --> killed["জোর মারা → ডেটা ক্ষতি"]
চিত্র 10: প্রতিটি প্রক্রিয়া চেকপয়েন্টে সেভ করলে অসংরক্ষিত ডেটা সবসময় ন্যূনতম থাকে, থামার নোটিফিকেশন এলে ক্লিনআপ কয়েক সেকেন্ডে শেষ হয়। প্রস্থানে সব সেভ করা ডিজাইন ছাড়ে মাপবে না, আর জোর-শেষ ডেটা হারায়।
.NET Worker Service (UseWindowsService)-এ SERVICE_CONTROL_STOP ও SHUTDOWN হোস্ট থামানোয় অনুবাদ হয়, আর BackgroundService.StopAsync ডাকা হয়। এই লেখার সময় স্টক বাস্তবায়ন STOP/SHUTDOWN পরিবার গ্রহণ করে; PRESHUTDOWNও লাগলে সম্প্রসারিত হ্যান্ডলার লাগে। যেভাবেই হোক HostOptions.ShutdownTimeout স্পষ্ট করুন আর StopAsync কয়েক সেকেন্ডে শেষ করুন। সার্ভিস তৈরির সাধারণ বিষয়ে “Windows সার্ভিস কীভাবে তৈরি ও চালাবেন” দেখুন।
৭. রিস্টার্টের পর স্বয়ংক্রিয় পুনরুদ্ধার
ডিভাইস PC বা অনাগত PC-তে ডিজাইন পরিসর শুধু “শাটডাউন সহ্য করা” নয়, “রিস্টার্টের পর নিজে ফেরা”ও।
৭.১. RegisterApplicationRestart ও পুনরুদ্ধার কলব্যাক
RegisterApplicationRestart কল করলে অ্যাপ ক্র্যাশ (আনহ্যান্ডলড এক্সেপশন), সাড়া না দেওয়া, আপডেট-চালিত অ্যাপ রিস্টার্ট, আর আপডেট-চালিত OS রিস্টার্ট-এর জন্য রিস্টার্ট প্রার্থী নিবন্ধ হয়। রিস্টার্টের কমান্ড-লাইন আর্গুমেন্ট নিবন্ধ করা যায়, তাই “কোন ফাইল খোলা ছিল” ও “কোন পুনরুদ্ধার বিন্দু” রাখলে রিস্টার্টের পর যেখানে ছেড়েছিলেন সেখান থেকে চালিয়ে যেতে পারেন।10
গ্রহণ করার স্পেস নিম্নরূপ।10
- নিবন্ধ সমস্যা হওয়ার আগে শেষ হতে হবে (আপডেট পরিস্থিতিতে WM_QUERYENDSESSION হ্যান্ডলিং শেষ সুযোগ)
- রিস্টার্ট লুপ আটকাতে ৬০ সেকেন্ডের কম চলা প্রক্রিয়া রিস্টার্ট হয় না
- উন্নীত চলা প্রক্রিয়া স্বয়ংক্রিয় রিস্টার্টের প্রার্থী নয় (উন্নয়ন সম্মতি ছাড়া প্রক্রিয়া আবার তৈরি হয় না)। উন্নয়ন লাগে এমন অ্যাপের স্বয়ংক্রিয় পুনরুদ্ধার UI মানক বিশেষাধিকারে রেখে বিশেষাধিকার কাজ সার্ভিসে আলাদা করে, অথবা Task Scheduler কাজ “সর্বোচ্চ বিশেষাধিকারে চালান” এর মতো স্পষ্ট লঞ্চ পথে ডিজাইন হয়
- ক্র্যাশ বা হ্যাং-এর পর রিস্টার্ট ব্যবহারকারীর সম্মতি দিয়ে যায়; আপডেটের পর রিস্টার্ট স্বয়ংক্রিয়
- OS রিস্টার্ট পার করে পুনরুদ্ধার করতে রিস্টার্ট চাওয়া পাশকে (ইনস্টলার ইত্যাদি) EWX_RESTARTAPPS / SHUTDOWN_RESTARTAPPS পতাকাসহ শাটডাউন API কল করতে হয়
RegisterApplicationRecoveryCallbackও নিবন্ধ করলে ক্র্যাশে WER (Windows Error Reporting) কলব্যাক ডাকে আর চলতি ডেটা সেভের ছাড় দেয়। সেভ সময় নিলে নিবন্ধে নির্দিষ্ট পিং ব্যবধানে ApplicationRecoveryInProgress বারবার কল করতে হয় নইলে পুনরুদ্ধার কাজ মাঝপথে কাটে। সেভ শেষে ApplicationRecoveryFinished দিয়ে সম্পূর্ণতা জানান। অ্যাপ-আপডেট সময়ে “ব্যবহারে থাকা ফাইল বদলে রিস্টার্ট” Restart Manager-এর এলাকা, বিস্তারে “ব্যবহারে থাকা exe বা DLL কীভাবে বদলাবেন“-এ।
৭.২. ARSO — আপডেট রিস্টার্টের পর স্বয়ংক্রিয় সাইন-ইন
Windows Update রিস্টার্টের পর কেউ সাইন-ইন না করলে ব্যবহারকারী-সেশন অ্যাপ ফেরে না। সেই ফাঁক ভরে ARSO (Winlogon Automatic Restart Sign-On)। Windows Update রিস্টার্ট শুরু করলে শেষ ইন্টারঅ্যাকটিভ ব্যবহারকারীর ক্রেডেনশিয়াল নিরাপদে সেভ করে, Autologon কনফিগার করে, আর রিস্টার্টের পর সেই ব্যবহারকারীকে স্বয়ংক্রিয় সাইন-ইন করে তারপর স্ক্রিন লক করে।11 shutdown /g এর মতো কমান্ডও আছে যা রিস্টার্ট প্লাস নিবন্ধ অ্যাপ পুনরায় শুরু চায়। কিছু পরিবেশ সংগঠন নীতি (DisableAutomaticRestartSignOn ইত্যাদি) দিয়ে এটি বন্ধ করে, তাই অনাগত পুনরুদ্ধার ডিজাইন করলে এই সেটিং সেট হিসেবে দেখুন। আর সবসময় দরকার এমন ব্যাকগ্রাউন্ড কাজের জন্য ব্যবহারকারী সেশনে স্বয়ংক্রিয় লঞ্চের উপর নির্ভর করলে সঠিক পদক্ষেপ শুরু থেকে Windows সার্ভিস করা।
flowchart TB
accTitle: রিস্টার্টের পর অ্যাপ স্বয়ংক্রিয় কীভাবে ফেরে
accDescr: সমস্যার আগে RegisterApplicationRestart নিবন্ধ করলে ক্র্যাশ বা সাড়া না দেওয়ায় ব্যবহারকারীর সম্মতির পর অ্যাপ রিস্টার্ট হয়, আর আপডেট-চালিত রিস্টার্টে ARSO স্বয়ংক্রিয় সাইন-ইন ও স্ক্রিন লকের পর। ৬০ সেকেন্ডের কম রানটাইম ও উন্নীত প্রক্রিয়া পরিসরের বাইরে
reg["RegisterApplicationRestart"]
reg --> crash["ক্র্যাশ বা হ্যাং"]
reg --> update["আপডেট রিস্টার্ট"]
crash -->|"সম্মতি"| restart["অ্যাপ রিস্টার্ট"]
update --> arso["ARSO সাইন-ইন + লক"]
arso --> restart
restart -.-> limits["নয়: ৬০ সেকেন্ডের কম / উন্নীত"]
চিত্র 11: সমস্যার আগে RegisterApplicationRestart নিবন্ধ করলে ক্র্যাশ বা সাড়া না দেওয়ায় ব্যবহারকারীর সম্মতির পর অ্যাপ রিস্টার্ট হয়, আর আপডেট-চালিত রিস্টার্টে ARSO স্বয়ংক্রিয় সাইন-ইন ও স্ক্রিন লকের পর। ৬০ সেকেন্ডের কম রানটাইম ও উন্নীত প্রক্রিয়া পরিসরের বাইরে।
৮. নোটিফিকেশনহীন বিদ্যুৎ বিচ্ছিন্নতা সহ্য করা — লেখার ডিজাইন ও UPS
৮.১. এমন লেখা যা “যখনই কাটুক না ভাঙে” — অস্থায়ী ফাইল + ReplaceFile
ট্রিপ হওয়া ব্রেকার, ফেল PSU, বা টানা প্লাগ WM_ENDSESSIONও আনে না PRESHUTDOWNও না। সেটিং বা মাপের ফলের জন্য “মূল ফাইল জায়গায় ওভাররাইট” করলে লিখতে লিখতে বিদ্যুৎ কাটলে পুরনো-নতুন মেশানো ভাঙা ফাইল থেকে যেতে পারে।
মানক আকৃতি একই ভলিউমে অস্থায়ী ফাইলে পুরো লিখে তারপর অদলবদল। ReplaceFile “নতুন ফাইলে সেভ → মূল সরিয়ে রাখা → নাম বদল → মুছে ফেলা” ক্রম এক API-তে প্যাক করে, আর মূল ফাইলের তৈরির সময়, ACL, ও অল্টারনেট স্ট্রিমের মতো গুণও নিয়ে যায় (তিন ফাইল একই ভলিউমে থাকতে হবে)।12 .NET-এর File.Replace এটি যেমন তেমন কল করে।
flowchart TB
accTitle: অস্থায়ী ফাইল ও ReplaceFile দিয়ে সেভ ও পুনরুদ্ধার প্রবাহ
accDescr: সেভে অস্থায়ী ফাইলে পুরো লিখুন, ফ্লাশ করুন, আর ReplaceFile দিয়ে অদলবদল করুন, পুরনো বিষয়বস্তু .bak-এ রাখুন। পরের লঞ্চে প্রাথমিক ফাইল যাচাই করুন আর ভাঙা হলে .bak-এ যান
subgraph save["সেভে"]
w["পুরো অস্থায়ী ফাইল লিখুন"] --> f["ডিস্কে ফ্লাশ"]
f --> r["ReplaceFile → .bak"]
end
subgraph startup["পরের লঞ্চে"]
v["প্রাথমিক যাচাই"]
v -->|"অক্ষত"| use["যেমন আছে ব্যবহার"]
v -->|"ভাঙা"| bak[".bak-এ যান"]
end
r -.->|"যে ধাপেই বিদ্যুৎ কাটুক"| v
চিত্র 12: সেভে অস্থায়ী ফাইলে পুরো লিখুন, ফ্লাশ করুন, আর ReplaceFile দিয়ে অদলবদল করুন, পুরনো বিষয়বস্তু .bak-এ রাখুন। পরের লঞ্চে প্রাথমিক ফাইল যাচাই করুন আর ভাঙা হলে .bak-এ যান।
// The standard pattern for settings and data: write completely to a temporary file, then swap, and keep the old contents
public static void SaveAtomically(string path, string content)
{
string dir = Path.GetDirectoryName(path)!;
string tmp = Path.Combine(dir, Path.GetRandomFileName()); // Create it on the same volume
try
{
using (var fs = new FileStream(tmp, FileMode.CreateNew, FileAccess.Write))
using (var writer = new StreamWriter(fs))
{
writer.Write(content);
writer.Flush();
fs.Flush(flushToDisk: true); // FlushFileBuffers equivalent. Write the OS buffer
// out to disk (device-side cache limits are in 8.2)
}
if (File.Exists(path))
File.Replace(tmp, path, path + ".bak"); // Calls ReplaceFile. Keep the old contents as .bak
else
File.Move(tmp, path);
}
catch
{
// If we fail mid-way, do not leave the temporary file. Repeated failures
// of a periodic save would fill the volume with complete copies
try { File.Delete(tmp); } catch { /* Prefer the original exception if delete fails */ }
throw;
}
}
এতে সাধারণ কাজ সবসময় হয় “পুরো পুরনো ফাইল” না হয় “পুরো নতুন ফাইল” পড়তে দেয়। তবে ReplaceFile বহু-ধাপ নেমস্পেস কাজ, আর বিদ্যুৎ কাটার উপর পরমাণবিকতা স্পেসে গ্যারান্টি নয়। তাই উপরের উদাহরণ ব্যাকআপ (.bak) রাখে — পড়ার পাশ লঞ্চে প্রাথমিক ফাইল যাচাই করে ভাঙা হলে ব্যাকআপে যায়, সেট হিসেবে। শুধু-যোগ লগ বা CSV-তে এটি ব্যবহার করা যায় না, তাই সেগুলো ভাঙন ভিতরে গড়া ফরম্যাট ব্যবহার করে, যেমন “এক লাইন = এক রেকর্ড, আর পড়তে ভাঙা শেষ লাইন ফেলে দিন”।
৮.২. WriteFile-এর সাফল্য ডিস্কে পৌঁছানো নয়
অন্য ধারণা WriteFile সাফল্য ফেরালেও ডেটা শুধু OS ক্যাশে থাকতে পারে। Windows ফাইল পড়া-লেখা সিস্টেম বাফারে রাখে আর অলস লেখায় সময়ে সময়ে ডিস্কে প্রতিফলিত করে। ডেটা নিশ্চিত ডিস্কে নিতে FlushFileBuffers দিয়ে স্পষ্ট ফ্লাশ করুন, অথবা CreateFile-এ FILE_FLAG_WRITE_THROUGH নির্দিষ্ট করুন যাতে প্রতিটি লেখা ক্যাশ পার হয়। ফাইল-সিস্টেম মেটাডেটা সবসময় ক্যাশ হয়, তাই মেটাডেটা নিশ্চিত করতেও ফ্লাশ বা write-through লাগে।13
প্রতিবার FlushFileBuffers কল অদক্ষ, তবে, আর ডকুমেন্টও ঘন কলের বদলে FILE_FLAG_NO_BUFFERING+WRITE_THROUGH ভাবার উৎসাহ দেয়।13 বাস্তবে “শুধু লেনদেন চেকপয়েন্টে বা ফাইল বন্ধের ঠিক আগে ফ্লাশ” বাস্তবসম্মত আপস। এই স্তরের যান্ত্রিকতা — ক্যাশ ম্যানেজার, অলস লেখা, আর হার্ডওয়্যার ক্যাশের কারণে “ফ্লাশ করলাম তবু ডিস্কে নাও পৌঁছাতে পারে” — গভীরে “Cache Manager: আপনার WriteFile আসলে ডিস্কে কখন পৌঁছায়?“-এ আছে।
৮.৩. UPS ও ব্যাটারি নিরীক্ষণ — বিদ্যুৎ বিচ্ছিন্নতাকে শাটডাউন বানানো
ডিভাইস PC-তে বিদ্যুৎ বিচ্ছিন্নতার আসল প্রতিকার UPS। UPS-এর ভূমিকা “বিদ্যুৎ বিভ্রাট থামানো” নয়, “নোটিফিকেশনহীন বিদ্যুৎ বিচ্ছিন্নতা”কে “নোটিফিকেশনসহ পরিকল্পিত শাটডাউন” বানানো ধরুন। ডিজাইন দুই-ধাপ সেটআপ।
- ছাড় ডিজাইন: UPS ব্যাটারি হোল্ড সময় > “ব্যাটারি সুইচ ধরুন → অ্যাপ ও সার্ভিস ক্লিনআপ → OS শাটডাউন সম্পূর্ণ”-এর যোগ। সার্ভিস থামার প্রক্রিয়া ধীর হলে এই সমীকরণ দাঁড়ায় না (খণ্ড ৬.২)
- ধরা: AC থেকে ব্যাটারি সুইচ, আর অবশিষ্ট ক্ষমতা কম, PBT_APMPOWERSTATUSCHANGE ইভেন্টে জানানো হয়। উইন্ডোওয়ালা অ্যাপ এটি WM_POWERBROADCAST হিসেবে পায়; উইন্ডোহীন সার্ভিস SERVICE_ACCEPT_POWEREVENT ঘোষণা করে HandlerEx-এ SERVICE_CONTROL_POWEREVENT হিসেবে পায় (WM_POWERBROADCAST সার্ভিস কন্ট্রোল হ্যান্ডলারে আসে না)। পেলে GetSystemPowerStatus কল করুন, ACLineStatus (AC-তে কি না) ও BatteryLifePercent দেখুন, আর মাপ থামানো, সেভ, আর শাটডাউন অনুরোধে নিয়ে যান15
flowchart TB
accTitle: UPS দিয়ে বিদ্যুৎ বিচ্ছিন্নতাকে পরিকল্পিত শাটডাউন বানানোর প্রবাহ
accDescr: বিভ্রাটে UPS ব্যাটারিতে গেলে PBT_APMPOWERSTATUSCHANGE জানানো হয়, পাওয়ার স্টেট যাচাই হয়, আর সেভ প্লাস শাটডাউন অনুরোধ নোটিফিকেশনহীন বিদ্যুৎ বিচ্ছিন্নতাকে নোটিফিকেশনসহ পরিকল্পিত শাটডাউনে বদলায়
outage["বিভ্রাট"] --> ups["UPS ব্যাটারিতে"]
ups --> pbt["PBT_APMPOWERSTATUSCHANGE"]
pbt --> check["GetSystemPowerStatus"]
check --> saveop["থামান ও সেভ করুন"]
saveop --> req["শাটডাউন অনুরোধ"]
req --> normal["সাধারণ নোটিফিকেশন প্রবাহ(৩ থেকে ৬)"]
চিত্র 13: বিভ্রাটে UPS ব্যাটারিতে গেলে PBT_APMPOWERSTATUSCHANGE জানানো হয়, পাওয়ার স্টেট যাচাই হয়, আর সেভ প্লাস শাটডাউন অনুরোধ নোটিফিকেশনহীন বিদ্যুৎ বিচ্ছিন্নতাকে নোটিফিকেশনসহ পরিকল্পিত শাটডাউনে বদলায়।
সাধারণ USB-জোড়া UPS Windows-এ ব্যাটারি হিসেবে দেখায়, তাই এই মানক API দিয়ে ধরা যায়। ভেন্ডর ম্যানেজমেন্ট সফটওয়্যারে “N% অবশিষ্টে OS শাটডাউন” সুবিধা থাকলে সীমা অ্যাপের ক্লিনআপ সময়ের সাথে মেলে কি না তাও দেখুন। ঘুম বা হাইবারনেশন থেকে জাগরণ, আর দীর্ঘসময় চলা সমস্যা, আলাদা অক্ষ, “ঘুম, হাইবারনেশন, Modern Standby, ও দীর্ঘসময় চলা অ্যাপ“-এ।
৯. কীভাবে যাচাই করবেন — শাটডাউন নিরাপদে চেষ্টা
শাটডাউন হ্যান্ডলিং “লিখেছি কিন্তু উৎপাদন-সমান অবস্থায় কখনো চেষ্টা করিনি” হয়ে যায়। নিরাপদে যাচাই করার পদ্ধতি রাখুন।
- পরীক্ষা মেশিন বা VM-এ চেষ্টা করুন: প্রথমে উৎপাদন ডিভাইস PC-তে চেষ্টা করবেন না। Hyper-V চেকপয়েন্ট (স্ন্যাপশট) থাকা পরীক্ষা পরিবেশে শাটডাউন, রিস্টার্ট, আর জোর বিদ্যুৎ বিচ্ছিন্নতা (VM বন্ধ) পুনরাবৃত্তি করুন। তবে VM “পাওয়ার অফ” শুধু “অতিথি OS নোটিস ছাড়া থামা” পুনরুৎপাদন করে; ভৌত ডিস্কের অস্থির ক্যাশ বা কন্ট্রোলার-নির্ভর ভাঙন নয়। ডিভাইস PC হিসেবে পাঠালে চূড়ান্ত পরীক্ষা উৎপাদন-সমান হার্ডওয়্যারে আসল বিদ্যুৎ-কাটা পরীক্ষা
- সাইন-আউট দিয়ে দ্রুত পরীক্ষা: WM_QUERYENDSESSION → WM_ENDSESSION পথ সাইন-আউটেও চলে (পার্থক্য শুধু lParam-এ ENDSESSION_LOGOFF বিট), তাই ডেভেলপমেন্ট মেশিনে ক্লিনআপ-কোড আচরণ সুবিধাজনকভাবে নিশ্চিত করা যায়1
- পূর্ণ শাটডাউন ও হাইব্রিড আলাদা চেষ্টা করুন:
shutdown /s /t 0(পূর্ণ),shutdown /s /hybrid /t 0(ডিফল্ট আচরণ), আরshutdown /r /t 0(রিস্টার্ট) প্রতিটি চেষ্টা করুন2 - ক্লিনআপ কত সময় নেয় মাপুন: ক্লিনআপ ফাংশনের শুরু ও শেষে লগে টাইমস্ট্যাম্প লিখুন, আর মাপুন ৫ সেকেন্ডে (বা সার্ভিসের কনফিগার ছাড়ে) মাপে কি না
flowchart TB
accTitle: যাচাইয়ের কাজ ও প্রতিটি কী নিশ্চিত করতে পারে
accDescr: সাইন-আউট নোটিফিকেশন পথের সুবিধাজনক পরীক্ষা; শাটডাউন-কমান্ড পূর্ণ, হাইব্রিড ও রিস্টার্ট উৎপাদন নোটিফিকেশন পথ ও ছাড় নিশ্চিত করে; VM পাওয়ার-অফ হঠাৎ-থামার সহনশীলতা পরীক্ষা করে; ভৌত বিদ্যুৎ-কাটা চূড়ান্ত পরীক্ষা যাতে ভৌত স্টোরেজ অন্তর্ভুক্ত
signtest["সাইন-আউট"] -.-> path1["QUERY → ENDSESSION পথ"]
signtest --> shuttest["shutdown /s /hybrid /r"]
shuttest -.-> path2["উৎপাদন পথ + ছাড়"]
shuttest --> vmtest["VM পাওয়ার-অফ"]
vmtest -.-> path3["অতিথি হঠাৎ থামা"]
vmtest --> hwtest["ভৌত বিদ্যুৎ-কাটা"]
hwtest -.-> path4["স্টোরেজসহ(চূড়ান্ত)"]
চিত্র 14: সাইন-আউট নোটিফিকেশন পথের সুবিধাজনক পরীক্ষা; শাটডাউন-কমান্ড পূর্ণ, হাইব্রিড ও রিস্টার্ট উৎপাদন নোটিফিকেশন পথ ও ছাড় নিশ্চিত করে; VM পাওয়ার-অফ হঠাৎ-থামার সহনশীলতা পরীক্ষা করে; ভৌত বিদ্যুৎ-কাটা চূড়ান্ত পরীক্ষা যাতে ভৌত স্টোরেজ অন্তর্ভুক্ত।
পরের আলাদা করার জন্য ইভেন্ট লগ (System) কাজে লাগে। সাধারণ শাটডাউন বা রিস্টার্টে ইভেন্ট ID 1074 (কোন প্রক্রিয়া শাটডাউন শুরু করেছে, কার জন্য, কোন কারণে) নথিভুক্ত হয়। হঠাৎ বিদ্যুৎ বিচ্ছিন্নতা বা ক্র্যাশে 1074 থাকে না, আর পরের বুটে ইভেন্ট ID 41 (Kernel-Power) ও 6008 (আগের সিস্টেম শাটডাউন অপ্রত্যাশিত ছিল) নথিভুক্ত হয়।14 “রাতে কী হয়েছিল” এখান থেকে শুরু।
# Check the recent history of shutdown-related events
Get-WinEvent -FilterHashtable @{ LogName = 'System'; Id = 1074, 6008, 41 } -MaxEvents 20 |
Select-Object TimeCreated, Id, ProviderName, Message |
Format-List
1074 “Windows Update দিয়ে রিস্টার্ট” দেখালে আর অ্যাপের ডেটা ভাঙা থাকলে সমস্যা ক্লিনআপ কোড। 6008/41 শুধু “অপ্রত্যাশিত শাটডাউন” দেখায়; সেগুলো ব্লু-স্ক্রিন (ক্র্যাশ) বা জোর রিসেটেও নথিভুক্ত হয়, শুধু বিদ্যুৎ বিচ্ছিন্নতায় নয়। 41-এর BugcheckCode শূন্যেতর হলে ক্র্যাশ; ০ হলে আর মেমরি ডাম্পও না থাকলে বিদ্যুৎ বিচ্ছিন্নতা সম্ভাব্য — আশপাশের তথ্য থেকে কারণ আলাদা করুন, আর বিদ্যুৎ বিচ্ছিন্নতা জানলে অধ্যায় ৮-এর লেখার ডিজাইন ও UPS পরের ধাপ।
১০. সারসংক্ষেপ
- শাটডাউন “স্বাভাবিক ইভেন্ট যা দেরিতে হোক তাড়াতাড়ি আসবে”। নোটিফিকেশনের পর ছাড় নীতিগতভাবে প্রায় ৫ সেকেন্ডই, তাই পূর্বশর্ত ঘন ঘন অটোসেভ যাতে “প্রস্থানে যা করেন” ন্যূনতম থাকে।
- Windows 8 থেকে পরের ক্লায়েন্ট OS-এ fast startup চালু থাকলে Shut down hybrid shutdown আর কার্নেল শুধু হাইবারনেট করছে। পূর্ণ রিসেট শুধু Restart — ঘটনা পদ্ধতিতে Restart লিখুন।
- GUI অ্যাপ WM_QUERYENDSESSION-এ সঙ্গে সঙ্গে TRUE ফেরায়, আর নিশ্চিত ক্লিনআপ WM_ENDSESSION-এ করে। WinForms/WPF FormClosing ও SessionEnding কুয়েরি পর্যায়ের সাথে মিলে, তাই সেখানে সর্বোচ্চ idempotent স্ন্যাপশট সেভ। শাটডাউনের সময় ডায়ালগ দেখাবেন না।
- সত্যিই মাঝপথে কাটা যায় না এমন কাজ ShutdownBlockReasonCreate দিয়ে কারণ দেখিয়ে সুরক্ষিত হয়। তবে কোথাও গ্যারান্টি নেই যে ব্লক করতে পারবেন।
- কনসোল অ্যাপ নোটিফিকেশন পায় SetConsoleCtrlHandler দিয়ে; সার্ভিস SERVICE_ACCEPT_PRESHUTDOWN/SHUTDOWN দিয়ে। বর্তমান OS-এ ডিফল্ট PRESHUTDOWN ছাড় ১০ সেকেন্ড। .NET-এ ProcessExit-এর উপর নির্ভরতা ছেড়ে অ্যাপ মডেলের মানক পথে যান।
- রিস্টার্টের পর পুনরুদ্ধার RegisterApplicationRestart (প্লাস পুনরুদ্ধার কলব্যাক) ও ARSO দিয়ে অনাগত হতে পারে।
- বিদ্যুৎ বিচ্ছিন্নতা কোনো নোটিফিকেশন আনে না। অস্থায়ী-ফাইল + ReplaceFile অদলবদল (ব্যাকআপ + লোড-সময় যাচাইয়ের সেটসহ), চেকপয়েন্টে ফ্লাশ, আর UPS যা “বিদ্যুৎ বিচ্ছিন্নতাকে পরিকল্পিত শাটডাউন বানায়” দিয়ে প্রস্তুতি নিন।
flowchart TB
accTitle: শাটডাউন হ্যান্ডলিংয়ের সামগ্রিক ছবি
accDescr: নোটিফিকেশনসহ শেষের জন্য কয়েক সেকেন্ডে দোকান বন্ধ করতে পারা ক্লিনআপ ও রিস্টার্টের পর স্বয়ংক্রিয় পুনরুদ্ধার; নোটিফিকেশনহীন বিদ্যুৎ বিচ্ছিন্নতার জন্য যখনই কাটুক না ভাঙা লেখা ও UPS, ভৌত হার্ডওয়্যারসহ যাচাই। এই দুই স্তম্ভ নিবন্ধের উপসংহার
ending{"কীভাবে শেষ হয়"}
ending -->|"নোটিফিকেশনসহ"| pillar1["কয়েক-সেকেন্ড ক্লিনআপ(৩ থেকে ৬)"]
ending -->|"নোটিফিকেশন নেই"| pillar2["নিরাপদ লেখা + UPS(৮)"]
pillar1 --> recover["রিস্টার্টের পর স্বয়ংক্রিয় পুনরুদ্ধার(৭)"]
pillar2 --> verifytest["হার্ডওয়্যারে যাচাই(৯)"]
চিত্র 15: নোটিফিকেশনসহ শেষের জন্য কয়েক সেকেন্ডে দোকান বন্ধ করতে পারা ক্লিনআপ ও রিস্টার্টের পর স্বয়ংক্রিয় পুনরুদ্ধার; নোটিফিকেশনহীন বিদ্যুৎ বিচ্ছিন্নতার জন্য যখনই কাটুক না ভাঙা লেখা ও UPS, ভৌত হার্ডওয়্যারসহ যাচাই। এই দুই স্তম্ভ নিবন্ধের উপসংহার।
- VM ও সাইন-আউট দিয়ে নিরাপদে যাচাই করুন, আর পরে ইভেন্ট ID 1074/41/6008 দিয়ে আলাদা করুন।
পরেরবার অ্যাপে ফিচার যোগ করার সময় নিজেকে একবার জিজ্ঞাসা করুন: এই কাজের মাঝে WM_ENDSESSION এলে, অথবা বিদ্যুৎ টানা হলে, পরের লঞ্চে কী থাকে? সেই উত্তর ডিজাইনে লেখা ডিভাইস PC-র সামনে সকালে মাথা ধরে দাঁড়াতে না হওয়ার সবচেয়ে ছোট পথ।
সম্পর্কিত নিবন্ধ
- ব্যবহারে থাকা exe বা DLL কীভাবে বদলাবেন — Restart Manager ও স্বয়ংক্রিয় আপডেটে “File In Use” সমস্যা
- Windows সার্ভিস কীভাবে তৈরি ও চালাবেন ── Task Scheduler ও সার্ভিসের মধ্যে বেছে BackgroundService-কে Windows সার্ভিস বানানো
- ঘুম, হাইবারনেশন, Modern Standby, ও দীর্ঘসময় চলা অ্যাপ — ‘সারারাত থেমে গেল’ ঘিরে ডিজাইন
- Windows I/O-এর গভীরতা(পর্ব ৪)— Cache Manager: আপনার WriteFile আসলে ডিস্কে কখন পৌঁছায়?
- ক্র্যাশ হলে লগ ও ডাম্প রেখে যাওয়া Windows অ্যাপ ডিজাইন
- Windows অ্যাপে চাইল্ড প্রক্রিয়া নিরাপদে সামলানোর চেকলিস্ট
সম্পর্কিত পরামর্শ ক্ষেত্র
KomuraSoft LLC ডিভাইস-PC ও দীর্ঘসময় চলা অ্যাপের জন্য শাটডাউন ও বিদ্যুৎ-বিচ্ছিন্নতা প্রতিকারের ডিজাইন ও বাস্তবায়ন, Windows Update রিস্টার্ট বা সাইন-আউট থেকে শুরু ডেটা নষ্ট ও “সকাল পর্যন্ত থেমে ছিল” ঘটনার মূল কারণ অনুসন্ধান, আর Windows সার্ভিস থামার প্রক্রিয়া ও স্বয়ংক্রিয় পুনরুদ্ধারের ডিজাইন রিভিউ করে। “প্রতি শাটডাউনে কিছু ভাঙে মনে হয়, আর কোথা থেকে শুরু জানি না” ধাপ থেকে শুরু করা ঠিক আছে।
- Windows অ্যাপ্লিকেশন ডেভেলপমেন্ট
- বাগ অনুসন্ধান ও মূল কারণ বিশ্লেষণ
- টেকনিক্যাল কনসালটিং ও ডিজাইন রিভিউ
- যোগাযোগ করুন
তথ্যসূত্র
-
Microsoft Learn, WM_QUERYENDSESSION message. যে WM_QUERYENDSESSION সেশন শেষে পাঠানো হয় আর অ্যাপের TRUE ফেরিয়ে ব্যবহারকারীর ইচ্ছা সম্মান করা উচিত (DefWindowProc-এর ডিফল্টও TRUE); যে ক্লিনআপ WM_ENDSESSION পর্যন্ত স্থগিত রাখা উচিত; যে ৫ সেকেন্ড পর সিস্টেম শাটডাউন আটকানো অ্যাপের জন্য UI দেখায় আর ব্যবহারকারী জোর করে শেষ করতে পারেন; lParam-এ ENDSESSION_LOGOFF/CLOSEAPP/CRITICAL বিটের অর্থ; যে শাটডাউন ও রিস্টার্ট আলাদা করা যায় না; আর যে ডেটা ঘন ঘন সেভ করা উচিত যাতে প্রস্থানে কম সেভ করতে হয়। ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
Microsoft Learn, Fast startup causes hibernation or shutdown to fail in Windows 10 or Windows 8.1. যে fast startup-এ কার্নেল সেশন বন্ধ হয় না ও হাইবারনেশন ধরা হয়, আর কার্নেল ও ডিভাইস-ড্রাইভার স্টেট hiberfil.sys-এ সেভ হয়; যে “Restart” সবসময় পূর্ণ বুট করে কারণ পুরোপুরি নতুন Windows স্টেট লাগে; যে fast startup ডিফল্টে চালু আর বন্ধ করা সুপারিশ নয়; আর যে Shutdown.exe-এর ডিফল্ট পূর্ণ শাটডাউন, /hybrid অপশন হাইব্রিড আচরণ দেয়। ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, ShutdownBlockReasonCreate function (winuser.h). যে অবিচ্ছিন্ন কাজ শুরুতে কারণ স্ট্রিং নিবন্ধ করতে কল করুন আর শেষে ShutdownBlockReasonDestroy কল করুন; যে এটি শুধু যে থ্রেড উইন্ডো বানিয়েছে সেখান থেকে কল করা যায়; আর যে ব্যবহারকারী কারণ কয়েক সেকেন্ডই পড়বেন, তাই স্ট্রিং ছোট ও স্পষ্ট হোক। ↩ ↩2 ↩3
-
Microsoft Learn, Shutdown Changes for Windows Vista. যে WM_QUERYENDSESSION/WM_ENDSESSION-এর উত্তর প্রতিটিতে ৫ সেকেন্ড দেরি করা যায় আর তখন ব্যবহারকারী চালিয়ে যাওয়া বা বাতিল বেছে নিতে পারেন; যে কনসোল অ্যাপ বা দৃশ্যমান উইন্ডোহীন অ্যাপ শাটডাউন বাতিল করতে পারে না আর ৫ সেকেন্ড সাড়া না দিলে বা FALSE ফেরালে স্বয়ংক্রিয় শেষ হয়; যে ব্লক লাগলে ShutdownBlockReasonCreate দিয়ে কারণ নিবন্ধ করা উচিত; আর যে অ্যাপ শাটডাউন ব্লক করতে পারার উপর নির্ভর করবে না। ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, HandlerRoutine callback function. SetConsoleCtrlHandler দিয়ে নিবন্ধ হ্যান্ডলার যে CTRL_C/BREAK/CLOSE/LOGOFF/SHUTDOWN ইভেন্ট পায়; যে CTRL_CLOSE_EVENT-এর ডিফল্ট টাইমআউট প্রায় ৫০০০ মিলিসেকেন্ড আর সার্ভিস প্রক্রিয়ায় CTRL_SHUTDOWN_EVENT প্রায় ২০০০০ মিলিসেকেন্ড; যে CTRL_LOGOFF/SHUTDOWN_EVENT মূলে শুধু সার্ভিস পায় কারণ ইন্টারঅ্যাকটিভ অ্যাপ লগঅফে শেষ হয়; আর যে হ্যান্ডলার আলাদা থ্রেডে চলে। ↩ ↩2 ↩3
-
Microsoft Learn, SetConsoleCtrlHandler function. যে gdi32.dll বা user32.dll লোড করা প্রক্রিয়া Windows অ্যাপ ধরা হয় আর CTRL_LOGOFF_EVENT/CTRL_SHUTDOWN_EVENT হ্যান্ডলার ডাকা হয় না; যে সমাধান লুকানো উইন্ডো বানিয়ে WM_QUERYENDSESSION/WM_ENDSESSION সামলানো; আর যে সিগন্যাল হ্যান্ডলিংয়ের সময় কনসোল ফাংশন সঠিক কাজ নাও করতে পারে। ↩ ↩2
-
Microsoft Learn, .NET runtime no longer provides default termination signal handlers. যে .NET 10 থেকে রানটাইম Windows CTRL_SHUTDOWN_EVENT/CTRL_CLOSE_EVENT (Unix SIGTERM/SIGHUP সমতুল্য)-এর ডিফল্ট হ্যান্ডলার দেয় না; যে OS ডিফল্ট হ্যান্ডলিং অ্যাপ সঙ্গে সঙ্গে শেষ করে আর AppDomain.ProcessExit ও AssemblyLoadContext.Unloading আর চলে না; আর যে অ্যাপ মডেলের উপযোগী সিগন্যাল হ্যান্ডলিং উচ্চ-স্তরের লাইব্রেরি বা অ্যাপ কোডে নিবন্ধ করা উচিত। ↩ ↩2
-
Microsoft Learn, Service Control Handler Function. যে SERVICE_ACCEPT_PRESHUTDOWN ঘোষিত সার্ভিস আগে SERVICE_CONTROL_PRESHUTDOWN পায়, তারপর SERVICE_ACCEPT_SHUTDOWN সার্ভিস SERVICE_CONTROL_SHUTDOWN; যে শাটডাউনে ডিফল্ট ছাড় প্রায় ২০ সেকেন্ড আর OS রিস্টার্টে ছাদ WaitToKillServiceTimeout; যে এই মান বাড়ানো উচিত নয়; যে কন্ট্রোল হ্যান্ডলার ৩০ সেকেন্ডে ফিরুক, STOP_PENDING ও wait hint রিপোর্ট করুক, আর লম্বা কাজ অন্য থ্রেডে রাখুক; যে UPS চালনা মাথায় রেখে ক্লিনআপ যত তাড়াতাড়ি সম্ভব শেষ হোক; আর যে SCM শাটডাউনে ডিফল্টে নির্ভরতা দেখে না। ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, SERVICE_PRESHUTDOWN_INFO structure (winsvc.h). যে PRESHUTDOWN নোটিফিকেশনের পর SCM সার্ভিস থামা বা টাইমআউট পর্যন্ত অপেক্ষা করে; যে ডিফল্ট টাইমআউট Windows 10 Creators Update (build 15063) থেকে ১০ সেকেন্ড আর তার আগে ৩ মিনিট; যে ChangeServiceConfig2 দিয়ে কনফিগার হয়; আর যে SERVICE_STOP_PENDING চলাকালীন স্টেট আপডেট চালিয়ে যাওয়া যায়। ↩ ↩2
-
Microsoft Learn, RegisterApplicationRestart function (winbase.h). যে ক্র্যাশ, সাড়া না দেওয়া, আপডেট, আর আপডেটের সাথে কম্পিউটার রিস্টার্টের জন্য রিস্টার্ট নিবন্ধ করা যায়; যে রিস্টার্টের কমান্ড-লাইন আর্গুমেন্ট নির্দিষ্ট করা যায়; যে নিবন্ধ সমস্যার আগে হতে হবে আর আপডেট পরিস্থিতিতে WM_QUERYENDSESSION হ্যান্ডলিং শেষ সুযোগ; যে ৬০ সেকেন্ডের কম রানটাইম প্রক্রিয়া রিস্টার্ট হয় না; যে ক্র্যাশ বা হ্যাং-এর পর রিস্টার্ট ব্যবহারকারীর সম্মতি দিয়ে যায়; আর যে OS রিস্টার্ট পার করতে EWX_RESTARTAPPS/SHUTDOWN_RESTARTAPPSসহ শাটডাউন লাগে। ↩ ↩2 ↩3
-
Microsoft Learn, Winlogon automatic restart sign-on (ARSO). যে Windows Update স্বয়ংক্রিয় রিস্টার্ট শুরু করলে শেষ ইন্টারঅ্যাকটিভ ব্যবহারকারীর ক্রেডেনশিয়াল সেভ করে Autologon কনফিগার করে; যে রিস্টার্টের পর ব্যবহারকারীকে স্বয়ংক্রিয় সাইন-ইন করে সেশন লক করে; যে সফল সাইন-ইনের পর সেভ করা ক্রেডেনশিয়াল মুছে যায়; আর যে Group Policy (DisableAutomaticRestartSignOn ইত্যাদি) দিয়ে কনফিগার করা যায়। ↩ ↩2
-
Microsoft Learn, ReplaceFileW function (winbase.h). যে ReplaceFile “নতুন ফাইলে সেভ, মূলের অস্থায়ী নাম, নতুন ফাইলের নাম, মূল মুছে ফেলা”-এর সমতুল্য বহু ধাপ এক ফাংশনে প্যাক করে; যে মূল ফাইলের তৈরির সময়, DACL, এনক্রিপশন, সংকোচন ও named streams-এর মতো গুণ রাখে; আর যে ব্যাকআপ, বদলানো ফাইল, ও প্রতিস্থাপন ফাইল একই ভলিউমে থাকতে হবে। ↩ ↩2
-
Microsoft Learn, File Caching. যে লেখা ডিফল্টে সিস্টেম ক্যাশে যায় আর অলস লেখায় ডিস্কে প্রতিফলিত হয়; যে FILE_FLAG_WRITE_THROUGH সঙ্গে সঙ্গে ডিস্কে লেখে; যে FlushFileBuffers স্পষ্ট ফ্লাশ করতে পারে; আর যে ফাইল-সিস্টেম মেটাডেটা সবসময় ক্যাশ হয়, তাই মেটাডেটা নিশ্চিত করতে ফ্লাশ বা write-through লাগে। ↩ ↩2 ↩3
-
Microsoft Learn, Troubleshoot unexpected reboots using system event logs. যে সাধারণ রিস্টার্ট ইভেন্ট ID 1074 নথিভুক্ত করে (কোন প্রক্রিয়া শাটডাউন শুরু করেছে, কার জন্য, কোন কারণে); যে অপ্রত্যাশিত রিস্টার্ট ইভেন্ট ID 41 (Kernel-Power) ও 6008 নথিভুক্ত করে; আর যে এই ID রিস্টার্টের ধরন আলাদা করতে পারে। ↩ ↩2
-
Microsoft Learn, PBT_APMPOWERSTATUSCHANGE event. যে এই ইভেন্ট ব্যাটারি ও AC-এর মধ্যে সুইচ বা অবশিষ্ট ক্ষমতা কমলে WM_POWERBROADCAST দিয়ে জানানো হয়; আর যে পেলে GetSystemPowerStatus কল করে ACLineStatus, BatteryFlag, ও BatteryLifePercent-এর মতো SYSTEM_POWER_STATUS ফিল্ড দেখা উচিত। ↩
সম্পর্কিত নিবন্ধ
কাছাকাছি বিষয়ে গভীরে যেতে একই ট্যাগযুক্ত সাম্প্রতিক নিবন্ধ।
Win32 থ্রেড পুল API — CreateThreadpoolWork দিয়ে থ্রেড তৈরি না করে কনকারেন্সি
নেটিভ কোডে চারদিকে CreateThread ডাকছেন? এই নিবন্ধ Vista-তে নতুন করে সাজানো Win32 থ্রেড পুল API ব্যাখ্যা করে — work, timer, wait ও io চারট...
নেমড পাইপ ব্যবহারিকভাবে — ডিজাইন থেকে নিরাপত্তা পর্যন্ত Windows-এর মানক IPC
Windows-এর মানক আন্তঃপ্রক্রিয়া যোগাযোগ নেমড পাইপের ব্যবহারিক গাইড। প্রাথমিক উৎস থেকে এই নিবন্ধ বাইট ও মেসেজ মোডের পছন্দ, একাধিক ক্লায়েন...
ঘুম থেকে জাগলে ভাঙে যে অ্যাপ — Windows পাওয়ার ইভেন্টের কাজ ও যে ব্যবসায়িক অ্যাপ তা সহ্য করে
ল্যাপটপ খুললেন আর ব্যবসায়িক অ্যাপের সংযোগ মৃত — কারণ ঘুম ধরে না নেওয়া ডিজাইন। এই নিবন্ধ WM_POWERBROADCAST নোটিফিকেশন প্রবাহ, Modern Sta...
DllMain ও লোডার লক — DLL ইনিশিয়ালাইজেশনে "কিছুই করবেন না" বলা হয় তার আসল কারণ
DllMain থেকে LoadLibrary ডাকা বা অন্য থ্রেডের সাথে সিঙ্ক্রোনাইজ করা যায় না কেন। প্রাথমিক উৎস থেকে এই নিবন্ধ ব্যাখ্যা করে লোডার লক প্রতিট...
"Not Responding" আসলে কী — Windows কীভাবে অ্যাপ হ্যাং ধরে, আর যে ডিজাইন হ্যাং করে না
Windows-এর "Not Responding" এমন যন্ত্র যেখানে OS বিচার করে উইন্ডো ৫ সেকেন্ড মেসেজ তোলেনি আর তাকে ঘোস্ট উইন্ডো দিয়ে বদলায়। এই নিবন্ধ সেই...
সম্পর্কিত বিষয়
এই পৃষ্ঠাগুলো বিষয়টিকে সেবা ও সিদ্ধান্তের বৃহত্তর প্রেক্ষাপটে স্থাপন করে।
Windows-এর প্রযুক্তিগত বিষয়
Windows ডেভেলপমেন্ট, বাগ তদন্ত ও বিদ্যমান সম্পদ ব্যবহারের প্রবেশদ্বার।
এই বিষয়ের সাথে সম্পর্কিত সেবা
নিবন্ধটি নিচের সেবাগুলোর সাথে সরাসরি সম্পর্কিত।
Windows অ্যাপ ডেভেলপমেন্ট
ব্যবসায়িক অ্যাপ, ডিভাইস ইন্টিগ্রেশন ও যোগাযোগ টুল, চাহিদা থেকে ডেভেলপমেন্ট পর্যন্ত।
প্রায়শ জিজ্ঞাসিত প্রশ্ন
এই নিবন্ধের বিষয়ে পরামর্শে প্রায়ই আসা প্রশ্ন।
- "Shut down"-এর পর যা যায়নি, "Restart"-এর পর গেল। কেন?
- Windows 8 থেকে পরের ক্লায়েন্ট OS-এ, fast startup চালু থাকলে (হাইবারনেশন-সমর্থিত বেশিরভাগ PC-তে ডিফল্ট) "Shut down" hybrid shutdown নামের কৌশল ব্যবহার করে। ব্যবহারকারী সাইন-আউট হন, কিন্তু কার্নেল ও ড্রাইভার স্টেট হাইবারনেশন ফাইলে সেভ হয়ে পরের বুটে যেমন ছিল তেমন ফেরে। অর্থাৎ OS-এর মূল রিসেট হয়নি। অন্যদিকে "Restart" সবসময় পূর্ণ বুট করে, তাই ড্রাইভার ও সার্ভিসের সমস্যা রিসেট হয়। আলাদা করার পদ্ধতিতে "Restart" লিখুন, "Shut down করে আবার চালু" নয়। কমান্ড লাইন থেকে পূর্ণ শাটডাউন চাইলে shutdown /s ব্যবহার করতে পারেন।
- অ্যাপ সেভ শেষ না করা পর্যন্ত শাটডাউন আটকাতে পারি?
- সাময়িক অপেক্ষা চাইতে পারেন, কিন্তু নির্ভরযোগ্যভাবে আটকানো যায় না। শুধু অবিচ্ছিন্ন কাজ চলাকালীন ShutdownBlockReasonCreate দিয়ে কারণ স্ট্রিং নিবন্ধ করলে সেই কারণ "এই অ্যাপ শাটডাউন আটকাচ্ছে" স্ক্রিনে দেখা যায় আর ব্যবহারকারী চালিয়ে যাবেন না বাতিল করবেন সিদ্ধান্ত নিতে পারেন। তবু ব্যবহারকারী জোর করে চালিয়ে যেতে পারেন, আর জোর শাটডাউন বা আপডেট-চালিত রিস্টার্ট একেবারে অপেক্ষা নাও করতে পারে। সঠিক পথ তাই "ব্লক" নয়, বরং ঘন ঘন অটোসেভ যাতে ঝুঁকিতে কম ডেটা থাকে, সাথে প্রস্থান নোটিফিকেশন থেকে কয়েক সেকেন্ডে শেষ হওয়া ক্লিনআপ।
- আমার Windows সার্ভিস থামাতে অনেক সময় লাগে। শাটডাউন ছাড় বাড়াতে পারি?
- SERVICE_CONTROL_SHUTDOWN পাওয়া ডিফল্ট কনফিগে ছাড় প্রায় ২০ সেকেন্ড এবং WaitToKillServiceTimeout রেজিস্ট্রি মানের উপর নির্ভর করে। অ্যাপ পাশ থেকে সেই মান বাড়িয়ে লেখা সুপারিশ নয়। লম্বা ছাড় লাগলে SERVICE_ACCEPT_PRESHUTDOWN ঘোষণা করে SERVICE_CONTROL_PRESHUTDOWN পেতে পারেন; অন্যদের আগে জানানো হয়, আর টাইমআউট ChangeServiceConfig2 দিয়ে সেট করা যায় (ডিফল্ট Windows 10 Creators Update থেকে ১০ সেকেন্ড, তার আগে ৩ মিনিট)। তবে PRESHUTDOWN সেই অংশে পুরো শাটডাউন আটকে রাখে, তাই সত্যিই দরকার এমন ক্ষেত্রে সীমাবদ্ধ রাখুন, আর মূলে থামার কাজই কয়েক সেকেন্ডে শেষ হয় এমন ডিজাইন করুন।
- .NET-এর AppDomain.ProcessExit-এ শাটডাউন ক্লিনআপ নিরাপদ?
- এর উপর নির্ভর না করার পরামর্শ। ইতিহাসে রানটাইম ডিফল্ট সিগন্যাল হ্যান্ডলার নিবন্ধ করত, আর CTRL_CLOSE_EVENT ও CTRL_SHUTDOWN_EVENT-এ ProcessExit চলত, কিন্তু .NET 10 থেকে রানটাইম ডিফল্ট সমাপ্তি-সিগন্যাল হ্যান্ডলার দেয় না, আর সেই ক্ষেত্রে ProcessExit চলে না। অ্যাপ মডেলের সাথে মিলে এমন নোটিফিকেশন পথে ক্লিনআপ করুন: GUI অ্যাপ FormClosing বা SessionEnding ব্যবহার করুন (এগুলো কুয়েরি-পর্যায়ের নোটিফিকেশন, তাই idempotent সেভে সীমাবদ্ধ রাখুন; সেশন নিশ্চিত হওয়ার পরেই চলতে পারে এমন ক্লিনআপ WM_ENDSESSION হুকে); Generic Host / Worker Service IHostApplicationLifetime ও StopAsync ব্যবহার করুন; কনসোল অ্যাপ SetConsoleCtrlHandler বা PosixSignalRegistration ব্যবহার করুন।
- হঠাৎ বিদ্যুৎ কাটলে ফাইল নষ্ট হওয়া থেকে কীভাবে বাঁচাব?
- বিদ্যুৎ বিচ্ছিন্নতা কোনো নোটিফিকেশন আনে না, তাই একমাত্র পথ এমনভাবে লেখা যা বিদ্যুৎ যখনই কাটুক না ভাঙে। ভিত্তি মূল ফাইল জায়গায় ওভাররাইট না করা: একই ভলিউমে অস্থায়ী ফাইলে পুরো লিখুন, ফ্লাশ করুন, আর ReplaceFile (.NET-এ File.Replace) দিয়ে অদলবদল করুন। সাধারণ কাজে এতে হয় পুরো পুরনো ফাইল না হয় পুরো নতুন ফাইল পড়া যায়, কিন্তু বিদ্যুৎ কাটার উপর ReplaceFile-এর পরমাণবিকতা স্পেসে গ্যারান্টি নয়, তাই ব্যাকআপ (তৃতীয় আর্গুমেন্ট) রাখুন আর লোড-সময় পুনরুদ্ধার করুন যা প্রাথমিক ফাইল যাচাই করে ভাঙা হলে ব্যাকআপে যায়। এছাড়া WriteFile-এর সাফল্য মানে ডেটা ডিস্কে পৌঁছানো নয়, তাই গুরুত্বপূর্ণ চেকপয়েন্টে FlushFileBuffers বা FILE_FLAG_WRITE_THROUGH দিয়ে লেখা নিশ্চিত করুন। ডিভাইস PC-তে মানক সেটআপ একে UPS-এর সাথে জোড়া, ব্যাটারি সুইচ ধরা, আর নিরাপদ শাটডাউনে নিয়ে যাওয়া।