昨天,潘弄了一下午的Solaris10+OpenFiler,iscsiadm无论如何都连不上OpenFiler。
最后,把OpenFiler的Network Access Cinfiguration中NetMask设成了255.255.255.255,然后就连上了。
哈哈哈,这个坑不错,鄙视潘潘一下。
Learn and share.
昨天,潘弄了一下午的Solaris10+OpenFiler,iscsiadm无论如何都连不上OpenFiler。
最后,把OpenFiler的Network Access Cinfiguration中NetMask设成了255.255.255.255,然后就连上了。
哈哈哈,这个坑不错,鄙视潘潘一下。
大家都知道,使用微软的MFC ActiveX控件向导生成的控件类,是基于COleControl的,而COleControl是基于CWnd类。这样很多MFC的特性,如CFrameWnd的特性,CSingleDocTemplate(SDI)的特性等就无法使用了。如果要把用到这些类的MFC程序封装为ActiveX插件,就会有不少麻烦。
其实这个问题,在上个世纪MFC诞生不久,就有人解决了,并提供了完整的示例代码。微软官方的这篇文章《Designing ActiveX Components with the MFC Document/View Model》,在原地址http://www.microsoft.com/mind/0497/mfc.asp已经无法找到了。
但好在这里还有完整的备份《Designing ActiveX Components with the MFC Document/View Model》。
原文的作者,实现了CActiveXDocTemplate和CActiveXDocControl两个类,而用户只需要将控件的基类从COleControl换为CActiveXDocControl,并做简单修改,就可以方便的使用SDI的特性了。
整体思路其实是使用CActiveXDocControl扩展了COleControl。在CActiveXDocControl中,作者初始化了CDocManager,使用CActiveXDocTemplate控制了document、view、frame的生成,处理了OnSize事件,并使用Timer定时获取消息处理更新。
我们使用的时候,主要就是用这两个类,代码如下(两个类相互引用,所以放到了同一文件中):
1、ActivDoc.h
class CActiveXDocTemplate : public CSingleDocTemplate
{
enum { IDR_NOTUSED = 0x7FFF };
CWnd* m_pParentWnd;
CFrameWnd* m_pFrameWnd;
CString m_docFile;
public:
CActiveXDocTemplate(CRuntimeClass* pDocClass,
CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass);
CFrameWnd* CreateDocViewFrame(CWnd* pParentWnd);
void SaveDocumentFile();
virtual CFrameWnd* CreateNewFrame(CDocument* pDoc,
CFrameWnd* pOther);
virtual CDocument* OpenDocumentFile(
LPCTSTR lpszPathName, BOOL bVerifyExists = TRUE);
};
//===================================================
class CActiveXDocControl : public COleControl
{
enum { WM_IDLEUPDATECMDUI = 0x0363 };
static BOOL m_bDocInitialized;
CActiveXDocTemplate* m_pDocTemplate;
CFrameWnd* m_pFrameWnd;
DECLARE_DYNAMIC(CActiveXDocControl)
protected:
void AddDocTemplate(CActiveXDocTemplate* pDocTemplate);
CDocTemplate* GetDocTemplate() { return m_pDocTemplate; }
//{{AFX_MSG(CActiveXDocControl)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnDestroy();
//}}AFX_MSG
//{{AFX_DISPATCH(CActiveXDocControl)
//}}AFX_DISPATCH
//{{AFX_EVENT(CActiveXDocControl)
//}}AFX_EVENT
DECLARE_MESSAGE_MAP()
DECLARE_DISPATCH_MAP()
DECLARE_EVENT_MAP()
public:
CActiveXDocControl();
virtual ~CActiveXDocControl();
enum {
//{{AFX_DISP_ID(CActiveXDocControl)
//}}AFX_DISP_ID
};
};
2、ActivDoc.cpp
// ActivDoc.cpp : implementation file
//
#include "stdafx.h"
#include "ActivDoc.h"
CActiveXDocTemplate::CActiveXDocTemplate(CRuntimeClass* pDocClass,
CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass)
: CSingleDocTemplate(IDR_NOTUSED, pDocClass, pFrameClass,
pViewClass)
{
ASSERT(pFrameClass);
}
CFrameWnd* CActiveXDocTemplate::CreateDocViewFrame(CWnd* pParentWnd)
{
ASSERT(pParentWnd && IsWindow(*pParentWnd));
ASSERT_KINDOF(CActiveXDocControl, pParentWnd);
m_pParentWnd = pParentWnd;
m_pFrameWnd = NULL;
// OpenDocumentFile is a virtual method (implemented in
// the CSingleDocTemplate base class) that creates
// the document (either empty or loaded from the specified
// file) and calls our CreateNewFrame function. Passing
// NULL to the function creates a new document. Incidentally,
// the view is created by the CFrameWnd's OnCreateClient()
// method.
if (!OpenDocumentFile(NULL))
return NULL;
// Since OpenDocumentFile sets m_pFrame, we can now use it.
ASSERT(m_pFrameWnd);
ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);
m_pFrameWnd->ShowWindow(SW_SHOWNORMAL);
return m_pFrameWnd;
}
CFrameWnd* CActiveXDocTemplate::CreateNewFrame(CDocument* pDoc,
CFrameWnd* pOther)
{
ASSERT(pOther == NULL);
ASSERT(m_pFrameClass != NULL);
if (pDoc != NULL)
ASSERT_VALID(pDoc);
// Create a frame wired to the specified document
CCreateContext context;
context.m_pCurrentFrame = pOther;
context.m_pCurrentDoc = pDoc;
context.m_pNewViewClass = m_pViewClass;
context.m_pNewDocTemplate = this;
m_pFrameWnd = (CFrameWnd*)m_pFrameClass->CreateObject();
if (m_pFrameWnd == NULL)
{
TRACE1("Warning: Dynamic create of frame %hs failed.\n",
m_pFrameClass->m_lpszClassName);
return NULL;
}
ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);
if (context.m_pNewViewClass == NULL)
TRACE0("Warning: creating frame with no default view.\n");
// The frame is created as a menu-less child of the
// CActiveXDocControl in which it will reside.
ASSERT_KINDOF(CActiveXDocControl, m_pParentWnd);
if (!m_pFrameWnd->Create(NULL, "", WS_CHILD|WS_VISIBLE,
CFrameWnd::rectDefault, m_pParentWnd, NULL, 0, &context))
{
TRACE0("Warning: CDocTemplate couldn't create a frame.\n");
return NULL;
}
return m_pFrameWnd;
}
CDocument* CActiveXDocTemplate::OpenDocumentFile(
LPCTSTR lpszPathName, BOOL bVerifyExists)
{
SaveDocumentFile();
m_docFile = lpszPathName;
if (bVerifyExists)
{
DWORD dwAttrib = GetFileAttributes(m_docFile);
if (dwAttrib == 0xFFFFFFFF ||
dwAttrib == FILE_ATTRIBUTE_DIRECTORY)
{
lpszPathName = NULL;
}
}
return CSingleDocTemplate::OpenDocumentFile(
lpszPathName, TRUE);
}
void CActiveXDocTemplate::SaveDocumentFile()
{
if (m_pOnlyDoc != NULL)
{
if (!m_docFile.IsEmpty())
m_pOnlyDoc->OnSaveDocument(m_docFile);
else
m_pOnlyDoc->SetModifiedFlag(FALSE);
}
}
//===================================================
// CActiveXDocControl
IMPLEMENT_DYNAMIC(CActiveXDocControl, COleControl)
BEGIN_MESSAGE_MAP(CActiveXDocControl, COleControl)
//{{AFX_MSG_MAP(CActiveXDocControl)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_TIMER()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()
BEGIN_DISPATCH_MAP(CActiveXDocControl, COleControl)
//{{AFX_DISPATCH_MAP(CActiveXDocControl)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
BEGIN_EVENT_MAP(CActiveXDocControl, COleControl)
//{{AFX_EVENT_MAP(COleFrameCtrl)
//}}AFX_EVENT_MAP
END_EVENT_MAP()
int CActiveXDocControl::m_bDocInitialized = FALSE;
CActiveXDocControl::CActiveXDocControl()
{
m_pDocTemplate = NULL;
m_pFrameWnd = NULL;
// Since we're in an OCX, CWinApp::InitApplication() is
// not called by the framework. Unfortunately, that method
// performs CDocManager initialization that is necessary
// in order for our DocTemplate to clean up after itself.
// We simulate the same initialization by calling the
// following code the first time we create a control.
if (!m_bDocInitialized)
{
CDocManager docManager;
docManager.AddDocTemplate(NULL);
m_bDocInitialized = TRUE;
}
}
CActiveXDocControl::~CActiveXDocControl()
{
// Note that the frame, the document, and the view are
// all deleted automatically by the framework!
delete m_pDocTemplate;
}
void CActiveXDocControl::AddDocTemplate(CActiveXDocTemplate* pDocTemplate)
{
// I've decided to call this function AddDocTemplate to
// be consistent with naming of CWinApp::AddDocTemplate.
// However, only one DocTemplate is allowed per control.
ASSERT(pDocTemplate);
ASSERT(m_pDocTemplate == NULL);
m_pDocTemplate = pDocTemplate;
}
int CActiveXDocControl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (COleControl::OnCreate(lpCreateStruct) == -1)
return -1;
// The CActiveXDocTemplate object will create the
// document, the view, and the frame inside the
// control. The reason we need a handle to the frame
// is so that we can resize it when the control is
// resized.
ASSERT(m_pDocTemplate); // Set in call to AddDocTemplate
m_pFrameWnd = m_pDocTemplate->CreateDocViewFrame(this);
ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);
// By default, we'll create the control with a border,
// since it looks better for frames containing a toolbar.
SetBorderStyle(TRUE);
SetTimer(WM_IDLEUPDATECMDUI, 300, NULL);
return 0;
}
void CActiveXDocControl::OnSize(UINT nType, int cx, int cy)
{
COleControl::OnSize(nType, cx, cy);
// The CFrameWnd should always fill up the entire client
// area of the control.
if (m_pFrameWnd != NULL)
{
ASSERT(IsWindow(*m_pFrameWnd));
CRect area;
GetClientRect(area);
m_pFrameWnd->MoveWindow(area.left, area.top, area.right,
area.bottom);
}
}
void CActiveXDocControl::OnTimer(UINT nIDEvent)
{
// Since we're in an OCX, we don't control the message loop,
// so CWinThread::OnIdle is never called. That means we have
// to periodically pump the ON_UPDATE_COMMAND_UI messages
// by hand.
SendMessageToDescendants(WM_IDLEUPDATECMDUI, TRUE);
COleControl::OnTimer(nIDEvent);
}
void CActiveXDocControl::OnDestroy()
{
AfxGetApp()->m_pMainWnd = NULL;
m_pDocTemplate->SaveDocumentFile();
COleControl::OnDestroy();
}
困了,回去再写。。。
windows 系统服务分为独立进程和共享进程两种:
A、独立进程服务,一般都是一个EXE文件,里面有WinMain、ServiceMain和MessageHandler,用于安装、卸载、处理服务消息、提供服务等。
比如:
Windows Search
C:\Windows\system32\SearchIndexer.exe /Embedding
Windows Installer
C:\Windows\system32\msiexec.exe /V
B、共享进程服务,一般都是一个DLL文件,里面有DllMain、ServiceMain和MessageHandler,用于处理服务消息、提供服务。共享进程服务,一般用Svchost作为宿主进程,宿主进程只是一个框架,该进程通过启动参数+注册表定位到服务DLL,通过调用DLL中的函数,来实现业务逻辑。
比如:
Background Intelligent Transfer Service的启动参数为
C:\Windows\System32\svchost.exe -k netsvcs
Windows Firewall的启动参数为
C:\Windows\system32\svchost.exe -k LocalServiceNoNetwork
独立进程都会指定是哪个EXE,但svchost是如何知道启动netsvcs或LocalServiceNoNetwork要用哪个DLL呢?答案是在注册表中:
比如Background Intelligent Transfer Service的服务名为BITS,在下面路径中
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\BITS\Parameters\ServiceDll
指定了调用的dll为%SystemRoot%\System32\qmgr.dll
Windows Firewall的服务名为MpsSvc,在下面路径中
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\MpsSvc\Parameters\ServiceDll
指定了调用的dll为%SystemRoot%\system32\mpssvc.dll
既然这些服务是使用共享进程方式由svchost启动的,为什么系统中会有多个svchost进程呢?微软把这些服务进行了分组,同组服务共享一个svchost进程,不同组服务使用多个svchost进程,组的区别是由服务的可执行程序后边的参数决定的。
因此Background Intelligent Transfer Service的分组为netsvcs,Windows Firewall的分组为LocalServiceNoNetwork,这两个服务属于两个组,在两个不同的svchost进程中。
可以在下面的位置,找到svchost的所有组和组内的所有服务:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost
在我的Win7系统中,有如下分组:
AxInstSVGroup, DcomLaunch, LocalService, LocalServiceAndNoImpersonation, LocalServiceNetworkRestricted, LocalServiceNoNetwork, LocalServicePeerNet, LocalSystemNetworkRestricted, NetworkService, NetworkServiceAndNoImpersonation, NetworkServiceNetworkRestricted, PeerDist, RPCSS, WbioSvcGroup, WerSvcGroup, apphost, bthsvcs, defragsvc, iissvcs, imgsvc, netsvcs, regsvc, sdrsvc, secsvcs, swprv, termsvcs, wcssvc
而在netsvcs分组下,有
AeLookupSvc, AppMgmt, AudioSrv, BITS, CertPropSvc, FastUserSwitchingCompatibility, Ias, Irmon, LogonHours, NWCWorkstation, Nla, Ntmssvc, Nwsapagent, PCAudit, Rasauto, Rasman, Remoteaccess, SCPolicySvc, SENS, SRService, SessionEnv, Sharedaccess, ShellHWDetection, Tapisrv, TermService, WmdmPmSp, Wmi, gpsvc, helpsvc, iphlpsvc, lanmanserver, msiscsi, schedule, uploadmgr, winmgmt, wuauserv
这样,服务启动时,ServiceManager会查看该分组的svchost的进程是否启动,如果已经启动,则不需要新开启svchost进程,只需要直接加载服务即可。
那如何增加一个新的分组,和一个新的服务呢?那就需要修改注册表啦:
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost] "NeoTest"=hex(7):53,00,68,00,54,00,73,00,74,00,00,00,00,00
重启后才会有效。
调试的时候,应该自己新建一个分类,否则有了问题,将其他系统服务搞挂就不好了。
自己新建分类,不爽的时候,可以直接杀掉改svchost进程。
PS:在XP时代的头几年,伪装Svchost进程的恶意软件还是很多的,但现在杀毒软件都会重点处理这块儿内容,也就慢慢淡出了。
svchost一般来说,运行的都是windows内部服务,不给第三方开放。
但如果我们要自己写一个这样的服务,那实现这样的服务需要什么呢?
1、Dll入口函数:DllMain,dll入口函数
2、服务入口函数:ServiceMain,Service入口函数
3、rundll32安装服务函数:RundllInstall,生成注册表信息
4、rundll32卸载服务函数:RundllUninstall,删除注册表信息
5、将自己添加为一个新的svchost服务
比如下面的例子,将自己注册为一个NeoTest的SvchostTest服务:
Win7+VS2012u4+Unicode+MDd+Use Standard Windows Libraries
svchosttest.h
#include <windows.h> //服务主进程入口函数 void WINAPI ServiceMain( DWORD dwArgc, LPTSTR* lpszArgv); //服务消息处理函数 void WINAPI ServiceHandlerEx( DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext); //更新服务状态 int UpdateSvcStatus( DWORD dwState, DWORD dwExitCode, DWORD dwProgress ); //实际业务数据处理 int StartProcessing( TCHAR *cmd, int bInteract); //安装服务 int InstallService(TCHAR *name); //卸载服务 int UninstallService(TCHAR *name); //Rundll接口 void CALLBACK RundllInstall( HWND hwnd, HINSTANCE hinst, TCHAR *param, int nCmdShow); //Rundll接口 void CALLBACK RundllUninstall( HWND hwnd, HINSTANCE hinst, TCHAR *param, int nCmdShow); //输出调试内容 void OutputString(TCHAR *lpFmt, ... );
svchosttest.cpp
#include <stdio.h>
#include <time.h>
#include <assert.h>
#include <tchar.h>
#include "svchosttest.h"
#define DEFAULT_SERVICE_NAME TEXT("SvchostTest")
#define DEFAULT_SERVICE_GROUP TEXT("NeoTest")
#define SERVICE_START_CMD TEXT("%SystemRoot%\\System32\\svchost.exe -k NeoTest")
#define SERVICE_DLL TEXT("ServiceDll")
#define MY_EXECUTE_NAME TEXT("Notepad.exe")
#define WAIT_INTERVAL (100)
//dll模块句柄
HANDLE hDll = NULL;
//描述服务状态的服务句柄和状态
SERVICE_STATUS_HANDLE hSrv;
DWORD dwCurrState;
//关键区用于同步服务状态
CRITICAL_SECTION criticalStatus;
//dll入口函数
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hDll = hModule;
#ifdef _DEBUG
AllocConsole();
OutputString(TEXT("SvcHostDLL: DllMain called DLL_PROCESS_ATTACH"));
break;
case DLL_THREAD_ATTACH:
OutputString(TEXT("SvcHostDLL: DllMain called DLL_THREAD_ATTACH"));
break;
case DLL_THREAD_DETACH:
OutputString(TEXT("SvcHostDLL: DllMain called DLL_THREAD_DETACH"));
break;
case DLL_PROCESS_DETACH:
UpdateSvcStatus( SERVICE_STOP_PENDING, 0, 0 );
Sleep(WAIT_INTERVAL);
UpdateSvcStatus( SERVICE_STOPPED, 0, 0 );
OutputString(TEXT("SvcHostDLL: DllMain called DLL_PROCESS_DETACH"));
#endif
break;
}
return TRUE;
}
//服务入口函数
void WINAPI ServiceMain(
DWORD dwArgc,
LPTSTR *lpszArgv)
{
//For Debug
//直接DebugBreak会导致服务退出
//DebugBreak();
//下面也不好用
//DWORD pId = GetCurrentProcessId();
//DebugActiveProcess(pId);
//手动附加到进程还可以的
#ifdef _DEBUG
while(!IsDebuggerPresent())
{
Sleep(WAIT_INTERVAL);
}
DebugBreak();
#endif
//使用ANSI编译时,字符集与Schost.exe传递过来的不同,
//从而导致lpszArgv里面只有服务名称的第一个字母,而不是服务全名,需要自行处理
//使用Unicode编译时,就不会有这个问题
//TCHAR svcname[256];
//_tcsncpy(svcname, (TCHAR*)lpszArgv[0], _countof(svcname));
//OutputString(TEXT("SvcHostDLL: ServiceMain(%d, %s) called"), dwArgc, svcname);
TCHAR svcname[256];
_tcsncpy(svcname, DEFAULT_SERVICE_NAME, _countof(svcname));
hSrv = RegisterServiceCtrlHandlerEx(svcname, (LPHANDLER_FUNCTION_EX)ServiceHandlerEx, NULL );
if( hSrv == NULL )
{
OutputString(TEXT("SvcHostDLL: RegisterServiceCtrlHandler %S failed"), lpszArgv[0]);
#ifdef _DEBUG
FreeConsole();
#endif
return;
}
InitializeCriticalSection(&criticalStatus);
UpdateSvcStatus( SERVICE_START_PENDING, 0, 0 );
OutputString(TEXT("SvcHostDLL: ServiceMain() Start Pending"));
Sleep(WAIT_INTERVAL);
UpdateSvcStatus( SERVICE_RUNNING, 0, 0 );
OutputString(TEXT("SvcHostDLL: ServiceMain() Running"));
//开启服务
TCHAR svccmd[256];
if(dwArgc > 1)
{
_tcsncpy(svccmd, (TCHAR*)lpszArgv[1], _countof(svccmd));
}
else
{
_tcsncpy(svccmd, MY_EXECUTE_NAME, _countof(svccmd));
}
int bInteract = dwArgc > 2 ? 1 : 0;
StartProcessing(svccmd, bInteract);
do{
//这里也可以用其它同步方式处理
Sleep(WAIT_INTERVAL);
}while(dwCurrState != SERVICE_STOP_PENDING && dwCurrState != SERVICE_STOPPED);
OutputString(TEXT("SvcHostDLL: ServiceMain done"));
#ifdef _DEBUG
FreeConsole();
#endif
return;
}
//调用SetServiceStatus设置服务状态
int UpdateSvcStatus( DWORD dwState, DWORD dwExitCode, DWORD dwProgress )
{
EnterCriticalSection(&criticalStatus);
SERVICE_STATUS srvStatus;
srvStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
srvStatus.dwCurrentState = dwCurrState = dwState;
srvStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN;
srvStatus.dwWin32ExitCode = dwExitCode;
srvStatus.dwServiceSpecificExitCode = NO_ERROR;
srvStatus.dwCheckPoint = dwProgress;
srvStatus.dwWaitHint = 3000;
BOOL bRet = SetServiceStatus( hSrv, &srvStatus );
LeaveCriticalSection(&criticalStatus);
return bRet;
}
//服务消息处理函数
void WINAPI ServiceHandlerEx(
DWORD dwControl,
DWORD dwEventType,
LPVOID lpEventData,
LPVOID lpContext)
{
switch( dwControl )
{
case SERVICE_CONTROL_STOP:
UpdateSvcStatus( SERVICE_STOP_PENDING, 0, 1 );
OutputString(TEXT("SvcHostDLL: ServiceHandler called SERVICE_CONTROL_STOP"));
Sleep(WAIT_INTERVAL);
UpdateSvcStatus( SERVICE_STOPPED, 0, 0 );
break;
case SERVICE_CONTROL_PAUSE:
UpdateSvcStatus( SERVICE_PAUSE_PENDING, 0, 1 );
OutputString(TEXT("SvcHostDLL: ServiceHandler called SERVICE_CONTROL_PAUSE"));
UpdateSvcStatus( SERVICE_PAUSED, 0, 0 );
break;
case SERVICE_CONTROL_CONTINUE:
UpdateSvcStatus( SERVICE_CONTINUE_PENDING, 0, 1 );
OutputString(TEXT("SvcHostDLL: ServiceHandler called SERVICE_CONTROL_CONTINUE"));
UpdateSvcStatus( SERVICE_RUNNING, 0, 0 );
break;
case SERVICE_CONTROL_INTERROGATE:
OutputString(TEXT("SvcHostDLL: ServiceHandler called SERVICE_CONTROL_INTERROGATE"));
UpdateSvcStatus( dwCurrState, 0, 0 );
break;
case SERVICE_CONTROL_SHUTDOWN:
OutputString(TEXT("SvcHostDLL: ServiceHandler called SERVICE_CONTROL_SHUTDOWN"));
UpdateSvcStatus( SERVICE_STOPPED, 0, 0 );
break;
}
}
//服务主进程
//这里只是启动了一个进程,就退出了
//如果要在这里实现业务逻辑的话,需要自己做好同步
int StartProcessing(TCHAR *cmd, int bInteract)
{
OutputString(TEXT("SvcHostDLL: RealService called '%s' %s"), cmd, bInteract ? "Interact" : "");
STARTUPINFO si = {0};
si.cb = sizeof(si);
//winlogon初始桌面:
//应用程序桌面(\Windows\WinSta0\Default)
//Winlogon桌面(\Windows\WinSta0\Winlogon)
//屏幕保护桌面(\Windows\WinSta0\ScrenSaver)
//相关API:
//OpenWindowStation,SetProcessWindowStation
//OpenDesktop,SetThreadDesktop,ConnectToDesktop,SwitchDesktop
if(bInteract) si.lpDesktop = TEXT("WinSta0\\Default");
PROCESS_INFORMATION pi;
if(!CreateProcess(NULL, cmd, NULL, NULL, false, 0, NULL, NULL, &si, &pi))
{
OutputString(TEXT("SvcHostDLL: CreateProcess(%s) error:%d"), cmd, GetLastError());
}
else
{
OutputString(TEXT("SvcHostDLL: CreateProcess(%s) to %d"), cmd, pi.dwProcessId);
}
return 0;
}
//写注册表安装服务
//HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost\\netsvcs
//HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\服务名称\\Parameters\\ServiceDll
//这里默认设置为自动启动,不与桌面交互,调整要修改注册表
int InstallService(TCHAR *newName)
{
// 注册表中查找svchost配置信息
// 调阅API注册服务
// 配置服务所需的启动参数
int rc = 0;
HKEY hkRoot = HKEY_LOCAL_MACHINE, hkParam = 0;
SC_HANDLE hscm = NULL, schService = NULL;
try{
TCHAR buff[500];
TCHAR *svcname = DEFAULT_SERVICE_NAME;
if(newName && newName[0]) svcname = newName;
//新增服务
hscm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hscm == NULL)
{
throw "OpenSCManager()";
}
TCHAR *svhostStartCmd = SERVICE_START_CMD;
schService = CreateService(
hscm, // SCManager database
svcname, // name of service
NULL, // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_SHARE_PROCESS,// service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
svhostStartCmd, // service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL); // no password
if (schService == NULL)
{
OutputString(TEXT("CreateService(%s) error %d"), svcname, rc = GetLastError());
throw "";
}
OutputString(TEXT("CreateService(%s) SUCCESS. Config it"), svcname);
CloseServiceHandle(schService);
CloseServiceHandle(hscm);
//新增服务配置,设置服务dll路径
hkRoot = HKEY_LOCAL_MACHINE;
_tcsncpy(buff, TEXT("SYSTEM\\CurrentControlSet\\Services\\"), _countof(buff));
_tcsnccat(buff, svcname, 100);
rc = RegOpenKeyEx(hkRoot, buff, 0, KEY_ALL_ACCESS, &hkRoot);
if(ERROR_SUCCESS != rc)
{
OutputString(TEXT("RegOpenKeyEx(%s) KEY_SET_VALUE error %d."), svcname, rc);
throw "";
}
rc = RegCreateKey(hkRoot, TEXT("Parameters"), &hkParam);
SetLastError(rc);
if(ERROR_SUCCESS != rc)
{
throw "RegCreateKey(Parameters)";
}
if(!GetModuleFileName(HMODULE(hDll), buff, _countof(buff)))
{
throw "GetModuleFileName() get dll path";
}
rc = RegSetValueEx(hkParam, TEXT("ServiceDll"), 0, REG_EXPAND_SZ, (BYTE*)buff, _tcsclen(buff)+1);
SetLastError(rc);
if(ERROR_SUCCESS != rc)
{
throw "RegSetValueEx(ServiceDll)";
}
OutputString(TEXT("Config service %s ok."), svcname);
}
catch(TCHAR *ex)
{
if(ex && ex[0])
{
rc = GetLastError();
OutputString(TEXT("%s error %d"), ex, rc);
}
}
if(hkRoot)
{
RegCloseKey(hkRoot);
}
if(hkParam)
{
RegCloseKey(hkParam);
}
if(schService)
{
CloseServiceHandle(schService);
}
if(hscm)
{
CloseServiceHandle(hscm);
}
return rc;
}
//用于rundll32.exe安装服务
//rundll32.exe SvchostTest.dll,RundllInstall
void CALLBACK RundllInstall(
HWND hwnd, // handle to owner window
HINSTANCE hinst, // instance handle for the DLL
TCHAR *param, // string the DLL will parse
int nCmdShow // show state
)
{
InstallService(param);
}
//写注册表卸载服务
int UninstallService(TCHAR *newName)
{
int rc = 0;
SC_HANDLE schService;
SC_HANDLE hscm;
try
{
hscm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hscm == NULL)
{
OutputString(TEXT("OpenSCManager() error %d"), rc = GetLastError() );
return rc;
}
TCHAR *svcname = DEFAULT_SERVICE_NAME;
if(newName && newName[0]) svcname = newName;
schService = OpenService(hscm, svcname, DELETE);
if (schService == NULL)
{
OutputString(TEXT("OpenService(%s) error %d"), svcname, rc = GetLastError() );
return rc;
}
if (!DeleteService(schService) )
{
OutputString(TEXT("OpenService(%s) error %d"), svcname, rc = GetLastError() );
return rc;
}
OutputString(TEXT("DeleteService(%s) SUCCESS."), svcname);
}
catch(TCHAR* ex)
{
rc = GetLastError();
OutputString(TEXT("Exception Catched 0x%X"), rc);
}
CloseServiceHandle(schService);
CloseServiceHandle(hscm);
return rc;
}
//用于rundll32.exe卸载服务
//rundll32.exe SvchostTest.dll,RundllUninstall
void CALLBACK RundllUninstall(
HWND hwnd, // handle to owner window
HINSTANCE hinst, // instance handle for the DLL
TCHAR *param, // string the DLL will parse
int nCmdShow // show state
)
{
UninstallService(param);
}
//输出日志到日志文件和DbgPrint
void OutputString( TCHAR *lpFmt, ... )
{
TCHAR buff[1024];
va_list arglist;
va_start( arglist, lpFmt );
_vsntprintf( buff, _countof(buff), lpFmt, arglist );
va_end( arglist );
DWORD len;
HANDLE herr = GetStdHandle(STD_OUTPUT_HANDLE);
if(herr != INVALID_HANDLE_VALUE)
{
WriteFile(herr, buff, _tcslen(buff), &len, NULL);
WriteFile(herr, "\r\n", 2, &len, NULL);
}
else
{
FILE *fp = fopen("SvcHost.DLL.log", "a");
if(fp)
{
TCHAR date[20], time[20];
fprintf(fp, "%s %s - %s\n", _tstrdate(date), _tstrtime(time), buff);
if(!stderr) fclose(fp);
}
}
OutputDebugString(buff);
return;
}
svchosttest.def
EXPORTS ServiceMain RundllUninstall RundllInstall
参考(部分资料未能找到原文出处):
Writing a service that runs under svcho
Svchost.exe的原理
for %%I in (*.jar)do ( echo --unzipping %%~nI 7z x %%I -o%%~nI ) pause
上周调试Win7下的一个服务程序,以前都是用Debugbreak()直接可以进入调试的,但这次直接退出了。
查了一下,这样设置一下就可以:
控制面板->操作中心->维护->检查问题报告的解决方案->设置
每次发生问题时,在检查解决方案之前先询问我
保存设置后,就可以进入断点了,再次鄙视微软。
后来,又发现,即使设置后,仍然无法响应断点,没办法,只好用比较挫的代码搞定了:
//在第一个DebugBreak()前面,添加下面的语句
while(!IsDebuggerPresent())
{
Sleep(100);
}
DebugBreak();
这样,服务启动后,会一直等待调试器。启动服务后,手动通过VS、任务管理器或Process Explorer附加到进程,就可以对启动的服务进行调试了。
Win2008下调试Service程序时,发现无法使用DebugBreak(),否则程序直接挂掉,无法进行调试。
有资料说是,修改错误报告的选项就可以修正这个问题了,尝试后发现无效,暂时只能一点儿一点儿调试了。
另外,Win2008上内存检测严格了很多,需要注意。
最近遇到了Windows网络地址无法访问的问题,总结了一下,解决步骤如下:
表现为:
用localhost可以访问本机共享地址
但用网卡ip就不可以访问
1、开启对应的服务(Services.msc)
TCP/IP NetBios Helper
Computer Browser
Workstation
Server
2、网卡
对应的网卡-》Properties
启用Internet Protoclo Version 4
启用File and Printer Sharing for Microsoft Networks
对应的网卡-》Properties-》Networking-》Internet Protoclo Version 4-》Properties-》General->Advanced->WINS->NetBIOS Setting->Enable NetBIOS over TCP/IP
3、共享设置
控制面板Network and Sharing Center
-》Advanced sharing settings
-》(Home or Work/Public)
Trun on network discovery
Turn on file and printer sharing
Turn off Public folder sharing
Use 128-bit encryptiong to help …
Turn on password protected sharing…
4、防火墙
先关闭,尝试是否可以联通
如果可以通过的话,允许网络共享就可以解决问题
5、查看组策略,看下是否有端口禁用配置
如果有的话,禁用该策略
6、如果还不行,还原网卡配置
netsh interface ip reset log.txt
重启,会丢失全部网卡配置信息
说起gpt来,就一把鼻涕一把泪的,因为工作原因,需要在windows进行开发,
没办法在mac book pro里安了个win7,后来为了方便,在mac下安了ntfs的读写驱动,
悲剧发生了,某天开机进入mac,很久没反应,强制重启后,windows分区已经挂掉了。
于是重装,用win7的光盘进行的分区,后来用第三方分区工具调整了下,ntfs不负众望,又挂了
好吧~~,又重装了一次
一波三折,终于稳定了。
但mac下,却认不到ntfs分区,一直认为是mac下ntfs驱动的问题,尝试过一些解决方案,都不行。
今天发现,mac下分区大小和win7下分区大小不一样,mac下的分区大小,仍是我在win7下调整前的状态
懂了,明显是gpt分区表错了啊。
网上找了一堆工具,还差点用gpt把hybrid MBR给覆盖了,晕。
最后,用gdisk终于搞定了,修改gpt的神器啊。
http://sourceforge.net/projects/gptfdisk/files/gptfdisk/0.8.5/
http://www.rodsbooks.com/gdisk/walkthrough.html
sudo进入gdisk后,选用/dev/disk0,然后用v命令进行校验,
gdisk发警告,mbr里有两个分区在gpt中不存在,
进入expert模式,用p和o命令打印gpt和mbr分区信息,发现真的对不上,
把分区表记录好,gpt备份好。
然后将gpt中错误的两个分区删掉,再根据mbr里的数据,重新建立两个分区,
再用v命令校验,没有问题,
保持修改,重启,终于搞定了。
注意:
我的情况是,在mac分区表错误,而win7下分区表正确,这说明是gpt错了,而hybrid MBR是对的。
而如果是相反的情况,就要根据gpt重新编辑mbr,这样的工具很多,貌似在mac,win,linux共存的时候发生的几率会比较高。
对硬盘分区表的修改,是很危险的工作,一定要备份数据,备份分区表,将风险尽量降低。
最近在Windows2008R2上架设了Windows的FPT服务。
但无论怎样配置防火墙,本地都可以访问,远程只能显示登录框,登录后就卡住不动了。
各种配置入站出站规则。
1、允许了端口
2、允许了服务通过Microsoft FTP Service
还是不行。
最后,增加了一条配置:
允许C:\Windows\System32\svchost.exe通过防火墙,一切正常了。
好吧。。。
虽然这样有风险,但至少管用。
Finder:
killall -KILL Finder
Dock:
killall -KILL Dock
Menubar
killall -KILL SystemUIServer