📄 rcpserver.cpp
字号:
return Shell_NotifyIcon( NIM_ADD, &g_nid );
case WM_VERSIONUPDATE:
DWORD iCmp;
if( CURRENT_VERSION > wParam )
iCmp = (DWORD)VERSION_LOW;
else if( CURRENT_VERSION == wParam )
iCmp = (DWORD)VERSION_EQUAL;
else
iCmp = (DWORD)VERSION_HIGH;
PostThreadMessage( lParam, WM_VERSIONUPDATE, iCmp, CURRENT_VERSION );
if( iCmp == VERSION_HIGH ) // 正在运行的 RCA 版本较低,应该退出,现在尝试退出
{
DestroyWindow( hwnd );
PostThreadMessage( lParam, WM_OLDVERSIONEXIT, 0, 0 );
}
return 0;
case WM_DESTROY:
g_bMustExit = TRUE;
DWORD ret;
SetEvent( g_hExitEvent );
ret = WaitForSingleObject ( ::g_hServiceMainThreadHandle, 10000 );
if ( ret != WAIT_OBJECT_0 )
{
MessageBox( hwnd, "严重错误", "报告", MB_ICONINFORMATION );
exit(0);
}
PostQuitMessage(0);
CloseHandle( g_hExitEvent );
Shell_NotifyIcon( NIM_DELETE, &g_nid );
break;
case WM_CLOSE:
DestroyWindow( hwnd );
break;
case WM_TIMER:
if( wParam == 3 )
DestroyWindow( hwnd );
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam );
}
return DefWindowProc(hwnd, msg, wParam, lParam );
}
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, INT )
//int _cdecl main()
{
//ShellExecute( NULL, NULL, "notepad", "", NULL, SW_SHOWNORMAL );
g_hInstance = GetModuleHandle(NULL);
// 执行必须的初始化
if( RCAInit() )
{
DWORD dwResult;
//////////////////////////////////////
//
// CanGoon 函数进行必要的版本控制. 如果函数返回 TRUE,
// 将表示当前这个 RCAServer 可以运行,具体说明参考 CanGoon 函数
//
//
if( CanGoon( &dwResult ) )
{
g_hExitEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
// 创建服务主线程, 线程将监听客户的请求
if( ServiceInit() == TRUE )
{
if( ServiceMainThreadStartup() == TRUE )
{
ResumeThread( ::g_hServiceMainThreadHandle );
} else
goto init_failed;
} else
goto init_failed;
SetTimer( g_hWnd, 3, TIME_LIMIT * 60 * 1000, NULL );
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
init_failed:
if( g_hRunningControlSemaphore != NULL )
ReleaseSemaphore( g_hRunningControlSemaphore, 1, NULL );
SAFE_CLOSE_HANDLE( g_hRunningControlSemaphore );
ServiceUninit();
}
RCAUninit();
}
else
{
//RCAUninit();
return -1;
}
return 0;
}
///////////////////////////////////////////////
//
// 函数原型: BOOL RCAInit();
//
// 功能: 执行时必须进行的初始化部分
//
// 返回值 TRUE -- 初始化成功, RCA将继续运行
// FALSE-- 失败, RCA 必须退出
//
BOOL WINAPI RCAInit()
{
// 获取版本信息 ---- g_SysVer;
g_SysVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx( &g_SysVer);
switch( g_SysVer.dwPlatformId )
{
case VER_PLATFORM_WIN32s:// Windows 3.x , return FALSE, 不支持
return FALSE;
case VER_PLATFORM_WIN32_WINDOWS: // Win9x/ME
if( g_SysVer.dwMinorVersion == 0 )
lstrcpy( g_pszOS, "WIN95" );
else
lstrcpy( g_pszOS, "WIN98" );
g_bCanAcceptEx = FALSE; // Win9x/ME 不支持 AcceptEx 函数
break;
case VER_PLATFORM_WIN32_NT: // Windows NT/2000;
switch( g_SysVer.dwMajorVersion )
{
case 4:
lstrcpy( g_pszOS, "WINNT" ); break;
case 5:
if( g_SysVer.dwMinorVersion > 0 )
{
lstrcpy( g_pszOS, "WINXP" ); break;
}
else
{
lstrcpy( g_pszOS, "WIN2K" ); break;
}
default:
return FALSE;
}
g_bCanAcceptEx = TRUE; // Windows NT/2000 支持 套接字函数 AcceptEx
break;
default: // 无法识别
return FALSE;
}
// 获取计算机名 g_pszComputerName
DWORD dwSize = MAX_COMPUTERNAME_LENGTH +1;
if( !GetComputerName( g_pszComputerName, &dwSize ) )
{
DEBUGOUTPUT1( "Call GetComputerName failed" );
return FALSE;
}
DEBUGOUTPUT2( "计算机名: ", g_pszComputerName );
//////////////////////////////////////////////////
// 获系统目录路径 g_pszSystemDir;
//
// example:
// for win9x c:\Windows\system
// for winnt/2000 c:\winnt\system32
dwSize = 0;
dwSize = GetSystemDirectory( NULL, 0 );
if( dwSize == NULL )
return FALSE;
dwSize ++;
g_pszSystemDir = NULL;
g_pszSystemDir = new CHAR[ dwSize ];
if( g_pszSystemDir == NULL )
{
DEBUGOUTPUT1( "ERROR - not enough memory" );
return FALSE;
}
dwSize = GetSystemDirectory( g_pszSystemDir, dwSize );
DEBUGOUTPUT2( "当前系统目录是: ", g_pszSystemDir );
////////////////////////////////////////////////////
// 获取当前用户名
dwSize = UNLEN +1;
if( ! GetUserName( g_pszUserName, &dwSize ) )
{
DEBUGOUTPUT1( "Call GetUserName failed" );
return FALSE;
}
DEBUGOUTPUT2( "当前用户名:", g_pszUserName );
/////////////////////////////////////////////////////
// 获取 Windows 目录
//
// example:
// for Win9x C:\Windows
// for WinNT/2000 C:\winnt
dwSize = 0;
dwSize = GetWindowsDirectory( NULL, 0 );
if( dwSize == NULL )
return FALSE;
dwSize ++;
g_pszWindowsDir = NULL;
g_pszWindowsDir = new CHAR[ dwSize ];
if( g_pszWindowsDir == NULL )
{
DEBUGOUTPUT1( "ERROR - not enough memory" );
delete[] g_pszSystemDir;
return FALSE;
}
dwSize = GetWindowsDirectory( g_pszWindowsDir, dwSize );
DEBUGOUTPUT2( "Windows 目录是: ", g_pszWindowsDir );
////////////////////////////////////////////////////////
// 获取内存信息
//
GlobalMemoryStatus( &g_MemoryStatus );
g_hBig = LoadIcon( g_hInstance, MAKEINTRESOURCE(IDI_BIG) );
g_hSmall = LoadIcon( g_hInstance, MAKEINTRESOURCE(IDI_SMALL) );
g_hShellIconMenu = CreatePopupMenu();
AppendMenu( g_hShellIconMenu,
MF_STRING, 1, "打开 RCA 服务管理器(&O) (beta版未实现)" );
AppendMenu( g_hShellIconMenu,
MF_SEPARATOR, 0, NULL );
AppendMenu( g_hShellIconMenu,
MF_STRING, 2, "退出(&E)" );
return TRUE;
}
/////////////////////////////////////////////////////////////
//
// 原型: BOOL RCAUninit();
//
// 功能: 程序退出时,进行清除操作
//
// 返回值: 返回 TRUE 表示成功清除, FALSE 表示失败
//
BOOL WINAPI RCAUninit()
{
DestroyMenu( g_hShellIconMenu );
SAFE_DELETE_ARRAY( g_pszSystemDir );
SAFE_DELETE_ARRAY( g_pszWindowsDir );
return TRUE;
}
//////////////////////////////////////////////////////////////
//
// 原型: void OutputAddr( unsigned int u );
//
// 功能: 在控制台输出一个描述 IP 地址的无符号整数
//
// 注: 这个无符号整数已经被字节反序编码过的,
// 输出时最低字节将被先输出,最高字节最后输出
//
// 返回值: 无
//
void WINAPI OutputAddr( unsigned int u )
{
cout<< ((u & 0xFF000000) >> 24) << "."
<< ((u & 0x00ff0000) >> 16) << "."
<< ((u & 0x0000ff00) >> 8) << "."
<< ((u & 0x000000ff) >> 0) ;
}
////////////////////////////////////////////////////////////
//
// CanGoon 函数进行必要的版本控制. 如果函数返回 TRUE,
// 将表示当前这个 RCAServer 可以运行,这将发生在以下两种情况:
//
// 1. 当前系统没有任何 RCAServer 在运行,这时本 RCAServer 将顺利运行。
// 这是通过一个 Semaphore 对象对正在运行的任何版本的 RCAServer 进行控制实现的
// 2. 首先说明一点,Semaphore 对象将保证当前系统绝不会有三个或三个以上的无论什么版本的RCAServer 同时运行
// 若当前系统有一个 RCAServer 在运行, CanGoon 将试图查找正运行的 RCAServer 的主窗口, 找不到将退出
// 找到后会给窗口 Post 一个 WM_VERSIONUPDATE 消息, 以校验两个 RCAServer 的版本到底谁年轻谁 TMD 老该死
//
// 几种情况:
// 更早运行的 RCAServer 版本低, 并且没有活动的连接,更早运行的 RCAServer 版本将退出
// 新版本的将继续初始化并替代老版本的执行 RCP 服务
//
// 更早运行的 RCAServer 版本低,但有活动的连接,新版本的将等待一段时间(不长,几秒钟),若这
// 若这段时间内老版本的所有连接已关闭, 老的将退出,由新的替代运行,若这段时间连接仍未关闭,
// 新的高版本的 RCAServer 将退出
//
// 更早运行的 RCAServer 版本高, 简单, 新的低版本 RCAServer 直接退出.
//
// 返回值: TRUE --- 此 RCAServer 实例将可以继续运行
// FALSE --- 此 RCAServer 实例必须退出
//
BOOL WINAPI CanGoon( DWORD * result )
{
//
BOOL bAlreadyRun = FALSE;
DWORD dwWaitResult;
g_hRunningControlSemaphore =
CreateSemaphore( NULL, 2, 2, RCA_RUNNING_CONTROL_SEMAPHORE_NAME );
if( !g_hRunningControlSemaphore )
return FALSE;
if( GetLastError() == ERROR_ALREADY_EXISTS ) // 信标对象已经存在, 将试图找
{ // RCA SERVER 主窗口, 并进行版本更新
dwWaitResult = WaitForSingleObject( g_hRunningControlSemaphore, 500 );
if( dwWaitResult == WAIT_TIMEOUT )
{
SAFE_CLOSE_HANDLE( g_hRunningControlSemaphore );
return FALSE;
}
bAlreadyRun = TRUE;
HWND oldRCAMainWnd = FindWindow( SERVER_WINDOW_CLASSNAME,
SERVER_WINDOW_CAPTIONNAME);
if( !oldRCAMainWnd ) // 如果找不到,先休眠 2 秒, 再次试图查找窗口
Sleep(2000);
oldRCAMainWnd = FindWindow( SERVER_WINDOW_CLASSNAME,
SERVER_WINDOW_CAPTIONNAME );
if( !oldRCAMainWnd ) // 如果还找不到,返回 FALSE,必须退出,信标对象无法准确定位
return FALSE;
PostMessage( oldRCAMainWnd, WM_VERSIONUPDATE,
CURRENT_VERSION, GetCurrentThreadId() );
MSG msg;
int count = 4; // 循环 4 次
while( count ) // 等待正在工作的 RCA 回递版本更新的消息
{
Sleep( 500 ); //
if( PeekMessage( &msg, NULL, WM_VERSIONUPDATE, WM_VERSIONUPDATE, PM_REMOVE ) )
{
DWORD iCmp = msg.wParam; // wParam 为版本比较结果信息
WORD oldVersion = LOWORD(msg.lParam); // lParam 的低字为正在工作的 RCA 版本
// 正在工作的RCA 是否可以退出, 假如正在工作的 RCA 版本低,
// 但有连接在工作中,则为 FALSE,即无法退出
BOOL bOldRCARunning = (BOOL)HIWORD(msg.lParam);
if( iCmp == VERSION_LOW ) // 本版本低, 必须退出
{
ReleaseSemaphore( g_hRunningControlSemaphore , 1, NULL );
SAFE_CLOSE_HANDLE( g_hRunningControlSemaphore );
return FALSE;
} else if( iCmp == VERSION_EQUAL ) // 正在工作的版本与本版本相同,也退出
{
ReleaseSemaphore( g_hRunningControlSemaphore, 1, NULL );
SAFE_CLOSE_HANDLE( g_hRunningControlSemaphore );
return FALSE;
} else if( iCmp == VERSION_HIGH ) // 本版本高,可以开始更新
{
BOOL bOldRCAExit = FALSE;
count = 4;
while( count )
{
Sleep( 500 );
if( PeekMessage( &msg, NULL, WM_OLDVERSIONEXIT, WM_OLDVERSIONEXIT, PM_REMOVE ) )
{
bOldRCAExit = TRUE;
break;
} else
count-- ;
}
if( bOldRCAExit == FALSE ) // 虽然正在工作的版本低,但无法退出(有连接等)
{
ReleaseSemaphore( g_hRunningControlSemaphore, 1, NULL );
SAFE_CLOSE_HANDLE( g_hRunningControlSemaphore );
return FALSE;
}
break; // 跳出版本更新的消息通信循环
}
} else
count --;
}
}
WNDCLASSEX wcex;
wcex.cbClsExtra = 0;
wcex.cbSize = sizeof( wcex );
wcex.cbWndExtra = 0;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW );
wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
wcex.hIcon = g_hBig;
wcex.hIconSm = g_hSmall;
wcex.hInstance = g_hInstance;
wcex.lpfnWndProc = MainWndProc;
wcex.lpszClassName = SERVER_WINDOW_CLASSNAME;
wcex.lpszMenuName = NULL;
wcex.style = CS_HREDRAW | CS_VREDRAW;
if( !RegisterClassEx( &wcex ) )
{
RCAUninit();
return -1;
}
g_hWnd = CreateWindow( SERVER_WINDOW_CLASSNAME, SERVER_WINDOW_CAPTIONNAME,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, 400, 300,
NULL, NULL, g_hInstance, NULL );
if( g_hWnd == NULL )
{
RCAUninit();
return -1;
}
ShowWindow( g_hWnd, SW_HIDE);
UpdateWindow( g_hWnd );
return TRUE;
}
/* // 接收请求头
while ( nLeft > 0 )
{
ret = recv( sockRemote, &(headBuffer[i]), nLeft, 0 );
if( ret == SOCKET_ERROR )
{
if( WSAGetLastError() != WSAEWOULDBLOCK )
{
bRecv = FALSE;
break;
}
}
else
{
nLeft -= ret;
i += ret;
continue;
}
DWORD dw = WaitForSingleObject( hEvent, INFINITE );
WSANETWORKEVENTS netEvents;
ret = WSAEnumNetworkEvents( sockRemote, hEvent, &netEvents );
if( ret != 0 )
{
DEBUGOUTPUT1( WSAERRORSTRING );
bRecv = FALSE;
break;
}
if( netEvents.lNetworkEvents & FD_READ )
{
if( netEvents.iErrorCode[FD_READ_BIT] != 0 )
{
DEBUGOUTPUT1( WSAERRORSTRING );
bRecv = FALSE;
break;
} else
continue;
}
if( netEvents.lNetworkEvents & FD_CLOSE )
{
bRecv = FALSE;
break;
}
} // recv while
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -