MFC怎样编写后台运行的程序
---------------------------------------------------------------
http://www.codeproject.com/system/xservice.asp
---------------------------------------------------------------
以下为转载---------
1、实现开机自运行
我在csdn网站上经常看到有人问这样的问题,其实要实现开机时就自动运行自己的程序并不难。在注册表的HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run键下可以看到有一系列键值,它们都是开机自动运行的软件的路径。那么我们要做的就是编程实现将我们的程序的路径也添加到这个键值下,就搞定了。著名的“windows优化大师”也就是用去掉不必要的开机运行软件这个方法来实现开机速度优化的。
既然要读写注册表,就要用到两个重要的操作注册表的函数:RegOpenKey()和RegSetValueEx()。前者用于打开注册表的键,后者则为打开的键设置键值,至于这两个API函数的具体参数,请参见MSDN。为了代码重用的要求,我为此封装了一个专门的函数,如下所示:
BOOL SetAutoRun(CString strPath)//开机自动运行
{
CString str;
HKEY hRegKey;
BOOL bResult;
str=_T("Software\\Microsoft\\Windows\\CurrentVersion\\Run");
if(RegOpenKey(HKEY_LOCAL_MACHINE, str, &hRegKey) != ERROR_SUCCESS)
bResult=FALSE;
else
{
_splitpath(strPath.GetBuffer(0),NULL,NULL,str.GetBufferSetLength(MAX_PATH+1),NULL);
strPath.ReleaseBuffer();
str.ReleaseBuffer();
if(::RegSetValueEx( hRegKey,
str,
0,
REG_SZ,
(CONST BYTE *)strPath.GetBuffer(0),
strPath.GetLength() ) != ERROR_SUCCESS)
bResult=FALSE;
else
bResult=TRUE;
strPath.ReleaseBuffer();
}
return bResult;
}
其中strPath参数表示要设置为自运行的程序的绝对路径。当设置成功时返回true,否则返回false。
这里又带来一个问题:既然需要本程序的绝对路径,那么怎么得到它呢?总不能指定一个值吧,那么当本程序的路径改变时就又要修改程序,太麻烦了。可以用这个封装的函数来实现:
//得到程序文件本身的路径(包括文件名)
CString GetMyPath()
{
CString strPath;
GetModuleFileName(NULL,strPath.GetBufferSetLength(MAX_PATH+1),MAX_PATH);
strPath.ReleaseBuffer();
return strPath;
}
其中GetModuleFileName()是一个得到路径的API函数。本函数将这个API函数封装在其中,为的是简化调用的目的。
当执行这个函数时,返回本程序所在的绝对路径,包括本程序的文件名。
好了,得到本程序的路径,然后将它加载到注册表中,下次系统启动时,我们的程序就能自动随之启动了。
2、实现运行时自动隐藏
这是一个很有趣很古老的话题,csdn上经常有人为此讨论不休,提出不少方案,比如在对话框的OnInitDialog()中添加一句:ShowWindow(SW_HIDE);,或者在对话框属性框中去掉对话框的Visible属性;或者将对话框移到桌面以外的地方去;或者首先将对话框最小化,然后实现最小化时隐藏……有趣的是这些很容易想到的常规方法都不能解决这个问题,或者说解决的不够好。我通过查找相关文章和多次修改代码,找出了真正解决这个问题的办法。
之所以用ShowWindow()函数失效,我认为可能是对话框的DoModal()在作怪,这么一来就只能绕开DoModal(),那么就自然想到可以把对话框变成一个无模式对话框。无模式对话框平时我们用到的不多,它与模式对话框不同,是用Create方法Create出来的,而不是DoModal()创建的。
假设建立一个VC.NET工程GetTime,首先在CGetTimeApp类中添加一个成员变量:CGetTimeDlg *dlg;然后在InitInstance()中将原来的:
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
以及return FALSE;全部删除掉,改为: dlg=new CGetTimeDlg;
m_pMainWnd = dlg;
return dlg->Create(IDD_GETTIME_DIALOG);
最后别忘了在ExitInstance()中加上一句:delete dlg;好了,这下把本程序的对话框变成了一个无模式对话框。不过既然是无模式对话框,就不能再用OnOK(),OnCancel()来退出了,要用DestroyWindow()。
由于在上面的代码中没有将对话框设为可见,所以运行时就实现了隐藏,而且在Windows任务栏上也没有显示。至此,第二个问题得到完美解决。
****************************************************************************************************************************************************
基于对话框的的程序,如果要达到完全运行时隐藏,光将对话框的Visible属性设为FALSE是不够的,因为副对话框在App初始化的时候一个DoModal(),对话框就会显示出来,如果在对话框的OnInitDialog()使用如下两行代码:
SetWindowPos(&wndBottom, 0, 0, 0, 0, SWP_HIDEWINDOW); ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);
虽然能去掉窗体和任务栏上的图标,但避免不了,程序窗口的一闪,而且,在任务管理器的任务列表里会有该程序的运行图标。
如果在App的InitInstance()里将显示对话框的模式从“模式”改写为“无模式”,则能达到后台执行该对话框程序的目的,首先将父对话框的Visible属性设为FALSE,然后在程序的App类中定义一个成员变量:
CWnd* m_pWnd;
在程序的App类里面的InitInstance()里面将模式显示部分注释掉,改为:
CMyTestDlg* pDlg = new CMyTestDlg(); m_pWnd = pDlg; m_pMainWnd = pDlg; return pDlg->Create(IDD_MYTEST_DIALOG);
重写ExitInstance(),加入:
delete m_pWnd;
这样就达到了后台启动MFC对话框程序了。