VC++ 开发总结回顾(一)
做过一段时间vc++,虽说我现在也经常在群里喷微软的vc++ 各种不好用和繁琐,而且我认为c++已经越来越变质了,尤其到c++ 11再也不是我认识的c++了,可是即使这样,再让我做windows 软件我还是用vc++,因为我不会.net也不会qt
我回顾一下我之前vc++经常用的东西,我一直用的是vs2015,尽管我听说vs已经出了2017而且好像支持交叉编译了。。。
vc++开发其实就像php的框架一样 一般只需要在主程序文件 和 initDialog 和 OnPaint 以及一些事件里绘制一些东西即可
1.windows 程序分为 控制台程序 和 服务程序,控制台程序 不用说 是非常常见 的,主要说一下服务程序
别人的博客地址:
https://blog.csdn.net/lincyang/article/details/6231406
1)初始化一部分全局变量
void Init();
BOOL IsInstalled();
BOOL Install();
BOOL Uninstall();
void LogEvent(LPCTSTR pszFormat, ...);
void WINAPI ServiceMain();
void WINAPI ServiceStrl(DWORD dwOpcode);
TCHAR szServiceName[] = _T("ServiceTest");
BOOL bInstall;
SERVICE_STATUS_HANDLE hServiceStatus;
SERVICE_STATUS status;
DWORD dwThreadID;
2)初始化服务句柄
void init()
{
hEvent = CreateEvent(NULL, TRUE, FALSE,NULL);
hServiceStatus = NULL;
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
status.dwCurrentState = SERVICE_START_PENDING;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
status.dwWin32ExitCode = 0;
status.dwServiceSpecificExitCode = 0;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
}
3)安装和卸载服务和是否安装
是否安装过服务:
BOOL IsInstalled()
{
BOOL bResult = FALSE;
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
/*CString errorno;
errorno.Format("%d", GetLastError());
AfxMessageBox(errno);*/
if (hSCM != NULL)
{
SC_HANDLE hService = ::OpenService(hSCM,szServiceName,SERVICE_QUERY_CONFIG);
if (hService != NULL)
{
bResult = TRUE;
::CloseServiceHandle(hService);
}
::CloseServiceHandle(hSCM);
}
else {
AfxMessageBox("服务出现异常不能打开");
return FALSE;
}
return bResult;
}
安装服务:
BOOL Install()
{
//这里列出主要的两个函数,其它的可以在代码里找。
if (IsInstalled())
return TRUE;
//打开服务控制管理器
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
AfxMessageBox("不能打开服务");
return FALSE;
}
//创建服务
CHAR szFilePath[MAX_PATH];
::GetModuleFileName(NULL, szFilePath, MAX_PATH);
SC_HANDLE hService = ::CreateService(
hSCM, szServiceName, szServiceName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
szFilePath, NULL, NULL, "", NULL, NULL);
CString errorno;
errorno.Format("%d",GetLastError());
if (errorno == "1073")
{
AfxMessageBox("指定的服务已经存在");
return false;
}
else if(hService == NULL){
AfxMessageBox("服务打开失败");
return false;
}
::CloseServiceHandle(hService);
::CloseServiceHandle(hSCM);
return TRUE;
}
卸载服务
BOOL Uninstall()
{
//这里列出主要的两个函数,其它的可以在代码里找。
//打开服务控制管理器
BOOL result = FALSE;
SC_HANDLE hSCM = ::OpenService(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM != NULL) {
SC_HANDLE hService = ::OpenService(hSCM, szServiceName, SERVICE_QUERY_CONFIG);
if (hService != NULL) {
OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
//打开服务
OpenService(hSCM, szServiceName, SERVICE_STOP | DELETE);
//停止服务
ControlService(hService, SERVICE_CONTROL_STOP, &status);
//删除服务
DeleteService(hService);
result = TRUE;
return result;
}
}
return result;
}
小结:
把握住几个核心的函数
打开服务前 必须 OpenSCManager 打开服务管理器,然后才能OpenService,创建服务的时候必须也是要先OpenSCManager 然后才能CreateService,卸载服务的几个核心函数 也是 OpenSCManager,OpenService,ControlService,DeleteService,最后就是windows 上句柄资源是十分珍贵的 我们用完了必须要及时Close 释放掉。
4)服务程序主函数ServiceMain
服务ServiceMain函数 当一个服务控制程序请求开启一个新的服务时,SCM(服务控制管理器)开启服务的同时,向控制调度器发送一个开始请求。控制调度器为服务创建一个新的线程来运行ServiceMain函数。
ServiceMain函数应该执行下面的这些任务:
1、立刻为服务调用RegisterServiceCtrlHandlerEx函数,用来注册一个处理控制请求的HandlerEx函数。RegisterServiceCtrlHandlerEx函数的返回值是一个service status handle(服务状态句柄),稍后向SCM通知当前服务状态会用到。
2、执行初始化。如果初始化的时间非常短(小于一秒),可以直接在ServiceMain函数中完成。
如果预期初始化的时间会比一秒长,调用SetServiceStatus函数,在SERVICESTATUS结构中指明等待间隔,以及当前的状态是SERVICESTART_PENDING。当初始化继续时,服务应该再调用SetServiceStatus函数来报告当前状态。多次调用SetServiceStatus函数对调试服务很有用。
3、初始化结束后,调用SetServiceStatus函数,在SERVICESTATUS结构中指明SERVICERUNNING状态。
4、执行服务的任务,或者已经没有未完成的任务,那就返回。服务状态有任何改变,都要保证调用SetServiceStatus函数来报告新的状态。
5、如果在初始化或者运行的过程中遇到错误并且清理的过程会很长,服务应该调用SetServiceStatus函数,在SERVICESTATUS结构中指定SERVICESTOPPENDING状态。一旦清理结束,在最后中止的线程中调用SetServiceStatus函数,在SERVICESTATUS结构中指定SERVICESTOPPED状态。确保向SERVICESTATUS结构里的dwServiceSpecificExitCode和dwWin32ExitCode赋值,来标志错误。
void WINAPI ServiceMain()
{
// Register the control request handler
status.dwCurrentState = SERVICE_START_PENDING;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;//这个要使用,否则你不能控制
//注册服务控制
hServiceStatus = RegisterServiceCtrlHandler(szServiceName, ServiceStrl);
if (hServiceStatus == NULL)
{
LogEvent(_T("Handler not installed"));
return;
}
SetServiceStatus(hServiceStatus, &status);
status.dwWin32ExitCode = S_OK;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
status.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hServiceStatus, &status);
//模拟服务的运行,10后自动退出。应用时将主要任务放于此即可
int i = 0;
while (i < 10)
{
Sleep(1000);
i++;
}
//
status.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hServiceStatus, &status);
LogEvent(_T("Service stopped"));
}
void WINAPI ServiceStrl(DWORD dwOpcode)
{
switch (dwOpcode)
{
case SERVICE_CONTROL_STOP:
status.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(hServiceStatus, &status);
PostThreadMessage(dwThreadID, WM_CLOSE, 0, 0);
//::PostMessage(dlg->m_hWnd,WM_ISER_CLOSE);
break;
case SERVICE_CONTROL_PAUSE:
break;
case SERVICE_CONTROL_CONTINUE:
break;
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
break;
default:
LogEvent(("Bad service request"));
}
}
2.对话框和非模态对话框(其实有的时候服务程序我任务比不上隐藏的非模态的程序)
1) 模态对话框 是非常简单的
dlg.DoModal();
2)非模态对话框
CbigScreenDownloadDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.Create(IDD_BIGSCREENDOWNLOAD_DIALOG);
dlg.ShowWindow(SW_HIDE);
dlg.RunModalLoop();
3.windows 软件开机自动运行,其实就是写入注册表
BOOL AutoBootSet()
{
HKEY hKey;
CString lpRun = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
long lRet = RegOpenKeyEx(HKEY_CURRENT_USER, lpRun, 0, KEY_ALL_ACCESS, &hKey);
if (lRet == ERROR_SUCCESS)
{
CHAR pFileName[MAX_PATH];
//获取程序自身的路径
DWORD dwRet = GetModuleFileName(NULL, pFileName, MAX_PATH);
/* _tcscat_s(pFileName, "-auto");*/
//添加一个子Key,并设置值, 下面应用程序名字(不加后缀.exe)
lRet = RegSetValueEx(hKey,"bigScreenRelease",0, REG_SZ, (const BYTE*)(LPCSTR)pFileName, (strlen(pFileName)));
//关闭注册表
RegCloseKey(hKey);
if (lRet != ERROR_SUCCESS)
{
return FALSE;
}
return TRUE;
}
return FALSE;
}
RegSetValueEx写入注册表 RegCloseKey 关闭注册表