// TalkManager.cpp: implementation of the CTalkManager class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "TalkManager.h" #include "TalkDialogTemplate.h" #include "Common.h" #include "resource.h" #include #include #if ENABLE_MESSAGE #pragma comment(lib, "WINMM.LIB") #define ID_TIMER_POP_WINDOW 1 #define ID_TIMER_DELAY_DISPLAY 2 #define ID_TIMER_CLOSE_WINDOW 3 #define WIN_WIDTH 360 #define WIN_HEIGHT 200 ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CTalkManager::CTalkManager(IOCPClient* ClientObject, int n, void* user):CManager(ClientObject) { m_hInstance = HINSTANCE(user); g_Event = 0; memset(g_Buffer, 0, sizeof(g_Buffer)); BYTE bToken = TOKEN_TALK_START; HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader()); m_ClientObject->Send2Server((char*)&bToken, 1, &mask); WaitForDialogOpen(); Mprintf("Talk 构造\n"); } CTalkManager::~CTalkManager() { Mprintf("Talk 析构\n"); } VOID CTalkManager::OnReceive(PBYTE szBuffer, ULONG ulLength) { switch(szBuffer[0]) { case COMMAND_NEXT: { NotifyDialogIsOpen(); break; } default: { // 服务端只发正文、不带结尾 NUL:按实际长度补终止符(留一格), // 否则正好填满缓冲区时 SetDlgItemText 会越界读 size_t nCopy = min(ulLength, sizeof(g_Buffer) - 1); memcpy(g_Buffer, szBuffer, nCopy); g_Buffer[nCopy] = '\0'; //创建一个DLG INT_PTR nRet = DialogBoxParamA(m_hInstance, MAKEINTRESOURCEA(IDD_DIALOG), NULL, DialogProc, (LPARAM)this); //SDK C MFC C++ if (nRet == -1) { // 与聊天窗口同样的原因:加壳部署(EXE + SC_AES/sRDI)时 m_hInstance 是 // 外壳进程映像,取不到 IDD_DIALOG 资源,DialogBoxParamA 直接失败(Win11 // 实测 err=1812/59),右下角消息窗口不会出现。回退到内嵌的编译后模板。 DWORD dwError = GetLastError(); Mprintf("DialogBoxParamA(%lu) 失败,改用内嵌对话框模板\n", dwError); DialogBoxIndirectParamA(m_hInstance, (LPCDLGTEMPLATEA)kTalkDialogTemplate, NULL, DialogProc, (LPARAM)this); } break; } } } INT_PTR CALLBACK CTalkManager::DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { static CTalkManager* This = nullptr; switch(uMsg) { case WM_TIMER: { if (This) This->OnDlgTimer(hDlg); break; } case WM_INITDIALOG: { // 获取当前窗口样式 LONG_PTR exStyle = GetWindowLongPtr(hDlg, GWL_EXSTYLE); // 移除 WS_EX_APPWINDOW 样式,添加 WS_EX_TOOLWINDOW 样式 exStyle &= ~WS_EX_APPWINDOW; exStyle |= WS_EX_TOOLWINDOW; SetWindowLongPtr(hDlg, GWL_EXSTYLE, exStyle); This = (CTalkManager*)lParam; if(This) This->OnInitDialog(hDlg); break; } case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { KillTimer(hDlg, ID_TIMER_CLOSE_WINDOW); BYTE bToken = TOKEN_TALKCMPLT; if (This) This->m_ClientObject->Send2Server((char*)&bToken, 1); EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return 0; } VOID CTalkManager::OnInitDialog(HWND hDlg) { MoveWindow(hDlg, 0, 0, 0, 0, TRUE); // 标题栏:DialogBoxParamA 会把模板里的 UTF-16 标题按系统 ANSI 代码页转换, // 德语等 1252 系统上"消息提示"会变成 "???"。这里在显示前用 W 接口重设标题 // (消息正文仍走 ANSI,保持原有编码语义)。中文系统显示中文,其余显示英文。 { static const bool bChineseUI = (PRIMARYLANGID(GetUserDefaultUILanguage()) == LANG_CHINESE); SetWindowTextW(hDlg, bChineseUI ? L"消息提示" : L"Message"); } static HICON hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_ICON_MSG)); ::SendMessage(hDlg, WM_SETICON, (WPARAM)hIcon, (LPARAM)hIcon); SetDlgItemText(hDlg,IDC_EDIT_MESSAGE,g_Buffer); ::SetFocus(GetDesktopWindow()); memset(g_Buffer,0,sizeof(g_Buffer)); g_Event = ID_TIMER_POP_WINDOW; SetTimer(hDlg, g_Event, 1, NULL); PlaySound(MAKEINTRESOURCE(IDR_WAVE), m_hInstance,SND_ASYNC|SND_RESOURCE|SND_NODEFAULT); } VOID CTalkManager::OnDlgTimer(HWND hDlg) //时钟回调 { RECT Rect; static int Height=0; SystemParametersInfo(SPI_GETWORKAREA, 0, &Rect,0); int y=Rect.bottom-Rect.top;; int x=Rect.right-Rect.left; x=x-WIN_WIDTH; switch(g_Event) { case ID_TIMER_CLOSE_WINDOW: { if(Height>=0) { Height-=5; MoveWindow(hDlg, x,y-Height, WIN_WIDTH, Height,TRUE); } else { KillTimer(hDlg,ID_TIMER_CLOSE_WINDOW); BYTE bToken = TOKEN_TALKCMPLT; // 包含头文件 Common.h m_ClientObject->Send2Server((char*)&bToken, 1); // 发送允许重新发送的指令 EndDialog(hDlg,0); } break; } case ID_TIMER_DELAY_DISPLAY: { KillTimer(hDlg,ID_TIMER_DELAY_DISPLAY); g_Event = ID_TIMER_CLOSE_WINDOW; SetTimer(hDlg,g_Event, 5, NULL); break; } case ID_TIMER_POP_WINDOW: { if(Height<=WIN_HEIGHT) { Height+=3; MoveWindow(hDlg,x, y-Height, WIN_WIDTH, Height,TRUE); } else { KillTimer(hDlg,ID_TIMER_POP_WINDOW); g_Event = ID_TIMER_DELAY_DISPLAY; SetTimer(hDlg,g_Event, 4000, NULL); } break; } } } #endif