Win98能创建一个Service吗? Service是基于nt/2000提出的概念 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 VC:WIN9x的后台进程 黄飞 (12/17/1999) ---- 1.后台进程 ----在WINDOWS NT中有一个功能强大的SERVICE管理器,它管理着一部分实现重要功能的后台进程,例如FTP.HTTP.RAS.网络Message等等,这些后台进程被称之为Service,他们可以在系统启动时就加载,可以运行在较高的优先级,可以说是非常靠近系统核心的设备驱动程序中的一种.在WINDOWS95下,Microsoft没有提供这样一个高度集中化了的管理器,不过我们通过VC自带的PVIEW可以看到,在桌面背后同样有秘密的后台进程存在,例如:SysTray,电源管理等.其实,这些就是WINDOWS95管理的后台进程,WINDOWS95没有提供SERVICE管理器,取而代之的是一个简单的登记接口,可以类似的称之为WINDOWS95下的Service(不过严格的讲,WINDOWS95下是没有Service的),同样的,通过这个登记接口,我们可以使自己的程序随系统启动而最先运行,随系统关闭而最后停止,和操作系统结合在一起,实现许多独特的功能.我在实际工作中,仔细的分析了这个Windows95的接口,并且测试后发现,在WINDOWS97和最新的WINDOWS98中它一样有效.并通过这个机制,成功的实现了WINDOWS95.98下的无人职守监控.下面是关于这个接口的分析结果和一些准备知识. ---- 2.进程数据库(PDB)介绍 ----在Windows的核心数据结构中,有一个重要的进程管理结构叫进程数据库,它位于Kernel32的公用内存堆中,可以通过GetCurrentProcessID(...)得到指向该结构的指针,以下是部分PDB的组成,与本文直接相关的是PDB偏移21h处的Service标志字节,通过后面的伪码分析,我们可以清楚的看到所谓登记为Windows95或Windows98下的Service进程,只不过是把它相应的PDB中该标志字节置为1而已. 偏移量长度 说明 ============================================ +00h DWORD Type // Kernel32对象的类型 +04h DWORD CReference //参考计数 +08h DWORD Un1 //未知 +0ch DWORD pSomeEvent //指向K32OBJ_EVENT指针 +10h DWORD TerminationStatus //活动标志或返回值 +14h DWORD Un2 //未知 ..... +21h BYTE Flags1 // Service标记, // "1"是Service进程, // "0"普通进程 ..... +24h DWORD pPSP // DOS PSP指针 ..... ---- 3.实现接口 ---- (1) Windows95中提供的简单的Service接口是一个32位的API: RegisterServiceProcess,由于在VC++的Online help中得不到关于这个API的确切解释,笔者不得不针对此API进行了逆向分析,以下是在Windows95的Kernel32.dll中该API的伪码.我们可以清楚的看到Window95内部到底是怎样做的,其实处理的非常简单. BOOL RegisterServiceProcess( DWORD dwProcessID, DWORD dwType ) { HANDLE dwPID; if( dwProcessID == NULL ) dwPID = dwCurrentProcessID; // Get global kernel32 variable else // Call some kernel functions if( ( dwPID = CheckPID( dwProcessID ) == NULL ) return FALSE; if( dwType == 1 ) { *(BYTE *)( dwPID + 0x21 ) | = 0x01; return TRUE; } if( dwType == 0 ) { *(BYTE *)( dwPID + 0x21 ) & = 0xFE; return TRUE; } return FALSE; } 以下为函数原形: BOOL RegisterServiceProcess( DWORD dwPID, DWORD dwType ) 参数: dwPID:进程ID, NULL代表当前进程 dwType: RSP_SIMPLE_SERVICE为登记 RSP_UNREGISTER_SERVICE为取消登记 返回值: TRUE: 调用成功 FALSE: 调用失败 ---- (2)另外,为了让Service进程有机会在BOOT后就启动,Windows95的Registry中提供了加载方法:在KEY " MyComputer HKEY_LOCAL_MACHINESOFTWARE MicrosoftWindows CurrentVersion RunServices "加入自己的应用程序命令行,即可实现开机自动加载.当然,如果你得机器中没有这个Key,自己建一个也是可以的. ----4.例程 ----下面是实现例程,所有代码经过了WINDOWS95. WINDOWS98 BETA3的测试,可以方便的加入到自己的项目文件中. ----头文件: // File: service.h // The head file of "service.cpp" // Note: 1. You must use C++ compiler // 2. The platform is WIN32 (WINNT & WIN95) #ifndef _SERVICE_H #define _SERVICE_H /////////////////////////////////////////////////// USED FOR WIN95 SERVICE // Micros #define RSP_SIMPLE_SERVICE 1 #define RSP_UNREGISTER_SERVICE 0 // Function types for GetProcAddress #define RegisterServiceProcess_PROFILE (DWORD (__stdcall *) (DWORD, DWORD)) // Service Fuctions in Win95 BOOL W95ServiceRegister(DWORD dwType); BOOL W95StartService( DWORD dwType ); #endif CPP 文 件: // File: service.cpp --- implement the service #include "service.h" /////////////////////////////////////////////////// USED FOR WIN95 SERVICE登 记 为Service 子 程 序: ///////////////////////////////////////////////////////////////////////////////// // Define: BOOL W95ServiceRegister(DWORD dwType) // Parameters: dwType --- Flag to register or unregister the service // RSP_SIMPLE_SERVICE means register // RSP_UNREGISTER_SERVICE means unregister // Return: TRUE --- call success; FALSE --- call failer BOOL W95ServiceRegister( DWORD dwType ) { // Function address defination DWORD (__stdcall * hookRegisterServiceProcess) ( DWORD dwProcessId, DWORD dwType ); // Get address of function hookRegisterServiceProcess = RegisterServiceProcess_PROFILE GetProcAddress (GetModuleHandle("KERNEL32"), TEXT("RegisterServiceProcess")); // Register the WIN95 service if(hookRegisterServiceProcess(NULL,dwType)==0) return FALSE; return TRUE; } ---- 加 入 注 册 表 子 程 序: #define SERVICE_NAME TEXT("SERVICE") // Define: BOOL W95StartService( DWORD dwType ) // Parameters: dwType --- Flag to register or unregister the service // RSP_SIMPLE_SERVICE means register // RSP_UNREGISTER_SERVICE means unregister // Return: TRUE --- call success; FALSE --- call failer BOOL W95StartService( DWORD dwType ) { // Local Variables TCHAR lpszBuff[256]; LPTSTR lpszStr = lpszBuff +128; LPTSTR lpszName = lpszBuff; HANDLE hKey = NULL; DWORD dwStrCb = 0; DWORD dwValueType = 0; // Get service name currently lpszName = GetCommandLine(); for( int i = _tcslen(lpszName)-1; I >=0; i-- ) { if( ( lpszName[i] != '"' )&&( lpszName[i]!=' ') ) break; else if( lpszName[i] == '"' ) lpszName[i] = '0'; } if( lpszName[0] == '"' ) lpszName = lpszName +1; // Registe as start up service if( RegOpenKeyEx (HKEY_LOCAL_MACHINE, TEXT( "SOFTWARE\Microsoft\Windows\ CurrentVersion\RunServices"), 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hKey ) != ERROR_SUCCESS ) { if( RegCreateKey( HKEY_LOCAL_MACHINE, TEXT( "SOFTWARE\Microsoft\ Windows\CurrentVersion\RunServices"), &hKey ) != ERROR_SUCCESS ) { //DebugOut( "RegCreateKey() error!"); return FALSE; } } dwValueType = REG_SZ; dwStrCb = 128; // Take value if( RegQueryValueEx(hKey, SERVICE_NAME, 0, &dwValueType, (LPBYTE)lpszStr, &dwStrCb ) == ERROR_SUCCESS ) { // Find this key value if( _tcscmp( lpszStr, lpszName )==0 ) { // Remove the service if( dwType == RSP_UNREGISTER_SERVICE ) { if(RegDeleteValue( hKey, SERVICE_NAME ) == ERROR_SUCCESS ) { RegCloseKey ( hKey ); return TRUE; } RegCloseKey( hKey ); return FALSE; } // Already exist service if( dwType == RSP_SIMPLE_SERVICE ) { //DebugOut("Already registed!"); RegCloseKey( hKey ); return TRUE; } } // Not find it } // No this value // Unregiste return if( dwType == RSP_UNREGISTER_SERVICE ) { RegCloseKey( hKey ); return TRUE; } // No this value then create it if( dwType == RSP_SIMPLE_SERVICE ) { dwStrCb = 128; // Set value if( RegSetValueEx(hKey, SERVICE_NAME, 0, REG_SZ, (CONST BYTE *)lpszName, dwStrCb ) != ERROR_SUCCESS ) { //DebugOut("RegSetValueEx() error!"); RegCloseKey( hKey ); return FALSE; } RegCloseKey( hKey ); return TRUE; } // Unknow type RegCloseKey( hKey ); return FALSE; } ---- 主 程 序: // WinMain function is the entry of the this program int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if( W95ServiceRegister( RSP_SIMPLE_SERVICE ) ) { W95StartService( RSP_SIMPLE_SERVICE ); } MessageBox(NULL, "Sample service", "SERVICE", MB_OK ); UNREFERENCED_PARAMETER( hInstance ); UNREFERENCED_PARAMETER( lpCmdLine ); UNREFERENCED_PARAMETER( nCmdShow ); UNREFERENCED_PARAMETER( hPrevInstance ); return 0; } ----运行这个程序,等到MessageBox弹出后,从WINDOWS中退出到LOG ON状态,你会看见MessageBox一直保持打开状态直至受到响应或系统关机.所以要做WINDOWS95下系统级的后台进程,并不一定非要去编写容易引起系统混乱的VXD程序,在硬件部分允 请教一个图形操作的问题? 求一个面试用的程序 如何运行这段vc++程序 看看VC这个的题目,你们觉得难吗? 在调用StartServiceCtrlDispatcher函数时返回1063的错误是怎么回事啊? 如何控制一个应用程序让它只启动一个 简单问题:怎么从“std::string”转换为“LPTSTR” unicode 和mbcs 什么关系???? 大家看看,帮帮忙。是关于IE接口的问题。如果有详细解释,请发至我的邮箱 VC编译器有问题吗? Virtual 的問題 about VRFY Command
黄飞 (12/17/1999)
---- 1.后台进程 ----在WINDOWS NT中有一个功能强大的SERVICE管理器,它管理着一部分实现重要功能的后台进程,例如FTP.HTTP.RAS.网络Message等等,这些后台进程被称之为Service,他们可以在系统启动时就加载,可以运行在较高的优先级,可以说是非常靠近系统核心的设备驱动程序中的一种.在WINDOWS95下,Microsoft没有提供这样一个高度集中化了的管理器,不过我们通过VC自带的PVIEW可以看到,在桌面背后同样有秘密的后台进程存在,例如:SysTray,电源管理等.其实,这些就是WINDOWS95管理的后台进程,WINDOWS95没有提供SERVICE管理器,取而代之的是一个简单的登记接口,可以类似的称之为WINDOWS95下的Service(不过严格的讲,WINDOWS95下是没有Service的),同样的,通过这个登记接口,我们可以使自己的程序随系统启动而最先运行,随系统关闭而最后停止,和操作系统结合在一起,实现许多独特的功能.我在实际工作中,仔细的分析了这个Windows95的接口,并且测试后发现,在WINDOWS97和最新的WINDOWS98中它一样有效.并通过这个机制,成功的实现了WINDOWS95.98下的无人职守监控.下面是关于这个接口的分析结果和一些准备知识. ---- 2.进程数据库(PDB)介绍 ----在Windows的核心数据结构中,有一个重要的进程管理结构叫进程数据库,它位于Kernel32的公用内存堆中,可以通过GetCurrentProcessID(...)得到指向该结构的指针,以下是部分PDB的组成,与本文直接相关的是PDB偏移21h处的Service标志字节,通过后面的伪码分析,我们可以清楚的看到所谓登记为Windows95或Windows98下的Service进程,只不过是把它相应的PDB中该标志字节置为1而已. 偏移量长度 说明
============================================
+00h DWORD Type // Kernel32对象的类型
+04h DWORD CReference //参考计数
+08h DWORD Un1 //未知
+0ch DWORD pSomeEvent //指向K32OBJ_EVENT指针
+10h DWORD TerminationStatus //活动标志或返回值
+14h DWORD Un2 //未知
.....
+21h BYTE Flags1 // Service标记,
// "1"是Service进程,
// "0"普通进程
.....
+24h DWORD pPSP // DOS PSP指针
..... ---- 3.实现接口 ---- (1) Windows95中提供的简单的Service接口是一个32位的API: RegisterServiceProcess,由于在VC++的Online help中得不到关于这个API的确切解释,笔者不得不针对此API进行了逆向分析,以下是在Windows95的Kernel32.dll中该API的伪码.我们可以清楚的看到Window95内部到底是怎样做的,其实处理的非常简单. BOOL RegisterServiceProcess( DWORD dwProcessID, DWORD dwType )
{
HANDLE dwPID;
if( dwProcessID == NULL )
dwPID = dwCurrentProcessID;
// Get global kernel32 variable
else
// Call some kernel functions
if( ( dwPID = CheckPID( dwProcessID ) == NULL )
return FALSE;
if( dwType == 1 )
{
*(BYTE *)( dwPID + 0x21 ) | = 0x01;
return TRUE;
}
if( dwType == 0 )
{
*(BYTE *)( dwPID + 0x21 ) & = 0xFE;
return TRUE;
}
return FALSE;
}
以下为函数原形:
BOOL RegisterServiceProcess( DWORD dwPID, DWORD dwType )
参数:
dwPID:进程ID, NULL代表当前进程
dwType: RSP_SIMPLE_SERVICE为登记
RSP_UNREGISTER_SERVICE为取消登记
返回值: TRUE: 调用成功
FALSE: 调用失败 ---- (2)另外,为了让Service进程有机会在BOOT后就启动,Windows95的Registry中提供了加载方法:在KEY " MyComputer HKEY_LOCAL_MACHINESOFTWARE MicrosoftWindows CurrentVersion RunServices "加入自己的应用程序命令行,即可实现开机自动加载.当然,如果你得机器中没有这个Key,自己建一个也是可以的. ----4.例程 ----下面是实现例程,所有代码经过了WINDOWS95. WINDOWS98 BETA3的测试,可以方便的加入到自己的项目文件中. ----头文件: // File: service.h
// The head file of "service.cpp"
// Note: 1. You must use C++ compiler
// 2. The platform is WIN32 (WINNT & WIN95) #ifndef _SERVICE_H
#define _SERVICE_H /////////////////////////////////////////////////// USED FOR WIN95 SERVICE
// Micros
#define RSP_SIMPLE_SERVICE 1
#define RSP_UNREGISTER_SERVICE 0 // Function types for GetProcAddress
#define RegisterServiceProcess_PROFILE
(DWORD (__stdcall *) (DWORD, DWORD)) // Service Fuctions in Win95
BOOL W95ServiceRegister(DWORD dwType);
BOOL W95StartService( DWORD dwType ); #endif CPP 文 件:
// File: service.cpp --- implement the service #include "service.h"
/////////////////////////////////////////////////// USED FOR WIN95 SERVICE登 记 为Service 子 程 序:
/////////////////////////////////////////////////////////////////////////////////
// Define: BOOL
W95ServiceRegister(DWORD dwType)
// Parameters: dwType --- Flag to
register or unregister the service
// RSP_SIMPLE_SERVICE means register
// RSP_UNREGISTER_SERVICE means unregister
// Return: TRUE --- call success;
FALSE --- call failer BOOL W95ServiceRegister( DWORD dwType )
{
// Function address defination
DWORD (__stdcall * hookRegisterServiceProcess)
( DWORD dwProcessId, DWORD dwType ); // Get address of function
hookRegisterServiceProcess =
RegisterServiceProcess_PROFILE
GetProcAddress
(GetModuleHandle("KERNEL32"),
TEXT("RegisterServiceProcess")); // Register the WIN95 service
if(hookRegisterServiceProcess(NULL,dwType)==0)
return FALSE;
return TRUE;
}
---- 加 入 注 册 表 子 程 序: #define SERVICE_NAME TEXT("SERVICE")
// Define: BOOL W95StartService( DWORD dwType )
// Parameters: dwType --- Flag to
register or unregister the service
// RSP_SIMPLE_SERVICE means register
// RSP_UNREGISTER_SERVICE means unregister
// Return: TRUE --- call success; FALSE --- call failer BOOL W95StartService( DWORD dwType )
{
// Local Variables
TCHAR lpszBuff[256];
LPTSTR lpszStr = lpszBuff +128;
LPTSTR lpszName = lpszBuff;
HANDLE hKey = NULL;
DWORD dwStrCb = 0;
DWORD dwValueType = 0; // Get service name currently
lpszName = GetCommandLine();
for( int i = _tcslen(lpszName)-1; I >=0; i-- )
{
if( ( lpszName[i] != '"' )&&( lpszName[i]!=' ') )
break;
else if( lpszName[i] == '"' )
lpszName[i] = '0';
}
if( lpszName[0] == '"' )
lpszName = lpszName +1; // Registe as start up service
if( RegOpenKeyEx (HKEY_LOCAL_MACHINE,
TEXT( "SOFTWARE\Microsoft\Windows\
CurrentVersion\RunServices"),
0,
KEY_QUERY_VALUE | KEY_SET_VALUE,
&hKey ) != ERROR_SUCCESS )
{
if( RegCreateKey( HKEY_LOCAL_MACHINE,
TEXT( "SOFTWARE\Microsoft\
Windows\CurrentVersion\RunServices"),
&hKey ) != ERROR_SUCCESS )
{
//DebugOut( "RegCreateKey() error!");
return FALSE;
}
} dwValueType = REG_SZ;
dwStrCb = 128; // Take value
if( RegQueryValueEx(hKey,
SERVICE_NAME,
0,
&dwValueType,
(LPBYTE)lpszStr,
&dwStrCb ) == ERROR_SUCCESS ) {
// Find this key value
if( _tcscmp( lpszStr, lpszName )==0 )
{
// Remove the service
if( dwType == RSP_UNREGISTER_SERVICE )
{
if(RegDeleteValue( hKey, SERVICE_NAME )
== ERROR_SUCCESS )
{
RegCloseKey ( hKey );
return TRUE;
}
RegCloseKey( hKey );
return FALSE;
}
// Already exist service
if( dwType == RSP_SIMPLE_SERVICE )
{
//DebugOut("Already registed!");
RegCloseKey( hKey );
return TRUE;
}
}
// Not find it
} // No this value // Unregiste return
if( dwType == RSP_UNREGISTER_SERVICE )
{
RegCloseKey( hKey );
return TRUE;
} // No this value then create it
if( dwType == RSP_SIMPLE_SERVICE )
{
dwStrCb = 128; // Set value
if( RegSetValueEx(hKey,
SERVICE_NAME,
0,
REG_SZ,
(CONST BYTE *)lpszName,
dwStrCb ) != ERROR_SUCCESS )
{
//DebugOut("RegSetValueEx() error!");
RegCloseKey( hKey ); return FALSE;
}
RegCloseKey( hKey );
return TRUE;
} // Unknow type
RegCloseKey( hKey );
return FALSE;
}
---- 主 程 序: // WinMain function is the entry of the this program
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
if( W95ServiceRegister( RSP_SIMPLE_SERVICE ) )
{
W95StartService( RSP_SIMPLE_SERVICE );
} MessageBox(NULL, "Sample service", "SERVICE", MB_OK );
UNREFERENCED_PARAMETER( hInstance );
UNREFERENCED_PARAMETER( lpCmdLine );
UNREFERENCED_PARAMETER( nCmdShow );
UNREFERENCED_PARAMETER( hPrevInstance );
return 0;
} ----运行这个程序,等到MessageBox弹出后,从WINDOWS中退出到LOG ON状态,你会看见MessageBox一直保持打开状态直至受到响应或系统关机.所以要做WINDOWS95下系统级的后台进程,并不一定非要去编写容易引起系统混乱的VXD程序,在硬件部分允