本框架實現一個同時具備 MFC 對話框介面與 NT 服務身分的應用程式,可在使用者登入前於開機階段自動啟動。整合系統托盤功能,支援安裝/移除服務、除錯模式、優雅關機與 Explorer 重啟時的圖示自動恢復。
-install 安裝、-remove 移除、-debug 除錯模式SetCurrentDirectory 至模組所在目錄,便於相對路徑存取
// 服務安裝邏輯 (簡化)
if (strcmp(cmdParam, "-install") == 0) {
SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
SC_HANDLE svc = CreateService(scm,
serviceName, displayName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
exePath, NULL, NULL, dependencies, NULL, NULL);
}
// 啟動/停止:net start/stop ServiceName 或服務管理員
// 服務主函數
void WINAPI ServiceMain(DWORD argc, LPTSTR* argv) {
// 註冊控制處理器
g_statusHandle = RegisterServiceCtrlHandler(serviceName, ServiceCtrlHandler);
// 初始化完成回報
SetServiceStatus(g_statusHandle, &status);
// 建立 MFC 應用程式物件並進入訊息迴圈
CWinApp* pApp = AfxGetApp();
pApp->InitInstance(); // 包含對話框建立
pApp->Run(); // 訊息迴圈
}
// 控制處理器
void WINAPI ServiceCtrlHandler(DWORD ctrlCode) {
switch (ctrlCode) {
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
// 發送 WM_CLOSE 給主視窗
PostMessage(hMainWnd, WM_CLOSE, 0, 0);
break;
}
}
void CMyDialog::OnEndSession(BOOL bEnding) {
if (bEnding) {
// 系統關機/登出時,必須正確關閉資源
// 否則使用者重新登入後對話框將失去回應
CleanupResources();
}
CDialog::OnEndSession(bEnding);
}
Shell_NotifyIcon(NIM_ADD, ...) 註冊圖示WM_TRAYNOTIFY 處理滑鼠事件TaskbarCreated 訊息處理:Explorer 重啟時重新註冊圖示
// 系統選單與關閉鈕均改為隱藏
void CMyDialog::OnSysCommand(UINT nID, LPARAM lParam) {
if ((nID & 0xFFF0) == SC_CLOSE) {
AnimateWindow(1000, AW_HIDE | AW_BLEND); // 淡出動畫
ShowWindow(SW_HIDE);
return;
}
CDialog::OnSysCommand(nID, lParam);
}
// 真正退出僅透過托盤選單「退出」項
void CMyDialog::OnTrayExit() {
if (AfxMessageBox("確定退出?", MB_YESNO) == IDYES) {
::PostQuitMessage(0);
}
}
服務在使用者登入前啟動,若需存取網路共享:
WNetAddConnection2 提供明確使用者名稱/密碼文獻常建議呼叫 OpenWindowStation("winsta0") 以取得互動式桌面存取權,但本框架未顯式呼叫仍能正常顯示介面,具體原因有待深入研究 (可能與服務類型 SERVICE_INTERACTIVE_PROCESS 相關)。
本程式碼為業餘時間開發,雖曾用於商業專案,但版權歸屬個人,不屬任何公司。自由複製、修改、發布,無需授權。